openMSX
imgui.cc
Go to the documentation of this file.
1// dear imgui, v1.91.0
2// (main code and documentation)
3
4// Help:
5// - See links below.
6// - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that.
7// - Read top of imgui.cpp for more details, links and comments.
8
9// Resources:
10// - FAQ ........................ https://dearimgui.com/faq (in repository as docs/FAQ.md)
11// - Homepage ................... https://github.com/ocornut/imgui
12// - Releases & changelog ....... https://github.com/ocornut/imgui/releases
13// - Gallery .................... https://github.com/ocornut/imgui/issues/7503 (please post your screenshots/video there!)
14// - Wiki ....................... https://github.com/ocornut/imgui/wiki (lots of good stuff there)
15// - Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started (how to integrate in an existing app by adding ~25 lines of code)
16// - Third-party Extensions https://github.com/ocornut/imgui/wiki/Useful-Extensions (ImPlot & many more)
17// - Bindings/Backends https://github.com/ocornut/imgui/wiki/Bindings (language bindings, backends for various tech/engines)
18// - Glossary https://github.com/ocornut/imgui/wiki/Glossary
19// - Debug Tools https://github.com/ocornut/imgui/wiki/Debug-Tools
20// - Software using Dear ImGui https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui
21// - Issues & support ........... https://github.com/ocornut/imgui/issues
22// - Test Engine & Automation ... https://github.com/ocornut/imgui_test_engine (test suite, test engine to automate your apps)
23
24// For first-time users having issues compiling/linking/running/loading fonts:
25// please post in https://github.com/ocornut/imgui/discussions if you cannot find a solution in resources above.
26// Everything else should be asked in 'Issues'! We are building a database of cross-linked knowledge there.
27
28// Copyright (c) 2014-2024 Omar Cornut
29// Developed by Omar Cornut and every direct or indirect contributors to the GitHub.
30// See LICENSE.txt for copyright and licensing details (standard MIT License).
31// This library is free but needs your support to sustain development and maintenance.
32// Businesses: you can support continued development via B2B invoiced technical support, maintenance and sponsoring contracts.
33// PLEASE reach out at omar AT dearimgui DOT com. See https://github.com/ocornut/imgui/wiki/Funding
34// Businesses: you can also purchase licenses for the Dear ImGui Automation/Test Engine.
35
36// It is recommended that you don't modify imgui.cpp! It will become difficult for you to update the library.
37// Note that 'ImGui::' being a namespace, you can add functions into the namespace from your own source files, without
38// modifying imgui.h or imgui.cpp. You may include imgui_internal.h to access internal data structures, but it doesn't
39// come with any guarantee of forward compatibility. Discussing your changes on the GitHub Issue Tracker may lead you
40// to a better solution or official support for them.
41
42/*
43
44Index of this file:
45
46DOCUMENTATION
47
48- MISSION STATEMENT
49- CONTROLS GUIDE
50- PROGRAMMER GUIDE
51 - READ FIRST
52 - HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI
53 - GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE
54 - HOW A SIMPLE APPLICATION MAY LOOK LIKE
55 - HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE
56- API BREAKING CHANGES (read me when you update!)
57- FREQUENTLY ASKED QUESTIONS (FAQ)
58 - Read all answers online: https://www.dearimgui.com/faq, or in docs/FAQ.md (with a Markdown viewer)
59
60CODE
61(search for "[SECTION]" in the code to find them)
62
63// [SECTION] INCLUDES
64// [SECTION] FORWARD DECLARATIONS
65// [SECTION] CONTEXT AND MEMORY ALLOCATORS
66// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO)
67// [SECTION] MISC HELPERS/UTILITIES (Geometry functions)
68// [SECTION] MISC HELPERS/UTILITIES (String, Format, Hash functions)
69// [SECTION] MISC HELPERS/UTILITIES (File functions)
70// [SECTION] MISC HELPERS/UTILITIES (ImText* functions)
71// [SECTION] MISC HELPERS/UTILITIES (Color functions)
72// [SECTION] ImGuiStorage
73// [SECTION] ImGuiTextFilter
74// [SECTION] ImGuiTextBuffer, ImGuiTextIndex
75// [SECTION] ImGuiListClipper
76// [SECTION] STYLING
77// [SECTION] RENDER HELPERS
78// [SECTION] INITIALIZATION, SHUTDOWN
79// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!)
80// [SECTION] ID STACK
81// [SECTION] INPUTS
82// [SECTION] ERROR CHECKING
83// [SECTION] ITEM SUBMISSION
84// [SECTION] LAYOUT
85// [SECTION] SCROLLING
86// [SECTION] TOOLTIPS
87// [SECTION] POPUPS
88// [SECTION] KEYBOARD/GAMEPAD NAVIGATION
89// [SECTION] DRAG AND DROP
90// [SECTION] LOGGING/CAPTURING
91// [SECTION] SETTINGS
92// [SECTION] LOCALIZATION
93// [SECTION] VIEWPORTS, PLATFORM WINDOWS
94// [SECTION] DOCKING
95// [SECTION] PLATFORM DEPENDENT HELPERS
96// [SECTION] METRICS/DEBUGGER WINDOW
97// [SECTION] DEBUG LOG WINDOW
98// [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, ID STACK TOOL)
99
100*/
101
102//-----------------------------------------------------------------------------
103// DOCUMENTATION
104//-----------------------------------------------------------------------------
105
106/*
107
108 MISSION STATEMENT
109 =================
110
111 - Easy to use to create code-driven and data-driven tools.
112 - Easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools.
113 - Easy to hack and improve.
114 - Minimize setup and maintenance.
115 - Minimize state storage on user side.
116 - Minimize state synchronization.
117 - Portable, minimize dependencies, run on target (consoles, phones, etc.).
118 - Efficient runtime and memory consumption.
119
120 Designed primarily for developers and content-creators, not the typical end-user!
121 Some of the current weaknesses (which we aim to address in the future) includes:
122
123 - Doesn't look fancy.
124 - Limited layout features, intricate layouts are typically crafted in code.
125
126
127 CONTROLS GUIDE
128 ==============
129
130 - MOUSE CONTROLS
131 - Mouse wheel: Scroll vertically.
132 - SHIFT+Mouse wheel: Scroll horizontally.
133 - Click [X]: Close a window, available when 'bool* p_open' is passed to ImGui::Begin().
134 - Click ^, Double-Click title: Collapse window.
135 - Drag on corner/border: Resize window (double-click to auto fit window to its contents).
136 - Drag on any empty space: Move window (unless io.ConfigWindowsMoveFromTitleBarOnly = true).
137 - Left-click outside popup: Close popup stack (right-click over underlying popup: Partially close popup stack).
138
139 - TEXT EDITOR
140 - Hold SHIFT or Drag Mouse: Select text.
141 - CTRL+Left/Right: Word jump.
142 - CTRL+Shift+Left/Right: Select words.
143 - CTRL+A or Double-Click: Select All.
144 - CTRL+X, CTRL+C, CTRL+V: Use OS clipboard.
145 - CTRL+Z, CTRL+Y: Undo, Redo.
146 - ESCAPE: Revert text to its original value.
147 - On OSX, controls are automatically adjusted to match standard OSX text editing 2ts and behaviors.
148
149 - KEYBOARD CONTROLS
150 - Basic:
151 - Tab, SHIFT+Tab Cycle through text editable fields.
152 - CTRL+Tab, CTRL+Shift+Tab Cycle through windows.
153 - CTRL+Click Input text into a Slider or Drag widget.
154 - Extended features with `io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard`:
155 - Tab, SHIFT+Tab: Cycle through every items.
156 - Arrow keys Move through items using directional navigation. Tweak value.
157 - Arrow keys + Alt, Shift Tweak slower, tweak faster (when using arrow keys).
158 - Enter Activate item (prefer text input when possible).
159 - Space Activate item (prefer tweaking with arrows when possible).
160 - Escape Deactivate item, leave child window, close popup.
161 - Page Up, Page Down Previous page, next page.
162 - Home, End Scroll to top, scroll to bottom.
163 - Alt Toggle between scrolling layer and menu layer.
164 - CTRL+Tab then Ctrl+Arrows Move window. Hold SHIFT to resize instead of moving.
165 - Output when ImGuiConfigFlags_NavEnableKeyboard set,
166 - io.WantCaptureKeyboard flag is set when keyboard is claimed.
167 - io.NavActive: true when a window is focused and it doesn't have the ImGuiWindowFlags_NoNavInputs flag set.
168 - io.NavVisible: true when the navigation cursor is visible (usually goes to back false when mouse is used).
169
170 - GAMEPAD CONTROLS
171 - Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
172 - Particularly useful to use Dear ImGui on a console system (e.g. PlayStation, Switch, Xbox) without a mouse!
173 - Download controller mapping PNG/PSD at http://dearimgui.com/controls_sheets
174 - Backend support: backend needs to:
175 - Set 'io.BackendFlags |= ImGuiBackendFlags_HasGamepad' + call io.AddKeyEvent/AddKeyAnalogEvent() with ImGuiKey_Gamepad_XXX keys.
176 - For analog values (0.0f to 1.0f), backend is responsible to handling a dead-zone and rescaling inputs accordingly.
177 Backend code will probably need to transform your raw inputs (such as e.g. remapping your 0.2..0.9 raw input range to 0.0..1.0 imgui range, etc.).
178 - BEFORE 1.87, BACKENDS USED TO WRITE TO io.NavInputs[]. This is now obsolete. Please call io functions instead!
179 - If you need to share inputs between your game and the Dear ImGui interface, the easiest approach is to go all-or-nothing,
180 with a buttons combo to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved.
181
182 - REMOTE INPUTS SHARING & MOUSE EMULATION
183 - PS4/PS5 users: Consider emulating a mouse cursor with DualShock touch pad or a spare analog stick as a mouse-emulation fallback.
184 - Consoles/Tablet/Phone users: Consider using a Synergy 1.x server (on your PC) + run examples/libs/synergy/uSynergy.c (on your console/tablet/phone app)
185 in order to share your PC mouse/keyboard.
186 - See https://github.com/ocornut/imgui/wiki/Useful-Extensions#remoting for other remoting solutions.
187 - On a TV/console system where readability may be lower or mouse inputs may be awkward, you may want to set the ImGuiConfigFlags_NavEnableSetMousePos flag.
188 Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs Dear ImGui to move your mouse cursor along with navigation movements.
189 When enabled, the NewFrame() function may alter 'io.MousePos' and set 'io.WantSetMousePos' to notify you that it wants the mouse cursor to be moved.
190 When that happens your backend NEEDS to move the OS or underlying mouse cursor on the next frame. Some of the backends in examples/ do that.
191 (If you set the NavEnableSetMousePos flag but don't honor 'io.WantSetMousePos' properly, Dear ImGui will misbehave as it will see your mouse moving back & forth!)
192 (In a setup when you may not have easy control over the mouse cursor, e.g. uSynergy.c doesn't expose moving remote mouse cursor, you may want
193 to set a boolean to ignore your other external mouse positions until the external source is moved again.)
194
195
196 PROGRAMMER GUIDE
197 ================
198
199 READ FIRST
200 ----------
201 - Remember to check the wonderful Wiki (https://github.com/ocornut/imgui/wiki)
202 - Your code creates the UI every frame of your application loop, if your code doesn't run the UI is gone!
203 The UI can be highly dynamic, there are no construction or destruction steps, less superfluous
204 data retention on your side, less state duplication, less state synchronization, fewer bugs.
205 - Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features.
206 Or browse https://pthom.github.io/imgui_manual_online/manual/imgui_manual.html for interactive web version.
207 - The library is designed to be built from sources. Avoid pre-compiled binaries and packaged versions. See imconfig.h to configure your build.
208 - Dear ImGui is an implementation of the IMGUI paradigm (immediate-mode graphical user interface, a term coined by Casey Muratori).
209 You can learn about IMGUI principles at http://www.johno.se/book/imgui.html, http://mollyrocket.com/861 & more links in Wiki.
210 - Dear ImGui is a "single pass" rasterizing implementation of the IMGUI paradigm, aimed at ease of use and high-performances.
211 For every application frame, your UI code will be called only once. This is in contrast to e.g. Unity's implementation of an IMGUI,
212 where the UI code is called multiple times ("multiple passes") from a single entry point. There are pros and cons to both approaches.
213 - Our origin is on the top-left. In axis aligned bounding boxes, Min = top-left, Max = bottom-right.
214 - Please make sure you have asserts enabled (IM_ASSERT redirects to assert() by default, but can be redirected).
215 If you get an assert, read the messages and comments around the assert.
216 - This codebase aims to be highly optimized:
217 - A typical idle frame should never call malloc/free.
218 - We rely on a maximum of constant-time or O(N) algorithms. Limiting searches/scans as much as possible.
219 - We put particular energy in making sure performances are decent with typical "Debug" build settings as well.
220 Which mean we tend to avoid over-relying on "zero-cost abstraction" as they aren't zero-cost at all.
221 - This codebase aims to be both highly opinionated and highly flexible:
222 - This code works because of the things it choose to solve or not solve.
223 - C++: this is a pragmatic C-ish codebase: we don't use fancy C++ features, we don't include C++ headers,
224 and ImGui:: is a namespace. We rarely use member functions (and when we did, I am mostly regretting it now).
225 This is to increase compatibility, increase maintainability and facilitate use from other languages.
226 - C++: ImVec2/ImVec4 do not expose math operators by default, because it is expected that you use your own math types.
227 See FAQ "How can I use my own math types instead of ImVec2/ImVec4?" for details about setting up imconfig.h for that.
228 We can can optionally export math operators for ImVec2/ImVec4 using IMGUI_DEFINE_MATH_OPERATORS, which we use internally.
229 - C++: pay attention that ImVector<> manipulates plain-old-data and does not honor construction/destruction
230 (so don't use ImVector in your code or at our own risk!).
231 - Building: We don't use nor mandate a build system for the main library.
232 This is in an effort to ensure that it works in the real world aka with any esoteric build setup.
233 This is also because providing a build system for the main library would be of little-value.
234 The build problems are almost never coming from the main library but from specific backends.
235
236
237 HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI
238 ----------------------------------------------
239 - Update submodule or copy/overwrite every file.
240 - About imconfig.h:
241 - You may modify your copy of imconfig.h, in this case don't overwrite it.
242 - or you may locally branch to modify imconfig.h and merge/rebase latest.
243 - or you may '#define IMGUI_USER_CONFIG "my_config_file.h"' globally from your build system to
244 specify a custom path for your imconfig.h file and instead not have to modify the default one.
245
246 - Overwrite all the sources files except for imconfig.h (if you have modified your copy of imconfig.h)
247 - Or maintain your own branch where you have imconfig.h modified as a top-most commit which you can regularly rebase over "master".
248 - You can also use '#define IMGUI_USER_CONFIG "my_config_file.h" to redirect configuration to your own file.
249 - Read the "API BREAKING CHANGES" section (below). This is where we list occasional API breaking changes.
250 If a function/type has been renamed / or marked obsolete, try to fix the name in your code before it is permanently removed
251 from the public API. If you have a problem with a missing function/symbols, search for its name in the code, there will
252 likely be a comment about it. Please report any issue to the GitHub page!
253 - To find out usage of old API, you can add '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' in your configuration file.
254 - Try to keep your copy of Dear ImGui reasonably up to date!
255
256
257 GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE
258 ---------------------------------------------------------------
259 - See https://github.com/ocornut/imgui/wiki/Getting-Started.
260 - Run and study the examples and demo in imgui_demo.cpp to get acquainted with the library.
261 - In the majority of cases you should be able to use unmodified backends files available in the backends/ folder.
262 - Add the Dear ImGui source files + selected backend source files to your projects or using your preferred build system.
263 It is recommended you build and statically link the .cpp files as part of your project and NOT as a shared library (DLL).
264 - You can later customize the imconfig.h file to tweak some compile-time behavior, such as integrating Dear ImGui types with your own maths types.
265 - When using Dear ImGui, your programming IDE is your friend: follow the declaration of variables, functions and types to find comments about them.
266 - Dear ImGui never touches or knows about your GPU state. The only function that knows about GPU is the draw function that you provide.
267 Effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render"
268 phases of your own application. All rendering information is stored into command-lists that you will retrieve after calling ImGui::Render().
269 - Refer to the backends and demo applications in the examples/ folder for instruction on how to setup your code.
270 - If you are running over a standard OS with a common graphics API, you should be able to use unmodified imgui_impl_*** files from the examples/ folder.
271
272
273 HOW A SIMPLE APPLICATION MAY LOOK LIKE
274 --------------------------------------
275 EXHIBIT 1: USING THE EXAMPLE BACKENDS (= imgui_impl_XXX.cpp files from the backends/ folder).
276 The sub-folders in examples/ contain examples applications following this structure.
277
278 // Application init: create a dear imgui context, setup some options, load fonts
279 ImGui::CreateContext();
280 ImGuiIO& io = ImGui::GetIO();
281 // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls.
282 // TODO: Fill optional fields of the io structure later.
283 // TODO: Load TTF/OTF fonts if you don't want to use the default font.
284
285 // Initialize helper Platform and Renderer backends (here we are using imgui_impl_win32.cpp and imgui_impl_dx11.cpp)
286 ImGui_ImplWin32_Init(hwnd);
287 ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);
288
289 // Application main loop
290 while (true)
291 {
292 // Feed inputs to dear imgui, start new frame
293 ImGui_ImplDX11_NewFrame();
294 ImGui_ImplWin32_NewFrame();
295 ImGui::NewFrame();
296
297 // Any application code here
298 ImGui::Text("Hello, world!");
299
300 // Render dear imgui into screen
301 ImGui::Render();
302 ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
303 g_pSwapChain->Present(1, 0);
304 }
305
306 // Shutdown
307 ImGui_ImplDX11_Shutdown();
308 ImGui_ImplWin32_Shutdown();
309 ImGui::DestroyContext();
310
311 EXHIBIT 2: IMPLEMENTING CUSTOM BACKEND / CUSTOM ENGINE
312
313 // Application init: create a dear imgui context, setup some options, load fonts
314 ImGui::CreateContext();
315 ImGuiIO& io = ImGui::GetIO();
316 // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls.
317 // TODO: Fill optional fields of the io structure later.
318 // TODO: Load TTF/OTF fonts if you don't want to use the default font.
319
320 // Build and load the texture atlas into a texture
321 // (In the examples/ app this is usually done within the ImGui_ImplXXX_Init() function from one of the demo Renderer)
322 int width, height;
323 unsigned char* pixels = nullptr;
324 io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
325
326 // At this point you've got the texture data and you need to upload that to your graphic system:
327 // After we have created the texture, store its pointer/identifier (_in whichever format your engine uses_) in 'io.Fonts->TexID'.
328 // This will be passed back to your via the renderer. Basically ImTextureID == void*. Read FAQ for details about ImTextureID.
329 MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA32)
330 io.Fonts->SetTexID((void*)texture);
331
332 // Application main loop
333 while (true)
334 {
335 // Setup low-level inputs, e.g. on Win32: calling GetKeyboardState(), or write to those fields from your Windows message handlers, etc.
336 // (In the examples/ app this is usually done within the ImGui_ImplXXX_NewFrame() function from one of the demo Platform Backends)
337 io.DeltaTime = 1.0f/60.0f; // set the time elapsed since the previous frame (in seconds)
338 io.DisplaySize.x = 1920.0f; // set the current display width
339 io.DisplaySize.y = 1280.0f; // set the current display height here
340 io.AddMousePosEvent(mouse_x, mouse_y); // update mouse position
341 io.AddMouseButtonEvent(0, mouse_b[0]); // update mouse button states
342 io.AddMouseButtonEvent(1, mouse_b[1]); // update mouse button states
343
344 // Call NewFrame(), after this point you can use ImGui::* functions anytime
345 // (So you want to try calling NewFrame() as early as you can in your main loop to be able to use Dear ImGui everywhere)
346 ImGui::NewFrame();
347
348 // Most of your application code here
349 ImGui::Text("Hello, world!");
350 MyGameUpdate(); // may use any Dear ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End();
351 MyGameRender(); // may use any Dear ImGui functions as well!
352
353 // Render dear imgui, swap buffers
354 // (You want to try calling EndFrame/Render as late as you can, to be able to use Dear ImGui in your own game rendering code)
355 ImGui::EndFrame();
356 ImGui::Render();
357 ImDrawData* draw_data = ImGui::GetDrawData();
358 MyImGuiRenderFunction(draw_data);
359 SwapBuffers();
360 }
361
362 // Shutdown
363 ImGui::DestroyContext();
364
365 To decide whether to dispatch mouse/keyboard inputs to Dear ImGui to the rest of your application,
366 you should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags!
367 Please read the FAQ entry "How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application?" about this.
368
369
370 HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE
371 ---------------------------------------------
372 The backends in impl_impl_XXX.cpp files contain many working implementations of a rendering function.
373
374 void MyImGuiRenderFunction(ImDrawData* draw_data)
375 {
376 // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled
377 // TODO: Setup texture sampling state: sample with bilinear filtering (NOT point/nearest filtering). Use 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines;' to allow point/nearest filtering.
378 // TODO: Setup viewport covering draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize
379 // TODO: Setup orthographic projection matrix cover draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize
380 // TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color.
381 ImVec2 clip_off = draw_data->DisplayPos;
382 for (int n = 0; n < draw_data->CmdListsCount; n++)
383 {
384 const ImDrawList* cmd_list = draw_data->CmdLists[n];
385 const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; // vertex buffer generated by Dear ImGui
386 const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; // index buffer generated by Dear ImGui
387 for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
388 {
389 const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
390 if (pcmd->UserCallback)
391 {
392 pcmd->UserCallback(cmd_list, pcmd);
393 }
394 else
395 {
396 // Project scissor/clipping rectangles into framebuffer space
397 ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
398 ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
399 if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
400 continue;
401
402 // We are using scissoring to clip some objects. All low-level graphics API should support it.
403 // - If your engine doesn't support scissoring yet, you may ignore this at first. You will get some small glitches
404 // (some elements visible outside their bounds) but you can fix that once everything else works!
405 // - Clipping coordinates are provided in imgui coordinates space:
406 // - For a given viewport, draw_data->DisplayPos == viewport->Pos and draw_data->DisplaySize == viewport->Size
407 // - In a single viewport application, draw_data->DisplayPos == (0,0) and draw_data->DisplaySize == io.DisplaySize, but always use GetMainViewport()->Pos/Size instead of hardcoding those values.
408 // - In the interest of supporting multi-viewport applications (see 'docking' branch on github),
409 // always subtract draw_data->DisplayPos from clipping bounds to convert them to your viewport space.
410 // - Note that pcmd->ClipRect contains Min+Max bounds. Some graphics API may use Min+Max, other may use Min+Size (size being Max-Min)
411 MyEngineSetScissor(clip_min.x, clip_min.y, clip_max.x, clip_max.y);
412
413 // The texture for the draw call is specified by pcmd->GetTexID().
414 // The vast majority of draw calls will use the Dear ImGui texture atlas, which value you have set yourself during initialization.
415 MyEngineBindTexture((MyTexture*)pcmd->GetTexID());
416
417 // Render 'pcmd->ElemCount/3' indexed triangles.
418 // By default the indices ImDrawIdx are 16-bit, you can change them to 32-bit in imconfig.h if your engine doesn't support 16-bit indices.
419 MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer + pcmd->IdxOffset, vtx_buffer, pcmd->VtxOffset);
420 }
421 }
422 }
423 }
424
425
426 API BREAKING CHANGES
427 ====================
428
429 Occasionally introducing changes that are breaking the API. We try to make the breakage minor and easy to fix.
430 Below is a change-log of API breaking changes only. If you are using one of the functions listed, expect to have to fix some code.
431 When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files.
432 You can read releases logs https://github.com/ocornut/imgui/releases for more details.
433
434(Docking/Viewport Branch)
435 - 2024/XX/XX (1.XXXX) - when multi-viewports are enabled, all positions will be in your natural OS coordinates space. It means that:
436 - reference to hard-coded positions such as in SetNextWindowPos(ImVec2(0,0)) are probably not what you want anymore.
437 you may use GetMainViewport()->Pos to offset hard-coded positions, e.g. SetNextWindowPos(GetMainViewport()->Pos)
438 - likewise io.MousePos and GetMousePos() will use OS coordinates.
439 If you query mouse positions to interact with non-imgui coordinates you will need to offset them, e.g. subtract GetWindowViewport()->Pos.
440
441 - 2024/07/25 (1.91.0) - obsoleted GetContentRegionMax(), GetWindowContentRegionMin() and GetWindowContentRegionMax(). (see #7838 on GitHub for more info)
442 you should never need those functions. you can do everything with GetCursorScreenPos() and GetContentRegionAvail() in a more simple way.
443 - instead of: GetWindowContentRegionMax().x - GetCursorPos().x
444 - you can use: GetContentRegionAvail().x
445 - instead of: GetWindowContentRegionMax().x + GetWindowPos().x
446 - you can use: GetCursorScreenPos().x + GetContentRegionAvail().x // when called from left edge of window
447 - instead of: GetContentRegionMax()
448 - you can use: GetContentRegionAvail() + GetCursorScreenPos() - GetWindowPos() // right edge in local coordinates
449 - instead of: GetWindowContentRegionMax().x - GetWindowContentRegionMin().x
450 - you can use: GetContentRegionAvail() // when called from left edge of window
451 - 2024/07/15 (1.91.0) - renamed ImGuiSelectableFlags_DontClosePopups to ImGuiSelectableFlags_NoAutoClosePopups. (#1379, #1468, #2200, #4936, #5216, #7302, #7573)
452 (internals: also renamed ImGuiItemFlags_SelectableDontClosePopup into ImGuiItemFlags_AutoClosePopups with inverted behaviors)
453 - 2024/07/15 (1.91.0) - obsoleted PushButtonRepeat()/PopButtonRepeat() in favor of using new PushItemFlag(ImGuiItemFlags_ButtonRepeat, ...)/PopItemFlag().
454 - 2024/07/02 (1.91.0) - commented out obsolete ImGuiModFlags (renamed to ImGuiKeyChord in 1.89). (#4921, #456)
455 - commented out obsolete ImGuiModFlags_XXX values (renamed to ImGuiMod_XXX in 1.89). (#4921, #456)
456 - ImGuiModFlags_Ctrl -> ImGuiMod_Ctrl, ImGuiModFlags_Shift -> ImGuiMod_Shift etc.
457 - 2024/07/02 (1.91.0) - IO, IME: renamed platform IME hook and added explicit context for consistency and future-proofness.
458 - old: io.SetPlatformImeDataFn(ImGuiViewport* viewport, ImGuiPlatformImeData* data);
459 - new: io.PlatformSetImeDataFn(ImGuiContext* ctx, ImGuiViewport* viewport, ImGuiPlatformImeData* data);
460 - 2024/06/21 (1.90.9) - BeginChild: added ImGuiChildFlags_NavFlattened as a replacement for the window flag ImGuiWindowFlags_NavFlattened: the feature only ever made sense for BeginChild() anyhow.
461 - old: BeginChild("Name", size, 0, ImGuiWindowFlags_NavFlattened);
462 - new: BeginChild("Name", size, ImGuiChildFlags_NavFlattened, 0);
463 - 2024/06/21 (1.90.9) - io: ClearInputKeys() (first exposed in 1.89.8) doesn't clear mouse data, newly added ClearInputMouse() does.
464 - 2024/06/20 (1.90.9) - renamed ImGuiDragDropFlags_SourceAutoExpirePayload to ImGuiDragDropFlags_PayloadAutoExpire.
465 - 2024/06/18 (1.90.9) - style: renamed ImGuiCol_TabActive -> ImGuiCol_TabSelected, ImGuiCol_TabUnfocused -> ImGuiCol_TabDimmed, ImGuiCol_TabUnfocusedActive -> ImGuiCol_TabDimmedSelected.
466 - 2024/06/10 (1.90.9) - removed old nested structure: renaming ImGuiStorage::ImGuiStoragePair type to ImGuiStoragePair (simpler for many languages).
467 - 2024/06/06 (1.90.8) - reordered ImGuiInputTextFlags values. This should not be breaking unless you are using generated headers that have values not matching the main library.
468 - 2024/06/06 (1.90.8) - removed 'ImGuiButtonFlags_MouseButtonDefault_ = ImGuiButtonFlags_MouseButtonLeft', was mostly unused and misleading.
469 - 2024/05/27 (1.90.7) - commented out obsolete symbols marked obsolete in 1.88 (May 2022):
470 - old: CaptureKeyboardFromApp(bool)
471 - new: SetNextFrameWantCaptureKeyboard(bool)
472 - old: CaptureMouseFromApp(bool)
473 - new: SetNextFrameWantCaptureMouse(bool)
474 - 2024/05/22 (1.90.7) - inputs (internals): renamed ImGuiKeyOwner_None to ImGuiKeyOwner_NoOwner, to make use more explicit and reduce confusion with the default it is a non-zero value and cannot be the default value (never made public, but disclosing as I expect a few users caught on owner-aware inputs).
475 - inputs (internals): renamed ImGuiInputFlags_RouteGlobalLow -> ImGuiInputFlags_RouteGlobal, ImGuiInputFlags_RouteGlobal -> ImGuiInputFlags_RouteGlobalOverFocused, ImGuiInputFlags_RouteGlobalHigh -> ImGuiInputFlags_RouteGlobalHighest.
476 - inputs (internals): Shortcut(), SetShortcutRouting(): swapped last two parameters order in function signatures:
477 - old: Shortcut(ImGuiKeyChord key_chord, ImGuiID owner_id = 0, ImGuiInputFlags flags = 0);
478 - new: Shortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags = 0, ImGuiID owner_id = 0);
479 - inputs (internals): owner-aware versions of IsKeyPressed(), IsKeyChordPressed(), IsMouseClicked(): swapped last two parameters order in function signatures.
480 - old: IsKeyPressed(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags = 0);
481 - new: IsKeyPressed(ImGuiKey key, ImGuiInputFlags flags, ImGuiID owner_id = 0);
482 - old: IsMouseClicked(ImGuiMouseButton button, ImGuiID owner_id, ImGuiInputFlags flags = 0);
483 - new: IsMouseClicked(ImGuiMouseButton button, ImGuiInputFlags flags, ImGuiID owner_id = 0);
484 for various reasons those changes makes sense. They are being made because making some of those API public.
485 only past users of imgui_internal.h with the extra parameters will be affected. Added asserts for valid flags in various functions to detect _some_ misuses, BUT NOT ALL.
486 - 2024/05/21 (1.90.7) - docking: changed signature of DockSpaceOverViewport() to add explicit dockspace id if desired. pass 0 to use old behavior. (#7611)
487 - old: DockSpaceOverViewport(const ImGuiViewport* viewport = NULL, ImGuiDockNodeFlags flags = 0, ...);
488 - new: DockSpaceOverViewport(ImGuiID dockspace_id = 0, const ImGuiViewport* viewport = NULL, ImGuiDockNodeFlags flags = 0, ...);
489 - 2024/05/16 (1.90.7) - inputs: on macOS X, Cmd and Ctrl keys are now automatically swapped by io.AddKeyEvent() as this naturally align with how macOS X uses those keys.
490 - it shouldn't really affect you unless you had custom shortcut swapping in place for macOS X apps.
491 - removed ImGuiMod_Shortcut which was previously dynamically remapping to Ctrl or Cmd/Super. It is now unnecessary to specific cross-platform idiomatic shortcuts. (#2343, #4084, #5923, #456)
492 - 2024/05/14 (1.90.7) - backends: SDL_Renderer2 and SDL_Renderer3 backend now take a SDL_Renderer* in their RenderDrawData() functions.
493 - 2024/04/18 (1.90.6) - TreeNode: Fixed a layout inconsistency when using an empty/hidden label followed by a SameLine() call. (#7505, #282)
494 - old: TreeNode("##Hidden"); SameLine(); Text("Hello"); // <-- This was actually incorrect! BUT appeared to look ok with the default style where ItemSpacing.x == FramePadding.x * 2 (it didn't look aligned otherwise).
495 - new: TreeNode("##Hidden"); SameLine(0, 0); Text("Hello"); // <-- This is correct for all styles values.
496 with the fix, IF you were successfully using TreeNode("")+SameLine(); you will now have extra spacing between your TreeNode and the following item.
497 You'll need to change the SameLine() call to SameLine(0,0) to remove this extraneous spacing. This seemed like the more sensible fix that's not making things less consistent.
498 (Note: when using this idiom you are likely to also use ImGuiTreeNodeFlags_SpanAvailWidth).
499 - 2024/03/18 (1.90.5) - merged the radius_x/radius_y parameters in ImDrawList::AddEllipse(), AddEllipseFilled() and PathEllipticalArcTo() into a single ImVec2 parameter. Exceptionally, because those functions were added in 1.90, we are not adding inline redirection functions. The transition is easy and should affect few users. (#2743, #7417)
500 - 2024/03/08 (1.90.5) - inputs: more formally obsoleted GetKeyIndex() when IMGUI_DISABLE_OBSOLETE_FUNCTIONS is set. It has been unnecessary and a no-op since 1.87 (it returns the same value as passed when used with a 1.87+ backend using io.AddKeyEvent() function). (#4921)
501 - IsKeyPressed(GetKeyIndex(ImGuiKey_XXX)) -> use IsKeyPressed(ImGuiKey_XXX)
502 - 2024/01/15 (1.90.2) - commented out obsolete ImGuiIO::ImeWindowHandle marked obsolete in 1.87, favor of writing to 'void* ImGuiViewport::PlatformHandleRaw'.
503 - 2023/12/19 (1.90.1) - commented out obsolete ImGuiKey_KeyPadEnter redirection to ImGuiKey_KeypadEnter.
504 - 2023/11/06 (1.90.1) - removed CalcListClipping() marked obsolete in 1.86. Prefer using ImGuiListClipper which can return non-contiguous ranges.
505 - 2023/11/05 (1.90.1) - imgui_freetype: commented out ImGuiFreeType::BuildFontAtlas() obsoleted in 1.81. prefer using #define IMGUI_ENABLE_FREETYPE or see commented code for manual calls.
506 - 2023/11/05 (1.90.1) - internals,columns: commented out legacy ImGuiColumnsFlags_XXX symbols redirecting to ImGuiOldColumnsFlags_XXX, obsoleted from imgui_internal.h in 1.80.
507 - 2023/11/09 (1.90.0) - removed IM_OFFSETOF() macro in favor of using offsetof() available in C++11. Kept redirection define (will obsolete).
508 - 2023/11/07 (1.90.0) - removed BeginChildFrame()/EndChildFrame() in favor of using BeginChild() with the ImGuiChildFlags_FrameStyle flag. kept inline redirection function (will obsolete).
509 those functions were merely PushStyle/PopStyle helpers, the removal isn't so much motivated by needing to add the feature in BeginChild(), but by the necessity to avoid BeginChildFrame() signature mismatching BeginChild() signature and features.
510 - 2023/11/02 (1.90.0) - BeginChild: upgraded 'bool border = true' parameter to 'ImGuiChildFlags flags' type, added ImGuiChildFlags_Border equivalent. As with our prior "bool-to-flags" API updates, the ImGuiChildFlags_Border value is guaranteed to be == true forever to ensure a smoother transition, meaning all existing calls will still work.
511 - old: BeginChild("Name", size, true)
512 - new: BeginChild("Name", size, ImGuiChildFlags_Border)
513 - old: BeginChild("Name", size, false)
514 - new: BeginChild("Name", size) or BeginChild("Name", 0) or BeginChild("Name", size, ImGuiChildFlags_None)
515 - 2023/11/02 (1.90.0) - BeginChild: added child-flag ImGuiChildFlags_AlwaysUseWindowPadding as a replacement for the window-flag ImGuiWindowFlags_AlwaysUseWindowPadding: the feature only ever made sense for BeginChild() anyhow.
516 - old: BeginChild("Name", size, 0, ImGuiWindowFlags_AlwaysUseWindowPadding);
517 - new: BeginChild("Name", size, ImGuiChildFlags_AlwaysUseWindowPadding, 0);
518 - 2023/09/27 (1.90.0) - io: removed io.MetricsActiveAllocations introduced in 1.63. Same as 'g.DebugMemAllocCount - g.DebugMemFreeCount' (still displayed in Metrics, unlikely to be accessed by end-user).
519 - 2023/09/26 (1.90.0) - debug tools: Renamed ShowStackToolWindow() ("Stack Tool") to ShowIDStackToolWindow() ("ID Stack Tool"), as earlier name was misleading. Kept inline redirection function. (#4631)
520 - 2023/09/15 (1.90.0) - ListBox, Combo: changed signature of "name getter" callback in old one-liner ListBox()/Combo() apis. kept inline redirection function (will obsolete).
521 - old: bool Combo(const char* label, int* current_item, bool (*getter)(void* user_data, int idx, const char** out_text), ...)
522 - new: bool Combo(const char* label, int* current_item, const char* (*getter)(void* user_data, int idx), ...);
523 - old: bool ListBox(const char* label, int* current_item, bool (*getting)(void* user_data, int idx, const char** out_text), ...);
524 - new: bool ListBox(const char* label, int* current_item, const char* (*getter)(void* user_data, int idx), ...);
525 - 2023/09/08 (1.90.0) - commented out obsolete redirecting functions:
526 - GetWindowContentRegionWidth() -> use GetWindowContentRegionMax().x - GetWindowContentRegionMin().x. Consider that generally 'GetContentRegionAvail().x' is more useful.
527 - ImDrawCornerFlags_XXX -> use ImDrawFlags_RoundCornersXXX flags. Read 1.82 Changelog for details + grep commented names in sources.
528 - commented out runtime support for hardcoded ~0 or 0x01..0x0F rounding flags values for AddRect()/AddRectFilled()/PathRect()/AddImageRounded() -> use ImDrawFlags_RoundCornersXXX flags. Read 1.82 Changelog for details
529 - 2023/08/25 (1.89.9) - clipper: Renamed IncludeRangeByIndices() (also called ForceDisplayRangeByIndices() before 1.89.6) to IncludeItemsByIndex(). Kept inline redirection function. Sorry!
530 - 2023/07/12 (1.89.8) - ImDrawData: CmdLists now owned, changed from ImDrawList** to ImVector<ImDrawList*>. Majority of users shouldn't be affected, but you cannot compare to NULL nor reassign manually anymore. Instead use AddDrawList(). (#6406, #4879, #1878)
531 - 2023/06/28 (1.89.7) - overlapping items: obsoleted 'SetItemAllowOverlap()' (called after item) in favor of calling 'SetNextItemAllowOverlap()' (called before item). 'SetItemAllowOverlap()' didn't and couldn't work reliably since 1.89 (2022-11-15).
532 - 2023/06/28 (1.89.7) - overlapping items: renamed 'ImGuiTreeNodeFlags_AllowItemOverlap' to 'ImGuiTreeNodeFlags_AllowOverlap', 'ImGuiSelectableFlags_AllowItemOverlap' to 'ImGuiSelectableFlags_AllowOverlap'. Kept redirecting enums (will obsolete).
533 - 2023/06/28 (1.89.7) - overlapping items: IsItemHovered() now by default return false when querying an item using AllowOverlap mode which is being overlapped. Use ImGuiHoveredFlags_AllowWhenOverlappedByItem to revert to old behavior.
534 - 2023/06/28 (1.89.7) - overlapping items: Selectable and TreeNode don't allow overlap when active so overlapping widgets won't appear as hovered. While this fixes a common small visual issue, it also means that calling IsItemHovered() after a non-reactive elements - e.g. Text() - overlapping an active one may fail if you don't use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem). (#6610)
535 - 2023/06/20 (1.89.7) - moved io.HoverDelayShort/io.HoverDelayNormal to style.HoverDelayShort/style.HoverDelayNormal. As the fields were added in 1.89 and expected to be left unchanged by most users, or only tweaked once during app initialization, we are exceptionally accepting the breakage.
536 - 2023/05/30 (1.89.6) - backends: renamed "imgui_impl_sdlrenderer.cpp" to "imgui_impl_sdlrenderer2.cpp" and "imgui_impl_sdlrenderer.h" to "imgui_impl_sdlrenderer2.h". This is in prevision for the future release of SDL3.
537 - 2023/05/22 (1.89.6) - listbox: commented out obsolete/redirecting functions that were marked obsolete more than two years ago:
538 - ListBoxHeader() -> use BeginListBox() (note how two variants of ListBoxHeader() existed. Check commented versions in imgui.h for reference)
539 - ListBoxFooter() -> use EndListBox()
540 - 2023/05/15 (1.89.6) - clipper: commented out obsolete redirection constructor 'ImGuiListClipper(int items_count, float items_height = -1.0f)' that was marked obsolete in 1.79. Use default constructor + clipper.Begin().
541 - 2023/05/15 (1.89.6) - clipper: renamed ImGuiListClipper::ForceDisplayRangeByIndices() to ImGuiListClipper::IncludeRangeByIndices().
542 - 2023/03/14 (1.89.4) - commented out redirecting enums/functions names that were marked obsolete two years ago:
543 - ImGuiSliderFlags_ClampOnInput -> use ImGuiSliderFlags_AlwaysClamp
544 - ImGuiInputTextFlags_AlwaysInsertMode -> use ImGuiInputTextFlags_AlwaysOverwrite
545 - ImDrawList::AddBezierCurve() -> use ImDrawList::AddBezierCubic()
546 - ImDrawList::PathBezierCurveTo() -> use ImDrawList::PathBezierCubicCurveTo()
547 - 2023/03/09 (1.89.4) - renamed PushAllowKeyboardFocus()/PopAllowKeyboardFocus() to PushTabStop()/PopTabStop(). Kept inline redirection functions (will obsolete).
548 - 2023/03/09 (1.89.4) - tooltips: Added 'bool' return value to BeginTooltip() for API consistency. Please only submit contents and call EndTooltip() if BeginTooltip() returns true. In reality the function will _currently_ always return true, but further changes down the line may change this, best to clarify API sooner.
549 - 2023/02/15 (1.89.4) - moved the optional "courtesy maths operators" implementation from imgui_internal.h in imgui.h.
550 Even though we encourage using your own maths types and operators by setting up IM_VEC2_CLASS_EXTRA,
551 it has been frequently requested by people to use our own. We had an opt-in define which was
552 previously fulfilled in imgui_internal.h. It is now fulfilled in imgui.h. (#6164)
553 - OK: #define IMGUI_DEFINE_MATH_OPERATORS / #include "imgui.h" / #include "imgui_internal.h"
554 - Error: #include "imgui.h" / #define IMGUI_DEFINE_MATH_OPERATORS / #include "imgui_internal.h"
555 - 2023/02/07 (1.89.3) - backends: renamed "imgui_impl_sdl.cpp" to "imgui_impl_sdl2.cpp" and "imgui_impl_sdl.h" to "imgui_impl_sdl2.h". (#6146) This is in prevision for the future release of SDL3.
556 - 2022/10/26 (1.89) - commented out redirecting OpenPopupContextItem() which was briefly the name of OpenPopupOnItemClick() from 1.77 to 1.79.
557 - 2022/10/12 (1.89) - removed runtime patching of invalid "%f"/"%0.f" format strings for DragInt()/SliderInt(). This was obsoleted in 1.61 (May 2018). See 1.61 changelog for details.
558 - 2022/09/26 (1.89) - renamed and merged keyboard modifiers key enums and flags into a same set. Kept inline redirection enums (will obsolete).
559 - ImGuiKey_ModCtrl and ImGuiModFlags_Ctrl -> ImGuiMod_Ctrl
560 - ImGuiKey_ModShift and ImGuiModFlags_Shift -> ImGuiMod_Shift
561 - ImGuiKey_ModAlt and ImGuiModFlags_Alt -> ImGuiMod_Alt
562 - ImGuiKey_ModSuper and ImGuiModFlags_Super -> ImGuiMod_Super
563 the ImGuiKey_ModXXX were introduced in 1.87 and mostly used by backends.
564 the ImGuiModFlags_XXX have been exposed in imgui.h but not really used by any public api only by third-party extensions.
565 exceptionally commenting out the older ImGuiKeyModFlags_XXX names ahead of obsolescence schedule to reduce confusion and because they were not meant to be used anyway.
566 - 2022/09/20 (1.89) - ImGuiKey is now a typed enum, allowing ImGuiKey_XXX symbols to be named in debuggers.
567 this will require uses of legacy backend-dependent indices to be casted, e.g.
568 - with imgui_impl_glfw: IsKeyPressed(GLFW_KEY_A) -> IsKeyPressed((ImGuiKey)GLFW_KEY_A);
569 - with imgui_impl_win32: IsKeyPressed('A') -> IsKeyPressed((ImGuiKey)'A')
570 - etc. However if you are upgrading code you might well use the better, backend-agnostic IsKeyPressed(ImGuiKey_A) now!
571 - 2022/09/12 (1.89) - removed the bizarre legacy default argument for 'TreePush(const void* ptr = NULL)', always pass a pointer value explicitly. NULL/nullptr is ok but require cast, e.g. TreePush((void*)nullptr);
572 - 2022/09/05 (1.89) - commented out redirecting functions/enums names that were marked obsolete in 1.77 and 1.78 (June 2020):
573 - DragScalar(), DragScalarN(), DragFloat(), DragFloat2(), DragFloat3(), DragFloat4(): For old signatures ending with (..., const char* format, float power = 1.0f) -> use (..., format ImGuiSliderFlags_Logarithmic) if power != 1.0f.
574 - SliderScalar(), SliderScalarN(), SliderFloat(), SliderFloat2(), SliderFloat3(), SliderFloat4(): For old signatures ending with (..., const char* format, float power = 1.0f) -> use (..., format ImGuiSliderFlags_Logarithmic) if power != 1.0f.
575 - BeginPopupContextWindow(const char*, ImGuiMouseButton, bool) -> use BeginPopupContextWindow(const char*, ImGuiPopupFlags)
576 - 2022/09/02 (1.89) - obsoleted using SetCursorPos()/SetCursorScreenPos() to extend parent window/cell boundaries.
577 this relates to when moving the cursor position beyond current boundaries WITHOUT submitting an item.
578 - previously this would make the window content size ~200x200:
579 Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + End();
580 - instead, please submit an item:
581 Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + Dummy(ImVec2(0,0)) + End();
582 - alternative:
583 Begin(...) + Dummy(ImVec2(200,200)) + End();
584 - content size is now only extended when submitting an item!
585 - with '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' this will now be detected and assert.
586 - without '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' this will silently be fixed until we obsolete it.
587 - 2022/08/03 (1.89) - changed signature of ImageButton() function. Kept redirection function (will obsolete).
588 - added 'const char* str_id' parameter + removed 'int frame_padding = -1' parameter.
589 - old signature: bool ImageButton(ImTextureID tex_id, ImVec2 size, ImVec2 uv0 = ImVec2(0,0), ImVec2 uv1 = ImVec2(1,1), int frame_padding = -1, ImVec4 bg_col = ImVec4(0,0,0,0), ImVec4 tint_col = ImVec4(1,1,1,1));
590 - used the ImTextureID value to create an ID. This was inconsistent with other functions, led to ID conflicts, and caused problems with engines using transient ImTextureID values.
591 - had a FramePadding override which was inconsistent with other functions and made the already-long signature even longer.
592 - new signature: bool ImageButton(const char* str_id, ImTextureID tex_id, ImVec2 size, ImVec2 uv0 = ImVec2(0,0), ImVec2 uv1 = ImVec2(1,1), ImVec4 bg_col = ImVec4(0,0,0,0), ImVec4 tint_col = ImVec4(1,1,1,1));
593 - requires an explicit identifier. You may still use e.g. PushID() calls and then pass an empty identifier.
594 - always uses style.FramePadding for padding, to be consistent with other buttons. You may use PushStyleVar() to alter this.
595 - 2022/07/08 (1.89) - inputs: removed io.NavInputs[] and ImGuiNavInput enum (following 1.87 changes).
596 - Official backends from 1.87+ -> no issue.
597 - Official backends from 1.60 to 1.86 -> will build and convert gamepad inputs, unless IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Need updating!
598 - Custom backends not writing to io.NavInputs[] -> no issue.
599 - Custom backends writing to io.NavInputs[] -> will build and convert gamepad inputs, unless IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Need fixing!
600 - TL;DR: Backends should call io.AddKeyEvent()/io.AddKeyAnalogEvent() with ImGuiKey_GamepadXXX values instead of filling io.NavInput[].
601 - 2022/06/15 (1.88) - renamed IMGUI_DISABLE_METRICS_WINDOW to IMGUI_DISABLE_DEBUG_TOOLS for correctness. kept support for old define (will obsolete).
602 - 2022/05/03 (1.88) - backends: osx: removed ImGui_ImplOSX_HandleEvent() from backend API in favor of backend automatically handling event capture. All ImGui_ImplOSX_HandleEvent() calls should be removed as they are now unnecessary.
603 - 2022/04/05 (1.88) - inputs: renamed ImGuiKeyModFlags to ImGuiModFlags. Kept inline redirection enums (will obsolete). This was never used in public API functions but technically present in imgui.h and ImGuiIO.
604 - 2022/01/20 (1.87) - inputs: reworded gamepad IO.
605 - Backend writing to io.NavInputs[] -> backend should call io.AddKeyEvent()/io.AddKeyAnalogEvent() with ImGuiKey_GamepadXXX values.
606 - 2022/01/19 (1.87) - sliders, drags: removed support for legacy arithmetic operators (+,+-,*,/) when inputing text. This doesn't break any api/code but a feature that used to be accessible by end-users (which seemingly no one used).
607 - 2022/01/17 (1.87) - inputs: reworked mouse IO.
608 - Backend writing to io.MousePos -> backend should call io.AddMousePosEvent()
609 - Backend writing to io.MouseDown[] -> backend should call io.AddMouseButtonEvent()
610 - Backend writing to io.MouseWheel -> backend should call io.AddMouseWheelEvent()
611 - Backend writing to io.MouseHoveredViewport -> backend should call io.AddMouseViewportEvent() [Docking branch w/ multi-viewports only]
612 note: for all calls to IO new functions, the Dear ImGui context should be bound/current.
613 read https://github.com/ocornut/imgui/issues/4921 for details.
614 - 2022/01/10 (1.87) - inputs: reworked keyboard IO. Removed io.KeyMap[], io.KeysDown[] in favor of calling io.AddKeyEvent(). Removed GetKeyIndex(), now unnecessary. All IsKeyXXX() functions now take ImGuiKey values. All features are still functional until IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Read Changelog and Release Notes for details.
615 - IsKeyPressed(MY_NATIVE_KEY_XXX) -> use IsKeyPressed(ImGuiKey_XXX)
616 - IsKeyPressed(GetKeyIndex(ImGuiKey_XXX)) -> use IsKeyPressed(ImGuiKey_XXX)
617 - Backend writing to io.KeyMap[],io.KeysDown[] -> backend should call io.AddKeyEvent() (+ call io.SetKeyEventNativeData() if you want legacy user code to stil function with legacy key codes).
618 - Backend writing to io.KeyCtrl, io.KeyShift.. -> backend should call io.AddKeyEvent() with ImGuiMod_XXX values. *IF YOU PULLED CODE BETWEEN 2021/01/10 and 2021/01/27: We used to have a io.AddKeyModsEvent() function which was now replaced by io.AddKeyEvent() with ImGuiMod_XXX values.*
619 - one case won't work with backward compatibility: if your custom backend used ImGuiKey as mock native indices (e.g. "io.KeyMap[ImGuiKey_A] = ImGuiKey_A") because those values are now larger than the legacy KeyDown[] array. Will assert.
620 - inputs: added ImGuiKey_ModCtrl/ImGuiKey_ModShift/ImGuiKey_ModAlt/ImGuiKey_ModSuper values to submit keyboard modifiers using io.AddKeyEvent(), instead of writing directly to io.KeyCtrl, io.KeyShift, io.KeyAlt, io.KeySuper.
621 - 2022/01/05 (1.87) - inputs: renamed ImGuiKey_KeyPadEnter to ImGuiKey_KeypadEnter to align with new symbols. Kept redirection enum.
622 - 2022/01/05 (1.87) - removed io.ImeSetInputScreenPosFn() in favor of more flexible io.SetPlatformImeDataFn(). Removed 'void* io.ImeWindowHandle' in favor of writing to 'void* ImGuiViewport::PlatformHandleRaw'.
623 - 2022/01/01 (1.87) - commented out redirecting functions/enums names that were marked obsolete in 1.69, 1.70, 1.71, 1.72 (March-July 2019)
624 - ImGui::SetNextTreeNodeOpen() -> use ImGui::SetNextItemOpen()
625 - ImGui::GetContentRegionAvailWidth() -> use ImGui::GetContentRegionAvail().x
626 - ImGui::TreeAdvanceToLabelPos() -> use ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetTreeNodeToLabelSpacing());
627 - ImFontAtlas::CustomRect -> use ImFontAtlasCustomRect
628 - ImGuiColorEditFlags_RGB/HSV/HEX -> use ImGuiColorEditFlags_DisplayRGB/HSV/Hex
629 - 2021/12/20 (1.86) - backends: removed obsolete Marmalade backend (imgui_impl_marmalade.cpp) + example. Find last supported version at https://github.com/ocornut/imgui/wiki/Bindings
630 - 2021/11/04 (1.86) - removed CalcListClipping() function. Prefer using ImGuiListClipper which can return non-contiguous ranges. Please open an issue if you think you really need this function.
631 - 2021/08/23 (1.85) - removed GetWindowContentRegionWidth() function. keep inline redirection helper. can use 'GetWindowContentRegionMax().x - GetWindowContentRegionMin().x' instead for generally 'GetContentRegionAvail().x' is more useful.
632 - 2021/07/26 (1.84) - commented out redirecting functions/enums names that were marked obsolete in 1.67 and 1.69 (March 2019):
633 - ImGui::GetOverlayDrawList() -> use ImGui::GetForegroundDrawList()
634 - ImFont::GlyphRangesBuilder -> use ImFontGlyphRangesBuilder
635 - 2021/05/19 (1.83) - backends: obsoleted direct access to ImDrawCmd::TextureId in favor of calling ImDrawCmd::GetTexID().
636 - if you are using official backends from the source tree: you have nothing to do.
637 - if you have copied old backend code or using your own: change access to draw_cmd->TextureId to draw_cmd->GetTexID().
638 - 2021/03/12 (1.82) - upgraded ImDrawList::AddRect(), AddRectFilled(), PathRect() to use ImDrawFlags instead of ImDrawCornersFlags.
639 - ImDrawCornerFlags_TopLeft -> use ImDrawFlags_RoundCornersTopLeft
640 - ImDrawCornerFlags_BotRight -> use ImDrawFlags_RoundCornersBottomRight
641 - ImDrawCornerFlags_None -> use ImDrawFlags_RoundCornersNone etc.
642 flags now sanely defaults to 0 instead of 0x0F, consistent with all other flags in the API.
643 breaking: the default with rounding > 0.0f is now "round all corners" vs old implicit "round no corners":
644 - rounding == 0.0f + flags == 0 --> meant no rounding --> unchanged (common use)
645 - rounding > 0.0f + flags != 0 --> meant rounding --> unchanged (common use)
646 - rounding == 0.0f + flags != 0 --> meant no rounding --> unchanged (unlikely use)
647 - rounding > 0.0f + flags == 0 --> meant no rounding --> BREAKING (unlikely use): will now round all corners --> use ImDrawFlags_RoundCornersNone or rounding == 0.0f.
648 this ONLY matters for hard coded use of 0 + rounding > 0.0f. Use of named ImDrawFlags_RoundCornersNone (new) or ImDrawCornerFlags_None (old) are ok.
649 the old ImDrawCornersFlags used awkward default values of ~0 or 0xF (4 lower bits set) to signify "round all corners" and we sometimes encouraged using them as shortcuts.
650 legacy path still support use of hard coded ~0 or any value from 0x1 or 0xF. They will behave the same with legacy paths enabled (will assert otherwise).
651 - 2021/03/11 (1.82) - removed redirecting functions/enums names that were marked obsolete in 1.66 (September 2018):
652 - ImGui::SetScrollHere() -> use ImGui::SetScrollHereY()
653 - 2021/03/11 (1.82) - clarified that ImDrawList::PathArcTo(), ImDrawList::PathArcToFast() won't render with radius < 0.0f. Previously it sorts of accidentally worked but would generally lead to counter-clockwise paths and have an effect on anti-aliasing.
654 - 2021/03/10 (1.82) - upgraded ImDrawList::AddPolyline() and PathStroke() "bool closed" parameter to "ImDrawFlags flags". The matching ImDrawFlags_Closed value is guaranteed to always stay == 1 in the future.
655 - 2021/02/22 (1.82) - (*undone in 1.84*) win32+mingw: Re-enabled IME functions by default even under MinGW. In July 2016, issue #738 had me incorrectly disable those default functions for MinGW. MinGW users should: either link with -limm32, either set their imconfig file with '#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS'.
656 - 2021/02/17 (1.82) - renamed rarely used style.CircleSegmentMaxError (old default = 1.60f) to style.CircleTessellationMaxError (new default = 0.30f) as the meaning of the value changed.
657 - 2021/02/03 (1.81) - renamed ListBoxHeader(const char* label, ImVec2 size) to BeginListBox(). Kept inline redirection function (will obsolete).
658 - removed ListBoxHeader(const char* label, int items_count, int height_in_items = -1) in favor of specifying size. Kept inline redirection function (will obsolete).
659 - renamed ListBoxFooter() to EndListBox(). Kept inline redirection function (will obsolete).
660 - 2021/01/26 (1.81) - removed ImGuiFreeType::BuildFontAtlas(). Kept inline redirection function. Prefer using '#define IMGUI_ENABLE_FREETYPE', but there's a runtime selection path available too. The shared extra flags parameters (very rarely used) are now stored in ImFontAtlas::FontBuilderFlags.
661 - renamed ImFontConfig::RasterizerFlags (used by FreeType) to ImFontConfig::FontBuilderFlags.
662 - renamed ImGuiFreeType::XXX flags to ImGuiFreeTypeBuilderFlags_XXX for consistency with other API.
663 - 2020/10/12 (1.80) - removed redirecting functions/enums that were marked obsolete in 1.63 (August 2018):
664 - ImGui::IsItemDeactivatedAfterChange() -> use ImGui::IsItemDeactivatedAfterEdit().
665 - ImGuiCol_ModalWindowDarkening -> use ImGuiCol_ModalWindowDimBg
666 - ImGuiInputTextCallback -> use ImGuiTextEditCallback
667 - ImGuiInputTextCallbackData -> use ImGuiTextEditCallbackData
668 - 2020/12/21 (1.80) - renamed ImDrawList::AddBezierCurve() to AddBezierCubic(), and PathBezierCurveTo() to PathBezierCubicCurveTo(). Kept inline redirection function (will obsolete).
669 - 2020/12/04 (1.80) - added imgui_tables.cpp file! Manually constructed project files will need the new file added!
670 - 2020/11/18 (1.80) - renamed undocumented/internals ImGuiColumnsFlags_* to ImGuiOldColumnFlags_* in prevision of incoming Tables API.
671 - 2020/11/03 (1.80) - renamed io.ConfigWindowsMemoryCompactTimer to io.ConfigMemoryCompactTimer as the feature will apply to other data structures
672 - 2020/10/14 (1.80) - backends: moved all backends files (imgui_impl_XXXX.cpp, imgui_impl_XXXX.h) from examples/ to backends/.
673 - 2020/10/12 (1.80) - removed redirecting functions/enums that were marked obsolete in 1.60 (April 2018):
674 - io.RenderDrawListsFn pointer -> use ImGui::GetDrawData() value and call the render function of your backend
675 - ImGui::IsAnyWindowFocused() -> use ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow)
676 - ImGui::IsAnyWindowHovered() -> use ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)
677 - ImGuiStyleVar_Count_ -> use ImGuiStyleVar_COUNT
678 - ImGuiMouseCursor_Count_ -> use ImGuiMouseCursor_COUNT
679 - removed redirecting functions names that were marked obsolete in 1.61 (May 2018):
680 - InputFloat (... int decimal_precision ...) -> use InputFloat (... const char* format ...) with format = "%.Xf" where X is your value for decimal_precision.
681 - same for InputFloat2()/InputFloat3()/InputFloat4() variants taking a `int decimal_precision` parameter.
682 - 2020/10/05 (1.79) - removed ImGuiListClipper: Renamed constructor parameters which created an ambiguous alternative to using the ImGuiListClipper::Begin() function, with misleading edge cases (note: imgui_memory_editor <0.40 from imgui_club/ used this old clipper API. Update your copy if needed).
683 - 2020/09/25 (1.79) - renamed ImGuiSliderFlags_ClampOnInput to ImGuiSliderFlags_AlwaysClamp. Kept redirection enum (will obsolete sooner because previous name was added recently).
684 - 2020/09/25 (1.79) - renamed style.TabMinWidthForUnselectedCloseButton to style.TabMinWidthForCloseButton.
685 - 2020/09/21 (1.79) - renamed OpenPopupContextItem() back to OpenPopupOnItemClick(), reverting the change from 1.77. For varieties of reason this is more self-explanatory.
686 - 2020/09/21 (1.79) - removed return value from OpenPopupOnItemClick() - returned true on mouse release on an item - because it is inconsistent with other popup APIs and makes others misleading. It's also and unnecessary: you can use IsWindowAppearing() after BeginPopup() for a similar result.
687 - 2020/09/17 (1.79) - removed ImFont::DisplayOffset in favor of ImFontConfig::GlyphOffset. DisplayOffset was applied after scaling and not very meaningful/useful outside of being needed by the default ProggyClean font. If you scaled this value after calling AddFontDefault(), this is now done automatically. It was also getting in the way of better font scaling, so let's get rid of it now!
688 - 2020/08/17 (1.78) - obsoleted use of the trailing 'float power=1.0f' parameter for DragFloat(), DragFloat2(), DragFloat3(), DragFloat4(), DragFloatRange2(), DragScalar(), DragScalarN(), SliderFloat(), SliderFloat2(), SliderFloat3(), SliderFloat4(), SliderScalar(), SliderScalarN(), VSliderFloat() and VSliderScalar().
689 replaced the 'float power=1.0f' argument with integer-based flags defaulting to 0 (as with all our flags).
690 worked out a backward-compatibility scheme so hopefully most C++ codebase should not be affected. in short, when calling those functions:
691 - if you omitted the 'power' parameter (likely!), you are not affected.
692 - if you set the 'power' parameter to 1.0f (same as previous default value): 1/ your compiler may warn on float>int conversion, 2/ everything else will work. 3/ you can replace the 1.0f value with 0 to fix the warning, and be technically correct.
693 - if you set the 'power' parameter to >1.0f (to enable non-linear editing): 1/ your compiler may warn on float>int conversion, 2/ code will assert at runtime, 3/ in case asserts are disabled, the code will not crash and enable the _Logarithmic flag. 4/ you can replace the >1.0f value with ImGuiSliderFlags_Logarithmic to fix the warning/assert and get a _similar_ effect as previous uses of power >1.0f.
694 see https://github.com/ocornut/imgui/issues/3361 for all details.
695 kept inline redirection functions (will obsolete) apart for: DragFloatRange2(), VSliderFloat(), VSliderScalar(). For those three the 'float power=1.0f' version was removed directly as they were most unlikely ever used.
696 for shared code, you can version check at compile-time with `#if IMGUI_VERSION_NUM >= 17704`.
697 - obsoleted use of v_min > v_max in DragInt, DragFloat, DragScalar to lock edits (introduced in 1.73, was not demoed nor documented very), will be replaced by a more generic ReadOnly feature. You may use the ImGuiSliderFlags_ReadOnly internal flag in the meantime.
698 - 2020/06/23 (1.77) - removed BeginPopupContextWindow(const char*, int mouse_button, bool also_over_items) in favor of BeginPopupContextWindow(const char*, ImGuiPopupFlags flags) with ImGuiPopupFlags_NoOverItems.
699 - 2020/06/15 (1.77) - renamed OpenPopupOnItemClick() to OpenPopupContextItem(). Kept inline redirection function (will obsolete). [NOTE: THIS WAS REVERTED IN 1.79]
700 - 2020/06/15 (1.77) - removed CalcItemRectClosestPoint() entry point which was made obsolete and asserting in December 2017.
701 - 2020/04/23 (1.77) - removed unnecessary ID (first arg) of ImFontAtlas::AddCustomRectRegular().
702 - 2020/01/22 (1.75) - ImDrawList::AddCircle()/AddCircleFilled() functions don't accept negative radius any more.
703 - 2019/12/17 (1.75) - [undid this change in 1.76] made Columns() limited to 64 columns by asserting above that limit. While the current code technically supports it, future code may not so we're putting the restriction ahead.
704 - 2019/12/13 (1.75) - [imgui_internal.h] changed ImRect() default constructor initializes all fields to 0.0f instead of (FLT_MAX,FLT_MAX,-FLT_MAX,-FLT_MAX). If you used ImRect::Add() to create bounding boxes by adding multiple points into it, you may need to fix your initial value.
705 - 2019/12/08 (1.75) - removed redirecting functions/enums that were marked obsolete in 1.53 (December 2017):
706 - ShowTestWindow() -> use ShowDemoWindow()
707 - IsRootWindowFocused() -> use IsWindowFocused(ImGuiFocusedFlags_RootWindow)
708 - IsRootWindowOrAnyChildFocused() -> use IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows)
709 - SetNextWindowContentWidth(w) -> use SetNextWindowContentSize(ImVec2(w, 0.0f)
710 - GetItemsLineHeightWithSpacing() -> use GetFrameHeightWithSpacing()
711 - ImGuiCol_ChildWindowBg -> use ImGuiCol_ChildBg
712 - ImGuiStyleVar_ChildWindowRounding -> use ImGuiStyleVar_ChildRounding
713 - ImGuiTreeNodeFlags_AllowOverlapMode -> use ImGuiTreeNodeFlags_AllowItemOverlap
714 - IMGUI_DISABLE_TEST_WINDOWS -> use IMGUI_DISABLE_DEMO_WINDOWS
715 - 2019/12/08 (1.75) - obsoleted calling ImDrawList::PrimReserve() with a negative count (which was vaguely documented and rarely if ever used). Instead, we added an explicit PrimUnreserve() API.
716 - 2019/12/06 (1.75) - removed implicit default parameter to IsMouseDragging(int button = 0) to be consistent with other mouse functions (none of the other functions have it).
717 - 2019/11/21 (1.74) - ImFontAtlas::AddCustomRectRegular() now requires an ID larger than 0x110000 (instead of 0x10000) to conform with supporting Unicode planes 1-16 in a future update. ID below 0x110000 will now assert.
718 - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS to IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS for consistency.
719 - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_MATH_FUNCTIONS to IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS for consistency.
720 - 2019/10/22 (1.74) - removed redirecting functions/enums that were marked obsolete in 1.52 (October 2017):
721 - Begin() [old 5 args version] -> use Begin() [3 args], use SetNextWindowSize() SetNextWindowBgAlpha() if needed
722 - IsRootWindowOrAnyChildHovered() -> use IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows)
723 - AlignFirstTextHeightToWidgets() -> use AlignTextToFramePadding()
724 - SetNextWindowPosCenter() -> use SetNextWindowPos() with a pivot of (0.5f, 0.5f)
725 - ImFont::Glyph -> use ImFontGlyph
726 - 2019/10/14 (1.74) - inputs: Fixed a miscalculation in the keyboard/mouse "typematic" repeat delay/rate calculation, used by keys and e.g. repeating mouse buttons as well as the GetKeyPressedAmount() function.
727 if you were using a non-default value for io.KeyRepeatRate (previous default was 0.250), you can add +io.KeyRepeatDelay to it to compensate for the fix.
728 The function was triggering on: 0.0 and (delay+rate*N) where (N>=1). Fixed formula responds to (N>=0). Effectively it made io.KeyRepeatRate behave like it was set to (io.KeyRepeatRate + io.KeyRepeatDelay).
729 If you never altered io.KeyRepeatRate nor used GetKeyPressedAmount() this won't affect you.
730 - 2019/07/15 (1.72) - removed TreeAdvanceToLabelPos() which is rarely used and only does SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()). Kept redirection function (will obsolete).
731 - 2019/07/12 (1.72) - renamed ImFontAtlas::CustomRect to ImFontAtlasCustomRect. Kept redirection typedef (will obsolete).
732 - 2019/06/14 (1.72) - removed redirecting functions/enums names that were marked obsolete in 1.51 (June 2017): ImGuiCol_Column*, ImGuiSetCond_*, IsItemHoveredRect(), IsPosHoveringAnyWindow(), IsMouseHoveringAnyWindow(), IsMouseHoveringWindow(), IMGUI_ONCE_UPON_A_FRAME. Grep this log for details and new names, or see how they were implemented until 1.71.
733 - 2019/06/07 (1.71) - rendering of child window outer decorations (bg color, border, scrollbars) is now performed as part of the parent window. If you have
734 overlapping child windows in a same parent, and relied on their relative z-order to be mapped to their submission order, this will affect your rendering.
735 This optimization is disabled if the parent window has no visual output, because it appears to be the most common situation leading to the creation of overlapping child windows.
736 Please reach out if you are affected.
737 - 2019/05/13 (1.71) - renamed SetNextTreeNodeOpen() to SetNextItemOpen(). Kept inline redirection function (will obsolete).
738 - 2019/05/11 (1.71) - changed io.AddInputCharacter(unsigned short c) signature to io.AddInputCharacter(unsigned int c).
739 - 2019/04/29 (1.70) - improved ImDrawList thick strokes (>1.0f) preserving correct thickness up to 90 degrees angles (e.g. rectangles). If you have custom rendering using thick lines, they will appear thicker now.
740 - 2019/04/29 (1.70) - removed GetContentRegionAvailWidth(), use GetContentRegionAvail().x instead. Kept inline redirection function (will obsolete).
741 - 2019/03/04 (1.69) - renamed GetOverlayDrawList() to GetForegroundDrawList(). Kept redirection function (will obsolete).
742 - 2019/02/26 (1.69) - renamed ImGuiColorEditFlags_RGB/ImGuiColorEditFlags_HSV/ImGuiColorEditFlags_HEX to ImGuiColorEditFlags_DisplayRGB/ImGuiColorEditFlags_DisplayHSV/ImGuiColorEditFlags_DisplayHex. Kept redirection enums (will obsolete).
743 - 2019/02/14 (1.68) - made it illegal/assert when io.DisplayTime == 0.0f (with an exception for the first frame). If for some reason your time step calculation gives you a zero value, replace it with an arbitrarily small value!
744 - 2019/02/01 (1.68) - removed io.DisplayVisibleMin/DisplayVisibleMax (which were marked obsolete and removed from viewport/docking branch already).
745 - 2019/01/06 (1.67) - renamed io.InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead!
746 - 2019/01/06 (1.67) - renamed ImFontAtlas::GlyphRangesBuilder to ImFontGlyphRangesBuilder. Kept redirection typedef (will obsolete).
747 - 2018/12/20 (1.67) - made it illegal to call Begin("") with an empty string. This somehow half-worked before but had various undesirable side-effects.
748 - 2018/12/10 (1.67) - renamed io.ConfigResizeWindowsFromEdges to io.ConfigWindowsResizeFromEdges as we are doing a large pass on configuration flags.
749 - 2018/10/12 (1.66) - renamed misc/stl/imgui_stl.* to misc/cpp/imgui_stdlib.* in prevision for other C++ helper files.
750 - 2018/09/28 (1.66) - renamed SetScrollHere() to SetScrollHereY(). Kept redirection function (will obsolete).
751 - 2018/09/06 (1.65) - renamed stb_truetype.h to imstb_truetype.h, stb_textedit.h to imstb_textedit.h, and stb_rect_pack.h to imstb_rectpack.h.
752 If you were conveniently using the imgui copy of those STB headers in your project you will have to update your include paths.
753 - 2018/09/05 (1.65) - renamed io.OptCursorBlink/io.ConfigCursorBlink to io.ConfigInputTextCursorBlink. (#1427)
754 - 2018/08/31 (1.64) - added imgui_widgets.cpp file, extracted and moved widgets code out of imgui.cpp into imgui_widgets.cpp. Re-ordered some of the code remaining in imgui.cpp.
755 NONE OF THE FUNCTIONS HAVE CHANGED. THE CODE IS SEMANTICALLY 100% IDENTICAL, BUT _EVERY_ FUNCTION HAS BEEN MOVED.
756 Because of this, any local modifications to imgui.cpp will likely conflict when you update. Read docs/CHANGELOG.txt for suggestions.
757 - 2018/08/22 (1.63) - renamed IsItemDeactivatedAfterChange() to IsItemDeactivatedAfterEdit() for consistency with new IsItemEdited() API. Kept redirection function (will obsolete soonish as IsItemDeactivatedAfterChange() is very recent).
758 - 2018/08/21 (1.63) - renamed ImGuiTextEditCallback to ImGuiInputTextCallback, ImGuiTextEditCallbackData to ImGuiInputTextCallbackData for consistency. Kept redirection types (will obsolete).
759 - 2018/08/21 (1.63) - removed ImGuiInputTextCallbackData::ReadOnly since it is a duplication of (ImGuiInputTextCallbackData::Flags & ImGuiInputTextFlags_ReadOnly).
760 - 2018/08/01 (1.63) - removed per-window ImGuiWindowFlags_ResizeFromAnySide beta flag in favor of a global io.ConfigResizeWindowsFromEdges [update 1.67 renamed to ConfigWindowsResizeFromEdges] to enable the feature.
761 - 2018/08/01 (1.63) - renamed io.OptCursorBlink to io.ConfigCursorBlink [-> io.ConfigInputTextCursorBlink in 1.65], io.OptMacOSXBehaviors to ConfigMacOSXBehaviors for consistency.
762 - 2018/07/22 (1.63) - changed ImGui::GetTime() return value from float to double to avoid accumulating floating point imprecisions over time.
763 - 2018/07/08 (1.63) - style: renamed ImGuiCol_ModalWindowDarkening to ImGuiCol_ModalWindowDimBg for consistency with other features. Kept redirection enum (will obsolete).
764 - 2018/06/08 (1.62) - examples: the imgui_impl_XXX files have been split to separate platform (Win32, GLFW, SDL2, etc.) from renderer (DX11, OpenGL, Vulkan, etc.).
765 old backends will still work as is, however prefer using the separated backends as they will be updated to support multi-viewports.
766 when adopting new backends follow the main.cpp code of your preferred examples/ folder to know which functions to call.
767 in particular, note that old backends called ImGui::NewFrame() at the end of their ImGui_ImplXXXX_NewFrame() function.
768 - 2018/06/06 (1.62) - renamed GetGlyphRangesChinese() to GetGlyphRangesChineseFull() to distinguish other variants and discourage using the full set.
769 - 2018/06/06 (1.62) - TreeNodeEx()/TreeNodeBehavior(): the ImGuiTreeNodeFlags_CollapsingHeader helper now include the ImGuiTreeNodeFlags_NoTreePushOnOpen flag. See Changelog for details.
770 - 2018/05/03 (1.61) - DragInt(): the default compile-time format string has been changed from "%.0f" to "%d", as we are not using integers internally any more.
771 If you used DragInt() with custom format strings, make sure you change them to use %d or an integer-compatible format.
772 To honor backward-compatibility, the DragInt() code will currently parse and modify format strings to replace %*f with %d, giving time to users to upgrade their code.
773 If you have IMGUI_DISABLE_OBSOLETE_FUNCTIONS enabled, the code will instead assert! You may run a reg-exp search on your codebase for e.g. "DragInt.*%f" to help you find them.
774 - 2018/04/28 (1.61) - obsoleted InputFloat() functions taking an optional "int decimal_precision" in favor of an equivalent and more flexible "const char* format",
775 consistent with other functions. Kept redirection functions (will obsolete).
776 - 2018/04/09 (1.61) - IM_DELETE() helper function added in 1.60 doesn't clear the input _pointer_ reference, more consistent with expectation and allows passing r-value.
777 - 2018/03/20 (1.60) - renamed io.WantMoveMouse to io.WantSetMousePos for consistency and ease of understanding (was added in 1.52, _not_ used by core and only honored by some backend ahead of merging the Nav branch).
778 - 2018/03/12 (1.60) - removed ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered as the closing cross uses regular button colors now.
779 - 2018/03/08 (1.60) - changed ImFont::DisplayOffset.y to default to 0 instead of +1. Fixed rounding of Ascent/Descent to match TrueType renderer. If you were adding or subtracting to ImFont::DisplayOffset check if your fonts are correctly aligned vertically.
780 - 2018/03/03 (1.60) - renamed ImGuiStyleVar_Count_ to ImGuiStyleVar_COUNT and ImGuiMouseCursor_Count_ to ImGuiMouseCursor_COUNT for consistency with other public enums.
781 - 2018/02/18 (1.60) - BeginDragDropSource(): temporarily removed the optional mouse_button=0 parameter because it is not really usable in many situations at the moment.
782 - 2018/02/16 (1.60) - obsoleted the io.RenderDrawListsFn callback, you can call your graphics engine render function after ImGui::Render(). Use ImGui::GetDrawData() to retrieve the ImDrawData* to display.
783 - 2018/02/07 (1.60) - reorganized context handling to be more explicit,
784 - YOU NOW NEED TO CALL ImGui::CreateContext() AT THE BEGINNING OF YOUR APP, AND CALL ImGui::DestroyContext() AT THE END.
785 - removed Shutdown() function, as DestroyContext() serve this purpose.
786 - you may pass a ImFontAtlas* pointer to CreateContext() to share a font atlas between contexts. Otherwise CreateContext() will create its own font atlas instance.
787 - removed allocator parameters from CreateContext(), they are now setup with SetAllocatorFunctions(), and shared by all contexts.
788 - removed the default global context and font atlas instance, which were confusing for users of DLL reloading and users of multiple contexts.
789 - 2018/01/31 (1.60) - moved sample TTF files from extra_fonts/ to misc/fonts/. If you loaded files directly from the imgui repo you may need to update your paths.
790 - 2018/01/11 (1.60) - obsoleted IsAnyWindowHovered() in favor of IsWindowHovered(ImGuiHoveredFlags_AnyWindow). Kept redirection function (will obsolete).
791 - 2018/01/11 (1.60) - obsoleted IsAnyWindowFocused() in favor of IsWindowFocused(ImGuiFocusedFlags_AnyWindow). Kept redirection function (will obsolete).
792 - 2018/01/03 (1.60) - renamed ImGuiSizeConstraintCallback to ImGuiSizeCallback, ImGuiSizeConstraintCallbackData to ImGuiSizeCallbackData.
793 - 2017/12/29 (1.60) - removed CalcItemRectClosestPoint() which was weird and not really used by anyone except demo code. If you need it it's easy to replicate on your side.
794 - 2017/12/24 (1.53) - renamed the emblematic ShowTestWindow() function to ShowDemoWindow(). Kept redirection function (will obsolete).
795 - 2017/12/21 (1.53) - ImDrawList: renamed style.AntiAliasedShapes to style.AntiAliasedFill for consistency and as a way to explicitly break code that manipulate those flag at runtime. You can now manipulate ImDrawList::Flags
796 - 2017/12/21 (1.53) - ImDrawList: removed 'bool anti_aliased = true' final parameter of ImDrawList::AddPolyline() and ImDrawList::AddConvexPolyFilled(). Prefer manipulating ImDrawList::Flags if you need to toggle them during the frame.
797 - 2017/12/14 (1.53) - using the ImGuiWindowFlags_NoScrollWithMouse flag on a child window forwards the mouse wheel event to the parent window, unless either ImGuiWindowFlags_NoInputs or ImGuiWindowFlags_NoScrollbar are also set.
798 - 2017/12/13 (1.53) - renamed GetItemsLineHeightWithSpacing() to GetFrameHeightWithSpacing(). Kept redirection function (will obsolete).
799 - 2017/12/13 (1.53) - obsoleted IsRootWindowFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootWindow). Kept redirection function (will obsolete).
800 - obsoleted IsRootWindowOrAnyChildFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows). Kept redirection function (will obsolete).
801 - 2017/12/12 (1.53) - renamed ImGuiTreeNodeFlags_AllowOverlapMode to ImGuiTreeNodeFlags_AllowItemOverlap. Kept redirection enum (will obsolete).
802 - 2017/12/10 (1.53) - removed SetNextWindowContentWidth(), prefer using SetNextWindowContentSize(). Kept redirection function (will obsolete).
803 - 2017/11/27 (1.53) - renamed ImGuiTextBuffer::append() helper to appendf(), appendv() to appendfv(). If you copied the 'Log' demo in your code, it uses appendv() so that needs to be renamed.
804 - 2017/11/18 (1.53) - Style, Begin: removed ImGuiWindowFlags_ShowBorders window flag. Borders are now fully set up in the ImGuiStyle structure (see e.g. style.FrameBorderSize, style.WindowBorderSize). Use ImGui::ShowStyleEditor() to look them up.
805 Please note that the style system will keep evolving (hopefully stabilizing in Q1 2018), and so custom styles will probably subtly break over time. It is recommended you use the StyleColorsClassic(), StyleColorsDark(), StyleColorsLight() functions.
806 - 2017/11/18 (1.53) - Style: removed ImGuiCol_ComboBg in favor of combo boxes using ImGuiCol_PopupBg for consistency.
807 - 2017/11/18 (1.53) - Style: renamed ImGuiCol_ChildWindowBg to ImGuiCol_ChildBg.
808 - 2017/11/18 (1.53) - Style: renamed style.ChildWindowRounding to style.ChildRounding, ImGuiStyleVar_ChildWindowRounding to ImGuiStyleVar_ChildRounding.
809 - 2017/11/02 (1.53) - obsoleted IsRootWindowOrAnyChildHovered() in favor of using IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows);
810 - 2017/10/24 (1.52) - renamed IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS/IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS to IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS/IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS for consistency.
811 - 2017/10/20 (1.52) - changed IsWindowHovered() default parameters behavior to return false if an item is active in another window (e.g. click-dragging item from another window to this window). You can use the newly introduced IsWindowHovered() flags to requests this specific behavior if you need it.
812 - 2017/10/20 (1.52) - marked IsItemHoveredRect()/IsMouseHoveringWindow() as obsolete, in favor of using the newly introduced flags for IsItemHovered() and IsWindowHovered(). See https://github.com/ocornut/imgui/issues/1382 for details.
813 removed the IsItemRectHovered()/IsWindowRectHovered() names introduced in 1.51 since they were merely more consistent names for the two functions we are now obsoleting.
814 IsItemHoveredRect() --> IsItemHovered(ImGuiHoveredFlags_RectOnly)
815 IsMouseHoveringAnyWindow() --> IsWindowHovered(ImGuiHoveredFlags_AnyWindow)
816 IsMouseHoveringWindow() --> IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) [weird, old behavior]
817 - 2017/10/17 (1.52) - marked the old 5-parameters version of Begin() as obsolete (still available). Use SetNextWindowSize()+Begin() instead!
818 - 2017/10/11 (1.52) - renamed AlignFirstTextHeightToWidgets() to AlignTextToFramePadding(). Kept inline redirection function (will obsolete).
819 - 2017/09/26 (1.52) - renamed ImFont::Glyph to ImFontGlyph. Kept redirection typedef (will obsolete).
820 - 2017/09/25 (1.52) - removed SetNextWindowPosCenter() because SetNextWindowPos() now has the optional pivot information to do the same and more. Kept redirection function (will obsolete).
821 - 2017/08/25 (1.52) - io.MousePos needs to be set to ImVec2(-FLT_MAX,-FLT_MAX) when mouse is unavailable/missing. Previously ImVec2(-1,-1) was enough but we now accept negative mouse coordinates. In your backend if you need to support unavailable mouse, make sure to replace "io.MousePos = ImVec2(-1,-1)" with "io.MousePos = ImVec2(-FLT_MAX,-FLT_MAX)".
822 - 2017/08/22 (1.51) - renamed IsItemHoveredRect() to IsItemRectHovered(). Kept inline redirection function (will obsolete). -> (1.52) use IsItemHovered(ImGuiHoveredFlags_RectOnly)!
823 - renamed IsMouseHoveringAnyWindow() to IsAnyWindowHovered() for consistency. Kept inline redirection function (will obsolete).
824 - renamed IsMouseHoveringWindow() to IsWindowRectHovered() for consistency. Kept inline redirection function (will obsolete).
825 - 2017/08/20 (1.51) - renamed GetStyleColName() to GetStyleColorName() for consistency.
826 - 2017/08/20 (1.51) - added PushStyleColor(ImGuiCol idx, ImU32 col) overload, which _might_ cause an "ambiguous call" compilation error if you are using ImColor() with implicit cast. Cast to ImU32 or ImVec4 explicily to fix.
827 - 2017/08/15 (1.51) - marked the weird IMGUI_ONCE_UPON_A_FRAME helper macro as obsolete. prefer using the more explicit ImGuiOnceUponAFrame type.
828 - 2017/08/15 (1.51) - changed parameter order for BeginPopupContextWindow() from (const char*,int buttons,bool also_over_items) to (const char*,int buttons,bool also_over_items). Note that most calls relied on default parameters completely.
829 - 2017/08/13 (1.51) - renamed ImGuiCol_Column to ImGuiCol_Separator, ImGuiCol_ColumnHovered to ImGuiCol_SeparatorHovered, ImGuiCol_ColumnActive to ImGuiCol_SeparatorActive. Kept redirection enums (will obsolete).
830 - 2017/08/11 (1.51) - renamed ImGuiSetCond_Always to ImGuiCond_Always, ImGuiSetCond_Once to ImGuiCond_Once, ImGuiSetCond_FirstUseEver to ImGuiCond_FirstUseEver, ImGuiSetCond_Appearing to ImGuiCond_Appearing. Kept redirection enums (will obsolete).
831 - 2017/08/09 (1.51) - removed ValueColor() helpers, they are equivalent to calling Text(label) + SameLine() + ColorButton().
832 - 2017/08/08 (1.51) - removed ColorEditMode() and ImGuiColorEditMode in favor of ImGuiColorEditFlags and parameters to the various Color*() functions. The SetColorEditOptions() allows to initialize default but the user can still change them with right-click context menu.
833 - changed prototype of 'ColorEdit4(const char* label, float col[4], bool show_alpha = true)' to 'ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0)', where passing flags = 0x01 is a safe no-op (hello dodgy backward compatibility!). - check and run the demo window, under "Color/Picker Widgets", to understand the various new options.
834 - changed prototype of rarely used 'ColorButton(ImVec4 col, bool small_height = false, bool outline_border = true)' to 'ColorButton(const char* desc_id, ImVec4 col, ImGuiColorEditFlags flags = 0, ImVec2 size = ImVec2(0, 0))'
835 - 2017/07/20 (1.51) - removed IsPosHoveringAnyWindow(ImVec2), which was partly broken and misleading. ASSERT + redirect user to io.WantCaptureMouse
836 - 2017/05/26 (1.50) - removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset.
837 - 2017/05/01 (1.50) - renamed ImDrawList::PathFill() (rarely used directly) to ImDrawList::PathFillConvex() for clarity.
838 - 2016/11/06 (1.50) - BeginChild(const char*) now applies the stack id to the provided label, consistently with other functions as it should always have been. It shouldn't affect you unless (extremely unlikely) you were appending multiple times to a same child from different locations of the stack id. If that's the case, generate an id with GetID() and use it instead of passing string to BeginChild().
839 - 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it.
840 - 2016/09/25 (1.50) - style.WindowTitleAlign is now a ImVec2 (ImGuiAlign enum was removed). set to (0.5f,0.5f) for horizontal+vertical centering, (0.0f,0.0f) for upper-left, etc.
841 - 2016/07/30 (1.50) - SameLine(x) with x>0.0f is now relative to left of column/group if any, and not always to left of window. This was sort of always the intent and hopefully, breakage should be minimal.
842 - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore.
843 If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you, otherwise if <1.0f you need to tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar.
844 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:
845 ImVec4 ConvertTitleBgCol(const ImVec4& win_bg_col, const ImVec4& title_bg_col) { float new_a = 1.0f - ((1.0f - win_bg_col.w) * (1.0f - title_bg_col.w)), k = title_bg_col.w / new_a; return ImVec4((win_bg_col.x * win_bg_col.w + title_bg_col.x) * k, (win_bg_col.y * win_bg_col.w + title_bg_col.y) * k, (win_bg_col.z * win_bg_col.w + title_bg_col.z) * k, new_a); }
846 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.
847 - 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext().
848 - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection.
849 - 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).
850 - 2016/04/26 (1.49) - changed ImDrawList::PushClipRect(ImVec4 rect) to ImDrawList::PushClipRect(Imvec2 min,ImVec2 max,bool intersect_with_current_clip_rect=false). Note that higher-level ImGui::PushClipRect() is preferable because it will clip at logic/widget level, whereas ImDrawList::PushClipRect() only affect your renderer.
851 - 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).
852 - 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)
853 - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete).
854 - 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.
855 - 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.
856 - 2015/12/27 (1.48) - fixed ImDrawList::AddRect() which used to render a rectangle 1 px too large on each axis.
857 - 2015/12/04 (1.47) - renamed Color() helpers to ValueColor() - dangerously named, rarely used and probably to be made obsolete.
858 - 2015/08/29 (1.45) - with the addition of horizontal scrollbar we made various fixes to inconsistencies with dealing with cursor position.
859 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.
860 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!
861 - 2015/08/29 (1.45) - renamed style.ScrollbarWidth to style.ScrollbarSize
862 - 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.
863 - 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
864 - 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.
865 you need to render your textured triangles with bilinear filtering to benefit from sub-pixel positioning of text.
866 - 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.
867 this necessary change will break your rendering function! the fix should be very easy. sorry for that :(
868 - if you are using a vanilla copy of one of the imgui_impl_XXX.cpp provided in the example, you just need to update your copy and you can ignore the rest.
869 - the signature of the io.RenderDrawListsFn handler has changed!
870 old: ImGui_XXXX_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
871 new: ImGui_XXXX_RenderDrawLists(ImDrawData* draw_data).
872 parameters: 'cmd_lists' becomes 'draw_data->CmdLists', 'cmd_lists_count' becomes 'draw_data->CmdListsCount'
873 ImDrawList: 'commands' becomes 'CmdBuffer', 'vtx_buffer' becomes 'VtxBuffer', 'IdxBuffer' is new.
874 ImDrawCmd: 'vtx_count' becomes 'ElemCount', 'clip_rect' becomes 'ClipRect', 'user_callback' becomes 'UserCallback', 'texture_id' becomes 'TextureId'.
875 - 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.
876 - 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!
877 - refer to code in the examples/ folder or ask on the GitHub if you are unsure of how to upgrade. please upgrade!
878 - 2015/07/10 (1.43) - changed SameLine() parameters from int to float.
879 - 2015/07/02 (1.42) - renamed SetScrollPosHere() to SetScrollFromCursorPos(). Kept inline redirection function (will obsolete).
880 - 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.
881 - 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
882 - 2015/06/14 (1.41) - changed Selectable() API from (label, selected, size) to (label, selected, flags, size). Size override should have been rarely used. Sorry!
883 - 2015/05/31 (1.40) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete).
884 - 2015/05/31 (1.40) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete).
885 - 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.
886 - 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.
887 - 2015/05/03 (1.40) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same).
888 - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function until 1.50.
889 - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API
890 - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive.
891 - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead.
892 - 2015/03/17 (1.36) - renamed GetItemBoxMin()/GetItemBoxMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function until 1.50.
893 - 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing
894 - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function until 1.50.
895 - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth (casing)
896 - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function until 1.50.
897 - 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once.
898 - 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now.
899 - 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior
900 - 2015/02/08 (1.31) - renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing()
901 - 2015/02/01 (1.31) - removed IO.MemReallocFn (unused)
902 - 2015/01/19 (1.30) - renamed ImGuiStorage::GetIntPtr()/GetFloatPtr() to GetIntRef()/GetIntRef() because Ptr was conflicting with actual pointer storage functions.
903 - 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader.
904 - 2015/01/11 (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels.
905 - old: const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); [..Upload texture to GPU..];
906 - new: unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); [..Upload texture to GPU..]; io.Fonts->SetTexID(YourTexIdentifier);
907 you now have more flexibility to load multiple TTF fonts and manage the texture buffer for internal needs. It is now recommended that you sample the font texture with bilinear interpolation.
908 - 2015/01/11 (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to call io.Fonts->SetTexID()
909 - 2015/01/11 (1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix)
910 - 2015/01/11 (1.30) - removed ImGui::IsItemFocused() in favor of ImGui::IsItemActive() which handles all widgets
911 - 2014/12/10 (1.18) - removed SetNewWindowDefaultPos() in favor of new generic API SetNextWindowPos(pos, ImGuiSetCondition_FirstUseEver)
912 - 2014/11/28 (1.17) - moved IO.Font*** options to inside the IO.Font-> structure (FontYOffset, FontTexUvForWhite, FontBaseScale, FontFallbackGlyph)
913 - 2014/11/26 (1.17) - reworked syntax of IMGUI_ONCE_UPON_A_FRAME helper macro to increase compiler compatibility
914 - 2014/11/07 (1.15) - renamed IsHovered() to IsItemHovered()
915 - 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)
916 - 2014/09/25 (1.13) - removed 'text_end' parameter from IO.SetClipboardTextFn (the string is now always zero-terminated for simplicity)
917 - 2014/09/24 (1.12) - renamed SetFontScale() to SetWindowFontScale()
918 - 2014/09/24 (1.12) - moved IM_MALLOC/IM_REALLOC/IM_FREE preprocessor defines to IO.MemAllocFn/IO.MemReallocFn/IO.MemFreeFn
919 - 2014/08/30 (1.09) - removed IO.FontHeight (now computed automatically)
920 - 2014/08/30 (1.09) - moved IMGUI_FONT_TEX_UV_FOR_WHITE preprocessor define to IO.FontTexUvForWhite
921 - 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes
922
923
924 FREQUENTLY ASKED QUESTIONS (FAQ)
925 ================================
926
927 Read all answers online:
928 https://www.dearimgui.com/faq or https://github.com/ocornut/imgui/blob/master/docs/FAQ.md (same url)
929 Read all answers locally (with a text editor or ideally a Markdown viewer):
930 docs/FAQ.md
931 Some answers are copied down here to facilitate searching in code.
932
933 Q&A: Basics
934 ===========
935
936 Q: Where is the documentation?
937 A: This library is poorly documented at the moment and expects the user to be acquainted with C/C++.
938 - Run the examples/ applications and explore them.
939 - Read Getting Started (https://github.com/ocornut/imgui/wiki/Getting-Started) guide.
940 - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
941 - The demo covers most features of Dear ImGui, so you can read the code and see its output.
942 - See documentation and comments at the top of imgui.cpp + effectively imgui.h.
943 - 20+ standalone example applications using e.g. OpenGL/DirectX are provided in the
944 examples/ folder to explain how to integrate Dear ImGui with your own engine/application.
945 - The Wiki (https://github.com/ocornut/imgui/wiki) has many resources and links.
946 - The Glossary (https://github.com/ocornut/imgui/wiki/Glossary) page also may be useful.
947 - Your programming IDE is your friend, find the type or function declaration to find comments
948 associated with it.
949
950 Q: What is this library called?
951 Q: Which version should I get?
952 >> This library is called "Dear ImGui", please don't call it "ImGui" :)
953 >> See https://www.dearimgui.com/faq for details.
954
955 Q&A: Integration
956 ================
957
958 Q: How to get started?
959 A: Read https://github.com/ocornut/imgui/wiki/Getting-Started. Read 'PROGRAMMER GUIDE' above. Read examples/README.txt.
960
961 Q: How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application?
962 A: You should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags!
963 >> See https://www.dearimgui.com/faq for a fully detailed answer. You really want to read this.
964
965 Q. How can I enable keyboard or gamepad controls?
966 Q: How can I use this on a machine without mouse, keyboard or screen? (input share, remote display)
967 Q: I integrated Dear ImGui in my engine and little squares are showing instead of text...
968 Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around...
969 Q: I integrated Dear ImGui in my engine and some elements are displaying outside their expected windows boundaries...
970 >> See https://www.dearimgui.com/faq
971
972 Q&A: Usage
973 ----------
974
975 Q: About the ID Stack system..
976 - Why is my widget not reacting when I click on it?
977 - How can I have widgets with an empty label?
978 - How can I have multiple widgets with the same label?
979 - How can I have multiple windows with the same label?
980 Q: How can I display an image? What is ImTextureID, how does it work?
981 Q: How can I use my own math types instead of ImVec2?
982 Q: How can I interact with standard C++ types (such as std::string and std::vector)?
983 Q: How can I display custom shapes? (using low-level ImDrawList API)
984 >> See https://www.dearimgui.com/faq
985
986 Q&A: Fonts, Text
987 ================
988
989 Q: How should I handle DPI in my application?
990 Q: How can I load a different font than the default?
991 Q: How can I easily use icons in my application?
992 Q: How can I load multiple fonts?
993 Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic?
994 >> See https://www.dearimgui.com/faq and https://github.com/ocornut/imgui/blob/master/docs/FONTS.md
995
996 Q&A: Concerns
997 =============
998
999 Q: Who uses Dear ImGui?
1000 Q: Can you create elaborate/serious tools with Dear ImGui?
1001 Q: Can you reskin the look of Dear ImGui?
1002 Q: Why using C++ (as opposed to C)?
1003 >> See https://www.dearimgui.com/faq
1004
1005 Q&A: Community
1006 ==============
1007
1008 Q: How can I help?
1009 A: - Businesses: please reach out to "omar AT dearimgui DOT com" if you work in a place using Dear ImGui!
1010 We can discuss ways for your company to fund development via invoiced technical support, maintenance or sponsoring contacts.
1011 This is among the most useful thing you can do for Dear ImGui. With increased funding, we sustain and grow work on this project.
1012 >>> See https://github.com/ocornut/imgui/wiki/Funding
1013 - Businesses: you can also purchase licenses for the Dear ImGui Automation/Test Engine.
1014 - If you are experienced with Dear ImGui and C++, look at the GitHub issues, look at the Wiki, and see how you want to help and can help!
1015 - Disclose your usage of Dear ImGui via a dev blog post, a tweet, a screenshot, a mention somewhere etc.
1016 You may post screenshot or links in the gallery threads. Visuals are ideal as they inspire other programmers.
1017 But even without visuals, disclosing your use of dear imgui helps the library grow credibility, and help other teams and programmers with taking decisions.
1018 - If you have issues or if you need to hack into the library, even if you don't expect any support it is useful that you share your issues (on GitHub or privately).
1019
1020*/
1021
1022//-------------------------------------------------------------------------
1023// [SECTION] INCLUDES
1024//-------------------------------------------------------------------------
1025
1026#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
1027#define _CRT_SECURE_NO_WARNINGS
1028#endif
1029
1030#ifndef IMGUI_DEFINE_MATH_OPERATORS
1031#define IMGUI_DEFINE_MATH_OPERATORS
1032#endif
1033
1034#include "imgui.h"
1035#ifndef IMGUI_DISABLE
1036#include "imgui_internal.h"
1037
1038// System includes
1039#include <stdio.h> // vsnprintf, sscanf, printf
1040#include <stdint.h> // intptr_t
1041
1042// [Windows] On non-Visual Studio compilers, we default to IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS unless explicitly enabled
1043#if defined(_WIN32) && !defined(_MSC_VER) && !defined(IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)
1044#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
1045#endif
1046
1047// [Windows] OS specific includes (optional)
1048#if defined(_WIN32) && defined(IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS) && defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) && defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) && defined(IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS)
1049#define IMGUI_DISABLE_WIN32_FUNCTIONS
1050#endif
1051#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS)
1052#ifndef WIN32_LEAN_AND_MEAN
1053#define WIN32_LEAN_AND_MEAN
1054#endif
1055#ifndef NOMINMAX
1056#define NOMINMAX
1057#endif
1058#ifndef __MINGW32__
1059#include <Windows.h> // _wfopen, OpenClipboard
1060#else
1061#include <windows.h>
1062#endif
1063#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP || WINAPI_FAMILY == WINAPI_FAMILY_GAMES)
1064// The UWP and GDK Win32 API subsets don't support clipboard nor IME functions
1065#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS
1066#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
1067#define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS
1068#endif
1069#endif
1070
1071// [Apple] OS specific includes
1072#if defined(__APPLE__)
1073#include <TargetConditionals.h>
1074#endif
1075
1076// Visual Studio warnings
1077#ifdef _MSC_VER
1078#pragma warning (disable: 4127) // condition expression is constant
1079#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
1080#if defined(_MSC_VER) && _MSC_VER >= 1922 // MSVC 2019 16.2 or later
1081#pragma warning (disable: 5054) // operator '|': deprecated between enumerations of different types
1082#endif
1083#pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to an 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2).
1084#pragma warning (disable: 26495) // [Static Analyzer] Variable 'XXX' is uninitialized. Always initialize a member variable (type.6).
1085#pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3).
1086#endif
1087
1088// Clang/GCC warnings with -Weverything
1089#if defined(__clang__)
1090#if __has_warning("-Wunknown-warning-option")
1091#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great!
1092#endif
1093#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx'
1094#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse.
1095#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok.
1096#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.
1097#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.
1098#pragma clang diagnostic ignored "-Wglobal-constructors" // warning: declaration requires a global destructor // similar to above, not sure what the exact difference is.
1099#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
1100#pragma clang diagnostic ignored "-Wformat-pedantic" // warning: format specifies type 'void *' but the argument has type 'xxxx *' // unreasonable, would lead to casting every %p arg to void*. probably enabled by -pedantic.
1101#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning: cast to 'void *' from smaller integer type 'int'
1102#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0
1103#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double.
1104#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
1105#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access
1106#elif defined(__GNUC__)
1107// We disable -Wpragmas because GCC doesn't provide a has_warning equivalent and some forks/patches may not follow the warning/version association.
1108#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
1109#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
1110#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size
1111#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'void*', but argument 6 has type 'ImGuiWindow*'
1112#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
1113#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value
1114#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked
1115#pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when assuming that (X - c) > X is always false
1116#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead
1117#endif
1118
1119// Debug options
1120#define IMGUI_DEBUG_NAV_SCORING 0 // Display navigation scoring preview when hovering items. Hold CTRL to display for all candidates. CTRL+Arrow to change last direction.
1121#define IMGUI_DEBUG_NAV_RECTS 0 // Display the reference navigation rectangle for each window
1122
1123// When using CTRL+TAB (or Gamepad Square+L/R) we delay the visual a little in order to reduce visual noise doing a fast switch.
1124static const float NAV_WINDOWING_HIGHLIGHT_DELAY = 0.20f; // Time before the highlight and screen dimming starts fading in
1125static const float NAV_WINDOWING_LIST_APPEAR_DELAY = 0.15f; // Time before the window list starts to appear
1126
1127static const float NAV_ACTIVATE_HIGHLIGHT_TIMER = 0.10f; // Time to highlight an item activated by a shortcut.
1128
1129// Window resizing from edges (when io.ConfigWindowsResizeFromEdges = true and ImGuiBackendFlags_HasMouseCursors is set in io.BackendFlags by backend)
1130static const float WINDOWS_HOVER_PADDING = 4.0f; // Extend outside window for hovering/resizing (maxxed with TouchPadding) and inside windows for borders. Affect FindHoveredWindow().
1131static const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04f; // Reduce visual noise by only highlighting the border after a certain time.
1132static const float WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER = 0.70f; // Lock scrolled window (so it doesn't pick child windows that are scrolling through) for a certain time, unless mouse moved.
1133
1134// Tooltip offset
1135static const ImVec2 TOOLTIP_DEFAULT_OFFSET = ImVec2(16, 10); // Multiplied by g.Style.MouseCursorScale
1136
1137// Docking
1138static const float DOCKING_TRANSPARENT_PAYLOAD_ALPHA = 0.50f; // For use with io.ConfigDockingTransparentPayload. Apply to Viewport _or_ WindowBg in host viewport.
1139
1140//-------------------------------------------------------------------------
1141// [SECTION] FORWARD DECLARATIONS
1142//-------------------------------------------------------------------------
1143
1144static void SetCurrentWindow(ImGuiWindow* window);
1145static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags);
1146static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window);
1147
1148static void AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window);
1149
1150// Settings
1151static void WindowSettingsHandler_ClearAll(ImGuiContext*, ImGuiSettingsHandler*);
1152static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name);
1153static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line);
1154static void WindowSettingsHandler_ApplyAll(ImGuiContext*, ImGuiSettingsHandler*);
1155static void WindowSettingsHandler_WriteAll(ImGuiContext*, ImGuiSettingsHandler*, ImGuiTextBuffer* buf);
1156
1157// Platform Dependents default implementation for IO functions
1158static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx);
1159static void SetClipboardTextFn_DefaultImpl(void* user_data_ctx, const char* text);
1160static void PlatformSetImeDataFn_DefaultImpl(ImGuiContext* ctx, ImGuiViewport* viewport, ImGuiPlatformImeData* data);
1161static bool PlatformOpenInShellFn_DefaultImpl(ImGuiContext* ctx, const char* path);
1162
1163namespace ImGui
1164{
1165// Item
1166static void ItemHandleShortcut(ImGuiID id);
1167
1168// Navigation
1169static void NavUpdate();
1170static void NavUpdateWindowing();
1171static void NavUpdateWindowingOverlay();
1172static void NavUpdateCancelRequest();
1173static void NavUpdateCreateMoveRequest();
1174static void NavUpdateCreateTabbingRequest();
1175static float NavUpdatePageUpPageDown();
1176static inline void NavUpdateAnyRequestFlag();
1177static void NavUpdateCreateWrappingRequest();
1178static void NavEndFrame();
1179static bool NavScoreItem(ImGuiNavItemData* result);
1180static void NavApplyItemToResult(ImGuiNavItemData* result);
1181static void NavProcessItem();
1182static void NavProcessItemForTabbingRequest(ImGuiID id, ImGuiItemFlags item_flags, ImGuiNavMoveFlags move_flags);
1183static ImVec2 NavCalcPreferredRefPos();
1184static void NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window);
1185static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window);
1186static void NavRestoreLayer(ImGuiNavLayer layer);
1187static int FindWindowFocusIndex(ImGuiWindow* window);
1188
1189// Error Checking and Debug Tools
1190static void ErrorCheckNewFrameSanityChecks();
1191static void ErrorCheckEndFrameSanityChecks();
1192static void UpdateDebugToolItemPicker();
1193static void UpdateDebugToolStackQueries();
1194static void UpdateDebugToolFlashStyleColor();
1195
1196// Inputs
1197static void UpdateKeyboardInputs();
1198static void UpdateMouseInputs();
1199static void UpdateMouseWheel();
1200static void UpdateKeyRoutingTable(ImGuiKeyRoutingTable* rt);
1201
1202// Misc
1203static void UpdateSettings();
1204static int UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_hovered, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect);
1205static void RenderWindowOuterBorders(ImGuiWindow* window);
1206static void RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, bool handle_borders_and_resize_grips, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size);
1207static void RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open);
1208static void RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 col);
1209static void RenderDimmedBackgrounds();
1210static void SetLastItemDataForWindow(ImGuiWindow* window, const ImRect& rect);
1211
1212// Viewports
1213const ImGuiID IMGUI_VIEWPORT_DEFAULT_ID = 0x11111111; // Using an arbitrary constant instead of e.g. ImHashStr("ViewportDefault", 0); so it's easier to spot in the debugger. The exact value doesn't matter.
1214static ImGuiViewportP* AddUpdateViewport(ImGuiWindow* window, ImGuiID id, const ImVec2& platform_pos, const ImVec2& size, ImGuiViewportFlags flags);
1215static void DestroyViewport(ImGuiViewportP* viewport);
1216static void UpdateViewportsNewFrame();
1217static void UpdateViewportsEndFrame();
1218static void WindowSelectViewport(ImGuiWindow* window);
1219static void WindowSyncOwnedViewport(ImGuiWindow* window, ImGuiWindow* parent_window_in_stack);
1220static bool UpdateTryMergeWindowIntoHostViewport(ImGuiWindow* window, ImGuiViewportP* host_viewport);
1221static bool UpdateTryMergeWindowIntoHostViewports(ImGuiWindow* window);
1222static bool GetWindowAlwaysWantOwnViewport(ImGuiWindow* window);
1223static int FindPlatformMonitorForPos(const ImVec2& pos);
1224static int FindPlatformMonitorForRect(const ImRect& r);
1225static void UpdateViewportPlatformMonitor(ImGuiViewportP* viewport);
1226
1227}
1228
1229//-----------------------------------------------------------------------------
1230// [SECTION] CONTEXT AND MEMORY ALLOCATORS
1231//-----------------------------------------------------------------------------
1232
1233// DLL users:
1234// - Heaps and globals are not shared across DLL boundaries!
1235// - You will need to call SetCurrentContext() + SetAllocatorFunctions() for each static/DLL boundary you are calling from.
1236// - Same applies for hot-reloading mechanisms that are reliant on reloading DLL (note that many hot-reloading mechanisms work without DLL).
1237// - Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
1238// - Confused? In a debugger: add GImGui to your watch window and notice how its value changes depending on your current location (which DLL boundary you are in).
1239
1240// Current context pointer. Implicitly used by all Dear ImGui functions. Always assumed to be != NULL.
1241// - ImGui::CreateContext() will automatically set this pointer if it is NULL.
1242// Change to a different context by calling ImGui::SetCurrentContext().
1243// - Important: Dear ImGui functions are not thread-safe because of this pointer.
1244// If you want thread-safety to allow N threads to access N different contexts:
1245// - Change this variable to use thread local storage so each thread can refer to a different context, in your imconfig.h:
1246// struct ImGuiContext;
1247// extern thread_local ImGuiContext* MyImGuiTLS;
1248// #define GImGui MyImGuiTLS
1249// And then define MyImGuiTLS in one of your cpp files. Note that thread_local is a C++11 keyword, earlier C++ uses compiler-specific keyword.
1250// - Future development aims to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586
1251// - If you need a finite number of contexts, you may compile and use multiple instances of the ImGui code from a different namespace.
1252// - DLL users: read comments above.
1253#ifndef GImGui
1254ImGuiContext* GImGui = NULL;
1255#endif
1256
1257// Memory Allocator functions. Use SetAllocatorFunctions() to change them.
1258// - You probably don't want to modify that mid-program, and if you use global/static e.g. ImVector<> instances you may need to keep them accessible during program destruction.
1259// - DLL users: read comments above.
1260#ifndef IMGUI_DISABLE_DEFAULT_ALLOCATORS
1261static void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); return malloc(size); }
1262static void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); free(ptr); }
1263#else
1264static void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); IM_UNUSED(size); IM_ASSERT(0); return NULL; }
1265static void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); IM_UNUSED(ptr); IM_ASSERT(0); }
1266#endif
1267static ImGuiMemAllocFunc GImAllocatorAllocFunc = MallocWrapper;
1268static ImGuiMemFreeFunc GImAllocatorFreeFunc = FreeWrapper;
1269static void* GImAllocatorUserData = NULL;
1270
1271//-----------------------------------------------------------------------------
1272// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO)
1273//-----------------------------------------------------------------------------
1274
1275ImGuiStyle::ImGuiStyle()
1276{
1277 Alpha = 1.0f; // Global alpha applies to everything in Dear ImGui.
1278 DisabledAlpha = 0.60f; // Additional alpha multiplier applied by BeginDisabled(). Multiply over current value of Alpha.
1279 WindowPadding = ImVec2(8,8); // Padding within a window
1280 WindowRounding = 0.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended.
1281 WindowBorderSize = 1.0f; // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested.
1282 WindowMinSize = ImVec2(32,32); // Minimum window size
1283 WindowTitleAlign = ImVec2(0.0f,0.5f);// Alignment for title bar text
1284 WindowMenuButtonPosition = ImGuiDir_Left; // Position of the collapsing/docking button in the title bar (left/right). Defaults to ImGuiDir_Left.
1285 ChildRounding = 0.0f; // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows
1286 ChildBorderSize = 1.0f; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. Other values not well tested.
1287 PopupRounding = 0.0f; // Radius of popup window corners rounding. Set to 0.0f to have rectangular child windows
1288 PopupBorderSize = 1.0f; // Thickness of border around popup or tooltip windows. Generally set to 0.0f or 1.0f. Other values not well tested.
1289 FramePadding = ImVec2(4,3); // Padding within a framed rectangle (used by most widgets)
1290 FrameRounding = 0.0f; // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets).
1291 FrameBorderSize = 0.0f; // Thickness of border around frames. Generally set to 0.0f or 1.0f. Other values not well tested.
1292 ItemSpacing = ImVec2(8,4); // Horizontal and vertical spacing between widgets/lines
1293 ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label)
1294 CellPadding = ImVec2(4,2); // Padding within a table cell. Cellpadding.x is locked for entire table. CellPadding.y may be altered between different rows.
1295 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!
1296 IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2).
1297 ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1).
1298 ScrollbarSize = 14.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar
1299 ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar
1300 GrabMinSize = 12.0f; // Minimum width/height of a grab box for slider/scrollbar
1301 GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
1302 LogSliderDeadzone = 4.0f; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero.
1303 TabRounding = 4.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs.
1304 TabBorderSize = 0.0f; // Thickness of border around tabs.
1305 TabMinWidthForCloseButton = 0.0f; // Minimum width for close button to appear on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected.
1306 TabBarBorderSize = 1.0f; // Thickness of tab-bar separator, which takes on the tab active color to denote focus.
1307 TabBarOverlineSize = 2.0f; // Thickness of tab-bar overline, which highlights the selected tab-bar.
1308 TableAngledHeadersAngle = 35.0f * (IM_PI / 180.0f); // Angle of angled headers (supported values range from -50 degrees to +50 degrees).
1309 TableAngledHeadersTextAlign = ImVec2(0.5f,0.0f);// Alignment of angled headers within the cell
1310 ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right.
1311 ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text.
1312 SelectableTextAlign = ImVec2(0.0f,0.0f);// Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line.
1313 SeparatorTextBorderSize = 3.0f; // Thickness of border in SeparatorText()
1314 SeparatorTextAlign = ImVec2(0.0f,0.5f);// Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center).
1315 SeparatorTextPadding = ImVec2(20.0f,3.f);// Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y.
1316 DisplayWindowPadding = ImVec2(19,19); // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows.
1317 DisplaySafeAreaPadding = ImVec2(3,3); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows.
1318 DockingSeparatorSize = 2.0f; // Thickness of resizing border between docked windows
1319 MouseCursorScale = 1.0f; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later.
1320 AntiAliasedLines = true; // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU.
1321 AntiAliasedLinesUseTex = true; // Enable anti-aliased lines/borders using textures where possible. Require backend to render with bilinear filtering (NOT point/nearest filtering).
1322 AntiAliasedFill = true; // Enable anti-aliased filled shapes (rounded rectangles, circles, etc.).
1323 CurveTessellationTol = 1.25f; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality.
1324 CircleTessellationMaxError = 0.30f; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry.
1325
1326 // Behaviors
1327 HoverStationaryDelay = 0.15f; // Delay for IsItemHovered(ImGuiHoveredFlags_Stationary). Time required to consider mouse stationary.
1328 HoverDelayShort = 0.15f; // Delay for IsItemHovered(ImGuiHoveredFlags_DelayShort). Usually used along with HoverStationaryDelay.
1329 HoverDelayNormal = 0.40f; // Delay for IsItemHovered(ImGuiHoveredFlags_DelayNormal). "
1330 HoverFlagsForTooltipMouse = ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayShort | ImGuiHoveredFlags_AllowWhenDisabled; // Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) or BeginItemTooltip()/SetItemTooltip() while using mouse.
1331 HoverFlagsForTooltipNav = ImGuiHoveredFlags_NoSharedDelay | ImGuiHoveredFlags_DelayNormal | ImGuiHoveredFlags_AllowWhenDisabled; // Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) or BeginItemTooltip()/SetItemTooltip() while using keyboard/gamepad.
1332
1333 // Default theme
1334 ImGui::StyleColorsDark(this);
1335}
1336
1337// To scale your entire UI (e.g. if you want your app to use High DPI or generally be DPI aware) you may use this helper function. Scaling the fonts is done separately and is up to you.
1338// Important: This operation is lossy because we round all sizes to integer. If you need to change your scale multiples, call this over a freshly initialized ImGuiStyle structure rather than scaling multiple times.
1339void ImGuiStyle::ScaleAllSizes(float scale_factor)
1340{
1341 WindowPadding = ImTrunc(WindowPadding * scale_factor);
1342 WindowRounding = ImTrunc(WindowRounding * scale_factor);
1343 WindowMinSize = ImTrunc(WindowMinSize * scale_factor);
1344 ChildRounding = ImTrunc(ChildRounding * scale_factor);
1345 PopupRounding = ImTrunc(PopupRounding * scale_factor);
1346 FramePadding = ImTrunc(FramePadding * scale_factor);
1347 FrameRounding = ImTrunc(FrameRounding * scale_factor);
1348 ItemSpacing = ImTrunc(ItemSpacing * scale_factor);
1349 ItemInnerSpacing = ImTrunc(ItemInnerSpacing * scale_factor);
1350 CellPadding = ImTrunc(CellPadding * scale_factor);
1351 TouchExtraPadding = ImTrunc(TouchExtraPadding * scale_factor);
1352 IndentSpacing = ImTrunc(IndentSpacing * scale_factor);
1353 ColumnsMinSpacing = ImTrunc(ColumnsMinSpacing * scale_factor);
1354 ScrollbarSize = ImTrunc(ScrollbarSize * scale_factor);
1355 ScrollbarRounding = ImTrunc(ScrollbarRounding * scale_factor);
1356 GrabMinSize = ImTrunc(GrabMinSize * scale_factor);
1357 GrabRounding = ImTrunc(GrabRounding * scale_factor);
1358 LogSliderDeadzone = ImTrunc(LogSliderDeadzone * scale_factor);
1359 TabRounding = ImTrunc(TabRounding * scale_factor);
1360 TabMinWidthForCloseButton = (TabMinWidthForCloseButton != FLT_MAX) ? ImTrunc(TabMinWidthForCloseButton * scale_factor) : FLT_MAX;
1361 TabBarOverlineSize = ImTrunc(TabBarOverlineSize * scale_factor);
1362 SeparatorTextPadding = ImTrunc(SeparatorTextPadding * scale_factor);
1363 DockingSeparatorSize = ImTrunc(DockingSeparatorSize * scale_factor);
1364 DisplayWindowPadding = ImTrunc(DisplayWindowPadding * scale_factor);
1365 DisplaySafeAreaPadding = ImTrunc(DisplaySafeAreaPadding * scale_factor);
1366 MouseCursorScale = ImTrunc(MouseCursorScale * scale_factor);
1367}
1368
1369ImGuiIO::ImGuiIO()
1370{
1371 // Most fields are initialized with zero
1372 memset(this, 0, sizeof(*this));
1373 IM_STATIC_ASSERT(IM_ARRAYSIZE(ImGuiIO::MouseDown) == ImGuiMouseButton_COUNT && IM_ARRAYSIZE(ImGuiIO::MouseClicked) == ImGuiMouseButton_COUNT);
1374
1375 // Settings
1376 ConfigFlags = ImGuiConfigFlags_None;
1377 BackendFlags = ImGuiBackendFlags_None;
1378 DisplaySize = ImVec2(-1.0f, -1.0f);
1379 DeltaTime = 1.0f / 60.0f;
1380 IniSavingRate = 5.0f;
1381 IniFilename = "imgui.ini"; // Important: "imgui.ini" is relative to current working dir, most apps will want to lock this to an absolute path (e.g. same path as executables).
1382 LogFilename = "imgui_log.txt";
1383#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
1384 for (int i = 0; i < ImGuiKey_COUNT; i++)
1385 KeyMap[i] = -1;
1386#endif
1387 UserData = NULL;
1388
1389 Fonts = NULL;
1390 FontGlobalScale = 1.0f;
1391 FontDefault = NULL;
1392 FontAllowUserScaling = false;
1393 DisplayFramebufferScale = ImVec2(1.0f, 1.0f);
1394
1395 // Docking options (when ImGuiConfigFlags_DockingEnable is set)
1396 ConfigDockingNoSplit = false;
1397 ConfigDockingWithShift = false;
1398 ConfigDockingAlwaysTabBar = false;
1399 ConfigDockingTransparentPayload = false;
1400
1401 // Viewport options (when ImGuiConfigFlags_ViewportsEnable is set)
1402 ConfigViewportsNoAutoMerge = false;
1403 ConfigViewportsNoTaskBarIcon = false;
1404 ConfigViewportsNoDecoration = true;
1405 ConfigViewportsNoDefaultParent = false;
1406
1407 // Miscellaneous options
1408 MouseDrawCursor = false;
1409#ifdef __APPLE__
1410 ConfigMacOSXBehaviors = true; // Set Mac OS X style defaults based on __APPLE__ compile time flag
1411#else
1412 ConfigMacOSXBehaviors = false;
1413#endif
1414 ConfigNavSwapGamepadButtons = false;
1415 ConfigInputTrickleEventQueue = true;
1416 ConfigInputTextCursorBlink = true;
1417 ConfigInputTextEnterKeepActive = false;
1418 ConfigDragClickToInputText = false;
1419 ConfigWindowsResizeFromEdges = true;
1420 ConfigWindowsMoveFromTitleBarOnly = false;
1421 ConfigMemoryCompactTimer = 60.0f;
1422 ConfigDebugBeginReturnValueOnce = false;
1423 ConfigDebugBeginReturnValueLoop = false;
1424
1425 // Inputs Behaviors
1426 MouseDoubleClickTime = 0.30f;
1427 MouseDoubleClickMaxDist = 6.0f;
1428 MouseDragThreshold = 6.0f;
1429 KeyRepeatDelay = 0.275f;
1430 KeyRepeatRate = 0.050f;
1431
1432 // Platform Functions
1433 // Note: Initialize() will setup default clipboard/ime handlers.
1434 BackendPlatformName = BackendRendererName = NULL;
1435 BackendPlatformUserData = BackendRendererUserData = BackendLanguageUserData = NULL;
1436 PlatformOpenInShellUserData = NULL;
1437 PlatformLocaleDecimalPoint = '.';
1438
1439 // Input (NB: we already have memset zero the entire structure!)
1440 MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
1441 MousePosPrev = ImVec2(-FLT_MAX, -FLT_MAX);
1442 MouseSource = ImGuiMouseSource_Mouse;
1443 for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[i] = MouseDownDurationPrev[i] = -1.0f;
1444 for (int i = 0; i < IM_ARRAYSIZE(KeysData); i++) { KeysData[i].DownDuration = KeysData[i].DownDurationPrev = -1.0f; }
1445 AppAcceptingEvents = true;
1446 BackendUsingLegacyKeyArrays = (ImS8)-1;
1447 BackendUsingLegacyNavInputArray = true; // assume using legacy array until proven wrong
1448}
1449
1450// Pass in translated ASCII characters for text input.
1451// - with glfw you can get those from the callback set in glfwSetCharCallback()
1452// - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message
1453// FIXME: Should in theory be called "AddCharacterEvent()" to be consistent with new API
1454void ImGuiIO::AddInputCharacter(unsigned int c)
1455{
1456 IM_ASSERT(Ctx != NULL);
1457 ImGuiContext& g = *Ctx;
1458 if (c == 0 || !AppAcceptingEvents)
1459 return;
1460
1461 ImGuiInputEvent e;
1462 e.Type = ImGuiInputEventType_Text;
1463 e.Source = ImGuiInputSource_Keyboard;
1464 e.EventId = g.InputEventsNextEventId++;
1465 e.Text.Char = c;
1466 g.InputEventsQueue.push_back(e);
1467}
1468
1469// UTF16 strings use surrogate pairs to encode codepoints >= 0x10000, so
1470// we should save the high surrogate.
1471void ImGuiIO::AddInputCharacterUTF16(ImWchar16 c)
1472{
1473 if ((c == 0 && InputQueueSurrogate == 0) || !AppAcceptingEvents)
1474 return;
1475
1476 if ((c & 0xFC00) == 0xD800) // High surrogate, must save
1477 {
1478 if (InputQueueSurrogate != 0)
1479 AddInputCharacter(IM_UNICODE_CODEPOINT_INVALID);
1480 InputQueueSurrogate = c;
1481 return;
1482 }
1483
1484 ImWchar cp = c;
1485 if (InputQueueSurrogate != 0)
1486 {
1487 if ((c & 0xFC00) != 0xDC00) // Invalid low surrogate
1488 {
1489 AddInputCharacter(IM_UNICODE_CODEPOINT_INVALID);
1490 }
1491 else
1492 {
1493#if IM_UNICODE_CODEPOINT_MAX == 0xFFFF
1494 cp = IM_UNICODE_CODEPOINT_INVALID; // Codepoint will not fit in ImWchar
1495#else
1496 cp = (ImWchar)(((InputQueueSurrogate - 0xD800) << 10) + (c - 0xDC00) + 0x10000);
1497#endif
1498 }
1499
1500 InputQueueSurrogate = 0;
1501 }
1502 AddInputCharacter((unsigned)cp);
1503}
1504
1505void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
1506{
1507 if (!AppAcceptingEvents)
1508 return;
1509 while (*utf8_chars != 0)
1510 {
1511 unsigned int c = 0;
1512 utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL);
1513 AddInputCharacter(c);
1514 }
1515}
1516
1517// Clear all incoming events.
1518void ImGuiIO::ClearEventsQueue()
1519{
1520 IM_ASSERT(Ctx != NULL);
1521 ImGuiContext& g = *Ctx;
1522 g.InputEventsQueue.clear();
1523}
1524
1525// Clear current keyboard/gamepad state + current frame text input buffer. Equivalent to releasing all keys/buttons.
1526void ImGuiIO::ClearInputKeys()
1527{
1528#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
1529 memset(KeysDown, 0, sizeof(KeysDown));
1530#endif
1531 for (int n = 0; n < IM_ARRAYSIZE(KeysData); n++)
1532 {
1533 if (ImGui::IsMouseKey((ImGuiKey)(n + ImGuiKey_KeysData_OFFSET)))
1534 continue;
1535 KeysData[n].Down = false;
1536 KeysData[n].DownDuration = -1.0f;
1537 KeysData[n].DownDurationPrev = -1.0f;
1538 }
1539 KeyCtrl = KeyShift = KeyAlt = KeySuper = false;
1540 KeyMods = ImGuiMod_None;
1541 InputQueueCharacters.resize(0); // Behavior of old ClearInputCharacters().
1542}
1543
1544void ImGuiIO::ClearInputMouse()
1545{
1546 for (ImGuiKey key = ImGuiKey_Mouse_BEGIN; key < ImGuiKey_Mouse_END; key = (ImGuiKey)(key + 1))
1547 {
1548 ImGuiKeyData* key_data = &KeysData[key - ImGuiKey_KeysData_OFFSET];
1549 key_data->Down = false;
1550 key_data->DownDuration = -1.0f;
1551 key_data->DownDurationPrev = -1.0f;
1552 }
1553 MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
1554 for (int n = 0; n < IM_ARRAYSIZE(MouseDown); n++)
1555 {
1556 MouseDown[n] = false;
1557 MouseDownDuration[n] = MouseDownDurationPrev[n] = -1.0f;
1558 }
1559 MouseWheel = MouseWheelH = 0.0f;
1560}
1561
1562// Removed this as it is ambiguous/misleading and generally incorrect to use with the existence of a higher-level input queue.
1563// Current frame character buffer is now also cleared by ClearInputKeys().
1564#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
1565void ImGuiIO::ClearInputCharacters()
1566{
1567 InputQueueCharacters.resize(0);
1568}
1569#endif
1570
1571static ImGuiInputEvent* FindLatestInputEvent(ImGuiContext* ctx, ImGuiInputEventType type, int arg = -1)
1572{
1573 ImGuiContext& g = *ctx;
1574 for (int n = g.InputEventsQueue.Size - 1; n >= 0; n--)
1575 {
1576 ImGuiInputEvent* e = &g.InputEventsQueue[n];
1577 if (e->Type != type)
1578 continue;
1579 if (type == ImGuiInputEventType_Key && e->Key.Key != arg)
1580 continue;
1581 if (type == ImGuiInputEventType_MouseButton && e->MouseButton.Button != arg)
1582 continue;
1583 return e;
1584 }
1585 return NULL;
1586}
1587
1588// Queue a new key down/up event.
1589// - ImGuiKey key: Translated key (as in, generally ImGuiKey_A matches the key end-user would use to emit an 'A' character)
1590// - bool down: Is the key down? use false to signify a key release.
1591// - float analog_value: 0.0f..1.0f
1592// IMPORTANT: THIS FUNCTION AND OTHER "ADD" GRABS THE CONTEXT FROM OUR INSTANCE.
1593// WE NEED TO ENSURE THAT ALL FUNCTION CALLS ARE FULFILLING THIS, WHICH IS WHY GetKeyData() HAS AN EXPLICIT CONTEXT.
1594void ImGuiIO::AddKeyAnalogEvent(ImGuiKey key, bool down, float analog_value)
1595{
1596 //if (e->Down) { IMGUI_DEBUG_LOG_IO("AddKeyEvent() Key='%s' %d, NativeKeycode = %d, NativeScancode = %d\n", ImGui::GetKeyName(e->Key), e->Down, e->NativeKeycode, e->NativeScancode); }
1597 IM_ASSERT(Ctx != NULL);
1598 if (key == ImGuiKey_None || !AppAcceptingEvents)
1599 return;
1600 ImGuiContext& g = *Ctx;
1601 IM_ASSERT(ImGui::IsNamedKeyOrMod(key)); // Backend needs to pass a valid ImGuiKey_ constant. 0..511 values are legacy native key codes which are not accepted by this API.
1602 IM_ASSERT(ImGui::IsAliasKey(key) == false); // Backend cannot submit ImGuiKey_MouseXXX values they are automatically inferred from AddMouseXXX() events.
1603
1604 // MacOS: swap Cmd(Super) and Ctrl
1605 if (g.IO.ConfigMacOSXBehaviors)
1606 {
1607 if (key == ImGuiMod_Super) { key = ImGuiMod_Ctrl; }
1608 else if (key == ImGuiMod_Ctrl) { key = ImGuiMod_Super; }
1609 else if (key == ImGuiKey_LeftSuper) { key = ImGuiKey_LeftCtrl; }
1610 else if (key == ImGuiKey_RightSuper){ key = ImGuiKey_RightCtrl; }
1611 else if (key == ImGuiKey_LeftCtrl) { key = ImGuiKey_LeftSuper; }
1612 else if (key == ImGuiKey_RightCtrl) { key = ImGuiKey_RightSuper; }
1613 }
1614
1615 // Verify that backend isn't mixing up using new io.AddKeyEvent() api and old io.KeysDown[] + io.KeyMap[] data.
1616#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
1617 IM_ASSERT((BackendUsingLegacyKeyArrays == -1 || BackendUsingLegacyKeyArrays == 0) && "Backend needs to either only use io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!");
1618 if (BackendUsingLegacyKeyArrays == -1)
1619 for (int n = ImGuiKey_NamedKey_BEGIN; n < ImGuiKey_NamedKey_END; n++)
1620 IM_ASSERT(KeyMap[n] == -1 && "Backend needs to either only use io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!");
1621 BackendUsingLegacyKeyArrays = 0;
1622#endif
1623 if (ImGui::IsGamepadKey(key))
1624 BackendUsingLegacyNavInputArray = false;
1625
1626 // Filter duplicate (in particular: key mods and gamepad analog values are commonly spammed)
1627 const ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_Key, (int)key);
1628 const ImGuiKeyData* key_data = ImGui::GetKeyData(&g, key);
1629 const bool latest_key_down = latest_event ? latest_event->Key.Down : key_data->Down;
1630 const float latest_key_analog = latest_event ? latest_event->Key.AnalogValue : key_data->AnalogValue;
1631 if (latest_key_down == down && latest_key_analog == analog_value)
1632 return;
1633
1634 // Add event
1635 ImGuiInputEvent e;
1636 e.Type = ImGuiInputEventType_Key;
1637 e.Source = ImGui::IsGamepadKey(key) ? ImGuiInputSource_Gamepad : ImGuiInputSource_Keyboard;
1638 e.EventId = g.InputEventsNextEventId++;
1639 e.Key.Key = key;
1640 e.Key.Down = down;
1641 e.Key.AnalogValue = analog_value;
1642 g.InputEventsQueue.push_back(e);
1643}
1644
1645void ImGuiIO::AddKeyEvent(ImGuiKey key, bool down)
1646{
1647 if (!AppAcceptingEvents)
1648 return;
1649 AddKeyAnalogEvent(key, down, down ? 1.0f : 0.0f);
1650}
1651
1652// [Optional] Call after AddKeyEvent().
1653// Specify native keycode, scancode + Specify index for legacy <1.87 IsKeyXXX() functions with native indices.
1654// If you are writing a backend in 2022 or don't use IsKeyXXX() with native values that are not ImGuiKey values, you can avoid calling this.
1655void ImGuiIO::SetKeyEventNativeData(ImGuiKey key, int native_keycode, int native_scancode, int native_legacy_index)
1656{
1657 if (key == ImGuiKey_None)
1658 return;
1659 IM_ASSERT(ImGui::IsNamedKey(key)); // >= 512
1660 IM_ASSERT(native_legacy_index == -1 || ImGui::IsLegacyKey((ImGuiKey)native_legacy_index)); // >= 0 && <= 511
1661 IM_UNUSED(native_keycode); // Yet unused
1662 IM_UNUSED(native_scancode); // Yet unused
1663
1664 // Build native->imgui map so old user code can still call key functions with native 0..511 values.
1665#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
1666 const int legacy_key = (native_legacy_index != -1) ? native_legacy_index : native_keycode;
1667 if (!ImGui::IsLegacyKey((ImGuiKey)legacy_key))
1668 return;
1669 KeyMap[legacy_key] = key;
1670 KeyMap[key] = legacy_key;
1671#else
1672 IM_UNUSED(key);
1673 IM_UNUSED(native_legacy_index);
1674#endif
1675}
1676
1677// Set master flag for accepting key/mouse/text events (default to true). Useful if you have native dialog boxes that are interrupting your application loop/refresh, and you want to disable events being queued while your app is frozen.
1678void ImGuiIO::SetAppAcceptingEvents(bool accepting_events)
1679{
1680 AppAcceptingEvents = accepting_events;
1681}
1682
1683// Queue a mouse move event
1684void ImGuiIO::AddMousePosEvent(float x, float y)
1685{
1686 IM_ASSERT(Ctx != NULL);
1687 ImGuiContext& g = *Ctx;
1688 if (!AppAcceptingEvents)
1689 return;
1690
1691 // Apply same flooring as UpdateMouseInputs()
1692 ImVec2 pos((x > -FLT_MAX) ? ImFloor(x) : x, (y > -FLT_MAX) ? ImFloor(y) : y);
1693
1694 // Filter duplicate
1695 const ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_MousePos);
1696 const ImVec2 latest_pos = latest_event ? ImVec2(latest_event->MousePos.PosX, latest_event->MousePos.PosY) : g.IO.MousePos;
1697 if (latest_pos.x == pos.x && latest_pos.y == pos.y)
1698 return;
1699
1700 ImGuiInputEvent e;
1701 e.Type = ImGuiInputEventType_MousePos;
1702 e.Source = ImGuiInputSource_Mouse;
1703 e.EventId = g.InputEventsNextEventId++;
1704 e.MousePos.PosX = pos.x;
1705 e.MousePos.PosY = pos.y;
1706 e.MousePos.MouseSource = g.InputEventsNextMouseSource;
1707 g.InputEventsQueue.push_back(e);
1708}
1709
1710void ImGuiIO::AddMouseButtonEvent(int mouse_button, bool down)
1711{
1712 IM_ASSERT(Ctx != NULL);
1713 ImGuiContext& g = *Ctx;
1714 IM_ASSERT(mouse_button >= 0 && mouse_button < ImGuiMouseButton_COUNT);
1715 if (!AppAcceptingEvents)
1716 return;
1717
1718 // On MacOS X: Convert Ctrl(Super)+Left click into Right-click: handle held button.
1719 if (ConfigMacOSXBehaviors && mouse_button == 0 && MouseCtrlLeftAsRightClick)
1720 {
1721 // Order of both statements matterns: this event will still release mouse button 1
1722 mouse_button = 1;
1723 if (!down)
1724 MouseCtrlLeftAsRightClick = false;
1725 }
1726
1727 // Filter duplicate
1728 const ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_MouseButton, (int)mouse_button);
1729 const bool latest_button_down = latest_event ? latest_event->MouseButton.Down : g.IO.MouseDown[mouse_button];
1730 if (latest_button_down == down)
1731 return;
1732
1733 // On MacOS X: Convert Ctrl(Super)+Left click into Right-click.
1734 // - Note that this is actual physical Ctrl which is ImGuiMod_Super for us.
1735 // - At this point we want from !down to down, so this is handling the initial press.
1736 if (ConfigMacOSXBehaviors && mouse_button == 0 && down)
1737 {
1738 const ImGuiInputEvent* latest_super_event = FindLatestInputEvent(&g, ImGuiInputEventType_Key, (int)ImGuiMod_Super);
1739 if (latest_super_event ? latest_super_event->Key.Down : g.IO.KeySuper)
1740 {
1741 IMGUI_DEBUG_LOG_IO("[io] Super+Left Click aliased into Right Click\n");
1742 MouseCtrlLeftAsRightClick = true;
1743 AddMouseButtonEvent(1, true); // This is just quicker to write that passing through, as we need to filter duplicate again.
1744 return;
1745 }
1746 }
1747
1748 ImGuiInputEvent e;
1749 e.Type = ImGuiInputEventType_MouseButton;
1750 e.Source = ImGuiInputSource_Mouse;
1751 e.EventId = g.InputEventsNextEventId++;
1752 e.MouseButton.Button = mouse_button;
1753 e.MouseButton.Down = down;
1754 e.MouseButton.MouseSource = g.InputEventsNextMouseSource;
1755 g.InputEventsQueue.push_back(e);
1756}
1757
1758// Queue a mouse wheel event (some mouse/API may only have a Y component)
1759void ImGuiIO::AddMouseWheelEvent(float wheel_x, float wheel_y)
1760{
1761 IM_ASSERT(Ctx != NULL);
1762 ImGuiContext& g = *Ctx;
1763
1764 // Filter duplicate (unlike most events, wheel values are relative and easy to filter)
1765 if (!AppAcceptingEvents || (wheel_x == 0.0f && wheel_y == 0.0f))
1766 return;
1767
1768 ImGuiInputEvent e;
1769 e.Type = ImGuiInputEventType_MouseWheel;
1770 e.Source = ImGuiInputSource_Mouse;
1771 e.EventId = g.InputEventsNextEventId++;
1772 e.MouseWheel.WheelX = wheel_x;
1773 e.MouseWheel.WheelY = wheel_y;
1774 e.MouseWheel.MouseSource = g.InputEventsNextMouseSource;
1775 g.InputEventsQueue.push_back(e);
1776}
1777
1778// This is not a real event, the data is latched in order to be stored in actual Mouse events.
1779// This is so that duplicate events (e.g. Windows sending extraneous WM_MOUSEMOVE) gets filtered and are not leading to actual source changes.
1780void ImGuiIO::AddMouseSourceEvent(ImGuiMouseSource source)
1781{
1782 IM_ASSERT(Ctx != NULL);
1783 ImGuiContext& g = *Ctx;
1784 g.InputEventsNextMouseSource = source;
1785}
1786
1787void ImGuiIO::AddMouseViewportEvent(ImGuiID viewport_id)
1788{
1789 IM_ASSERT(Ctx != NULL);
1790 ImGuiContext& g = *Ctx;
1791 //IM_ASSERT(g.IO.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport);
1792 if (!AppAcceptingEvents)
1793 return;
1794
1795 // Filter duplicate
1796 const ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_MouseViewport);
1797 const ImGuiID latest_viewport_id = latest_event ? latest_event->MouseViewport.HoveredViewportID : g.IO.MouseHoveredViewport;
1798 if (latest_viewport_id == viewport_id)
1799 return;
1800
1801 ImGuiInputEvent e;
1802 e.Type = ImGuiInputEventType_MouseViewport;
1803 e.Source = ImGuiInputSource_Mouse;
1804 e.MouseViewport.HoveredViewportID = viewport_id;
1805 g.InputEventsQueue.push_back(e);
1806}
1807
1808void ImGuiIO::AddFocusEvent(bool focused)
1809{
1810 IM_ASSERT(Ctx != NULL);
1811 ImGuiContext& g = *Ctx;
1812
1813 // Filter duplicate
1814 const ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_Focus);
1815 const bool latest_focused = latest_event ? latest_event->AppFocused.Focused : !g.IO.AppFocusLost;
1816 if (latest_focused == focused || (ConfigDebugIgnoreFocusLoss && !focused))
1817 return;
1818
1819 ImGuiInputEvent e;
1820 e.Type = ImGuiInputEventType_Focus;
1821 e.EventId = g.InputEventsNextEventId++;
1822 e.AppFocused.Focused = focused;
1823 g.InputEventsQueue.push_back(e);
1824}
1825
1826//-----------------------------------------------------------------------------
1827// [SECTION] MISC HELPERS/UTILITIES (Geometry functions)
1828//-----------------------------------------------------------------------------
1829
1830ImVec2 ImBezierCubicClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, int num_segments)
1831{
1832 IM_ASSERT(num_segments > 0); // Use ImBezierCubicClosestPointCasteljau()
1833 ImVec2 p_last = p1;
1834 ImVec2 p_closest;
1835 float p_closest_dist2 = FLT_MAX;
1836 float t_step = 1.0f / (float)num_segments;
1837 for (int i_step = 1; i_step <= num_segments; i_step++)
1838 {
1839 ImVec2 p_current = ImBezierCubicCalc(p1, p2, p3, p4, t_step * i_step);
1840 ImVec2 p_line = ImLineClosestPoint(p_last, p_current, p);
1841 float dist2 = ImLengthSqr(p - p_line);
1842 if (dist2 < p_closest_dist2)
1843 {
1844 p_closest = p_line;
1845 p_closest_dist2 = dist2;
1846 }
1847 p_last = p_current;
1848 }
1849 return p_closest;
1850}
1851
1852// Closely mimics PathBezierToCasteljau() in imgui_draw.cpp
1853static void ImBezierCubicClosestPointCasteljauStep(const ImVec2& p, ImVec2& p_closest, ImVec2& p_last, float& p_closest_dist2, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level)
1854{
1855 float dx = x4 - x1;
1856 float dy = y4 - y1;
1857 float d2 = ((x2 - x4) * dy - (y2 - y4) * dx);
1858 float d3 = ((x3 - x4) * dy - (y3 - y4) * dx);
1859 d2 = (d2 >= 0) ? d2 : -d2;
1860 d3 = (d3 >= 0) ? d3 : -d3;
1861 if ((d2 + d3) * (d2 + d3) < tess_tol * (dx * dx + dy * dy))
1862 {
1863 ImVec2 p_current(x4, y4);
1864 ImVec2 p_line = ImLineClosestPoint(p_last, p_current, p);
1865 float dist2 = ImLengthSqr(p - p_line);
1866 if (dist2 < p_closest_dist2)
1867 {
1868 p_closest = p_line;
1869 p_closest_dist2 = dist2;
1870 }
1871 p_last = p_current;
1872 }
1873 else if (level < 10)
1874 {
1875 float x12 = (x1 + x2)*0.5f, y12 = (y1 + y2)*0.5f;
1876 float x23 = (x2 + x3)*0.5f, y23 = (y2 + y3)*0.5f;
1877 float x34 = (x3 + x4)*0.5f, y34 = (y3 + y4)*0.5f;
1878 float x123 = (x12 + x23)*0.5f, y123 = (y12 + y23)*0.5f;
1879 float x234 = (x23 + x34)*0.5f, y234 = (y23 + y34)*0.5f;
1880 float x1234 = (x123 + x234)*0.5f, y1234 = (y123 + y234)*0.5f;
1881 ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1);
1882 ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1);
1883 }
1884}
1885
1886// tess_tol is generally the same value you would find in ImGui::GetStyle().CurveTessellationTol
1887// Because those ImXXX functions are lower-level than ImGui:: we cannot access this value automatically.
1888ImVec2 ImBezierCubicClosestPointCasteljau(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float tess_tol)
1889{
1890 IM_ASSERT(tess_tol > 0.0f);
1891 ImVec2 p_last = p1;
1892 ImVec2 p_closest;
1893 float p_closest_dist2 = FLT_MAX;
1894 ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, tess_tol, 0);
1895 return p_closest;
1896}
1897
1898ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p)
1899{
1900 ImVec2 ap = p - a;
1901 ImVec2 ab_dir = b - a;
1902 float dot = ap.x * ab_dir.x + ap.y * ab_dir.y;
1903 if (dot < 0.0f)
1904 return a;
1905 float ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y;
1906 if (dot > ab_len_sqr)
1907 return b;
1908 return a + ab_dir * dot / ab_len_sqr;
1909}
1910
1911bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p)
1912{
1913 bool b1 = ((p.x - b.x) * (a.y - b.y) - (p.y - b.y) * (a.x - b.x)) < 0.0f;
1914 bool b2 = ((p.x - c.x) * (b.y - c.y) - (p.y - c.y) * (b.x - c.x)) < 0.0f;
1915 bool b3 = ((p.x - a.x) * (c.y - a.y) - (p.y - a.y) * (c.x - a.x)) < 0.0f;
1916 return ((b1 == b2) && (b2 == b3));
1917}
1918
1919void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w)
1920{
1921 ImVec2 v0 = b - a;
1922 ImVec2 v1 = c - a;
1923 ImVec2 v2 = p - a;
1924 const float denom = v0.x * v1.y - v1.x * v0.y;
1925 out_v = (v2.x * v1.y - v1.x * v2.y) / denom;
1926 out_w = (v0.x * v2.y - v2.x * v0.y) / denom;
1927 out_u = 1.0f - out_v - out_w;
1928}
1929
1930ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p)
1931{
1932 ImVec2 proj_ab = ImLineClosestPoint(a, b, p);
1933 ImVec2 proj_bc = ImLineClosestPoint(b, c, p);
1934 ImVec2 proj_ca = ImLineClosestPoint(c, a, p);
1935 float dist2_ab = ImLengthSqr(p - proj_ab);
1936 float dist2_bc = ImLengthSqr(p - proj_bc);
1937 float dist2_ca = ImLengthSqr(p - proj_ca);
1938 float m = ImMin(dist2_ab, ImMin(dist2_bc, dist2_ca));
1939 if (m == dist2_ab)
1940 return proj_ab;
1941 if (m == dist2_bc)
1942 return proj_bc;
1943 return proj_ca;
1944}
1945
1946//-----------------------------------------------------------------------------
1947// [SECTION] MISC HELPERS/UTILITIES (String, Format, Hash functions)
1948//-----------------------------------------------------------------------------
1949
1950// Consider using _stricmp/_strnicmp under Windows or strcasecmp/strncasecmp. We don't actually use either ImStricmp/ImStrnicmp in the codebase any more.
1951int ImStricmp(const char* str1, const char* str2)
1952{
1953 int d;
1954 while ((d = ImToUpper(*str2) - ImToUpper(*str1)) == 0 && *str1) { str1++; str2++; }
1955 return d;
1956}
1957
1958int ImStrnicmp(const char* str1, const char* str2, size_t count)
1959{
1960 int d = 0;
1961 while (count > 0 && (d = ImToUpper(*str2) - ImToUpper(*str1)) == 0 && *str1) { str1++; str2++; count--; }
1962 return d;
1963}
1964
1965void ImStrncpy(char* dst, const char* src, size_t count)
1966{
1967 if (count < 1)
1968 return;
1969 if (count > 1)
1970 strncpy(dst, src, count - 1);
1971 dst[count - 1] = 0;
1972}
1973
1974char* ImStrdup(const char* str)
1975{
1976 size_t len = strlen(str);
1977 void* buf = IM_ALLOC(len + 1);
1978 return (char*)memcpy(buf, (const void*)str, len + 1);
1979}
1980
1981char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* src)
1982{
1983 size_t dst_buf_size = p_dst_size ? *p_dst_size : strlen(dst) + 1;
1984 size_t src_size = strlen(src) + 1;
1985 if (dst_buf_size < src_size)
1986 {
1987 IM_FREE(dst);
1988 dst = (char*)IM_ALLOC(src_size);
1989 if (p_dst_size)
1990 *p_dst_size = src_size;
1991 }
1992 return (char*)memcpy(dst, (const void*)src, src_size);
1993}
1994
1995const char* ImStrchrRange(const char* str, const char* str_end, char c)
1996{
1997 const char* p = (const char*)memchr(str, (int)c, str_end - str);
1998 return p;
1999}
2000
2001int ImStrlenW(const ImWchar* str)
2002{
2003 //return (int)wcslen((const wchar_t*)str); // FIXME-OPT: Could use this when wchar_t are 16-bit
2004 int n = 0;
2005 while (*str++) n++;
2006 return n;
2007}
2008
2009// Find end-of-line. Return pointer will point to either first \n, either str_end.
2010const char* ImStreolRange(const char* str, const char* str_end)
2011{
2012 const char* p = (const char*)memchr(str, '\n', str_end - str);
2013 return p ? p : str_end;
2014}
2015
2016const ImWchar* ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin) // find beginning-of-line
2017{
2018 while (buf_mid_line > buf_begin && buf_mid_line[-1] != '\n')
2019 buf_mid_line--;
2020 return buf_mid_line;
2021}
2022
2023const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end)
2024{
2025 if (!needle_end)
2026 needle_end = needle + strlen(needle);
2027
2028 const char un0 = (char)ImToUpper(*needle);
2029 while ((!haystack_end && *haystack) || (haystack_end && haystack < haystack_end))
2030 {
2031 if (ImToUpper(*haystack) == un0)
2032 {
2033 const char* b = needle + 1;
2034 for (const char* a = haystack + 1; b < needle_end; a++, b++)
2035 if (ImToUpper(*a) != ImToUpper(*b))
2036 break;
2037 if (b == needle_end)
2038 return haystack;
2039 }
2040 haystack++;
2041 }
2042 return NULL;
2043}
2044
2045// Trim str by offsetting contents when there's leading data + writing a \0 at the trailing position. We use this in situation where the cost is negligible.
2046void ImStrTrimBlanks(char* buf)
2047{
2048 char* p = buf;
2049 while (p[0] == ' ' || p[0] == '\t') // Leading blanks
2050 p++;
2051 char* p_start = p;
2052 while (*p != 0) // Find end of string
2053 p++;
2054 while (p > p_start && (p[-1] == ' ' || p[-1] == '\t')) // Trailing blanks
2055 p--;
2056 if (p_start != buf) // Copy memory if we had leading blanks
2057 memmove(buf, p_start, p - p_start);
2058 buf[p - p_start] = 0; // Zero terminate
2059}
2060
2061const char* ImStrSkipBlank(const char* str)
2062{
2063 while (str[0] == ' ' || str[0] == '\t')
2064 str++;
2065 return str;
2066}
2067
2068// A) MSVC version appears to return -1 on overflow, whereas glibc appears to return total count (which may be >= buf_size).
2069// Ideally we would test for only one of those limits at runtime depending on the behavior the vsnprintf(), but trying to deduct it at compile time sounds like a pandora can of worm.
2070// B) When buf==NULL vsnprintf() will return the output size.
2071#ifndef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
2072
2073// We support stb_sprintf which is much faster (see: https://github.com/nothings/stb/blob/master/stb_sprintf.h)
2074// You may set IMGUI_USE_STB_SPRINTF to use our default wrapper, or set IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
2075// and setup the wrapper yourself. (FIXME-OPT: Some of our high-level operations such as ImGuiTextBuffer::appendfv() are
2076// designed using two-passes worst case, which probably could be improved using the stbsp_vsprintfcb() function.)
2077#ifdef IMGUI_USE_STB_SPRINTF
2078#ifndef IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION
2079#define STB_SPRINTF_IMPLEMENTATION
2080#endif
2081#ifdef IMGUI_STB_SPRINTF_FILENAME
2082#include IMGUI_STB_SPRINTF_FILENAME
2083#else
2084#include "stb_sprintf.h"
2085#endif
2086#endif // #ifdef IMGUI_USE_STB_SPRINTF
2087
2088#if defined(_MSC_VER) && !defined(vsnprintf)
2089#define vsnprintf _vsnprintf
2090#endif
2091
2092int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...)
2093{
2094 va_list args;
2095 va_start(args, fmt);
2096#ifdef IMGUI_USE_STB_SPRINTF
2097 int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args);
2098#else
2099 int w = vsnprintf(buf, buf_size, fmt, args);
2100#endif
2101 va_end(args);
2102 if (buf == NULL)
2103 return w;
2104 if (w == -1 || w >= (int)buf_size)
2105 w = (int)buf_size - 1;
2106 buf[w] = 0;
2107 return w;
2108}
2109
2110int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args)
2111{
2112#ifdef IMGUI_USE_STB_SPRINTF
2113 int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args);
2114#else
2115 int w = vsnprintf(buf, buf_size, fmt, args);
2116#endif
2117 if (buf == NULL)
2118 return w;
2119 if (w == -1 || w >= (int)buf_size)
2120 w = (int)buf_size - 1;
2121 buf[w] = 0;
2122 return w;
2123}
2124#endif // #ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
2125
2126void ImFormatStringToTempBuffer(const char** out_buf, const char** out_buf_end, const char* fmt, ...)
2127{
2128 va_list args;
2129 va_start(args, fmt);
2130 ImFormatStringToTempBufferV(out_buf, out_buf_end, fmt, args);
2131 va_end(args);
2132}
2133
2134// FIXME: Should rework API toward allowing multiple in-flight temp buffers (easier and safer for caller)
2135// by making the caller acquire a temp buffer token, with either explicit or destructor release, e.g.
2136// ImGuiTempBufferToken token;
2137// ImFormatStringToTempBuffer(token, ...);
2138void ImFormatStringToTempBufferV(const char** out_buf, const char** out_buf_end, const char* fmt, va_list args)
2139{
2140 ImGuiContext& g = *GImGui;
2141 if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0)
2142 {
2143 const char* buf = va_arg(args, const char*); // Skip formatting when using "%s"
2144 if (buf == NULL)
2145 buf = "(null)";
2146 *out_buf = buf;
2147 if (out_buf_end) { *out_buf_end = buf + strlen(buf); }
2148 }
2149 else if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*' && fmt[3] == 's' && fmt[4] == 0)
2150 {
2151 int buf_len = va_arg(args, int); // Skip formatting when using "%.*s"
2152 const char* buf = va_arg(args, const char*);
2153 if (buf == NULL)
2154 {
2155 buf = "(null)";
2156 buf_len = ImMin(buf_len, 6);
2157 }
2158 *out_buf = buf;
2159 *out_buf_end = buf + buf_len; // Disallow not passing 'out_buf_end' here. User is expected to use it.
2160 }
2161 else
2162 {
2163 int buf_len = ImFormatStringV(g.TempBuffer.Data, g.TempBuffer.Size, fmt, args);
2164 *out_buf = g.TempBuffer.Data;
2165 if (out_buf_end) { *out_buf_end = g.TempBuffer.Data + buf_len; }
2166 }
2167}
2168
2169// CRC32 needs a 1KB lookup table (not cache friendly)
2170// Although the code to generate the table is simple and shorter than the table itself, using a const table allows us to easily:
2171// - avoid an unnecessary branch/memory tap, - keep the ImHashXXX functions usable by static constructors, - make it thread-safe.
2172static const ImU32 GCrc32LookupTable[256] =
2173{
2174 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91,
2175 0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5,
2176 0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59,
2177 0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F,0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D,
2178 0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01,
2179 0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65,
2180 0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9,
2181 0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD,
2182 0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1,
2183 0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5,
2184 0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79,
2185 0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D,
2186 0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21,
2187 0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45,
2188 0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9,
2189 0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D,
2190};
2191
2192// Known size hash
2193// It is ok to call ImHashData on a string with known length but the ### operator won't be supported.
2194// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements.
2195ImGuiID ImHashData(const void* data_p, size_t data_size, ImGuiID seed)
2196{
2197 ImU32 crc = ~seed;
2198 const unsigned char* data = (const unsigned char*)data_p;
2199 const ImU32* crc32_lut = GCrc32LookupTable;
2200 while (data_size-- != 0)
2201 crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *data++];
2202 return ~crc;
2203}
2204
2205// Zero-terminated string hash, with support for ### to reset back to seed value
2206// We support a syntax of "label###id" where only "###id" is included in the hash, and only "label" gets displayed.
2207// Because this syntax is rarely used we are optimizing for the common case.
2208// - If we reach ### in the string we discard the hash so far and reset to the seed.
2209// - We don't do 'current += 2; continue;' after handling ### to keep the code smaller/faster (measured ~10% diff in Debug build)
2210// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements.
2211ImGuiID ImHashStr(const char* data_p, size_t data_size, ImGuiID seed)
2212{
2213 seed = ~seed;
2214 ImU32 crc = seed;
2215 const unsigned char* data = (const unsigned char*)data_p;
2216 const ImU32* crc32_lut = GCrc32LookupTable;
2217 if (data_size != 0)
2218 {
2219 while (data_size-- != 0)
2220 {
2221 unsigned char c = *data++;
2222 if (c == '#' && data_size >= 2 && data[0] == '#' && data[1] == '#')
2223 crc = seed;
2224 crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
2225 }
2226 }
2227 else
2228 {
2229 while (unsigned char c = *data++)
2230 {
2231 if (c == '#' && data[0] == '#' && data[1] == '#')
2232 crc = seed;
2233 crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
2234 }
2235 }
2236 return ~crc;
2237}
2238
2239//-----------------------------------------------------------------------------
2240// [SECTION] MISC HELPERS/UTILITIES (File functions)
2241//-----------------------------------------------------------------------------
2242
2243// Default file functions
2244#ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
2245
2246ImFileHandle ImFileOpen(const char* filename, const char* mode)
2247{
2248#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(__CYGWIN__) && !defined(__GNUC__)
2249 // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames.
2250 // Previously we used ImTextCountCharsFromUtf8/ImTextStrFromUtf8 here but we now need to support ImWchar16 and ImWchar32!
2251 const int filename_wsize = ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0);
2252 const int mode_wsize = ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0);
2253
2254 // Use stack buffer if possible, otherwise heap buffer. Sizes include zero terminator.
2255 // We don't rely on current ImGuiContext as this is implied to be a helper function which doesn't depend on it (see #7314).
2256 wchar_t local_temp_stack[FILENAME_MAX];
2257 ImVector<wchar_t> local_temp_heap;
2258 if (filename_wsize + mode_wsize > IM_ARRAYSIZE(local_temp_stack))
2259 local_temp_heap.resize(filename_wsize + mode_wsize);
2260 wchar_t* filename_wbuf = local_temp_heap.Data ? local_temp_heap.Data : local_temp_stack;
2261 wchar_t* mode_wbuf = filename_wbuf + filename_wsize;
2262 ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, filename_wbuf, filename_wsize);
2263 ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, mode_wbuf, mode_wsize);
2264 return ::_wfopen(filename_wbuf, mode_wbuf);
2265#else
2266 return fopen(filename, mode);
2267#endif
2268}
2269
2270// We should in theory be using fseeko()/ftello() with off_t and _fseeki64()/_ftelli64() with __int64, waiting for the PR that does that in a very portable pre-C++11 zero-warnings way.
2271bool ImFileClose(ImFileHandle f) { return fclose(f) == 0; }
2272ImU64 ImFileGetSize(ImFileHandle f) { long off = 0, sz = 0; return ((off = ftell(f)) != -1 && !fseek(f, 0, SEEK_END) && (sz = ftell(f)) != -1 && !fseek(f, off, SEEK_SET)) ? (ImU64)sz : (ImU64)-1; }
2273ImU64 ImFileRead(void* data, ImU64 sz, ImU64 count, ImFileHandle f) { return fread(data, (size_t)sz, (size_t)count, f); }
2274ImU64 ImFileWrite(const void* data, ImU64 sz, ImU64 count, ImFileHandle f) { return fwrite(data, (size_t)sz, (size_t)count, f); }
2275#endif // #ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
2276
2277// Helper: Load file content into memory
2278// Memory allocated with IM_ALLOC(), must be freed by user using IM_FREE() == ImGui::MemFree()
2279// This can't really be used with "rt" because fseek size won't match read size.
2280void* ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_file_size, int padding_bytes)
2281{
2282 IM_ASSERT(filename && mode);
2283 if (out_file_size)
2284 *out_file_size = 0;
2285
2286 ImFileHandle f;
2287 if ((f = ImFileOpen(filename, mode)) == NULL)
2288 return NULL;
2289
2290 size_t file_size = (size_t)ImFileGetSize(f);
2291 if (file_size == (size_t)-1)
2292 {
2293 ImFileClose(f);
2294 return NULL;
2295 }
2296
2297 void* file_data = IM_ALLOC(file_size + padding_bytes);
2298 if (file_data == NULL)
2299 {
2300 ImFileClose(f);
2301 return NULL;
2302 }
2303 if (ImFileRead(file_data, 1, file_size, f) != file_size)
2304 {
2305 ImFileClose(f);
2306 IM_FREE(file_data);
2307 return NULL;
2308 }
2309 if (padding_bytes > 0)
2310 memset((void*)(((char*)file_data) + file_size), 0, (size_t)padding_bytes);
2311
2312 ImFileClose(f);
2313 if (out_file_size)
2314 *out_file_size = file_size;
2315
2316 return file_data;
2317}
2318
2319//-----------------------------------------------------------------------------
2320// [SECTION] MISC HELPERS/UTILITIES (ImText* functions)
2321//-----------------------------------------------------------------------------
2322
2323IM_MSVC_RUNTIME_CHECKS_OFF
2324
2325// Convert UTF-8 to 32-bit character, process single character input.
2326// A nearly-branchless UTF-8 decoder, based on work of Christopher Wellons (https://github.com/skeeto/branchless-utf8).
2327// We handle UTF-8 decoding error by skipping forward.
2328int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end)
2329{
2330 static const char lengths[32] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0 };
2331 static const int masks[] = { 0x00, 0x7f, 0x1f, 0x0f, 0x07 };
2332 static const uint32_t mins[] = { 0x400000, 0, 0x80, 0x800, 0x10000 };
2333 static const int shiftc[] = { 0, 18, 12, 6, 0 };
2334 static const int shifte[] = { 0, 6, 4, 2, 0 };
2335 int len = lengths[*(const unsigned char*)in_text >> 3];
2336 int wanted = len + (len ? 0 : 1);
2337
2338 if (in_text_end == NULL)
2339 in_text_end = in_text + wanted; // Max length, nulls will be taken into account.
2340
2341 // Copy at most 'len' bytes, stop copying at 0 or past in_text_end. Branch predictor does a good job here,
2342 // so it is fast even with excessive branching.
2343 unsigned char s[4];
2344 s[0] = in_text + 0 < in_text_end ? in_text[0] : 0;
2345 s[1] = in_text + 1 < in_text_end ? in_text[1] : 0;
2346 s[2] = in_text + 2 < in_text_end ? in_text[2] : 0;
2347 s[3] = in_text + 3 < in_text_end ? in_text[3] : 0;
2348
2349 // Assume a four-byte character and load four bytes. Unused bits are shifted out.
2350 *out_char = (uint32_t)(s[0] & masks[len]) << 18;
2351 *out_char |= (uint32_t)(s[1] & 0x3f) << 12;
2352 *out_char |= (uint32_t)(s[2] & 0x3f) << 6;
2353 *out_char |= (uint32_t)(s[3] & 0x3f) << 0;
2354 *out_char >>= shiftc[len];
2355
2356 // Accumulate the various error conditions.
2357 int e = 0;
2358 e = (*out_char < mins[len]) << 6; // non-canonical encoding
2359 e |= ((*out_char >> 11) == 0x1b) << 7; // surrogate half?
2360 e |= (*out_char > IM_UNICODE_CODEPOINT_MAX) << 8; // out of range?
2361 e |= (s[1] & 0xc0) >> 2;
2362 e |= (s[2] & 0xc0) >> 4;
2363 e |= (s[3] ) >> 6;
2364 e ^= 0x2a; // top two bits of each tail byte correct?
2365 e >>= shifte[len];
2366
2367 if (e)
2368 {
2369 // No bytes are consumed when *in_text == 0 || in_text == in_text_end.
2370 // One byte is consumed in case of invalid first byte of in_text.
2371 // All available bytes (at most `len` bytes) are consumed on incomplete/invalid second to last bytes.
2372 // Invalid or incomplete input may consume less bytes than wanted, therefore every byte has to be inspected in s.
2373 wanted = ImMin(wanted, !!s[0] + !!s[1] + !!s[2] + !!s[3]);
2374 *out_char = IM_UNICODE_CODEPOINT_INVALID;
2375 }
2376
2377 return wanted;
2378}
2379
2380int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_text_remaining)
2381{
2382 ImWchar* buf_out = buf;
2383 ImWchar* buf_end = buf + buf_size;
2384 while (buf_out < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text)
2385 {
2386 unsigned int c;
2387 in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
2388 *buf_out++ = (ImWchar)c;
2389 }
2390 *buf_out = 0;
2391 if (in_text_remaining)
2392 *in_text_remaining = in_text;
2393 return (int)(buf_out - buf);
2394}
2395
2396int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end)
2397{
2398 int char_count = 0;
2399 while ((!in_text_end || in_text < in_text_end) && *in_text)
2400 {
2401 unsigned int c;
2402 in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
2403 char_count++;
2404 }
2405 return char_count;
2406}
2407
2408// Based on stb_to_utf8() from github.com/nothings/stb/
2409static inline int ImTextCharToUtf8_inline(char* buf, int buf_size, unsigned int c)
2410{
2411 if (c < 0x80)
2412 {
2413 buf[0] = (char)c;
2414 return 1;
2415 }
2416 if (c < 0x800)
2417 {
2418 if (buf_size < 2) return 0;
2419 buf[0] = (char)(0xc0 + (c >> 6));
2420 buf[1] = (char)(0x80 + (c & 0x3f));
2421 return 2;
2422 }
2423 if (c < 0x10000)
2424 {
2425 if (buf_size < 3) return 0;
2426 buf[0] = (char)(0xe0 + (c >> 12));
2427 buf[1] = (char)(0x80 + ((c >> 6) & 0x3f));
2428 buf[2] = (char)(0x80 + ((c ) & 0x3f));
2429 return 3;
2430 }
2431 if (c <= 0x10FFFF)
2432 {
2433 if (buf_size < 4) return 0;
2434 buf[0] = (char)(0xf0 + (c >> 18));
2435 buf[1] = (char)(0x80 + ((c >> 12) & 0x3f));
2436 buf[2] = (char)(0x80 + ((c >> 6) & 0x3f));
2437 buf[3] = (char)(0x80 + ((c ) & 0x3f));
2438 return 4;
2439 }
2440 // Invalid code point, the max unicode is 0x10FFFF
2441 return 0;
2442}
2443
2444const char* ImTextCharToUtf8(char out_buf[5], unsigned int c)
2445{
2446 int count = ImTextCharToUtf8_inline(out_buf, 5, c);
2447 out_buf[count] = 0;
2448 return out_buf;
2449}
2450
2451// Not optimal but we very rarely use this function.
2452int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end)
2453{
2454 unsigned int unused = 0;
2455 return ImTextCharFromUtf8(&unused, in_text, in_text_end);
2456}
2457
2458static inline int ImTextCountUtf8BytesFromChar(unsigned int c)
2459{
2460 if (c < 0x80) return 1;
2461 if (c < 0x800) return 2;
2462 if (c < 0x10000) return 3;
2463 if (c <= 0x10FFFF) return 4;
2464 return 3;
2465}
2466
2467int ImTextStrToUtf8(char* out_buf, int out_buf_size, const ImWchar* in_text, const ImWchar* in_text_end)
2468{
2469 char* buf_p = out_buf;
2470 const char* buf_end = out_buf + out_buf_size;
2471 while (buf_p < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text)
2472 {
2473 unsigned int c = (unsigned int)(*in_text++);
2474 if (c < 0x80)
2475 *buf_p++ = (char)c;
2476 else
2477 buf_p += ImTextCharToUtf8_inline(buf_p, (int)(buf_end - buf_p - 1), c);
2478 }
2479 *buf_p = 0;
2480 return (int)(buf_p - out_buf);
2481}
2482
2483int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end)
2484{
2485 int bytes_count = 0;
2486 while ((!in_text_end || in_text < in_text_end) && *in_text)
2487 {
2488 unsigned int c = (unsigned int)(*in_text++);
2489 if (c < 0x80)
2490 bytes_count++;
2491 else
2492 bytes_count += ImTextCountUtf8BytesFromChar(c);
2493 }
2494 return bytes_count;
2495}
2496
2497const char* ImTextFindPreviousUtf8Codepoint(const char* in_text_start, const char* in_text_curr)
2498{
2499 while (in_text_curr > in_text_start)
2500 {
2501 in_text_curr--;
2502 if ((*in_text_curr & 0xC0) != 0x80)
2503 return in_text_curr;
2504 }
2505 return in_text_start;
2506}
2507
2508int ImTextCountLines(const char* in_text, const char* in_text_end)
2509{
2510 if (in_text_end == NULL)
2511 in_text_end = in_text + strlen(in_text); // FIXME-OPT: Not optimal approach, discourage use for now.
2512 int count = 0;
2513 while (in_text < in_text_end)
2514 {
2515 const char* line_end = (const char*)memchr(in_text, '\n', in_text_end - in_text);
2516 in_text = line_end ? line_end + 1 : in_text_end;
2517 count++;
2518 }
2519 return count;
2520}
2521
2522IM_MSVC_RUNTIME_CHECKS_RESTORE
2523
2524//-----------------------------------------------------------------------------
2525// [SECTION] MISC HELPERS/UTILITIES (Color functions)
2526// Note: The Convert functions are early design which are not consistent with other API.
2527//-----------------------------------------------------------------------------
2528
2529IMGUI_API ImU32 ImAlphaBlendColors(ImU32 col_a, ImU32 col_b)
2530{
2531 float t = ((col_b >> IM_COL32_A_SHIFT) & 0xFF) / 255.f;
2532 int r = ImLerp((int)(col_a >> IM_COL32_R_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_R_SHIFT) & 0xFF, t);
2533 int g = ImLerp((int)(col_a >> IM_COL32_G_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_G_SHIFT) & 0xFF, t);
2534 int b = ImLerp((int)(col_a >> IM_COL32_B_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_B_SHIFT) & 0xFF, t);
2535 return IM_COL32(r, g, b, 0xFF);
2536}
2537
2538ImVec4 ImGui::ColorConvertU32ToFloat4(ImU32 in)
2539{
2540 float s = 1.0f / 255.0f;
2541 return ImVec4(
2542 ((in >> IM_COL32_R_SHIFT) & 0xFF) * s,
2543 ((in >> IM_COL32_G_SHIFT) & 0xFF) * s,
2544 ((in >> IM_COL32_B_SHIFT) & 0xFF) * s,
2545 ((in >> IM_COL32_A_SHIFT) & 0xFF) * s);
2546}
2547
2548ImU32 ImGui::ColorConvertFloat4ToU32(const ImVec4& in)
2549{
2550 ImU32 out;
2551 out = ((ImU32)IM_F32_TO_INT8_SAT(in.x)) << IM_COL32_R_SHIFT;
2552 out |= ((ImU32)IM_F32_TO_INT8_SAT(in.y)) << IM_COL32_G_SHIFT;
2553 out |= ((ImU32)IM_F32_TO_INT8_SAT(in.z)) << IM_COL32_B_SHIFT;
2554 out |= ((ImU32)IM_F32_TO_INT8_SAT(in.w)) << IM_COL32_A_SHIFT;
2555 return out;
2556}
2557
2558// Convert rgb floats ([0-1],[0-1],[0-1]) to hsv floats ([0-1],[0-1],[0-1]), from Foley & van Dam p592
2559// Optimized http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv
2560void ImGui::ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v)
2561{
2562 float K = 0.f;
2563 if (g < b)
2564 {
2565 ImSwap(g, b);
2566 K = -1.f;
2567 }
2568 if (r < g)
2569 {
2570 ImSwap(r, g);
2571 K = -2.f / 6.f - K;
2572 }
2573
2574 const float chroma = r - (g < b ? g : b);
2575 out_h = ImFabs(K + (g - b) / (6.f * chroma + 1e-20f));
2576 out_s = chroma / (r + 1e-20f);
2577 out_v = r;
2578}
2579
2580// Convert hsv floats ([0-1],[0-1],[0-1]) to rgb floats ([0-1],[0-1],[0-1]), from Foley & van Dam p593
2581// also http://en.wikipedia.org/wiki/HSL_and_HSV
2582void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b)
2583{
2584 if (s == 0.0f)
2585 {
2586 // gray
2587 out_r = out_g = out_b = v;
2588 return;
2589 }
2590
2591 h = ImFmod(h, 1.0f) / (60.0f / 360.0f);
2592 int i = (int)h;
2593 float f = h - (float)i;
2594 float p = v * (1.0f - s);
2595 float q = v * (1.0f - s * f);
2596 float t = v * (1.0f - s * (1.0f - f));
2597
2598 switch (i)
2599 {
2600 case 0: out_r = v; out_g = t; out_b = p; break;
2601 case 1: out_r = q; out_g = v; out_b = p; break;
2602 case 2: out_r = p; out_g = v; out_b = t; break;
2603 case 3: out_r = p; out_g = q; out_b = v; break;
2604 case 4: out_r = t; out_g = p; out_b = v; break;
2605 case 5: default: out_r = v; out_g = p; out_b = q; break;
2606 }
2607}
2608
2609//-----------------------------------------------------------------------------
2610// [SECTION] ImGuiStorage
2611// Helper: Key->value storage
2612//-----------------------------------------------------------------------------
2613
2614// std::lower_bound but without the bullshit
2615ImGuiStoragePair* ImLowerBound(ImGuiStoragePair* in_begin, ImGuiStoragePair* in_end, ImGuiID key)
2616{
2617 ImGuiStoragePair* in_p = in_begin;
2618 for (size_t count = (size_t)(in_end - in_p); count > 0; )
2619 {
2620 size_t count2 = count >> 1;
2621 ImGuiStoragePair* mid = in_p + count2;
2622 if (mid->key < key)
2623 {
2624 in_p = ++mid;
2625 count -= count2 + 1;
2626 }
2627 else
2628 {
2629 count = count2;
2630 }
2631 }
2632 return in_p;
2633}
2634
2635IM_MSVC_RUNTIME_CHECKS_OFF
2636static int IMGUI_CDECL PairComparerByID(const void* lhs, const void* rhs)
2637{
2638 // We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that.
2639 ImGuiID lhs_v = ((const ImGuiStoragePair*)lhs)->key;
2640 ImGuiID rhs_v = ((const ImGuiStoragePair*)rhs)->key;
2641 return (lhs_v > rhs_v ? +1 : lhs_v < rhs_v ? -1 : 0);
2642}
2643
2644// For quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once.
2645void ImGuiStorage::BuildSortByKey()
2646{
2647 ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), PairComparerByID);
2648}
2649
2650int ImGuiStorage::GetInt(ImGuiID key, int default_val) const
2651{
2652 ImGuiStoragePair* it = ImLowerBound(const_cast<ImGuiStoragePair*>(Data.Data), const_cast<ImGuiStoragePair*>(Data.Data + Data.Size), key);
2653 if (it == Data.Data + Data.Size || it->key != key)
2654 return default_val;
2655 return it->val_i;
2656}
2657
2658bool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const
2659{
2660 return GetInt(key, default_val ? 1 : 0) != 0;
2661}
2662
2663float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const
2664{
2665 ImGuiStoragePair* it = ImLowerBound(const_cast<ImGuiStoragePair*>(Data.Data), const_cast<ImGuiStoragePair*>(Data.Data + Data.Size), key);
2666 if (it == Data.Data + Data.Size || it->key != key)
2667 return default_val;
2668 return it->val_f;
2669}
2670
2671void* ImGuiStorage::GetVoidPtr(ImGuiID key) const
2672{
2673 ImGuiStoragePair* it = ImLowerBound(const_cast<ImGuiStoragePair*>(Data.Data), const_cast<ImGuiStoragePair*>(Data.Data + Data.Size), key);
2674 if (it == Data.Data + Data.Size || it->key != key)
2675 return NULL;
2676 return it->val_p;
2677}
2678
2679// 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.
2680int* ImGuiStorage::GetIntRef(ImGuiID key, int default_val)
2681{
2682 ImGuiStoragePair* it = ImLowerBound(Data.Data, Data.Data + Data.Size, key);
2683 if (it == Data.Data + Data.Size || it->key != key)
2684 it = Data.insert(it, ImGuiStoragePair(key, default_val));
2685 return &it->val_i;
2686}
2687
2688bool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val)
2689{
2690 return (bool*)GetIntRef(key, default_val ? 1 : 0);
2691}
2692
2693float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val)
2694{
2695 ImGuiStoragePair* it = ImLowerBound(Data.Data, Data.Data + Data.Size, key);
2696 if (it == Data.Data + Data.Size || it->key != key)
2697 it = Data.insert(it, ImGuiStoragePair(key, default_val));
2698 return &it->val_f;
2699}
2700
2701void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val)
2702{
2703 ImGuiStoragePair* it = ImLowerBound(Data.Data, Data.Data + Data.Size, key);
2704 if (it == Data.Data + Data.Size || it->key != key)
2705 it = Data.insert(it, ImGuiStoragePair(key, default_val));
2706 return &it->val_p;
2707}
2708
2709// 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)
2710void ImGuiStorage::SetInt(ImGuiID key, int val)
2711{
2712 ImGuiStoragePair* it = ImLowerBound(Data.Data, Data.Data + Data.Size, key);
2713 if (it == Data.Data + Data.Size || it->key != key)
2714 Data.insert(it, ImGuiStoragePair(key, val));
2715 else
2716 it->val_i = val;
2717}
2718
2719void ImGuiStorage::SetBool(ImGuiID key, bool val)
2720{
2721 SetInt(key, val ? 1 : 0);
2722}
2723
2724void ImGuiStorage::SetFloat(ImGuiID key, float val)
2725{
2726 ImGuiStoragePair* it = ImLowerBound(Data.Data, Data.Data + Data.Size, key);
2727 if (it == Data.Data + Data.Size || it->key != key)
2728 Data.insert(it, ImGuiStoragePair(key, val));
2729 else
2730 it->val_f = val;
2731}
2732
2733void ImGuiStorage::SetVoidPtr(ImGuiID key, void* val)
2734{
2735 ImGuiStoragePair* it = ImLowerBound(Data.Data, Data.Data + Data.Size, key);
2736 if (it == Data.Data + Data.Size || it->key != key)
2737 Data.insert(it, ImGuiStoragePair(key, val));
2738 else
2739 it->val_p = val;
2740}
2741
2742void ImGuiStorage::SetAllInt(int v)
2743{
2744 for (int i = 0; i < Data.Size; i++)
2745 Data[i].val_i = v;
2746}
2747IM_MSVC_RUNTIME_CHECKS_RESTORE
2748
2749//-----------------------------------------------------------------------------
2750// [SECTION] ImGuiTextFilter
2751//-----------------------------------------------------------------------------
2752
2753// Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]"
2754ImGuiTextFilter::ImGuiTextFilter(const char* default_filter) //-V1077
2755{
2756 InputBuf[0] = 0;
2757 CountGrep = 0;
2758 if (default_filter)
2759 {
2760 ImStrncpy(InputBuf, default_filter, IM_ARRAYSIZE(InputBuf));
2761 Build();
2762 }
2763}
2764
2765bool ImGuiTextFilter::Draw(const char* label, float width)
2766{
2767 if (width != 0.0f)
2768 ImGui::SetNextItemWidth(width);
2769 bool value_changed = ImGui::InputText(label, InputBuf, IM_ARRAYSIZE(InputBuf));
2770 if (value_changed)
2771 Build();
2772 return value_changed;
2773}
2774
2775void ImGuiTextFilter::ImGuiTextRange::split(char separator, ImVector<ImGuiTextRange>* out) const
2776{
2777 out->resize(0);
2778 const char* wb = b;
2779 const char* we = wb;
2780 while (we < e)
2781 {
2782 if (*we == separator)
2783 {
2784 out->push_back(ImGuiTextRange(wb, we));
2785 wb = we + 1;
2786 }
2787 we++;
2788 }
2789 if (wb != we)
2790 out->push_back(ImGuiTextRange(wb, we));
2791}
2792
2793void ImGuiTextFilter::Build()
2794{
2795 Filters.resize(0);
2796 ImGuiTextRange input_range(InputBuf, InputBuf + strlen(InputBuf));
2797 input_range.split(',', &Filters);
2798
2799 CountGrep = 0;
2800 for (ImGuiTextRange& f : Filters)
2801 {
2802 while (f.b < f.e && ImCharIsBlankA(f.b[0]))
2803 f.b++;
2804 while (f.e > f.b && ImCharIsBlankA(f.e[-1]))
2805 f.e--;
2806 if (f.empty())
2807 continue;
2808 if (f.b[0] != '-')
2809 CountGrep += 1;
2810 }
2811}
2812
2813bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const
2814{
2815 if (Filters.Size == 0)
2816 return true;
2817
2818 if (text == NULL)
2819 text = text_end = "";
2820
2821 for (const ImGuiTextRange& f : Filters)
2822 {
2823 if (f.b == f.e)
2824 continue;
2825 if (f.b[0] == '-')
2826 {
2827 // Subtract
2828 if (ImStristr(text, text_end, f.b + 1, f.e) != NULL)
2829 return false;
2830 }
2831 else
2832 {
2833 // Grep
2834 if (ImStristr(text, text_end, f.b, f.e) != NULL)
2835 return true;
2836 }
2837 }
2838
2839 // Implicit * grep
2840 if (CountGrep == 0)
2841 return true;
2842
2843 return false;
2844}
2845
2846//-----------------------------------------------------------------------------
2847// [SECTION] ImGuiTextBuffer, ImGuiTextIndex
2848//-----------------------------------------------------------------------------
2849
2850// On some platform vsnprintf() takes va_list by reference and modifies it.
2851// va_copy is the 'correct' way to copy a va_list but Visual Studio prior to 2013 doesn't have it.
2852#ifndef va_copy
2853#if defined(__GNUC__) || defined(__clang__)
2854#define va_copy(dest, src) __builtin_va_copy(dest, src)
2855#else
2856#define va_copy(dest, src) (dest = src)
2857#endif
2858#endif
2859
2860char ImGuiTextBuffer::EmptyString[1] = { 0 };
2861
2862void ImGuiTextBuffer::append(const char* str, const char* str_end)
2863{
2864 int len = str_end ? (int)(str_end - str) : (int)strlen(str);
2865
2866 // Add zero-terminator the first time
2867 const int write_off = (Buf.Size != 0) ? Buf.Size : 1;
2868 const int needed_sz = write_off + len;
2869 if (write_off + len >= Buf.Capacity)
2870 {
2871 int new_capacity = Buf.Capacity * 2;
2872 Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity);
2873 }
2874
2875 Buf.resize(needed_sz);
2876 memcpy(&Buf[write_off - 1], str, (size_t)len);
2877 Buf[write_off - 1 + len] = 0;
2878}
2879
2880void ImGuiTextBuffer::appendf(const char* fmt, ...)
2881{
2882 va_list args;
2883 va_start(args, fmt);
2884 appendfv(fmt, args);
2885 va_end(args);
2886}
2887
2888// Helper: Text buffer for logging/accumulating text
2889void ImGuiTextBuffer::appendfv(const char* fmt, va_list args)
2890{
2891 va_list args_copy;
2892 va_copy(args_copy, args);
2893
2894 int len = ImFormatStringV(NULL, 0, fmt, args); // FIXME-OPT: could do a first pass write attempt, likely successful on first pass.
2895 if (len <= 0)
2896 {
2897 va_end(args_copy);
2898 return;
2899 }
2900
2901 // Add zero-terminator the first time
2902 const int write_off = (Buf.Size != 0) ? Buf.Size : 1;
2903 const int needed_sz = write_off + len;
2904 if (write_off + len >= Buf.Capacity)
2905 {
2906 int new_capacity = Buf.Capacity * 2;
2907 Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity);
2908 }
2909
2910 Buf.resize(needed_sz);
2911 ImFormatStringV(&Buf[write_off - 1], (size_t)len + 1, fmt, args_copy);
2912 va_end(args_copy);
2913}
2914
2915void ImGuiTextIndex::append(const char* base, int old_size, int new_size)
2916{
2917 IM_ASSERT(old_size >= 0 && new_size >= old_size && new_size >= EndOffset);
2918 if (old_size == new_size)
2919 return;
2920 if (EndOffset == 0 || base[EndOffset - 1] == '\n')
2921 LineOffsets.push_back(EndOffset);
2922 const char* base_end = base + new_size;
2923 for (const char* p = base + old_size; (p = (const char*)memchr(p, '\n', base_end - p)) != 0; )
2924 if (++p < base_end) // Don't push a trailing offset on last \n
2925 LineOffsets.push_back((int)(intptr_t)(p - base));
2926 EndOffset = ImMax(EndOffset, new_size);
2927}
2928
2929//-----------------------------------------------------------------------------
2930// [SECTION] ImGuiListClipper
2931//-----------------------------------------------------------------------------
2932
2933// FIXME-TABLE: This prevents us from using ImGuiListClipper _inside_ a table cell.
2934// The problem we have is that without a Begin/End scheme for rows using the clipper is ambiguous.
2935static bool GetSkipItemForListClipping()
2936{
2937 ImGuiContext& g = *GImGui;
2938 return (g.CurrentTable ? g.CurrentTable->HostSkipItems : g.CurrentWindow->SkipItems);
2939}
2940
2941static void ImGuiListClipper_SortAndFuseRanges(ImVector<ImGuiListClipperRange>& ranges, int offset = 0)
2942{
2943 if (ranges.Size - offset <= 1)
2944 return;
2945
2946 // Helper to order ranges and fuse them together if possible (bubble sort is fine as we are only sorting 2-3 entries)
2947 for (int sort_end = ranges.Size - offset - 1; sort_end > 0; --sort_end)
2948 for (int i = offset; i < sort_end + offset; ++i)
2949 if (ranges[i].Min > ranges[i + 1].Min)
2950 ImSwap(ranges[i], ranges[i + 1]);
2951
2952 // Now fuse ranges together as much as possible.
2953 for (int i = 1 + offset; i < ranges.Size; i++)
2954 {
2955 IM_ASSERT(!ranges[i].PosToIndexConvert && !ranges[i - 1].PosToIndexConvert);
2956 if (ranges[i - 1].Max < ranges[i].Min)
2957 continue;
2958 ranges[i - 1].Min = ImMin(ranges[i - 1].Min, ranges[i].Min);
2959 ranges[i - 1].Max = ImMax(ranges[i - 1].Max, ranges[i].Max);
2960 ranges.erase(ranges.Data + i);
2961 i--;
2962 }
2963}
2964
2965static void ImGuiListClipper_SeekCursorAndSetupPrevLine(float pos_y, float line_height)
2966{
2967 // Set cursor position and a few other things so that SetScrollHereY() and Columns() can work when seeking cursor.
2968 // FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue.
2969 // The clipper should probably have a final step to display the last item in a regular manner, maybe with an opt-out flag for data sets which may have costly seek?
2970 ImGuiContext& g = *GImGui;
2971 ImGuiWindow* window = g.CurrentWindow;
2972 float off_y = pos_y - window->DC.CursorPos.y;
2973 window->DC.CursorPos.y = pos_y;
2974 window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, pos_y - g.Style.ItemSpacing.y);
2975 window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height; // Setting those fields so that SetScrollHereY() can properly function after the end of our clipper usage.
2976 window->DC.PrevLineSize.y = (line_height - g.Style.ItemSpacing.y); // If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list.
2977 if (ImGuiOldColumns* columns = window->DC.CurrentColumns)
2978 columns->LineMinY = window->DC.CursorPos.y; // Setting this so that cell Y position are set properly
2979 if (ImGuiTable* table = g.CurrentTable)
2980 {
2981 if (table->IsInsideRow)
2982 ImGui::TableEndRow(table);
2983 table->RowPosY2 = window->DC.CursorPos.y;
2984 const int row_increase = (int)((off_y / line_height) + 0.5f);
2985 //table->CurrentRow += row_increase; // Can't do without fixing TableEndRow()
2986 table->RowBgColorCounter += row_increase;
2987 }
2988}
2989
2990ImGuiListClipper::ImGuiListClipper()
2991{
2992 memset(this, 0, sizeof(*this));
2993}
2994
2995ImGuiListClipper::~ImGuiListClipper()
2996{
2997 End();
2998}
2999
3000void ImGuiListClipper::Begin(int items_count, float items_height)
3001{
3002 if (Ctx == NULL)
3003 Ctx = ImGui::GetCurrentContext();
3004
3005 ImGuiContext& g = *Ctx;
3006 ImGuiWindow* window = g.CurrentWindow;
3007 IMGUI_DEBUG_LOG_CLIPPER("Clipper: Begin(%d,%.2f) in '%s'\n", items_count, items_height, window->Name);
3008
3009 if (ImGuiTable* table = g.CurrentTable)
3010 if (table->IsInsideRow)
3011 ImGui::TableEndRow(table);
3012
3013 StartPosY = window->DC.CursorPos.y;
3014 ItemsHeight = items_height;
3015 ItemsCount = items_count;
3016 DisplayStart = -1;
3017 DisplayEnd = 0;
3018
3019 // Acquire temporary buffer
3020 if (++g.ClipperTempDataStacked > g.ClipperTempData.Size)
3021 g.ClipperTempData.resize(g.ClipperTempDataStacked, ImGuiListClipperData());
3022 ImGuiListClipperData* data = &g.ClipperTempData[g.ClipperTempDataStacked - 1];
3023 data->Reset(this);
3024 data->LossynessOffset = window->DC.CursorStartPosLossyness.y;
3025 TempData = data;
3026 StartSeekOffsetY = data->LossynessOffset;
3027}
3028
3029void ImGuiListClipper::End()
3030{
3031 if (ImGuiListClipperData* data = (ImGuiListClipperData*)TempData)
3032 {
3033 // In theory here we should assert that we are already at the right position, but it seems saner to just seek at the end and not assert/crash the user.
3034 ImGuiContext& g = *Ctx;
3035 IMGUI_DEBUG_LOG_CLIPPER("Clipper: End() in '%s'\n", g.CurrentWindow->Name);
3036 if (ItemsCount >= 0 && ItemsCount < INT_MAX && DisplayStart >= 0)
3037 SeekCursorForItem(ItemsCount);
3038
3039 // Restore temporary buffer and fix back pointers which may be invalidated when nesting
3040 IM_ASSERT(data->ListClipper == this);
3041 data->StepNo = data->Ranges.Size;
3042 if (--g.ClipperTempDataStacked > 0)
3043 {
3044 data = &g.ClipperTempData[g.ClipperTempDataStacked - 1];
3045 data->ListClipper->TempData = data;
3046 }
3047 TempData = NULL;
3048 }
3049 ItemsCount = -1;
3050}
3051
3052void ImGuiListClipper::IncludeItemsByIndex(int item_begin, int item_end)
3053{
3054 ImGuiListClipperData* data = (ImGuiListClipperData*)TempData;
3055 IM_ASSERT(DisplayStart < 0); // Only allowed after Begin() and if there has not been a specified range yet.
3056 IM_ASSERT(item_begin <= item_end);
3057 if (item_begin < item_end)
3058 data->Ranges.push_back(ImGuiListClipperRange::FromIndices(item_begin, item_end));
3059}
3060
3061// This is already called while stepping.
3062// The ONLY reason you may want to call this is if you passed INT_MAX to ImGuiListClipper::Begin() because you couldn't step item count beforehand.
3063void ImGuiListClipper::SeekCursorForItem(int item_n)
3064{
3065 // - Perform the add and multiply with double to allow seeking through larger ranges.
3066 // - StartPosY starts from ItemsFrozen, by adding SeekOffsetY we generally cancel that out (SeekOffsetY == LossynessOffset - ItemsFrozen * ItemsHeight).
3067 // - The reason we store SeekOffsetY instead of inferring it, is because we want to allow user to perform Seek after the last step, where ImGuiListClipperData is already done.
3068 float pos_y = (float)((double)StartPosY + StartSeekOffsetY + (double)item_n * ItemsHeight);
3069 ImGuiListClipper_SeekCursorAndSetupPrevLine(pos_y, ItemsHeight);
3070}
3071
3072static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper)
3073{
3074 ImGuiContext& g = *clipper->Ctx;
3075 ImGuiWindow* window = g.CurrentWindow;
3076 ImGuiListClipperData* data = (ImGuiListClipperData*)clipper->TempData;
3077 IM_ASSERT(data != NULL && "Called ImGuiListClipper::Step() too many times, or before ImGuiListClipper::Begin() ?");
3078
3079 ImGuiTable* table = g.CurrentTable;
3080 if (table && table->IsInsideRow)
3081 ImGui::TableEndRow(table);
3082
3083 // No items
3084 if (clipper->ItemsCount == 0 || GetSkipItemForListClipping())
3085 return false;
3086
3087 // While we are in frozen row state, keep displaying items one by one, unclipped
3088 // FIXME: Could be stored as a table-agnostic state.
3089 if (data->StepNo == 0 && table != NULL && !table->IsUnfrozenRows)
3090 {
3091 clipper->DisplayStart = data->ItemsFrozen;
3092 clipper->DisplayEnd = ImMin(data->ItemsFrozen + 1, clipper->ItemsCount);
3093 if (clipper->DisplayStart < clipper->DisplayEnd)
3094 data->ItemsFrozen++;
3095 return true;
3096 }
3097
3098 // Step 0: Let you process the first element (regardless of it being visible or not, so we can measure the element height)
3099 bool calc_clipping = false;
3100 if (data->StepNo == 0)
3101 {
3102 clipper->StartPosY = window->DC.CursorPos.y;
3103 if (clipper->ItemsHeight <= 0.0f)
3104 {
3105 // Submit the first item (or range) so we can measure its height (generally the first range is 0..1)
3106 data->Ranges.push_front(ImGuiListClipperRange::FromIndices(data->ItemsFrozen, data->ItemsFrozen + 1));
3107 clipper->DisplayStart = ImMax(data->Ranges[0].Min, data->ItemsFrozen);
3108 clipper->DisplayEnd = ImMin(data->Ranges[0].Max, clipper->ItemsCount);
3109 data->StepNo = 1;
3110 return true;
3111 }
3112 calc_clipping = true; // If on the first step with known item height, calculate clipping.
3113 }
3114
3115 // Step 1: Let the clipper infer height from first range
3116 if (clipper->ItemsHeight <= 0.0f)
3117 {
3118 IM_ASSERT(data->StepNo == 1);
3119 if (table)
3120 IM_ASSERT(table->RowPosY1 == clipper->StartPosY && table->RowPosY2 == window->DC.CursorPos.y);
3121
3122 clipper->ItemsHeight = (window->DC.CursorPos.y - clipper->StartPosY) / (float)(clipper->DisplayEnd - clipper->DisplayStart);
3123 bool affected_by_floating_point_precision = ImIsFloatAboveGuaranteedIntegerPrecision(clipper->StartPosY) || ImIsFloatAboveGuaranteedIntegerPrecision(window->DC.CursorPos.y);
3124 if (affected_by_floating_point_precision)
3125 clipper->ItemsHeight = window->DC.PrevLineSize.y + g.Style.ItemSpacing.y; // FIXME: Technically wouldn't allow multi-line entries.
3126 if (clipper->ItemsHeight == 0.0f && clipper->ItemsCount == INT_MAX) // Accept that no item have been submitted if in indeterminate mode.
3127 return false;
3128 IM_ASSERT(clipper->ItemsHeight > 0.0f && "Unable to calculate item height! First item hasn't moved the cursor vertically!");
3129 calc_clipping = true; // If item height had to be calculated, calculate clipping afterwards.
3130 }
3131
3132 // Step 0 or 1: Calculate the actual ranges of visible elements.
3133 const int already_submitted = clipper->DisplayEnd;
3134 if (calc_clipping)
3135 {
3136 // Record seek offset, this is so ImGuiListClipper::Seek() can be called after ImGuiListClipperData is done
3137 clipper->StartSeekOffsetY = (double)data->LossynessOffset - data->ItemsFrozen * (double)clipper->ItemsHeight;
3138
3139 if (g.LogEnabled)
3140 {
3141 // If logging is active, do not perform any clipping
3142 data->Ranges.push_back(ImGuiListClipperRange::FromIndices(0, clipper->ItemsCount));
3143 }
3144 else
3145 {
3146 // Add range selected to be included for navigation
3147 const bool is_nav_request = (g.NavMoveScoringItems && g.NavWindow && g.NavWindow->RootWindowForNav == window->RootWindowForNav);
3148 if (is_nav_request)
3149 data->Ranges.push_back(ImGuiListClipperRange::FromPositions(g.NavScoringNoClipRect.Min.y, g.NavScoringNoClipRect.Max.y, 0, 0));
3150 if (is_nav_request && (g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) && g.NavTabbingDir == -1)
3151 data->Ranges.push_back(ImGuiListClipperRange::FromIndices(clipper->ItemsCount - 1, clipper->ItemsCount));
3152
3153 // Add focused/active item
3154 ImRect nav_rect_abs = ImGui::WindowRectRelToAbs(window, window->NavRectRel[0]);
3155 if (g.NavId != 0 && window->NavLastIds[0] == g.NavId)
3156 data->Ranges.push_back(ImGuiListClipperRange::FromPositions(nav_rect_abs.Min.y, nav_rect_abs.Max.y, 0, 0));
3157
3158 // Add visible range
3159 float min_y = window->ClipRect.Min.y;
3160 float max_y = window->ClipRect.Max.y;
3161
3162 // Add box selection range
3163 ImGuiBoxSelectState* bs = &g.BoxSelectState;
3164 if (bs->IsActive && bs->Window == window)
3165 {
3166 // FIXME: Selectable() use of half-ItemSpacing isn't consistent in matter of layout, as ItemAdd(bb) stray above ItemSize()'s CursorPos.
3167 // RangeSelect's BoxSelect relies on comparing overlap of previous and current rectangle and is sensitive to that.
3168 // As a workaround we currently half ItemSpacing worth on each side.
3169 min_y -= g.Style.ItemSpacing.y;
3170 max_y += g.Style.ItemSpacing.y;
3171
3172 // Box-select on 2D area requires different clipping.
3173 if (bs->UnclipMode)
3174 data->Ranges.push_back(ImGuiListClipperRange::FromPositions(bs->UnclipRect.Min.y, bs->UnclipRect.Max.y, 0, 0));
3175 }
3176
3177 const int off_min = (is_nav_request && g.NavMoveClipDir == ImGuiDir_Up) ? -1 : 0;
3178 const int off_max = (is_nav_request && g.NavMoveClipDir == ImGuiDir_Down) ? 1 : 0;
3179 data->Ranges.push_back(ImGuiListClipperRange::FromPositions(min_y, max_y, off_min, off_max));
3180 }
3181
3182 // Convert position ranges to item index ranges
3183 // - Very important: when a starting position is after our maximum item, we set Min to (ItemsCount - 1). This allows us to handle most forms of wrapping.
3184 // - Due to how Selectable extra padding they tend to be "unaligned" with exact unit in the item list,
3185 // which with the flooring/ceiling tend to lead to 2 items instead of one being submitted.
3186 for (ImGuiListClipperRange& range : data->Ranges)
3187 if (range.PosToIndexConvert)
3188 {
3189 int m1 = (int)(((double)range.Min - window->DC.CursorPos.y - data->LossynessOffset) / clipper->ItemsHeight);
3190 int m2 = (int)((((double)range.Max - window->DC.CursorPos.y - data->LossynessOffset) / clipper->ItemsHeight) + 0.999999f);
3191 range.Min = ImClamp(already_submitted + m1 + range.PosToIndexOffsetMin, already_submitted, clipper->ItemsCount - 1);
3192 range.Max = ImClamp(already_submitted + m2 + range.PosToIndexOffsetMax, range.Min + 1, clipper->ItemsCount);
3193 range.PosToIndexConvert = false;
3194 }
3195 ImGuiListClipper_SortAndFuseRanges(data->Ranges, data->StepNo);
3196 }
3197
3198 // Step 0+ (if item height is given in advance) or 1+: Display the next range in line.
3199 while (data->StepNo < data->Ranges.Size)
3200 {
3201 clipper->DisplayStart = ImMax(data->Ranges[data->StepNo].Min, already_submitted);
3202 clipper->DisplayEnd = ImMin(data->Ranges[data->StepNo].Max, clipper->ItemsCount);
3203 if (clipper->DisplayStart > already_submitted) //-V1051
3204 clipper->SeekCursorForItem(clipper->DisplayStart);
3205 data->StepNo++;
3206 if (clipper->DisplayStart == clipper->DisplayEnd && data->StepNo < data->Ranges.Size)
3207 continue;
3208 return true;
3209 }
3210
3211 // After the last step: Let the clipper validate that we have reached the expected Y position (corresponding to element DisplayEnd),
3212 // Advance the cursor to the end of the list and then returns 'false' to end the loop.
3213 if (clipper->ItemsCount < INT_MAX)
3214 clipper->SeekCursorForItem(clipper->ItemsCount);
3215
3216 return false;
3217}
3218
3219bool ImGuiListClipper::Step()
3220{
3221 ImGuiContext& g = *Ctx;
3222 bool need_items_height = (ItemsHeight <= 0.0f);
3223 bool ret = ImGuiListClipper_StepInternal(this);
3224 if (ret && (DisplayStart == DisplayEnd))
3225 ret = false;
3226 if (g.CurrentTable && g.CurrentTable->IsUnfrozenRows == false)
3227 IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): inside frozen table row.\n");
3228 if (need_items_height && ItemsHeight > 0.0f)
3229 IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): computed ItemsHeight: %.2f.\n", ItemsHeight);
3230 if (ret)
3231 {
3232 IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): display %d to %d.\n", DisplayStart, DisplayEnd);
3233 }
3234 else
3235 {
3236 IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): End.\n");
3237 End();
3238 }
3239 return ret;
3240}
3241
3242//-----------------------------------------------------------------------------
3243// [SECTION] STYLING
3244//-----------------------------------------------------------------------------
3245
3246ImGuiStyle& ImGui::GetStyle()
3247{
3248 IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?");
3249 return GImGui->Style;
3250}
3251
3252ImU32 ImGui::GetColorU32(ImGuiCol idx, float alpha_mul)
3253{
3254 ImGuiStyle& style = GImGui->Style;
3255 ImVec4 c = style.Colors[idx];
3256 c.w *= style.Alpha * alpha_mul;
3257 return ColorConvertFloat4ToU32(c);
3258}
3259
3260ImU32 ImGui::GetColorU32(const ImVec4& col)
3261{
3262 ImGuiStyle& style = GImGui->Style;
3263 ImVec4 c = col;
3264 c.w *= style.Alpha;
3265 return ColorConvertFloat4ToU32(c);
3266}
3267
3268const ImVec4& ImGui::GetStyleColorVec4(ImGuiCol idx)
3269{
3270 ImGuiStyle& style = GImGui->Style;
3271 return style.Colors[idx];
3272}
3273
3274ImU32 ImGui::GetColorU32(ImU32 col, float alpha_mul)
3275{
3276 ImGuiStyle& style = GImGui->Style;
3277 alpha_mul *= style.Alpha;
3278 if (alpha_mul >= 1.0f)
3279 return col;
3280 ImU32 a = (col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT;
3281 a = (ImU32)(a * alpha_mul); // We don't need to clamp 0..255 because alpha is in 0..1 range.
3282 return (col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT);
3283}
3284
3285// FIXME: This may incur a round-trip (if the end user got their data from a float4) but eventually we aim to store the in-flight colors as ImU32
3286void ImGui::PushStyleColor(ImGuiCol idx, ImU32 col)
3287{
3288 ImGuiContext& g = *GImGui;
3289 ImGuiColorMod backup;
3290 backup.Col = idx;
3291 backup.BackupValue = g.Style.Colors[idx];
3292 g.ColorStack.push_back(backup);
3293 if (g.DebugFlashStyleColorIdx != idx)
3294 g.Style.Colors[idx] = ColorConvertU32ToFloat4(col);
3295}
3296
3297void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col)
3298{
3299 ImGuiContext& g = *GImGui;
3300 ImGuiColorMod backup;
3301 backup.Col = idx;
3302 backup.BackupValue = g.Style.Colors[idx];
3303 g.ColorStack.push_back(backup);
3304 if (g.DebugFlashStyleColorIdx != idx)
3305 g.Style.Colors[idx] = col;
3306}
3307
3308void ImGui::PopStyleColor(int count)
3309{
3310 ImGuiContext& g = *GImGui;
3311 if (g.ColorStack.Size < count)
3312 {
3313 IM_ASSERT_USER_ERROR(g.ColorStack.Size > count, "Calling PopStyleColor() too many times!");
3314 count = g.ColorStack.Size;
3315 }
3316 while (count > 0)
3317 {
3318 ImGuiColorMod& backup = g.ColorStack.back();
3319 g.Style.Colors[backup.Col] = backup.BackupValue;
3320 g.ColorStack.pop_back();
3321 count--;
3322 }
3323}
3324
3325static const ImGuiCol GWindowDockStyleColors[ImGuiWindowDockStyleCol_COUNT] =
3326{
3327 ImGuiCol_Text, ImGuiCol_TabHovered, ImGuiCol_Tab, ImGuiCol_TabSelected, ImGuiCol_TabSelectedOverline, ImGuiCol_TabDimmed, ImGuiCol_TabDimmedSelected, ImGuiCol_TabDimmedSelectedOverline,
3328};
3329
3330static const ImGuiDataVarInfo GStyleVarInfo[] =
3331{
3332 { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, Alpha) }, // ImGuiStyleVar_Alpha
3333 { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, DisabledAlpha) }, // ImGuiStyleVar_DisabledAlpha
3334 { ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, WindowPadding) }, // ImGuiStyleVar_WindowPadding
3335 { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, WindowRounding) }, // ImGuiStyleVar_WindowRounding
3336 { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, WindowBorderSize) }, // ImGuiStyleVar_WindowBorderSize
3337 { ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, WindowMinSize) }, // ImGuiStyleVar_WindowMinSize
3338 { ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, WindowTitleAlign) }, // ImGuiStyleVar_WindowTitleAlign
3339 { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, ChildRounding) }, // ImGuiStyleVar_ChildRounding
3340 { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, ChildBorderSize) }, // ImGuiStyleVar_ChildBorderSize
3341 { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, PopupRounding) }, // ImGuiStyleVar_PopupRounding
3342 { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, PopupBorderSize) }, // ImGuiStyleVar_PopupBorderSize
3343 { ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, FramePadding) }, // ImGuiStyleVar_FramePadding
3344 { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, FrameRounding) }, // ImGuiStyleVar_FrameRounding
3345 { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, FrameBorderSize) }, // ImGuiStyleVar_FrameBorderSize
3346 { ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, ItemSpacing) }, // ImGuiStyleVar_ItemSpacing
3347 { ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, ItemInnerSpacing) }, // ImGuiStyleVar_ItemInnerSpacing
3348 { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, IndentSpacing) }, // ImGuiStyleVar_IndentSpacing
3349 { ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, CellPadding) }, // ImGuiStyleVar_CellPadding
3350 { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, ScrollbarSize) }, // ImGuiStyleVar_ScrollbarSize
3351 { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, ScrollbarRounding) }, // ImGuiStyleVar_ScrollbarRounding
3352 { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, GrabMinSize) }, // ImGuiStyleVar_GrabMinSize
3353 { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, GrabRounding) }, // ImGuiStyleVar_GrabRounding
3354 { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TabRounding) }, // ImGuiStyleVar_TabRounding
3355 { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TabBorderSize) }, // ImGuiStyleVar_TabBorderSize
3356 { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TabBarBorderSize) }, // ImGuiStyleVar_TabBarBorderSize
3357 { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TabBarOverlineSize) }, // ImGuiStyleVar_TabBarOverlineSize
3358 { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TableAngledHeadersAngle)}, // ImGuiStyleVar_TableAngledHeadersAngle
3359 { ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, TableAngledHeadersTextAlign)},// ImGuiStyleVar_TableAngledHeadersTextAlign
3360 { ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign
3361 { ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign
3362 { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, SeparatorTextBorderSize)}, // ImGuiStyleVar_SeparatorTextBorderSize
3363 { ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, SeparatorTextAlign) }, // ImGuiStyleVar_SeparatorTextAlign
3364 { ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, SeparatorTextPadding) }, // ImGuiStyleVar_SeparatorTextPadding
3365 { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, DockingSeparatorSize) }, // ImGuiStyleVar_DockingSeparatorSize
3366};
3367
3368const ImGuiDataVarInfo* ImGui::GetStyleVarInfo(ImGuiStyleVar idx)
3369{
3370 IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_COUNT);
3371 IM_STATIC_ASSERT(IM_ARRAYSIZE(GStyleVarInfo) == ImGuiStyleVar_COUNT);
3372 return &GStyleVarInfo[idx];
3373}
3374
3375void ImGui::PushStyleVar(ImGuiStyleVar idx, float val)
3376{
3377 ImGuiContext& g = *GImGui;
3378 const ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx);
3379 if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1)
3380 {
3381 float* pvar = (float*)var_info->GetVarPtr(&g.Style);
3382 g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar));
3383 *pvar = val;
3384 return;
3385 }
3386 IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!");
3387}
3388
3389void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val)
3390{
3391 ImGuiContext& g = *GImGui;
3392 const ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx);
3393 if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2)
3394 {
3395 ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style);
3396 g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar));
3397 *pvar = val;
3398 return;
3399 }
3400 IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!");
3401}
3402
3403void ImGui::PopStyleVar(int count)
3404{
3405 ImGuiContext& g = *GImGui;
3406 if (g.StyleVarStack.Size < count)
3407 {
3408 IM_ASSERT_USER_ERROR(g.StyleVarStack.Size > count, "Calling PopStyleVar() too many times!");
3409 count = g.StyleVarStack.Size;
3410 }
3411 while (count > 0)
3412 {
3413 // We avoid a generic memcpy(data, &backup.Backup.., GDataTypeSize[info->Type] * info->Count), the overhead in Debug is not worth it.
3414 ImGuiStyleMod& backup = g.StyleVarStack.back();
3415 const ImGuiDataVarInfo* info = GetStyleVarInfo(backup.VarIdx);
3416 void* data = info->GetVarPtr(&g.Style);
3417 if (info->Type == ImGuiDataType_Float && info->Count == 1) { ((float*)data)[0] = backup.BackupFloat[0]; }
3418 else if (info->Type == ImGuiDataType_Float && info->Count == 2) { ((float*)data)[0] = backup.BackupFloat[0]; ((float*)data)[1] = backup.BackupFloat[1]; }
3419 g.StyleVarStack.pop_back();
3420 count--;
3421 }
3422}
3423
3424const char* ImGui::GetStyleColorName(ImGuiCol idx)
3425{
3426 // Create switch-case from enum with regexp: ImGuiCol_{.*}, --> case ImGuiCol_\1: return "\1";
3427 switch (idx)
3428 {
3429 case ImGuiCol_Text: return "Text";
3430 case ImGuiCol_TextDisabled: return "TextDisabled";
3431 case ImGuiCol_WindowBg: return "WindowBg";
3432 case ImGuiCol_ChildBg: return "ChildBg";
3433 case ImGuiCol_PopupBg: return "PopupBg";
3434 case ImGuiCol_Border: return "Border";
3435 case ImGuiCol_BorderShadow: return "BorderShadow";
3436 case ImGuiCol_FrameBg: return "FrameBg";
3437 case ImGuiCol_FrameBgHovered: return "FrameBgHovered";
3438 case ImGuiCol_FrameBgActive: return "FrameBgActive";
3439 case ImGuiCol_TitleBg: return "TitleBg";
3440 case ImGuiCol_TitleBgActive: return "TitleBgActive";
3441 case ImGuiCol_TitleBgCollapsed: return "TitleBgCollapsed";
3442 case ImGuiCol_MenuBarBg: return "MenuBarBg";
3443 case ImGuiCol_ScrollbarBg: return "ScrollbarBg";
3444 case ImGuiCol_ScrollbarGrab: return "ScrollbarGrab";
3445 case ImGuiCol_ScrollbarGrabHovered: return "ScrollbarGrabHovered";
3446 case ImGuiCol_ScrollbarGrabActive: return "ScrollbarGrabActive";
3447 case ImGuiCol_CheckMark: return "CheckMark";
3448 case ImGuiCol_SliderGrab: return "SliderGrab";
3449 case ImGuiCol_SliderGrabActive: return "SliderGrabActive";
3450 case ImGuiCol_Button: return "Button";
3451 case ImGuiCol_ButtonHovered: return "ButtonHovered";
3452 case ImGuiCol_ButtonActive: return "ButtonActive";
3453 case ImGuiCol_Header: return "Header";
3454 case ImGuiCol_HeaderHovered: return "HeaderHovered";
3455 case ImGuiCol_HeaderActive: return "HeaderActive";
3456 case ImGuiCol_Separator: return "Separator";
3457 case ImGuiCol_SeparatorHovered: return "SeparatorHovered";
3458 case ImGuiCol_SeparatorActive: return "SeparatorActive";
3459 case ImGuiCol_ResizeGrip: return "ResizeGrip";
3460 case ImGuiCol_ResizeGripHovered: return "ResizeGripHovered";
3461 case ImGuiCol_ResizeGripActive: return "ResizeGripActive";
3462 case ImGuiCol_TabHovered: return "TabHovered";
3463 case ImGuiCol_Tab: return "Tab";
3464 case ImGuiCol_TabSelected: return "TabSelected";
3465 case ImGuiCol_TabSelectedOverline: return "TabSelectedOverline";
3466 case ImGuiCol_TabDimmed: return "TabDimmed";
3467 case ImGuiCol_TabDimmedSelected: return "TabDimmedSelected";
3468 case ImGuiCol_TabDimmedSelectedOverline: return "TabDimmedSelectedOverline";
3469 case ImGuiCol_DockingPreview: return "DockingPreview";
3470 case ImGuiCol_DockingEmptyBg: return "DockingEmptyBg";
3471 case ImGuiCol_PlotLines: return "PlotLines";
3472 case ImGuiCol_PlotLinesHovered: return "PlotLinesHovered";
3473 case ImGuiCol_PlotHistogram: return "PlotHistogram";
3474 case ImGuiCol_PlotHistogramHovered: return "PlotHistogramHovered";
3475 case ImGuiCol_TableHeaderBg: return "TableHeaderBg";
3476 case ImGuiCol_TableBorderStrong: return "TableBorderStrong";
3477 case ImGuiCol_TableBorderLight: return "TableBorderLight";
3478 case ImGuiCol_TableRowBg: return "TableRowBg";
3479 case ImGuiCol_TableRowBgAlt: return "TableRowBgAlt";
3480 case ImGuiCol_TextLink: return "TextLink";
3481 case ImGuiCol_TextSelectedBg: return "TextSelectedBg";
3482 case ImGuiCol_DragDropTarget: return "DragDropTarget";
3483 case ImGuiCol_NavHighlight: return "NavHighlight";
3484 case ImGuiCol_NavWindowingHighlight: return "NavWindowingHighlight";
3485 case ImGuiCol_NavWindowingDimBg: return "NavWindowingDimBg";
3486 case ImGuiCol_ModalWindowDimBg: return "ModalWindowDimBg";
3487 }
3488 IM_ASSERT(0);
3489 return "Unknown";
3490}
3491
3492
3493//-----------------------------------------------------------------------------
3494// [SECTION] RENDER HELPERS
3495// Some of those (internal) functions are currently quite a legacy mess - their signature and behavior will change,
3496// we need a nicer separation between low-level functions and high-level functions relying on the ImGui context.
3497// Also see imgui_draw.cpp for some more which have been reworked to not rely on ImGui:: context.
3498//-----------------------------------------------------------------------------
3499
3500const char* ImGui::FindRenderedTextEnd(const char* text, const char* text_end)
3501{
3502 const char* text_display_end = text;
3503 if (!text_end)
3504 text_end = (const char*)-1;
3505
3506 while (text_display_end < text_end && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#'))
3507 text_display_end++;
3508 return text_display_end;
3509}
3510
3511// Internal ImGui functions to render text
3512// RenderText***() functions calls ImDrawList::AddText() calls ImBitmapFont::RenderText()
3513void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool hide_text_after_hash)
3514{
3515 ImGuiContext& g = *GImGui;
3516 ImGuiWindow* window = g.CurrentWindow;
3517
3518 // Hide anything after a '##' string
3519 const char* text_display_end;
3520 if (hide_text_after_hash)
3521 {
3522 text_display_end = FindRenderedTextEnd(text, text_end);
3523 }
3524 else
3525 {
3526 if (!text_end)
3527 text_end = text + strlen(text); // FIXME-OPT
3528 text_display_end = text_end;
3529 }
3530
3531 if (text != text_display_end)
3532 {
3533 window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end);
3534 if (g.LogEnabled)
3535 LogRenderedText(&pos, text, text_display_end);
3536 }
3537}
3538
3539void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width)
3540{
3541 ImGuiContext& g = *GImGui;
3542 ImGuiWindow* window = g.CurrentWindow;
3543
3544 if (!text_end)
3545 text_end = text + strlen(text); // FIXME-OPT
3546
3547 if (text != text_end)
3548 {
3549 window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_end, wrap_width);
3550 if (g.LogEnabled)
3551 LogRenderedText(&pos, text, text_end);
3552 }
3553}
3554
3555// Default clip_rect uses (pos_min,pos_max)
3556// Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges)
3557// FIXME-OPT: Since we have or calculate text_size we could coarse clip whole block immediately, especally for text above draw_list->DrawList.
3558// Effectively as this is called from widget doing their own coarse clipping it's not very valuable presently. Next time function will take
3559// better advantage of the render function taking size into account for coarse clipping.
3560void ImGui::RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_display_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect)
3561{
3562 // Perform CPU side clipping for single clipped element to avoid using scissor state
3563 ImVec2 pos = pos_min;
3564 const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_display_end, false, 0.0f);
3565
3566 const ImVec2* clip_min = clip_rect ? &clip_rect->Min : &pos_min;
3567 const ImVec2* clip_max = clip_rect ? &clip_rect->Max : &pos_max;
3568 bool need_clipping = (pos.x + text_size.x >= clip_max->x) || (pos.y + text_size.y >= clip_max->y);
3569 if (clip_rect) // If we had no explicit clipping rectangle then pos==clip_min
3570 need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y);
3571
3572 // Align whole block. We should defer that to the better rendering function when we'll have support for individual line alignment.
3573 if (align.x > 0.0f) pos.x = ImMax(pos.x, pos.x + (pos_max.x - pos.x - text_size.x) * align.x);
3574 if (align.y > 0.0f) pos.y = ImMax(pos.y, pos.y + (pos_max.y - pos.y - text_size.y) * align.y);
3575
3576 // Render
3577 if (need_clipping)
3578 {
3579 ImVec4 fine_clip_rect(clip_min->x, clip_min->y, clip_max->x, clip_max->y);
3580 draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, &fine_clip_rect);
3581 }
3582 else
3583 {
3584 draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL);
3585 }
3586}
3587
3588void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect)
3589{
3590 // Hide anything after a '##' string
3591 const char* text_display_end = FindRenderedTextEnd(text, text_end);
3592 const int text_len = (int)(text_display_end - text);
3593 if (text_len == 0)
3594 return;
3595
3596 ImGuiContext& g = *GImGui;
3597 ImGuiWindow* window = g.CurrentWindow;
3598 RenderTextClippedEx(window->DrawList, pos_min, pos_max, text, text_display_end, text_size_if_known, align, clip_rect);
3599 if (g.LogEnabled)
3600 LogRenderedText(&pos_min, text, text_display_end);
3601}
3602
3603// Another overly complex function until we reorganize everything into a nice all-in-one helper.
3604// This is made more complex because we have dissociated the layout rectangle (pos_min..pos_max) which define _where_ the ellipsis is, from actual clipping of text and limit of the ellipsis display.
3605// This is because in the context of tabs we selectively hide part of the text when the Close Button appears, but we don't want the ellipsis to move.
3606void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end_full, const ImVec2* text_size_if_known)
3607{
3608 ImGuiContext& g = *GImGui;
3609 if (text_end_full == NULL)
3610 text_end_full = FindRenderedTextEnd(text);
3611 const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_end_full, false, 0.0f);
3612
3613 //draw_list->AddLine(ImVec2(pos_max.x, pos_min.y - 4), ImVec2(pos_max.x, pos_max.y + 4), IM_COL32(0, 0, 255, 255));
3614 //draw_list->AddLine(ImVec2(ellipsis_max_x, pos_min.y-2), ImVec2(ellipsis_max_x, pos_max.y+2), IM_COL32(0, 255, 0, 255));
3615 //draw_list->AddLine(ImVec2(clip_max_x, pos_min.y), ImVec2(clip_max_x, pos_max.y), IM_COL32(255, 0, 0, 255));
3616 // FIXME: We could technically remove (last_glyph->AdvanceX - last_glyph->X1) from text_size.x here and save a few pixels.
3617 if (text_size.x > pos_max.x - pos_min.x)
3618 {
3619 // Hello wo...
3620 // | | |
3621 // min max ellipsis_max
3622 // <-> this is generally some padding value
3623
3624 const ImFont* font = draw_list->_Data->Font;
3625 const float font_size = draw_list->_Data->FontSize;
3626 const float font_scale = draw_list->_Data->FontScale;
3627 const char* text_end_ellipsis = NULL;
3628 const float ellipsis_width = font->EllipsisWidth * font_scale;
3629
3630 // We can now claim the space between pos_max.x and ellipsis_max.x
3631 const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_width) - pos_min.x, 1.0f);
3632 float text_size_clipped_x = font->CalcTextSizeA(font_size, text_avail_width, 0.0f, text, text_end_full, &text_end_ellipsis).x;
3633 if (text == text_end_ellipsis && text_end_ellipsis < text_end_full)
3634 {
3635 // Always display at least 1 character if there's no room for character + ellipsis
3636 text_end_ellipsis = text + ImTextCountUtf8BytesFromChar(text, text_end_full);
3637 text_size_clipped_x = font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text, text_end_ellipsis).x;
3638 }
3639 while (text_end_ellipsis > text && ImCharIsBlankA(text_end_ellipsis[-1]))
3640 {
3641 // Trim trailing space before ellipsis (FIXME: Supporting non-ascii blanks would be nice, for this we need a function to backtrack in UTF-8 text)
3642 text_end_ellipsis--;
3643 text_size_clipped_x -= font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text_end_ellipsis, text_end_ellipsis + 1).x; // Ascii blanks are always 1 byte
3644 }
3645
3646 // Render text, render ellipsis
3647 RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f));
3648 ImVec2 ellipsis_pos = ImTrunc(ImVec2(pos_min.x + text_size_clipped_x, pos_min.y));
3649 if (ellipsis_pos.x + ellipsis_width <= ellipsis_max_x)
3650 for (int i = 0; i < font->EllipsisCharCount; i++, ellipsis_pos.x += font->EllipsisCharStep * font_scale)
3651 font->RenderChar(draw_list, font_size, ellipsis_pos, GetColorU32(ImGuiCol_Text), font->EllipsisChar);
3652 }
3653 else
3654 {
3655 RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_full, &text_size, ImVec2(0.0f, 0.0f));
3656 }
3657
3658 if (g.LogEnabled)
3659 LogRenderedText(&pos_min, text, text_end_full);
3660}
3661
3662// Render a rectangle shaped with optional rounding and borders
3663void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, float rounding)
3664{
3665 ImGuiContext& g = *GImGui;
3666 ImGuiWindow* window = g.CurrentWindow;
3667 window->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding);
3668 const float border_size = g.Style.FrameBorderSize;
3669 if (border && border_size > 0.0f)
3670 {
3671 window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, 0, border_size);
3672 window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, 0, border_size);
3673 }
3674}
3675
3676void ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding)
3677{
3678 ImGuiContext& g = *GImGui;
3679 ImGuiWindow* window = g.CurrentWindow;
3680 const float border_size = g.Style.FrameBorderSize;
3681 if (border_size > 0.0f)
3682 {
3683 window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, 0, border_size);
3684 window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, 0, border_size);
3685 }
3686}
3687
3688void ImGui::RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags)
3689{
3690 ImGuiContext& g = *GImGui;
3691 if (id != g.NavId)
3692 return;
3693 if (g.NavDisableHighlight && !(flags & ImGuiNavHighlightFlags_AlwaysDraw))
3694 return;
3695 ImGuiWindow* window = g.CurrentWindow;
3696 if (window->DC.NavHideHighlightOneFrame)
3697 return;
3698
3699 float rounding = (flags & ImGuiNavHighlightFlags_NoRounding) ? 0.0f : g.Style.FrameRounding;
3700 ImRect display_rect = bb;
3701 display_rect.ClipWith(window->ClipRect);
3702 const float thickness = 2.0f;
3703 if (flags & ImGuiNavHighlightFlags_Compact)
3704 {
3705 window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavHighlight), rounding, 0, thickness);
3706 }
3707 else
3708 {
3709 const float distance = 3.0f + thickness * 0.5f;
3710 display_rect.Expand(ImVec2(distance, distance));
3711 bool fully_visible = window->ClipRect.Contains(display_rect);
3712 if (!fully_visible)
3713 window->DrawList->PushClipRect(display_rect.Min, display_rect.Max);
3714 window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavHighlight), rounding, 0, thickness);
3715 if (!fully_visible)
3716 window->DrawList->PopClipRect();
3717 }
3718}
3719
3720void ImGui::RenderMouseCursor(ImVec2 base_pos, float base_scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow)
3721{
3722 ImGuiContext& g = *GImGui;
3723 IM_ASSERT(mouse_cursor > ImGuiMouseCursor_None && mouse_cursor < ImGuiMouseCursor_COUNT);
3724 ImFontAtlas* font_atlas = g.DrawListSharedData.Font->ContainerAtlas;
3725 for (ImGuiViewportP* viewport : g.Viewports)
3726 {
3727 // We scale cursor with current viewport/monitor, however Windows 10 for its own hardware cursor seems to be using a different scale factor.
3728 ImVec2 offset, size, uv[4];
3729 if (!font_atlas->GetMouseCursorTexData(mouse_cursor, &offset, &size, &uv[0], &uv[2]))
3730 continue;
3731 const ImVec2 pos = base_pos - offset;
3732 const float scale = base_scale * viewport->DpiScale;
3733 if (!viewport->GetMainRect().Overlaps(ImRect(pos, pos + ImVec2(size.x + 2, size.y + 2) * scale)))
3734 continue;
3735 ImDrawList* draw_list = GetForegroundDrawList(viewport);
3736 ImTextureID tex_id = font_atlas->TexID;
3737 draw_list->PushTextureID(tex_id);
3738 draw_list->AddImage(tex_id, pos + ImVec2(1, 0) * scale, pos + (ImVec2(1, 0) + size) * scale, uv[2], uv[3], col_shadow);
3739 draw_list->AddImage(tex_id, pos + ImVec2(2, 0) * scale, pos + (ImVec2(2, 0) + size) * scale, uv[2], uv[3], col_shadow);
3740 draw_list->AddImage(tex_id, pos, pos + size * scale, uv[2], uv[3], col_border);
3741 draw_list->AddImage(tex_id, pos, pos + size * scale, uv[0], uv[1], col_fill);
3742 draw_list->PopTextureID();
3743 }
3744}
3745
3746//-----------------------------------------------------------------------------
3747// [SECTION] INITIALIZATION, SHUTDOWN
3748//-----------------------------------------------------------------------------
3749
3750// Internal state access - if you want to share Dear ImGui state between modules (e.g. DLL) or allocate it yourself
3751// 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
3752ImGuiContext* ImGui::GetCurrentContext()
3753{
3754 return GImGui;
3755}
3756
3757void ImGui::SetCurrentContext(ImGuiContext* ctx)
3758{
3759#ifdef IMGUI_SET_CURRENT_CONTEXT_FUNC
3760 IMGUI_SET_CURRENT_CONTEXT_FUNC(ctx); // For custom thread-based hackery you may want to have control over this.
3761#else
3762 GImGui = ctx;
3763#endif
3764}
3765
3766void ImGui::SetAllocatorFunctions(ImGuiMemAllocFunc alloc_func, ImGuiMemFreeFunc free_func, void* user_data)
3767{
3768 GImAllocatorAllocFunc = alloc_func;
3769 GImAllocatorFreeFunc = free_func;
3770 GImAllocatorUserData = user_data;
3771}
3772
3773// This is provided to facilitate copying allocators from one static/DLL boundary to another (e.g. retrieve default allocator of your executable address space)
3774void ImGui::GetAllocatorFunctions(ImGuiMemAllocFunc* p_alloc_func, ImGuiMemFreeFunc* p_free_func, void** p_user_data)
3775{
3776 *p_alloc_func = GImAllocatorAllocFunc;
3777 *p_free_func = GImAllocatorFreeFunc;
3778 *p_user_data = GImAllocatorUserData;
3779}
3780
3781ImGuiContext* ImGui::CreateContext(ImFontAtlas* shared_font_atlas)
3782{
3783 ImGuiContext* prev_ctx = GetCurrentContext();
3784 ImGuiContext* ctx = IM_NEW(ImGuiContext)(shared_font_atlas);
3785 SetCurrentContext(ctx);
3786 Initialize();
3787 if (prev_ctx != NULL)
3788 SetCurrentContext(prev_ctx); // Restore previous context if any, else keep new one.
3789 return ctx;
3790}
3791
3792void ImGui::DestroyContext(ImGuiContext* ctx)
3793{
3794 ImGuiContext* prev_ctx = GetCurrentContext();
3795 if (ctx == NULL) //-V1051
3796 ctx = prev_ctx;
3797 SetCurrentContext(ctx);
3798 Shutdown();
3799 SetCurrentContext((prev_ctx != ctx) ? prev_ctx : NULL);
3800 IM_DELETE(ctx);
3801}
3802
3803// IMPORTANT: ###xxx suffixes must be same in ALL languages to allow for automation.
3804static const ImGuiLocEntry GLocalizationEntriesEnUS[] =
3805{
3806 { ImGuiLocKey_VersionStr, "Dear ImGui " IMGUI_VERSION " (" IM_STRINGIFY(IMGUI_VERSION_NUM) ")" },
3807 { ImGuiLocKey_TableSizeOne, "Size column to fit###SizeOne" },
3808 { ImGuiLocKey_TableSizeAllFit, "Size all columns to fit###SizeAll" },
3809 { ImGuiLocKey_TableSizeAllDefault, "Size all columns to default###SizeAll" },
3810 { ImGuiLocKey_TableResetOrder, "Reset order###ResetOrder" },
3811 { ImGuiLocKey_WindowingMainMenuBar, "(Main menu bar)" },
3812 { ImGuiLocKey_WindowingPopup, "(Popup)" },
3813 { ImGuiLocKey_WindowingUntitled, "(Untitled)" },
3814 { ImGuiLocKey_CopyLink, "Copy Link###CopyLink" },
3815 { ImGuiLocKey_DockingHideTabBar, "Hide tab bar###HideTabBar" },
3816 { ImGuiLocKey_DockingHoldShiftToDock, "Hold SHIFT to enable Docking window." },
3817 { ImGuiLocKey_DockingDragToUndockOrMoveNode,"Click and drag to move or undock whole node." },
3818};
3819
3820void ImGui::Initialize()
3821{
3822 ImGuiContext& g = *GImGui;
3823 IM_ASSERT(!g.Initialized && !g.SettingsLoaded);
3824
3825 // Add .ini handle for ImGuiWindow and ImGuiTable types
3826 {
3827 ImGuiSettingsHandler ini_handler;
3828 ini_handler.TypeName = "Window";
3829 ini_handler.TypeHash = ImHashStr("Window");
3830 ini_handler.ClearAllFn = WindowSettingsHandler_ClearAll;
3831 ini_handler.ReadOpenFn = WindowSettingsHandler_ReadOpen;
3832 ini_handler.ReadLineFn = WindowSettingsHandler_ReadLine;
3833 ini_handler.ApplyAllFn = WindowSettingsHandler_ApplyAll;
3834 ini_handler.WriteAllFn = WindowSettingsHandler_WriteAll;
3835 AddSettingsHandler(&ini_handler);
3836 }
3837 TableSettingsAddSettingsHandler();
3838
3839 // Setup default localization table
3840 LocalizeRegisterEntries(GLocalizationEntriesEnUS, IM_ARRAYSIZE(GLocalizationEntriesEnUS));
3841
3842 // Setup default platform clipboard/IME handlers.
3843 g.IO.GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations
3844 g.IO.SetClipboardTextFn = SetClipboardTextFn_DefaultImpl;
3845 g.IO.ClipboardUserData = (void*)&g; // Default implementation use the ImGuiContext as user data (ideally those would be arguments to the function)
3846 g.IO.PlatformOpenInShellFn = PlatformOpenInShellFn_DefaultImpl;
3847 g.IO.PlatformSetImeDataFn = PlatformSetImeDataFn_DefaultImpl;
3848
3849 // Create default viewport
3850 ImGuiViewportP* viewport = IM_NEW(ImGuiViewportP)();
3851 viewport->ID = IMGUI_VIEWPORT_DEFAULT_ID;
3852 viewport->Idx = 0;
3853 viewport->PlatformWindowCreated = true;
3854 viewport->Flags = ImGuiViewportFlags_OwnedByApp;
3855 g.Viewports.push_back(viewport);
3856 g.TempBuffer.resize(1024 * 3 + 1, 0);
3857 g.ViewportCreatedCount++;
3858 g.PlatformIO.Viewports.push_back(g.Viewports[0]);
3859
3860 // Build KeysMayBeCharInput[] lookup table (1 bool per named key)
3861 for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1))
3862 if ((key >= ImGuiKey_0 && key <= ImGuiKey_9) || (key >= ImGuiKey_A && key <= ImGuiKey_Z) || (key >= ImGuiKey_Keypad0 && key <= ImGuiKey_Keypad9)
3863 || key == ImGuiKey_Tab || key == ImGuiKey_Space || key == ImGuiKey_Apostrophe || key == ImGuiKey_Comma || key == ImGuiKey_Minus || key == ImGuiKey_Period
3864 || key == ImGuiKey_Slash || key == ImGuiKey_Semicolon || key == ImGuiKey_Equal || key == ImGuiKey_LeftBracket || key == ImGuiKey_RightBracket || key == ImGuiKey_GraveAccent
3865 || key == ImGuiKey_KeypadDecimal || key == ImGuiKey_KeypadDivide || key == ImGuiKey_KeypadMultiply || key == ImGuiKey_KeypadSubtract || key == ImGuiKey_KeypadAdd || key == ImGuiKey_KeypadEqual)
3866 g.KeysMayBeCharInput.SetBit(key);
3867
3868#ifdef IMGUI_HAS_DOCK
3869 // Initialize Docking
3870 DockContextInitialize(&g);
3871#endif
3872
3873 g.Initialized = true;
3874}
3875
3876// This function is merely here to free heap allocations.
3877void ImGui::Shutdown()
3878{
3879 ImGuiContext& g = *GImGui;
3880 IM_ASSERT_USER_ERROR(g.IO.BackendPlatformUserData == NULL, "Forgot to shutdown Platform backend?");
3881 IM_ASSERT_USER_ERROR(g.IO.BackendRendererUserData == NULL, "Forgot to shutdown Renderer backend?");
3882
3883 // 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)
3884 if (g.IO.Fonts && g.FontAtlasOwnedByContext)
3885 {
3886 g.IO.Fonts->Locked = false;
3887 IM_DELETE(g.IO.Fonts);
3888 }
3889 g.IO.Fonts = NULL;
3890 g.DrawListSharedData.TempBuffer.clear();
3891
3892 // Cleanup of other data are conditional on actually having initialized Dear ImGui.
3893 if (!g.Initialized)
3894 return;
3895
3896 // Save settings (unless we haven't attempted to load them: CreateContext/DestroyContext without a call to NewFrame shouldn't save an empty file)
3897 if (g.SettingsLoaded && g.IO.IniFilename != NULL)
3898 SaveIniSettingsToDisk(g.IO.IniFilename);
3899
3900 // Destroy platform windows
3901 DestroyPlatformWindows();
3902
3903 // Shutdown extensions
3904 DockContextShutdown(&g);
3905
3906 CallContextHooks(&g, ImGuiContextHookType_Shutdown);
3907
3908 // Clear everything else
3909 g.Windows.clear_delete();
3910 g.WindowsFocusOrder.clear();
3911 g.WindowsTempSortBuffer.clear();
3912 g.CurrentWindow = NULL;
3913 g.CurrentWindowStack.clear();
3914 g.WindowsById.Clear();
3915 g.NavWindow = NULL;
3916 g.HoveredWindow = g.HoveredWindowUnderMovingWindow = NULL;
3917 g.ActiveIdWindow = g.ActiveIdPreviousFrameWindow = NULL;
3918 g.MovingWindow = NULL;
3919
3920 g.KeysRoutingTable.Clear();
3921
3922 g.ColorStack.clear();
3923 g.StyleVarStack.clear();
3924 g.FontStack.clear();
3925 g.OpenPopupStack.clear();
3926 g.BeginPopupStack.clear();
3927 g.TreeNodeStack.clear();
3928
3929 g.CurrentViewport = g.MouseViewport = g.MouseLastHoveredViewport = NULL;
3930 g.Viewports.clear_delete();
3931
3932 g.TabBars.Clear();
3933 g.CurrentTabBarStack.clear();
3934 g.ShrinkWidthBuffer.clear();
3935
3936 g.ClipperTempData.clear_destruct();
3937
3938 g.Tables.Clear();
3939 g.TablesTempData.clear_destruct();
3940 g.DrawChannelsTempMergeBuffer.clear();
3941
3942 g.MultiSelectStorage.Clear();
3943 g.MultiSelectTempData.clear_destruct();
3944
3945 g.ClipboardHandlerData.clear();
3946 g.MenusIdSubmittedThisFrame.clear();
3947 g.InputTextState.ClearFreeMemory();
3948 g.InputTextDeactivatedState.ClearFreeMemory();
3949
3950 g.SettingsWindows.clear();
3951 g.SettingsHandlers.clear();
3952
3953 if (g.LogFile)
3954 {
3955#ifndef IMGUI_DISABLE_TTY_FUNCTIONS
3956 if (g.LogFile != stdout)
3957#endif
3958 ImFileClose(g.LogFile);
3959 g.LogFile = NULL;
3960 }
3961 g.LogBuffer.clear();
3962 g.DebugLogBuf.clear();
3963 g.DebugLogIndex.clear();
3964
3965 g.Initialized = false;
3966}
3967
3968// No specific ordering/dependency support, will see as needed
3969ImGuiID ImGui::AddContextHook(ImGuiContext* ctx, const ImGuiContextHook* hook)
3970{
3971 ImGuiContext& g = *ctx;
3972 IM_ASSERT(hook->Callback != NULL && hook->HookId == 0 && hook->Type != ImGuiContextHookType_PendingRemoval_);
3973 g.Hooks.push_back(*hook);
3974 g.Hooks.back().HookId = ++g.HookIdNext;
3975 return g.HookIdNext;
3976}
3977
3978// Deferred removal, avoiding issue with changing vector while iterating it
3979void ImGui::RemoveContextHook(ImGuiContext* ctx, ImGuiID hook_id)
3980{
3981 ImGuiContext& g = *ctx;
3982 IM_ASSERT(hook_id != 0);
3983 for (ImGuiContextHook& hook : g.Hooks)
3984 if (hook.HookId == hook_id)
3985 hook.Type = ImGuiContextHookType_PendingRemoval_;
3986}
3987
3988// Call context hooks (used by e.g. test engine)
3989// We assume a small number of hooks so all stored in same array
3990void ImGui::CallContextHooks(ImGuiContext* ctx, ImGuiContextHookType hook_type)
3991{
3992 ImGuiContext& g = *ctx;
3993 for (ImGuiContextHook& hook : g.Hooks)
3994 if (hook.Type == hook_type)
3995 hook.Callback(&g, &hook);
3996}
3997
3998
3999//-----------------------------------------------------------------------------
4000// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!)
4001//-----------------------------------------------------------------------------
4002
4003// ImGuiWindow is mostly a dumb struct. It merely has a constructor and a few helper methods
4004ImGuiWindow::ImGuiWindow(ImGuiContext* ctx, const char* name) : DrawListInst(NULL)
4005{
4006 memset(this, 0, sizeof(*this));
4007 Ctx = ctx;
4008 Name = ImStrdup(name);
4009 NameBufLen = (int)strlen(name) + 1;
4010 ID = ImHashStr(name);
4011 IDStack.push_back(ID);
4012 ViewportAllowPlatformMonitorExtend = -1;
4013 ViewportPos = ImVec2(FLT_MAX, FLT_MAX);
4014 MoveId = GetID("#MOVE");
4015 TabId = GetID("#TAB");
4016 ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
4017 ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f);
4018 AutoFitFramesX = AutoFitFramesY = -1;
4019 AutoPosLastDirection = ImGuiDir_None;
4020 SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = SetWindowDockAllowFlags = 0;
4021 SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX);
4022 LastFrameActive = -1;
4023 LastFrameJustFocused = -1;
4024 LastTimeActive = -1.0f;
4025 FontWindowScale = FontDpiScale = 1.0f;
4026 SettingsOffset = -1;
4027 DockOrder = -1;
4028 DrawList = &DrawListInst;
4029 DrawList->_Data = &Ctx->DrawListSharedData;
4030 DrawList->_OwnerName = Name;
4031 NavPreferredScoringPosRel[0] = NavPreferredScoringPosRel[1] = ImVec2(FLT_MAX, FLT_MAX);
4032 IM_PLACEMENT_NEW(&WindowClass) ImGuiWindowClass();
4033}
4034
4035ImGuiWindow::~ImGuiWindow()
4036{
4037 IM_ASSERT(DrawList == &DrawListInst);
4038 IM_DELETE(Name);
4039 ColumnsStorage.clear_destruct();
4040}
4041
4042static void SetCurrentWindow(ImGuiWindow* window)
4043{
4044 ImGuiContext& g = *GImGui;
4045 g.CurrentWindow = window;
4046 g.CurrentTable = window && window->DC.CurrentTableIdx != -1 ? g.Tables.GetByIndex(window->DC.CurrentTableIdx) : NULL;
4047 if (window)
4048 {
4049 g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
4050 g.FontScale = g.FontSize / g.Font->FontSize;
4051 ImGui::NavUpdateCurrentWindowIsScrollPushableX();
4052 }
4053}
4054
4055void ImGui::GcCompactTransientMiscBuffers()
4056{
4057 ImGuiContext& g = *GImGui;
4058 g.ItemFlagsStack.clear();
4059 g.GroupStack.clear();
4060 g.MultiSelectTempDataStacked = 0;
4061 g.MultiSelectTempData.clear_destruct();
4062 TableGcCompactSettings();
4063}
4064
4065// Free up/compact internal window buffers, we can use this when a window becomes unused.
4066// Not freed:
4067// - ImGuiWindow, ImGuiWindowSettings, Name, StateStorage, ColumnsStorage (may hold useful data)
4068// This should have no noticeable visual effect. When the window reappear however, expect new allocation/buffer growth/copy cost.
4069void ImGui::GcCompactTransientWindowBuffers(ImGuiWindow* window)
4070{
4071 window->MemoryCompacted = true;
4072 window->MemoryDrawListIdxCapacity = window->DrawList->IdxBuffer.Capacity;
4073 window->MemoryDrawListVtxCapacity = window->DrawList->VtxBuffer.Capacity;
4074 window->IDStack.clear();
4075 window->DrawList->_ClearFreeMemory();
4076 window->DC.ChildWindows.clear();
4077 window->DC.ItemWidthStack.clear();
4078 window->DC.TextWrapPosStack.clear();
4079}
4080
4081void ImGui::GcAwakeTransientWindowBuffers(ImGuiWindow* window)
4082{
4083 // We stored capacity of the ImDrawList buffer to reduce growth-caused allocation/copy when awakening.
4084 // The other buffers tends to amortize much faster.
4085 window->MemoryCompacted = false;
4086 window->DrawList->IdxBuffer.reserve(window->MemoryDrawListIdxCapacity);
4087 window->DrawList->VtxBuffer.reserve(window->MemoryDrawListVtxCapacity);
4088 window->MemoryDrawListIdxCapacity = window->MemoryDrawListVtxCapacity = 0;
4089}
4090
4091void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
4092{
4093 ImGuiContext& g = *GImGui;
4094
4095 // Clear previous active id
4096 if (g.ActiveId != 0)
4097 {
4098 // While most behaved code would make an effort to not steal active id during window move/drag operations,
4099 // we at least need to be resilient to it. Canceling the move is rather aggressive and users of 'master' branch
4100 // may prefer the weird ill-defined half working situation ('docking' did assert), so may need to rework that.
4101 if (g.MovingWindow != NULL && g.ActiveId == g.MovingWindow->MoveId)
4102 {
4103 IMGUI_DEBUG_LOG_ACTIVEID("SetActiveID() cancel MovingWindow\n");
4104 g.MovingWindow = NULL;
4105 }
4106
4107 // This could be written in a more general way (e.g associate a hook to ActiveId),
4108 // but since this is currently quite an exception we'll leave it as is.
4109 // One common scenario leading to this is: pressing Key ->NavMoveRequestApplyResult() -> ClearActiveId()
4110 if (g.InputTextState.ID == g.ActiveId)
4111 InputTextDeactivateHook(g.ActiveId);
4112 }
4113
4114 // Set active id
4115 g.ActiveIdIsJustActivated = (g.ActiveId != id);
4116 if (g.ActiveIdIsJustActivated)
4117 {
4118 IMGUI_DEBUG_LOG_ACTIVEID("SetActiveID() old:0x%08X (window \"%s\") -> new:0x%08X (window \"%s\")\n", g.ActiveId, g.ActiveIdWindow ? g.ActiveIdWindow->Name : "", id, window ? window->Name : "");
4119 g.ActiveIdTimer = 0.0f;
4120 g.ActiveIdHasBeenPressedBefore = false;
4121 g.ActiveIdHasBeenEditedBefore = false;
4122 g.ActiveIdMouseButton = -1;
4123 if (id != 0)
4124 {
4125 g.LastActiveId = id;
4126 g.LastActiveIdTimer = 0.0f;
4127 }
4128 }
4129 g.ActiveId = id;
4130 g.ActiveIdAllowOverlap = false;
4131 g.ActiveIdNoClearOnFocusLoss = false;
4132 g.ActiveIdWindow = window;
4133 g.ActiveIdHasBeenEditedThisFrame = false;
4134 g.ActiveIdFromShortcut = false;
4135 if (id)
4136 {
4137 g.ActiveIdIsAlive = id;
4138 g.ActiveIdSource = (g.NavActivateId == id || g.NavJustMovedToId == id) ? g.NavInputSource : ImGuiInputSource_Mouse;
4139 IM_ASSERT(g.ActiveIdSource != ImGuiInputSource_None);
4140 }
4141
4142 // Clear declaration of inputs claimed by the widget
4143 // (Please note that this is WIP and not all keys/inputs are thoroughly declared by all widgets yet)
4144 g.ActiveIdUsingNavDirMask = 0x00;
4145 g.ActiveIdUsingAllKeyboardKeys = false;
4146}
4147
4148void ImGui::ClearActiveID()
4149{
4150 SetActiveID(0, NULL); // g.ActiveId = 0;
4151}
4152
4153void ImGui::SetHoveredID(ImGuiID id)
4154{
4155 ImGuiContext& g = *GImGui;
4156 g.HoveredId = id;
4157 g.HoveredIdAllowOverlap = false;
4158 if (id != 0 && g.HoveredIdPreviousFrame != id)
4159 g.HoveredIdTimer = g.HoveredIdNotActiveTimer = 0.0f;
4160}
4161
4162ImGuiID ImGui::GetHoveredID()
4163{
4164 ImGuiContext& g = *GImGui;
4165 return g.HoveredId ? g.HoveredId : g.HoveredIdPreviousFrame;
4166}
4167
4168void ImGui::MarkItemEdited(ImGuiID id)
4169{
4170 // This marking is solely to be able to provide info for IsItemDeactivatedAfterEdit().
4171 // ActiveId might have been released by the time we call this (as in the typical press/release button behavior) but still need to fill the data.
4172 ImGuiContext& g = *GImGui;
4173 if (g.LockMarkEdited > 0)
4174 return;
4175 if (g.ActiveId == id || g.ActiveId == 0)
4176 {
4177 g.ActiveIdHasBeenEditedThisFrame = true;
4178 g.ActiveIdHasBeenEditedBefore = true;
4179 }
4180
4181 // We accept a MarkItemEdited() on drag and drop targets (see https://github.com/ocornut/imgui/issues/1875#issuecomment-978243343)
4182 // We accept 'ActiveIdPreviousFrame == id' for InputText() returning an edit after it has been taken ActiveId away (#4714)
4183 IM_ASSERT(g.DragDropActive || g.ActiveId == id || g.ActiveId == 0 || g.ActiveIdPreviousFrame == id || (g.CurrentMultiSelect != NULL && g.BoxSelectState.IsActive));
4184
4185 //IM_ASSERT(g.CurrentWindow->DC.LastItemId == id);
4186 g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Edited;
4187}
4188
4189bool ImGui::IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags)
4190{
4191 // An active popup disable hovering on other windows (apart from its own children)
4192 // FIXME-OPT: This could be cached/stored within the window.
4193 ImGuiContext& g = *GImGui;
4194 if (g.NavWindow)
4195 if (ImGuiWindow* focused_root_window = g.NavWindow->RootWindowDockTree)
4196 if (focused_root_window->WasActive && focused_root_window != window->RootWindowDockTree)
4197 {
4198 // For the purpose of those flags we differentiate "standard popup" from "modal popup"
4199 // NB: The 'else' is important because Modal windows are also Popups.
4200 bool want_inhibit = false;
4201 if (focused_root_window->Flags & ImGuiWindowFlags_Modal)
4202 want_inhibit = true;
4203 else if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiHoveredFlags_AllowWhenBlockedByPopup))
4204 want_inhibit = true;
4205
4206 // Inhibit hover unless the window is within the stack of our modal/popup
4207 if (want_inhibit)
4208 if (!IsWindowWithinBeginStackOf(window->RootWindow, focused_root_window))
4209 return false;
4210 }
4211
4212 // Filter by viewport
4213 if (window->Viewport != g.MouseViewport)
4214 if (g.MovingWindow == NULL || window->RootWindowDockTree != g.MovingWindow->RootWindowDockTree)
4215 return false;
4216
4217 return true;
4218}
4219
4220static inline float CalcDelayFromHoveredFlags(ImGuiHoveredFlags flags)
4221{
4222 ImGuiContext& g = *GImGui;
4223 if (flags & ImGuiHoveredFlags_DelayNormal)
4224 return g.Style.HoverDelayNormal;
4225 if (flags & ImGuiHoveredFlags_DelayShort)
4226 return g.Style.HoverDelayShort;
4227 return 0.0f;
4228}
4229
4230static ImGuiHoveredFlags ApplyHoverFlagsForTooltip(ImGuiHoveredFlags user_flags, ImGuiHoveredFlags shared_flags)
4231{
4232 // Allow instance flags to override shared flags
4233 if (user_flags & (ImGuiHoveredFlags_DelayNone | ImGuiHoveredFlags_DelayShort | ImGuiHoveredFlags_DelayNormal))
4234 shared_flags &= ~(ImGuiHoveredFlags_DelayNone | ImGuiHoveredFlags_DelayShort | ImGuiHoveredFlags_DelayNormal);
4235 return user_flags | shared_flags;
4236}
4237
4238// This is roughly matching the behavior of internal-facing ItemHoverable()
4239// - we allow hovering to be true when ActiveId==window->MoveID, so that clicking on non-interactive items such as a Text() item still returns true with IsItemHovered()
4240// - this should work even for non-interactive items that have no ID, so we cannot use LastItemId
4241bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
4242{
4243 ImGuiContext& g = *GImGui;
4244 ImGuiWindow* window = g.CurrentWindow;
4245 IM_ASSERT((flags & ~ImGuiHoveredFlags_AllowedMaskForIsItemHovered) == 0 && "Invalid flags for IsItemHovered()!");
4246
4247 if (g.NavDisableMouseHover && !g.NavDisableHighlight && !(flags & ImGuiHoveredFlags_NoNavOverride))
4248 {
4249 if ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled))
4250 return false;
4251 if (!IsItemFocused())
4252 return false;
4253
4254 if (flags & ImGuiHoveredFlags_ForTooltip)
4255 flags = ApplyHoverFlagsForTooltip(flags, g.Style.HoverFlagsForTooltipNav);
4256 }
4257 else
4258 {
4259 // Test for bounding box overlap, as updated as ItemAdd()
4260 ImGuiItemStatusFlags status_flags = g.LastItemData.StatusFlags;
4261 if (!(status_flags & ImGuiItemStatusFlags_HoveredRect))
4262 return false;
4263
4264 if (flags & ImGuiHoveredFlags_ForTooltip)
4265 flags = ApplyHoverFlagsForTooltip(flags, g.Style.HoverFlagsForTooltipMouse);
4266
4267 IM_ASSERT((flags & (ImGuiHoveredFlags_AnyWindow | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy | ImGuiHoveredFlags_DockHierarchy)) == 0); // Flags not supported by this function
4268
4269 // Done with rectangle culling so we can perform heavier checks now
4270 // Test if we are hovering the right window (our window could be behind another window)
4271 // [2021/03/02] Reworked / reverted the revert, finally. Note we want e.g. BeginGroup/ItemAdd/EndGroup to work as well. (#3851)
4272 // [2017/10/16] Reverted commit 344d48be3 and testing RootWindow instead. I believe it is correct to NOT test for RootWindow but this leaves us unable
4273 // to use IsItemHovered() after EndChild() itself. Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was
4274 // the test that has been running for a long while.
4275 if (g.HoveredWindow != window && (status_flags & ImGuiItemStatusFlags_HoveredWindow) == 0)
4276 if ((flags & ImGuiHoveredFlags_AllowWhenOverlappedByWindow) == 0)
4277 return false;
4278
4279 // Test if another item is active (e.g. being dragged)
4280 const ImGuiID id = g.LastItemData.ID;
4281 if ((flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) == 0)
4282 if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap)
4283 if (g.ActiveId != window->MoveId && g.ActiveId != window->TabId)
4284 return false;
4285
4286 // Test if interactions on this window are blocked by an active popup or modal.
4287 // The ImGuiHoveredFlags_AllowWhenBlockedByPopup flag will be tested here.
4288 if (!IsWindowContentHoverable(window, flags) && !(g.LastItemData.InFlags & ImGuiItemFlags_NoWindowHoverableCheck))
4289 return false;
4290
4291 // Test if the item is disabled
4292 if ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled))
4293 return false;
4294
4295 // Special handling for calling after Begin() which represent the title bar or tab.
4296 // When the window is skipped/collapsed (SkipItems==true) that last item (always ->MoveId submitted by Begin)
4297 // will never be overwritten so we need to detect the case.
4298 if (id == window->MoveId && window->WriteAccessed)
4299 return false;
4300
4301 // Test if using AllowOverlap and overlapped
4302 if ((g.LastItemData.InFlags & ImGuiItemFlags_AllowOverlap) && id != 0)
4303 if ((flags & ImGuiHoveredFlags_AllowWhenOverlappedByItem) == 0)
4304 if (g.HoveredIdPreviousFrame != g.LastItemData.ID)
4305 return false;
4306 }
4307
4308 // Handle hover delay
4309 // (some ideas: https://www.nngroup.com/articles/timing-exposing-content)
4310 const float delay = CalcDelayFromHoveredFlags(flags);
4311 if (delay > 0.0f || (flags & ImGuiHoveredFlags_Stationary))
4312 {
4313 ImGuiID hover_delay_id = (g.LastItemData.ID != 0) ? g.LastItemData.ID : window->GetIDFromRectangle(g.LastItemData.Rect);
4314 if ((flags & ImGuiHoveredFlags_NoSharedDelay) && (g.HoverItemDelayIdPreviousFrame != hover_delay_id))
4315 g.HoverItemDelayTimer = 0.0f;
4316 g.HoverItemDelayId = hover_delay_id;
4317
4318 // When changing hovered item we requires a bit of stationary delay before activating hover timer,
4319 // but once unlocked on a given item we also moving.
4320 //if (g.HoverDelayTimer >= delay && (g.HoverDelayTimer - g.IO.DeltaTime < delay || g.MouseStationaryTimer - g.IO.DeltaTime < g.Style.HoverStationaryDelay)) { IMGUI_DEBUG_LOG("HoverDelayTimer = %f/%f, MouseStationaryTimer = %f\n", g.HoverDelayTimer, delay, g.MouseStationaryTimer); }
4321 if ((flags & ImGuiHoveredFlags_Stationary) != 0 && g.HoverItemUnlockedStationaryId != hover_delay_id)
4322 return false;
4323
4324 if (g.HoverItemDelayTimer < delay)
4325 return false;
4326 }
4327
4328 return true;
4329}
4330
4331// Internal facing ItemHoverable() used when submitting widgets. Differs slightly from IsItemHovered().
4332// (this does not rely on LastItemData it can be called from a ButtonBehavior() call not following an ItemAdd() call)
4333// FIXME-LEGACY: the 'ImGuiItemFlags item_flags' parameter was added on 2023-06-28.
4334// If you used this in your legacy/custom widgets code:
4335// - Commonly: if your ItemHoverable() call comes after an ItemAdd() call: pass 'item_flags = g.LastItemData.InFlags'.
4336// - Rare: otherwise you may pass 'item_flags = 0' (ImGuiItemFlags_None) unless you want to benefit from special behavior handled by ItemHoverable.
4337bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flags)
4338{
4339 ImGuiContext& g = *GImGui;
4340 ImGuiWindow* window = g.CurrentWindow;
4341 if (g.HoveredWindow != window)
4342 return false;
4343 if (!IsMouseHoveringRect(bb.Min, bb.Max))
4344 return false;
4345
4346 if (g.HoveredId != 0 && g.HoveredId != id && !g.HoveredIdAllowOverlap)
4347 return false;
4348 if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap)
4349 if (!g.ActiveIdFromShortcut)
4350 return false;
4351
4352 // Done with rectangle culling so we can perform heavier checks now.
4353 if (!(item_flags & ImGuiItemFlags_NoWindowHoverableCheck) && !IsWindowContentHoverable(window, ImGuiHoveredFlags_None))
4354 {
4355 g.HoveredIdIsDisabled = true;
4356 return false;
4357 }
4358
4359 // We exceptionally allow this function to be called with id==0 to allow using it for easy high-level
4360 // hover test in widgets code. We could also decide to split this function is two.
4361 if (id != 0)
4362 {
4363 // Drag source doesn't report as hovered
4364 if (g.DragDropActive && g.DragDropPayload.SourceId == id && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoDisableHover))
4365 return false;
4366
4367 SetHoveredID(id);
4368
4369 // AllowOverlap mode (rarely used) requires previous frame HoveredId to be null or to match.
4370 // This allows using patterns where a later submitted widget overlaps a previous one. Generally perceived as a front-to-back hit-test.
4371 if (item_flags & ImGuiItemFlags_AllowOverlap)
4372 {
4373 g.HoveredIdAllowOverlap = true;
4374 if (g.HoveredIdPreviousFrame != id)
4375 return false;
4376 }
4377
4378 // Display shortcut (only works with mouse)
4379 // (ImGuiItemStatusFlags_HasShortcut in LastItemData denotes we want a tooltip)
4380 if (id == g.LastItemData.ID && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasShortcut))
4381 if (IsItemHovered(ImGuiHoveredFlags_ForTooltip | ImGuiHoveredFlags_DelayNormal))
4382 SetTooltip("%s", GetKeyChordName(g.LastItemData.Shortcut));
4383 }
4384
4385 // When disabled we'll return false but still set HoveredId
4386 if (item_flags & ImGuiItemFlags_Disabled)
4387 {
4388 // Release active id if turning disabled
4389 if (g.ActiveId == id && id != 0)
4390 ClearActiveID();
4391 g.HoveredIdIsDisabled = true;
4392 return false;
4393 }
4394
4395#ifndef IMGUI_DISABLE_DEBUG_TOOLS
4396 if (id != 0)
4397 {
4398 // [DEBUG] Item Picker tool!
4399 // We perform the check here because reaching is path is rare (1~ time a frame),
4400 // making the cost of this tool near-zero! We could get better call-stack and support picking non-hovered
4401 // items if we performed the test in ItemAdd(), but that would incur a bigger runtime cost.
4402 if (g.DebugItemPickerActive && g.HoveredIdPreviousFrame == id)
4403 GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(255, 255, 0, 255));
4404 if (g.DebugItemPickerBreakId == id)
4405 IM_DEBUG_BREAK();
4406 }
4407#endif
4408
4409 if (g.NavDisableMouseHover)
4410 return false;
4411
4412 return true;
4413}
4414
4415// FIXME: This is inlined/duplicated in ItemAdd()
4416// FIXME: The id != 0 path is not used by our codebase, may get rid of it?
4417bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id)
4418{
4419 ImGuiContext& g = *GImGui;
4420 ImGuiWindow* window = g.CurrentWindow;
4421 if (!bb.Overlaps(window->ClipRect))
4422 if (id == 0 || (id != g.ActiveId && id != g.ActiveIdPreviousFrame && id != g.NavId && id != g.NavActivateId))
4423 if (!g.ItemUnclipByLog)
4424 return true;
4425 return false;
4426}
4427
4428// This is also inlined in ItemAdd()
4429// Note: if ImGuiItemStatusFlags_HasDisplayRect is set, user needs to set g.LastItemData.DisplayRect.
4430void ImGui::SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemStatusFlags item_flags, const ImRect& item_rect)
4431{
4432 ImGuiContext& g = *GImGui;
4433 g.LastItemData.ID = item_id;
4434 g.LastItemData.InFlags = in_flags;
4435 g.LastItemData.StatusFlags = item_flags;
4436 g.LastItemData.Rect = g.LastItemData.NavRect = item_rect;
4437}
4438
4439float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x)
4440{
4441 if (wrap_pos_x < 0.0f)
4442 return 0.0f;
4443
4444 ImGuiContext& g = *GImGui;
4445 ImGuiWindow* window = g.CurrentWindow;
4446 if (wrap_pos_x == 0.0f)
4447 {
4448 // We could decide to setup a default wrapping max point for auto-resizing windows,
4449 // or have auto-wrap (with unspecified wrapping pos) behave as a ContentSize extending function?
4450 //if (window->Hidden && (window->Flags & ImGuiWindowFlags_AlwaysAutoResize))
4451 // wrap_pos_x = ImMax(window->WorkRect.Min.x + g.FontSize * 10.0f, window->WorkRect.Max.x);
4452 //else
4453 wrap_pos_x = window->WorkRect.Max.x;
4454 }
4455 else if (wrap_pos_x > 0.0f)
4456 {
4457 wrap_pos_x += window->Pos.x - window->Scroll.x; // wrap_pos_x is provided is window local space
4458 }
4459
4460 return ImMax(wrap_pos_x - pos.x, 1.0f);
4461}
4462
4463// IM_ALLOC() == ImGui::MemAlloc()
4464void* ImGui::MemAlloc(size_t size)
4465{
4466 void* ptr = (*GImAllocatorAllocFunc)(size, GImAllocatorUserData);
4467#ifndef IMGUI_DISABLE_DEBUG_TOOLS
4468 if (ImGuiContext* ctx = GImGui)
4469 DebugAllocHook(&ctx->DebugAllocInfo, ctx->FrameCount, ptr, size);
4470#endif
4471 return ptr;
4472}
4473
4474// IM_FREE() == ImGui::MemFree()
4475void ImGui::MemFree(void* ptr)
4476{
4477#ifndef IMGUI_DISABLE_DEBUG_TOOLS
4478 if (ptr != NULL)
4479 if (ImGuiContext* ctx = GImGui)
4480 DebugAllocHook(&ctx->DebugAllocInfo, ctx->FrameCount, ptr, (size_t)-1);
4481#endif
4482 return (*GImAllocatorFreeFunc)(ptr, GImAllocatorUserData);
4483}
4484
4485// We record the number of allocation in recent frames, as a way to audit/sanitize our guiding principles of "no allocations on idle/repeating frames"
4486void ImGui::DebugAllocHook(ImGuiDebugAllocInfo* info, int frame_count, void* ptr, size_t size)
4487{
4488 ImGuiDebugAllocEntry* entry = &info->LastEntriesBuf[info->LastEntriesIdx];
4489 IM_UNUSED(ptr);
4490 if (entry->FrameCount != frame_count)
4491 {
4492 info->LastEntriesIdx = (info->LastEntriesIdx + 1) % IM_ARRAYSIZE(info->LastEntriesBuf);
4493 entry = &info->LastEntriesBuf[info->LastEntriesIdx];
4494 entry->FrameCount = frame_count;
4495 entry->AllocCount = entry->FreeCount = 0;
4496 }
4497 if (size != (size_t)-1)
4498 {
4499 entry->AllocCount++;
4500 info->TotalAllocCount++;
4501 //printf("[%05d] MemAlloc(%d) -> 0x%p\n", frame_count, size, ptr);
4502 }
4503 else
4504 {
4505 entry->FreeCount++;
4506 info->TotalFreeCount++;
4507 //printf("[%05d] MemFree(0x%p)\n", frame_count, ptr);
4508 }
4509}
4510
4511const char* ImGui::GetClipboardText()
4512{
4513 ImGuiContext& g = *GImGui;
4514 return g.IO.GetClipboardTextFn ? g.IO.GetClipboardTextFn(g.IO.ClipboardUserData) : "";
4515}
4516
4517void ImGui::SetClipboardText(const char* text)
4518{
4519 ImGuiContext& g = *GImGui;
4520 if (g.IO.SetClipboardTextFn)
4521 g.IO.SetClipboardTextFn(g.IO.ClipboardUserData, text);
4522}
4523
4524const char* ImGui::GetVersion()
4525{
4526 return IMGUI_VERSION;
4527}
4528
4529ImGuiIO& ImGui::GetIO()
4530{
4531 IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?");
4532 return GImGui->IO;
4533}
4534
4535ImGuiPlatformIO& ImGui::GetPlatformIO()
4536{
4537 IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext()?");
4538 return GImGui->PlatformIO;
4539}
4540
4541// Pass this to your backend rendering function! Valid after Render() and until the next call to NewFrame()
4542ImDrawData* ImGui::GetDrawData()
4543{
4544 ImGuiContext& g = *GImGui;
4545 ImGuiViewportP* viewport = g.Viewports[0];
4546 return viewport->DrawDataP.Valid ? &viewport->DrawDataP : NULL;
4547}
4548
4549double ImGui::GetTime()
4550{
4551 return GImGui->Time;
4552}
4553
4554int ImGui::GetFrameCount()
4555{
4556 return GImGui->FrameCount;
4557}
4558
4559static ImDrawList* GetViewportBgFgDrawList(ImGuiViewportP* viewport, size_t drawlist_no, const char* drawlist_name)
4560{
4561 // Create the draw list on demand, because they are not frequently used for all viewports
4562 ImGuiContext& g = *GImGui;
4563 IM_ASSERT(drawlist_no < IM_ARRAYSIZE(viewport->BgFgDrawLists));
4564 ImDrawList* draw_list = viewport->BgFgDrawLists[drawlist_no];
4565 if (draw_list == NULL)
4566 {
4567 draw_list = IM_NEW(ImDrawList)(&g.DrawListSharedData);
4568 draw_list->_OwnerName = drawlist_name;
4569 viewport->BgFgDrawLists[drawlist_no] = draw_list;
4570 }
4571
4572 // Our ImDrawList system requires that there is always a command
4573 if (viewport->BgFgDrawListsLastFrame[drawlist_no] != g.FrameCount)
4574 {
4575 draw_list->_ResetForNewFrame();
4576 draw_list->PushTextureID(g.IO.Fonts->TexID);
4577 draw_list->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size, false);
4578 viewport->BgFgDrawListsLastFrame[drawlist_no] = g.FrameCount;
4579 }
4580 return draw_list;
4581}
4582
4583ImDrawList* ImGui::GetBackgroundDrawList(ImGuiViewport* viewport)
4584{
4585 if (viewport == NULL)
4586 viewport = GImGui->CurrentWindow->Viewport;
4587 return GetViewportBgFgDrawList((ImGuiViewportP*)viewport, 0, "##Background");
4588}
4589
4590ImDrawList* ImGui::GetForegroundDrawList(ImGuiViewport* viewport)
4591{
4592 if (viewport == NULL)
4593 viewport = GImGui->CurrentWindow->Viewport;
4594 return GetViewportBgFgDrawList((ImGuiViewportP*)viewport, 1, "##Foreground");
4595}
4596
4597ImDrawListSharedData* ImGui::GetDrawListSharedData()
4598{
4599 return &GImGui->DrawListSharedData;
4600}
4601
4602void ImGui::StartMouseMovingWindow(ImGuiWindow* window)
4603{
4604 // Set ActiveId even if the _NoMove flag is set. Without it, dragging away from a window with _NoMove would activate hover on other windows.
4605 // We _also_ call this when clicking in a window empty space when io.ConfigWindowsMoveFromTitleBarOnly is set, but clear g.MovingWindow afterward.
4606 // This is because we want ActiveId to be set even when the window is not permitted to move.
4607 ImGuiContext& g = *GImGui;
4608 FocusWindow(window);
4609 SetActiveID(window->MoveId, window);
4610 g.NavDisableHighlight = true;
4611 g.ActiveIdClickOffset = g.IO.MouseClickedPos[0] - window->RootWindowDockTree->Pos;
4612 g.ActiveIdNoClearOnFocusLoss = true;
4613 SetActiveIdUsingAllKeyboardKeys();
4614
4615 bool can_move_window = true;
4616 if ((window->Flags & ImGuiWindowFlags_NoMove) || (window->RootWindowDockTree->Flags & ImGuiWindowFlags_NoMove))
4617 can_move_window = false;
4618 if (ImGuiDockNode* node = window->DockNodeAsHost)
4619 if (node->VisibleWindow && (node->VisibleWindow->Flags & ImGuiWindowFlags_NoMove))
4620 can_move_window = false;
4621 if (can_move_window)
4622 g.MovingWindow = window;
4623}
4624
4625// We use 'undock == false' when dragging from title bar to allow moving groups of floating nodes without undocking them.
4626void ImGui::StartMouseMovingWindowOrNode(ImGuiWindow* window, ImGuiDockNode* node, bool undock)
4627{
4628 ImGuiContext& g = *GImGui;
4629 bool can_undock_node = false;
4630 if (undock && node != NULL && node->VisibleWindow && (node->VisibleWindow->Flags & ImGuiWindowFlags_NoMove) == 0 && (node->MergedFlags & ImGuiDockNodeFlags_NoUndocking) == 0)
4631 {
4632 // Can undock if:
4633 // - part of a hierarchy with more than one visible node (if only one is visible, we'll just move the root window)
4634 // - part of a dockspace node hierarchy: so we can undock the last single visible node too (trivia: undocking from a fixed/central node will create a new node and copy windows)
4635 ImGuiDockNode* root_node = DockNodeGetRootNode(node);
4636 if (root_node->OnlyNodeWithWindows != node || root_node->CentralNode != NULL) // -V1051 PVS-Studio thinks node should be root_node and is wrong about that.
4637 can_undock_node = true;
4638 }
4639
4640 const bool clicked = IsMouseClicked(0);
4641 const bool dragging = IsMouseDragging(0);
4642 if (can_undock_node && dragging)
4643 DockContextQueueUndockNode(&g, node); // Will lead to DockNodeStartMouseMovingWindow() -> StartMouseMovingWindow() being called next frame
4644 else if (!can_undock_node && (clicked || dragging) && g.MovingWindow != window)
4645 StartMouseMovingWindow(window);
4646}
4647
4648// Handle mouse moving window
4649// Note: moving window with the navigation keys (Square + d-pad / CTRL+TAB + Arrows) are processed in NavUpdateWindowing()
4650// FIXME: We don't have strong guarantee that g.MovingWindow stay synched with g.ActiveId == g.MovingWindow->MoveId.
4651// This is currently enforced by the fact that BeginDragDropSource() is setting all g.ActiveIdUsingXXXX flags to inhibit navigation inputs,
4652// but if we should more thoroughly test cases where g.ActiveId or g.MovingWindow gets changed and not the other.
4653void ImGui::UpdateMouseMovingWindowNewFrame()
4654{
4655 ImGuiContext& g = *GImGui;
4656 if (g.MovingWindow != NULL)
4657 {
4658 // We actually want to move the root window. g.MovingWindow == window we clicked on (could be a child window).
4659 // We track it to preserve Focus and so that generally ActiveIdWindow == MovingWindow and ActiveId == MovingWindow->MoveId for consistency.
4660 KeepAliveID(g.ActiveId);
4661 IM_ASSERT(g.MovingWindow && g.MovingWindow->RootWindowDockTree);
4662 ImGuiWindow* moving_window = g.MovingWindow->RootWindowDockTree;
4663
4664 // When a window stop being submitted while being dragged, it may will its viewport until next Begin()
4665 const bool window_disappared = (!moving_window->WasActive && !moving_window->Active);
4666 if (g.IO.MouseDown[0] && IsMousePosValid(&g.IO.MousePos) && !window_disappared)
4667 {
4668 ImVec2 pos = g.IO.MousePos - g.ActiveIdClickOffset;
4669 if (moving_window->Pos.x != pos.x || moving_window->Pos.y != pos.y)
4670 {
4671 SetWindowPos(moving_window, pos, ImGuiCond_Always);
4672 if (moving_window->Viewport && moving_window->ViewportOwned) // Synchronize viewport immediately because some overlays may relies on clipping rectangle before we Begin() into the window.
4673 {
4674 moving_window->Viewport->Pos = pos;
4675 moving_window->Viewport->UpdateWorkRect();
4676 }
4677 }
4678 FocusWindow(g.MovingWindow);
4679 }
4680 else
4681 {
4682 if (!window_disappared)
4683 {
4684 // Try to merge the window back into the main viewport.
4685 // This works because MouseViewport should be != MovingWindow->Viewport on release (as per code in UpdateViewports)
4686 if (g.ConfigFlagsCurrFrame & ImGuiConfigFlags_ViewportsEnable)
4687 UpdateTryMergeWindowIntoHostViewport(moving_window, g.MouseViewport);
4688
4689 // Restore the mouse viewport so that we don't hover the viewport _under_ the moved window during the frame we released the mouse button.
4690 if (moving_window->Viewport && !IsDragDropPayloadBeingAccepted())
4691 g.MouseViewport = moving_window->Viewport;
4692
4693 // Clear the NoInput window flag set by the Viewport system
4694 if (moving_window->Viewport)
4695 moving_window->Viewport->Flags &= ~ImGuiViewportFlags_NoInputs;
4696 }
4697
4698 g.MovingWindow = NULL;
4699 ClearActiveID();
4700 }
4701 }
4702 else
4703 {
4704 // When clicking/dragging from a window that has the _NoMove flag, we still set the ActiveId in order to prevent hovering others.
4705 if (g.ActiveIdWindow && g.ActiveIdWindow->MoveId == g.ActiveId)
4706 {
4707 KeepAliveID(g.ActiveId);
4708 if (!g.IO.MouseDown[0])
4709 ClearActiveID();
4710 }
4711 }
4712}
4713
4714// Initiate moving window when clicking on empty space or title bar.
4715// Handle left-click and right-click focus.
4716void ImGui::UpdateMouseMovingWindowEndFrame()
4717{
4718 ImGuiContext& g = *GImGui;
4719 if (g.ActiveId != 0 || g.HoveredId != 0)
4720 return;
4721
4722 // Unless we just made a window/popup appear
4723 if (g.NavWindow && g.NavWindow->Appearing)
4724 return;
4725
4726 // Click on empty space to focus window and start moving
4727 // (after we're done with all our widgets, so e.g. clicking on docking tab-bar which have set HoveredId already and not get us here!)
4728 if (g.IO.MouseClicked[0])
4729 {
4730 // Handle the edge case of a popup being closed while clicking in its empty space.
4731 // If we try to focus it, FocusWindow() > ClosePopupsOverWindow() will accidentally close any parent popups because they are not linked together any more.
4732 ImGuiWindow* root_window = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL;
4733 const bool is_closed_popup = root_window && (root_window->Flags & ImGuiWindowFlags_Popup) && !IsPopupOpen(root_window->PopupId, ImGuiPopupFlags_AnyPopupLevel);
4734
4735 if (root_window != NULL && !is_closed_popup)
4736 {
4737 StartMouseMovingWindow(g.HoveredWindow); //-V595
4738
4739 // Cancel moving if clicked outside of title bar
4740 if (g.IO.ConfigWindowsMoveFromTitleBarOnly)
4741 if (!(root_window->Flags & ImGuiWindowFlags_NoTitleBar) || root_window->DockIsActive)
4742 if (!root_window->TitleBarRect().Contains(g.IO.MouseClickedPos[0]))
4743 g.MovingWindow = NULL;
4744
4745 // Cancel moving if clicked over an item which was disabled or inhibited by popups (note that we know HoveredId == 0 already)
4746 if (g.HoveredIdIsDisabled)
4747 g.MovingWindow = NULL;
4748 }
4749 else if (root_window == NULL && g.NavWindow != NULL)
4750 {
4751 // Clicking on void disable focus
4752 FocusWindow(NULL, ImGuiFocusRequestFlags_UnlessBelowModal);
4753 }
4754 }
4755
4756 // With right mouse button we close popups without changing focus based on where the mouse is aimed
4757 // Instead, focus will be restored to the window under the bottom-most closed popup.
4758 // (The left mouse button path calls FocusWindow on the hovered window, which will lead NewFrame->ClosePopupsOverWindow to trigger)
4759 if (g.IO.MouseClicked[1])
4760 {
4761 // Find the top-most window between HoveredWindow and the top-most Modal Window.
4762 // This is where we can trim the popup stack.
4763 ImGuiWindow* modal = GetTopMostPopupModal();
4764 bool hovered_window_above_modal = g.HoveredWindow && (modal == NULL || IsWindowAbove(g.HoveredWindow, modal));
4765 ClosePopupsOverWindow(hovered_window_above_modal ? g.HoveredWindow : modal, true);
4766 }
4767}
4768
4769// This is called during NewFrame()->UpdateViewportsNewFrame() only.
4770// Need to keep in sync with SetWindowPos()
4771static void TranslateWindow(ImGuiWindow* window, const ImVec2& delta)
4772{
4773 window->Pos += delta;
4774 window->ClipRect.Translate(delta);
4775 window->OuterRectClipped.Translate(delta);
4776 window->InnerRect.Translate(delta);
4777 window->DC.CursorPos += delta;
4778 window->DC.CursorStartPos += delta;
4779 window->DC.CursorMaxPos += delta;
4780 window->DC.IdealMaxPos += delta;
4781}
4782
4783static void ScaleWindow(ImGuiWindow* window, float scale)
4784{
4785 ImVec2 origin = window->Viewport->Pos;
4786 window->Pos = ImFloor((window->Pos - origin) * scale + origin);
4787 window->Size = ImTrunc(window->Size * scale);
4788 window->SizeFull = ImTrunc(window->SizeFull * scale);
4789 window->ContentSize = ImTrunc(window->ContentSize * scale);
4790}
4791
4792static bool IsWindowActiveAndVisible(ImGuiWindow* window)
4793{
4794 return (window->Active) && (!window->Hidden);
4795}
4796
4797// The reason this is exposed in imgui_internal.h is: on touch-based system that don't have hovering, we want to dispatch inputs to the right target (imgui vs imgui+app)
4798void ImGui::UpdateHoveredWindowAndCaptureFlags()
4799{
4800 ImGuiContext& g = *GImGui;
4801 ImGuiIO& io = g.IO;
4802
4803 // FIXME-DPI: This storage was added on 2021/03/31 for test engine, but if we want to multiply WINDOWS_HOVER_PADDING
4804 // by DpiScale, we need to make this window-agnostic anyhow, maybe need storing inside ImGuiWindow.
4805 g.WindowsHoverPadding = ImMax(g.Style.TouchExtraPadding, ImVec2(WINDOWS_HOVER_PADDING, WINDOWS_HOVER_PADDING));
4806
4807 // Find the window hovered by mouse:
4808 // - Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow.
4809 // - When moving a window we can skip the search, which also conveniently bypasses the fact that window->WindowRectClipped is lagging as this point of the frame.
4810 // - We also support the moved window toggling the NoInputs flag after moving has started in order to be able to detect windows below it, which is useful for e.g. docking mechanisms.
4811 bool clear_hovered_windows = false;
4812 FindHoveredWindowEx(g.IO.MousePos, false, &g.HoveredWindow, &g.HoveredWindowUnderMovingWindow);
4813 IM_ASSERT(g.HoveredWindow == NULL || g.HoveredWindow == g.MovingWindow || g.HoveredWindow->Viewport == g.MouseViewport);
4814 g.HoveredWindowBeforeClear = g.HoveredWindow;
4815
4816 // Modal windows prevents mouse from hovering behind them.
4817 ImGuiWindow* modal_window = GetTopMostPopupModal();
4818 if (modal_window && g.HoveredWindow && !IsWindowWithinBeginStackOf(g.HoveredWindow->RootWindow, modal_window)) // FIXME-MERGE: RootWindowDockTree ?
4819 clear_hovered_windows = true;
4820
4821 // Disabled mouse hovering (we don't currently clear MousePos, we could)
4822 if (io.ConfigFlags & ImGuiConfigFlags_NoMouse)
4823 clear_hovered_windows = true;
4824
4825 // We track click ownership. When clicked outside of a window the click is owned by the application and
4826 // won't report hovering nor request capture even while dragging over our windows afterward.
4827 const bool has_open_popup = (g.OpenPopupStack.Size > 0);
4828 const bool has_open_modal = (modal_window != NULL);
4829 int mouse_earliest_down = -1;
4830 bool mouse_any_down = false;
4831 for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
4832 {
4833 if (io.MouseClicked[i])
4834 {
4835 io.MouseDownOwned[i] = (g.HoveredWindow != NULL) || has_open_popup;
4836 io.MouseDownOwnedUnlessPopupClose[i] = (g.HoveredWindow != NULL) || has_open_modal;
4837 }
4838 mouse_any_down |= io.MouseDown[i];
4839 if (io.MouseDown[i] || io.MouseReleased[i]) // Increase release frame for our evaluation of earliest button (#1392)
4840 if (mouse_earliest_down == -1 || io.MouseClickedTime[i] < io.MouseClickedTime[mouse_earliest_down])
4841 mouse_earliest_down = i;
4842 }
4843 const bool mouse_avail = (mouse_earliest_down == -1) || io.MouseDownOwned[mouse_earliest_down];
4844 const bool mouse_avail_unless_popup_close = (mouse_earliest_down == -1) || io.MouseDownOwnedUnlessPopupClose[mouse_earliest_down];
4845
4846 // If mouse was first clicked outside of ImGui bounds we also cancel out hovering.
4847 // FIXME: For patterns of drag and drop across OS windows, we may need to rework/remove this test (first committed 311c0ca9 on 2015/02)
4848 const bool mouse_dragging_extern_payload = g.DragDropActive && (g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) != 0;
4849 if (!mouse_avail && !mouse_dragging_extern_payload)
4850 clear_hovered_windows = true;
4851
4852 if (clear_hovered_windows)
4853 g.HoveredWindow = g.HoveredWindowUnderMovingWindow = NULL;
4854
4855 // Update io.WantCaptureMouse for the user application (true = dispatch mouse info to Dear ImGui only, false = dispatch mouse to Dear ImGui + underlying app)
4856 // Update io.WantCaptureMouseAllowPopupClose (experimental) to give a chance for app to react to popup closure with a drag
4857 if (g.WantCaptureMouseNextFrame != -1)
4858 {
4859 io.WantCaptureMouse = io.WantCaptureMouseUnlessPopupClose = (g.WantCaptureMouseNextFrame != 0);
4860 }
4861 else
4862 {
4863 io.WantCaptureMouse = (mouse_avail && (g.HoveredWindow != NULL || mouse_any_down)) || has_open_popup;
4864 io.WantCaptureMouseUnlessPopupClose = (mouse_avail_unless_popup_close && (g.HoveredWindow != NULL || mouse_any_down)) || has_open_modal;
4865 }
4866
4867 // Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to Dear ImGui only, false = dispatch keyboard info to Dear ImGui + underlying app)
4868 io.WantCaptureKeyboard = (g.ActiveId != 0) || (modal_window != NULL);
4869 if (io.NavActive && (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && !(io.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard))
4870 io.WantCaptureKeyboard = true;
4871 if (g.WantCaptureKeyboardNextFrame != -1) // Manual override
4872 io.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != 0);
4873
4874 // Update io.WantTextInput flag, this is to allow systems without a keyboard (e.g. mobile, hand-held) to show a software keyboard if possible
4875 io.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false;
4876}
4877
4878// Calling SetupDrawListSharedData() is followed by SetCurrentFont() which sets up the remaining data.
4879static void SetupDrawListSharedData()
4880{
4881 ImGuiContext& g = *GImGui;
4882 ImRect virtual_space(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);
4883 for (ImGuiViewportP* viewport : g.Viewports)
4884 virtual_space.Add(viewport->GetMainRect());
4885 g.DrawListSharedData.ClipRectFullscreen = virtual_space.ToVec4();
4886 g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol;
4887 g.DrawListSharedData.SetCircleTessellationMaxError(g.Style.CircleTessellationMaxError);
4888 g.DrawListSharedData.InitialFlags = ImDrawListFlags_None;
4889 if (g.Style.AntiAliasedLines)
4890 g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLines;
4891 if (g.Style.AntiAliasedLinesUseTex && !(g.IO.Fonts->Flags & ImFontAtlasFlags_NoBakedLines))
4892 g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLinesUseTex;
4893 if (g.Style.AntiAliasedFill)
4894 g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedFill;
4895 if (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset)
4896 g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AllowVtxOffset;
4897}
4898
4899void ImGui::NewFrame()
4900{
4901 IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?");
4902 ImGuiContext& g = *GImGui;
4903
4904 // Remove pending delete hooks before frame start.
4905 // This deferred removal avoid issues of removal while iterating the hook vector
4906 for (int n = g.Hooks.Size - 1; n >= 0; n--)
4907 if (g.Hooks[n].Type == ImGuiContextHookType_PendingRemoval_)
4908 g.Hooks.erase(&g.Hooks[n]);
4909
4910 CallContextHooks(&g, ImGuiContextHookType_NewFramePre);
4911
4912 // Check and assert for various common IO and Configuration mistakes
4913 g.ConfigFlagsLastFrame = g.ConfigFlagsCurrFrame;
4914 ErrorCheckNewFrameSanityChecks();
4915 g.ConfigFlagsCurrFrame = g.IO.ConfigFlags;
4916
4917 // Load settings on first frame, save settings when modified (after a delay)
4918 UpdateSettings();
4919
4920 g.Time += g.IO.DeltaTime;
4921 g.WithinFrameScope = true;
4922 g.FrameCount += 1;
4923 g.TooltipOverrideCount = 0;
4924 g.WindowsActiveCount = 0;
4925 g.MenusIdSubmittedThisFrame.resize(0);
4926
4927 // Calculate frame-rate for the user, as a purely luxurious feature
4928 g.FramerateSecPerFrameAccum += g.IO.DeltaTime - g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx];
4929 g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx] = g.IO.DeltaTime;
4930 g.FramerateSecPerFrameIdx = (g.FramerateSecPerFrameIdx + 1) % IM_ARRAYSIZE(g.FramerateSecPerFrame);
4931 g.FramerateSecPerFrameCount = ImMin(g.FramerateSecPerFrameCount + 1, IM_ARRAYSIZE(g.FramerateSecPerFrame));
4932 g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)g.FramerateSecPerFrameCount)) : FLT_MAX;
4933
4934 // Process input queue (trickle as many events as possible), turn events into writes to IO structure
4935 g.InputEventsTrail.resize(0);
4936 UpdateInputEvents(g.IO.ConfigInputTrickleEventQueue);
4937
4938 // Update viewports (after processing input queue, so io.MouseHoveredViewport is set)
4939 UpdateViewportsNewFrame();
4940
4941 // Setup current font and draw list shared data
4942 // FIXME-VIEWPORT: the concept of a single ClipRectFullscreen is not ideal!
4943 g.IO.Fonts->Locked = true;
4944 SetupDrawListSharedData();
4945 SetCurrentFont(GetDefaultFont());
4946 IM_ASSERT(g.Font->IsLoaded());
4947
4948 // Mark rendering data as invalid to prevent user who may have a handle on it to use it.
4949 for (ImGuiViewportP* viewport : g.Viewports)
4950 {
4951 viewport->DrawData = NULL;
4952 viewport->DrawDataP.Valid = false;
4953 }
4954
4955 // Drag and drop keep the source ID alive so even if the source disappear our state is consistent
4956 if (g.DragDropActive && g.DragDropPayload.SourceId == g.ActiveId)
4957 KeepAliveID(g.DragDropPayload.SourceId);
4958
4959 // Update HoveredId data
4960 if (!g.HoveredIdPreviousFrame)
4961 g.HoveredIdTimer = 0.0f;
4962 if (!g.HoveredIdPreviousFrame || (g.HoveredId && g.ActiveId == g.HoveredId))
4963 g.HoveredIdNotActiveTimer = 0.0f;
4964 if (g.HoveredId)
4965 g.HoveredIdTimer += g.IO.DeltaTime;
4966 if (g.HoveredId && g.ActiveId != g.HoveredId)
4967 g.HoveredIdNotActiveTimer += g.IO.DeltaTime;
4968 g.HoveredIdPreviousFrame = g.HoveredId;
4969 g.HoveredId = 0;
4970 g.HoveredIdAllowOverlap = false;
4971 g.HoveredIdIsDisabled = false;
4972
4973 // Clear ActiveID if the item is not alive anymore.
4974 // In 1.87, the common most call to KeepAliveID() was moved from GetID() to ItemAdd().
4975 // As a result, custom widget using ButtonBehavior() _without_ ItemAdd() need to call KeepAliveID() themselves.
4976 if (g.ActiveId != 0 && g.ActiveIdIsAlive != g.ActiveId && g.ActiveIdPreviousFrame == g.ActiveId)
4977 {
4978 IMGUI_DEBUG_LOG_ACTIVEID("NewFrame(): ClearActiveID() because it isn't marked alive anymore!\n");
4979 ClearActiveID();
4980 }
4981
4982 // Update ActiveId data (clear reference to active widget if the widget isn't alive anymore)
4983 if (g.ActiveId)
4984 g.ActiveIdTimer += g.IO.DeltaTime;
4985 g.LastActiveIdTimer += g.IO.DeltaTime;
4986 g.ActiveIdPreviousFrame = g.ActiveId;
4987 g.ActiveIdPreviousFrameWindow = g.ActiveIdWindow;
4988 g.ActiveIdPreviousFrameHasBeenEditedBefore = g.ActiveIdHasBeenEditedBefore;
4989 g.ActiveIdIsAlive = 0;
4990 g.ActiveIdHasBeenEditedThisFrame = false;
4991 g.ActiveIdPreviousFrameIsAlive = false;
4992 g.ActiveIdIsJustActivated = false;
4993 if (g.TempInputId != 0 && g.ActiveId != g.TempInputId)
4994 g.TempInputId = 0;
4995 if (g.ActiveId == 0)
4996 {
4997 g.ActiveIdUsingNavDirMask = 0x00;
4998 g.ActiveIdUsingAllKeyboardKeys = false;
4999 }
5000
5001 // Record when we have been stationary as this state is preserved while over same item.
5002 // FIXME: The way this is expressed means user cannot alter HoverStationaryDelay during the frame to use varying values.
5003 // To allow this we should store HoverItemMaxStationaryTime+ID and perform the >= check in IsItemHovered() function.
5004 if (g.HoverItemDelayId != 0 && g.MouseStationaryTimer >= g.Style.HoverStationaryDelay)
5005 g.HoverItemUnlockedStationaryId = g.HoverItemDelayId;
5006 else if (g.HoverItemDelayId == 0)
5007 g.HoverItemUnlockedStationaryId = 0;
5008 if (g.HoveredWindow != NULL && g.MouseStationaryTimer >= g.Style.HoverStationaryDelay)
5009 g.HoverWindowUnlockedStationaryId = g.HoveredWindow->ID;
5010 else if (g.HoveredWindow == NULL)
5011 g.HoverWindowUnlockedStationaryId = 0;
5012
5013 // Update hover delay for IsItemHovered() with delays and tooltips
5014 g.HoverItemDelayIdPreviousFrame = g.HoverItemDelayId;
5015 if (g.HoverItemDelayId != 0)
5016 {
5017 g.HoverItemDelayTimer += g.IO.DeltaTime;
5018 g.HoverItemDelayClearTimer = 0.0f;
5019 g.HoverItemDelayId = 0;
5020 }
5021 else if (g.HoverItemDelayTimer > 0.0f)
5022 {
5023 // This gives a little bit of leeway before clearing the hover timer, allowing mouse to cross gaps
5024 // We could expose 0.25f as style.HoverClearDelay but I am not sure of the logic yet, this is particularly subtle.
5025 g.HoverItemDelayClearTimer += g.IO.DeltaTime;
5026 if (g.HoverItemDelayClearTimer >= ImMax(0.25f, g.IO.DeltaTime * 2.0f)) // ~7 frames at 30 Hz + allow for low framerate
5027 g.HoverItemDelayTimer = g.HoverItemDelayClearTimer = 0.0f; // May want a decaying timer, in which case need to clamp at max first, based on max of caller last requested timer.
5028 }
5029
5030 // Drag and drop
5031 g.DragDropAcceptIdPrev = g.DragDropAcceptIdCurr;
5032 g.DragDropAcceptIdCurr = 0;
5033 g.DragDropAcceptIdCurrRectSurface = FLT_MAX;
5034 g.DragDropWithinSource = false;
5035 g.DragDropWithinTarget = false;
5036 g.DragDropHoldJustPressedId = 0;
5037
5038 // Close popups on focus lost (currently wip/opt-in)
5039 //if (g.IO.AppFocusLost)
5040 // ClosePopupsExceptModals();
5041
5042 // Update keyboard input state
5043 UpdateKeyboardInputs();
5044
5045 //IM_ASSERT(g.IO.KeyCtrl == IsKeyDown(ImGuiKey_LeftCtrl) || IsKeyDown(ImGuiKey_RightCtrl));
5046 //IM_ASSERT(g.IO.KeyShift == IsKeyDown(ImGuiKey_LeftShift) || IsKeyDown(ImGuiKey_RightShift));
5047 //IM_ASSERT(g.IO.KeyAlt == IsKeyDown(ImGuiKey_LeftAlt) || IsKeyDown(ImGuiKey_RightAlt));
5048 //IM_ASSERT(g.IO.KeySuper == IsKeyDown(ImGuiKey_LeftSuper) || IsKeyDown(ImGuiKey_RightSuper));
5049
5050 // Update gamepad/keyboard navigation
5051 NavUpdate();
5052
5053 // Update mouse input state
5054 UpdateMouseInputs();
5055
5056 // Undocking
5057 // (needs to be before UpdateMouseMovingWindowNewFrame so the window is already offset and following the mouse on the detaching frame)
5058 DockContextNewFrameUpdateUndocking(&g);
5059
5060 // Find hovered window
5061 // (needs to be before UpdateMouseMovingWindowNewFrame so we fill g.HoveredWindowUnderMovingWindow on the mouse release frame)
5062 UpdateHoveredWindowAndCaptureFlags();
5063
5064 // Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering)
5065 UpdateMouseMovingWindowNewFrame();
5066
5067 // Background darkening/whitening
5068 if (GetTopMostPopupModal() != NULL || (g.NavWindowingTarget != NULL && g.NavWindowingHighlightAlpha > 0.0f))
5069 g.DimBgRatio = ImMin(g.DimBgRatio + g.IO.DeltaTime * 6.0f, 1.0f);
5070 else
5071 g.DimBgRatio = ImMax(g.DimBgRatio - g.IO.DeltaTime * 10.0f, 0.0f);
5072
5073 g.MouseCursor = ImGuiMouseCursor_Arrow;
5074 g.WantCaptureMouseNextFrame = g.WantCaptureKeyboardNextFrame = g.WantTextInputNextFrame = -1;
5075
5076 // Platform IME data: reset for the frame
5077 g.PlatformImeDataPrev = g.PlatformImeData;
5078 g.PlatformImeData.WantVisible = false;
5079
5080 // Mouse wheel scrolling, scale
5081 UpdateMouseWheel();
5082
5083 // Mark all windows as not visible and compact unused memory.
5084 IM_ASSERT(g.WindowsFocusOrder.Size <= g.Windows.Size);
5085 const float memory_compact_start_time = (g.GcCompactAll || g.IO.ConfigMemoryCompactTimer < 0.0f) ? FLT_MAX : (float)g.Time - g.IO.ConfigMemoryCompactTimer;
5086 for (ImGuiWindow* window : g.Windows)
5087 {
5088 window->WasActive = window->Active;
5089 window->Active = false;
5090 window->WriteAccessed = false;
5091 window->BeginCountPreviousFrame = window->BeginCount;
5092 window->BeginCount = 0;
5093
5094 // Garbage collect transient buffers of recently unused windows
5095 if (!window->WasActive && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time)
5096 GcCompactTransientWindowBuffers(window);
5097 }
5098
5099 // Garbage collect transient buffers of recently unused tables
5100 for (int i = 0; i < g.TablesLastTimeActive.Size; i++)
5101 if (g.TablesLastTimeActive[i] >= 0.0f && g.TablesLastTimeActive[i] < memory_compact_start_time)
5102 TableGcCompactTransientBuffers(g.Tables.GetByIndex(i));
5103 for (ImGuiTableTempData& table_temp_data : g.TablesTempData)
5104 if (table_temp_data.LastTimeActive >= 0.0f && table_temp_data.LastTimeActive < memory_compact_start_time)
5105 TableGcCompactTransientBuffers(&table_temp_data);
5106 if (g.GcCompactAll)
5107 GcCompactTransientMiscBuffers();
5108 g.GcCompactAll = false;
5109
5110 // Closing the focused window restore focus to the first active root window in descending z-order
5111 if (g.NavWindow && !g.NavWindow->WasActive)
5112 FocusTopMostWindowUnderOne(NULL, NULL, NULL, ImGuiFocusRequestFlags_RestoreFocusedChild);
5113
5114 // No window should be open at the beginning of the frame.
5115 // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear.
5116 g.CurrentWindowStack.resize(0);
5117 g.BeginPopupStack.resize(0);
5118 g.ItemFlagsStack.resize(0);
5119 g.ItemFlagsStack.push_back(ImGuiItemFlags_AutoClosePopups); // Default flags
5120 g.CurrentItemFlags = g.ItemFlagsStack.back();
5121 g.GroupStack.resize(0);
5122
5123 // Docking
5124 DockContextNewFrameUpdateDocking(&g);
5125
5126 // [DEBUG] Update debug features
5127#ifndef IMGUI_DISABLE_DEBUG_TOOLS
5128 UpdateDebugToolItemPicker();
5129 UpdateDebugToolStackQueries();
5130 UpdateDebugToolFlashStyleColor();
5131 if (g.DebugLocateFrames > 0 && --g.DebugLocateFrames == 0)
5132 {
5133 g.DebugLocateId = 0;
5134 g.DebugBreakInLocateId = false;
5135 }
5136 if (g.DebugLogAutoDisableFrames > 0 && --g.DebugLogAutoDisableFrames == 0)
5137 {
5138 DebugLog("(Debug Log: Auto-disabled some ImGuiDebugLogFlags after 2 frames)\n");
5139 g.DebugLogFlags &= ~g.DebugLogAutoDisableFlags;
5140 g.DebugLogAutoDisableFlags = ImGuiDebugLogFlags_None;
5141 }
5142#endif
5143
5144 // Create implicit/fallback window - which we will only render it if the user has added something to it.
5145 // We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags.
5146 // This fallback is particularly important as it prevents ImGui:: calls from crashing.
5147 g.WithinFrameScopeWithImplicitWindow = true;
5148 SetNextWindowSize(ImVec2(400, 400), ImGuiCond_FirstUseEver);
5149 Begin("Debug##Default");
5150 IM_ASSERT(g.CurrentWindow->IsFallbackWindow == true);
5151
5152 // [DEBUG] When io.ConfigDebugBeginReturnValue is set, we make Begin()/BeginChild() return false at different level of the window-stack,
5153 // allowing to validate correct Begin/End behavior in user code.
5154#ifndef IMGUI_DISABLE_DEBUG_TOOLS
5155 if (g.IO.ConfigDebugBeginReturnValueLoop)
5156 g.DebugBeginReturnValueCullDepth = (g.DebugBeginReturnValueCullDepth == -1) ? 0 : ((g.DebugBeginReturnValueCullDepth + ((g.FrameCount % 4) == 0 ? 1 : 0)) % 10);
5157 else
5158 g.DebugBeginReturnValueCullDepth = -1;
5159#endif
5160
5161 CallContextHooks(&g, ImGuiContextHookType_NewFramePost);
5162}
5163
5164// FIXME: Add a more explicit sort order in the window structure.
5165static int IMGUI_CDECL ChildWindowComparer(const void* lhs, const void* rhs)
5166{
5167 const ImGuiWindow* const a = *(const ImGuiWindow* const *)lhs;
5168 const ImGuiWindow* const b = *(const ImGuiWindow* const *)rhs;
5169 if (int d = (a->Flags & ImGuiWindowFlags_Popup) - (b->Flags & ImGuiWindowFlags_Popup))
5170 return d;
5171 if (int d = (a->Flags & ImGuiWindowFlags_Tooltip) - (b->Flags & ImGuiWindowFlags_Tooltip))
5172 return d;
5173 return (a->BeginOrderWithinParent - b->BeginOrderWithinParent);
5174}
5175
5176static void AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window)
5177{
5178 out_sorted_windows->push_back(window);
5179 if (window->Active)
5180 {
5181 int count = window->DC.ChildWindows.Size;
5182 ImQsort(window->DC.ChildWindows.Data, (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer);
5183 for (int i = 0; i < count; i++)
5184 {
5185 ImGuiWindow* child = window->DC.ChildWindows[i];
5186 if (child->Active)
5187 AddWindowToSortBuffer(out_sorted_windows, child);
5188 }
5189 }
5190}
5191
5192static void AddWindowToDrawData(ImGuiWindow* window, int layer)
5193{
5194 ImGuiContext& g = *GImGui;
5195 ImGuiViewportP* viewport = window->Viewport;
5196 IM_ASSERT(viewport != NULL);
5197 g.IO.MetricsRenderWindows++;
5198 if (window->DrawList->_Splitter._Count > 1)
5199 window->DrawList->ChannelsMerge(); // Merge if user forgot to merge back. Also required in Docking branch for ImGuiWindowFlags_DockNodeHost windows.
5200 ImGui::AddDrawListToDrawDataEx(&viewport->DrawDataP, viewport->DrawDataBuilder.Layers[layer], window->DrawList);
5201 for (ImGuiWindow* child : window->DC.ChildWindows)
5202 if (IsWindowActiveAndVisible(child)) // Clipped children may have been marked not active
5203 AddWindowToDrawData(child, layer);
5204}
5205
5206static inline int GetWindowDisplayLayer(ImGuiWindow* window)
5207{
5208 return (window->Flags & ImGuiWindowFlags_Tooltip) ? 1 : 0;
5209}
5210
5211// Layer is locked for the root window, however child windows may use a different viewport (e.g. extruding menu)
5212static inline void AddRootWindowToDrawData(ImGuiWindow* window)
5213{
5214 AddWindowToDrawData(window, GetWindowDisplayLayer(window));
5215}
5216
5217static void FlattenDrawDataIntoSingleLayer(ImDrawDataBuilder* builder)
5218{
5219 int n = builder->Layers[0]->Size;
5220 int full_size = n;
5221 for (int i = 1; i < IM_ARRAYSIZE(builder->Layers); i++)
5222 full_size += builder->Layers[i]->Size;
5223 builder->Layers[0]->resize(full_size);
5224 for (int layer_n = 1; layer_n < IM_ARRAYSIZE(builder->Layers); layer_n++)
5225 {
5226 ImVector<ImDrawList*>* layer = builder->Layers[layer_n];
5227 if (layer->empty())
5228 continue;
5229 memcpy(builder->Layers[0]->Data + n, layer->Data, layer->Size * sizeof(ImDrawList*));
5230 n += layer->Size;
5231 layer->resize(0);
5232 }
5233}
5234
5235static void InitViewportDrawData(ImGuiViewportP* viewport)
5236{
5237 ImGuiIO& io = ImGui::GetIO();
5238 ImDrawData* draw_data = &viewport->DrawDataP;
5239
5240 viewport->DrawData = draw_data; // Make publicly accessible
5241 viewport->DrawDataBuilder.Layers[0] = &draw_data->CmdLists;
5242 viewport->DrawDataBuilder.Layers[1] = &viewport->DrawDataBuilder.LayerData1;
5243 viewport->DrawDataBuilder.Layers[0]->resize(0);
5244 viewport->DrawDataBuilder.Layers[1]->resize(0);
5245
5246 // When minimized, we report draw_data->DisplaySize as zero to be consistent with non-viewport mode,
5247 // and to allow applications/backends to easily skip rendering.
5248 // FIXME: Note that we however do NOT attempt to report "zero drawlist / vertices" into the ImDrawData structure.
5249 // This is because the work has been done already, and its wasted! We should fix that and add optimizations for
5250 // it earlier in the pipeline, rather than pretend to hide the data at the end of the pipeline.
5251 const bool is_minimized = (viewport->Flags & ImGuiViewportFlags_IsMinimized) != 0;
5252
5253 draw_data->Valid = true;
5254 draw_data->CmdListsCount = 0;
5255 draw_data->TotalVtxCount = draw_data->TotalIdxCount = 0;
5256 draw_data->DisplayPos = viewport->Pos;
5257 draw_data->DisplaySize = is_minimized ? ImVec2(0.0f, 0.0f) : viewport->Size;
5258 draw_data->FramebufferScale = io.DisplayFramebufferScale; // FIXME-VIEWPORT: This may vary on a per-monitor/viewport basis?
5259 draw_data->OwnerViewport = viewport;
5260}
5261
5262// Push a clipping rectangle for both ImGui logic (hit-testing etc.) and low-level ImDrawList rendering.
5263// - When using this function it is sane to ensure that float are perfectly rounded to integer values,
5264// so that e.g. (int)(max.x-min.x) in user's render produce correct result.
5265// - If the code here changes, may need to update code of functions like NextColumn() and PushColumnClipRect():
5266// some frequently called functions which to modify both channels and clipping simultaneously tend to use the
5267// more specialized SetWindowClipRectBeforeSetChannel() to avoid extraneous updates of underlying ImDrawCmds.
5268void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect)
5269{
5270 ImGuiWindow* window = GetCurrentWindow();
5271 window->DrawList->PushClipRect(clip_rect_min, clip_rect_max, intersect_with_current_clip_rect);
5272 window->ClipRect = window->DrawList->_ClipRectStack.back();
5273}
5274
5275void ImGui::PopClipRect()
5276{
5277 ImGuiWindow* window = GetCurrentWindow();
5278 window->DrawList->PopClipRect();
5279 window->ClipRect = window->DrawList->_ClipRectStack.back();
5280}
5281
5282static ImGuiWindow* FindFrontMostVisibleChildWindow(ImGuiWindow* window)
5283{
5284 for (int n = window->DC.ChildWindows.Size - 1; n >= 0; n--)
5285 if (IsWindowActiveAndVisible(window->DC.ChildWindows[n]))
5286 return FindFrontMostVisibleChildWindow(window->DC.ChildWindows[n]);
5287 return window;
5288}
5289
5290static void ImGui::RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 col)
5291{
5292 if ((col & IM_COL32_A_MASK) == 0)
5293 return;
5294
5295 ImGuiViewportP* viewport = window->Viewport;
5296 ImRect viewport_rect = viewport->GetMainRect();
5297
5298 // Draw behind window by moving the draw command at the FRONT of the draw list
5299 {
5300 // Draw list have been trimmed already, hence the explicit recreation of a draw command if missing.
5301 // FIXME: This is creating complication, might be simpler if we could inject a drawlist in drawdata at a given position and not attempt to manipulate ImDrawCmd order.
5302 ImDrawList* draw_list = window->RootWindowDockTree->DrawList;
5303 draw_list->ChannelsMerge();
5304 if (draw_list->CmdBuffer.Size == 0)
5305 draw_list->AddDrawCmd();
5306 draw_list->PushClipRect(viewport_rect.Min - ImVec2(1, 1), viewport_rect.Max + ImVec2(1, 1), false); // FIXME: Need to stricty ensure ImDrawCmd are not merged (ElemCount==6 checks below will verify that)
5307 draw_list->AddRectFilled(viewport_rect.Min, viewport_rect.Max, col);
5308 ImDrawCmd cmd = draw_list->CmdBuffer.back();
5309 IM_ASSERT(cmd.ElemCount == 6);
5310 draw_list->CmdBuffer.pop_back();
5311 draw_list->CmdBuffer.push_front(cmd);
5312 draw_list->AddDrawCmd(); // We need to create a command as CmdBuffer.back().IdxOffset won't be correct if we append to same command.
5313 draw_list->PopClipRect();
5314 }
5315
5316 // Draw over sibling docking nodes in a same docking tree
5317 if (window->RootWindow->DockIsActive)
5318 {
5319 ImDrawList* draw_list = FindFrontMostVisibleChildWindow(window->RootWindowDockTree)->DrawList;
5320 draw_list->ChannelsMerge();
5321 if (draw_list->CmdBuffer.Size == 0)
5322 draw_list->AddDrawCmd();
5323 draw_list->PushClipRect(viewport_rect.Min, viewport_rect.Max, false);
5324 RenderRectFilledWithHole(draw_list, window->RootWindowDockTree->Rect(), window->RootWindow->Rect(), col, 0.0f);// window->RootWindowDockTree->WindowRounding);
5325 draw_list->PopClipRect();
5326 }
5327}
5328
5329ImGuiWindow* ImGui::FindBottomMostVisibleWindowWithinBeginStack(ImGuiWindow* parent_window)
5330{
5331 ImGuiContext& g = *GImGui;
5332 ImGuiWindow* bottom_most_visible_window = parent_window;
5333 for (int i = FindWindowDisplayIndex(parent_window); i >= 0; i--)
5334 {
5335 ImGuiWindow* window = g.Windows[i];
5336 if (window->Flags & ImGuiWindowFlags_ChildWindow)
5337 continue;
5338 if (!IsWindowWithinBeginStackOf(window, parent_window))
5339 break;
5340 if (IsWindowActiveAndVisible(window) && GetWindowDisplayLayer(window) <= GetWindowDisplayLayer(parent_window))
5341 bottom_most_visible_window = window;
5342 }
5343 return bottom_most_visible_window;
5344}
5345
5346// Important: AddWindowToDrawData() has not been called yet, meaning DockNodeHost windows needs a DrawList->ChannelsMerge() before usage.
5347// We call ChannelsMerge() lazily here at it is faster that doing a full iteration of g.Windows[] prior to calling RenderDimmedBackgrounds().
5348static void ImGui::RenderDimmedBackgrounds()
5349{
5350 ImGuiContext& g = *GImGui;
5351 ImGuiWindow* modal_window = GetTopMostAndVisiblePopupModal();
5352 if (g.DimBgRatio <= 0.0f && g.NavWindowingHighlightAlpha <= 0.0f)
5353 return;
5354 const bool dim_bg_for_modal = (modal_window != NULL);
5355 const bool dim_bg_for_window_list = (g.NavWindowingTargetAnim != NULL && g.NavWindowingTargetAnim->Active);
5356 if (!dim_bg_for_modal && !dim_bg_for_window_list)
5357 return;
5358
5359 ImGuiViewport* viewports_already_dimmed[2] = { NULL, NULL };
5360 if (dim_bg_for_modal)
5361 {
5362 // Draw dimming behind modal or a begin stack child, whichever comes first in draw order.
5363 ImGuiWindow* dim_behind_window = FindBottomMostVisibleWindowWithinBeginStack(modal_window);
5364 RenderDimmedBackgroundBehindWindow(dim_behind_window, GetColorU32(modal_window->DC.ModalDimBgColor, g.DimBgRatio));
5365 viewports_already_dimmed[0] = modal_window->Viewport;
5366 }
5367 else if (dim_bg_for_window_list)
5368 {
5369 // Draw dimming behind CTRL+Tab target window and behind CTRL+Tab UI window
5370 RenderDimmedBackgroundBehindWindow(g.NavWindowingTargetAnim, GetColorU32(ImGuiCol_NavWindowingDimBg, g.DimBgRatio));
5371 if (g.NavWindowingListWindow != NULL && g.NavWindowingListWindow->Viewport && g.NavWindowingListWindow->Viewport != g.NavWindowingTargetAnim->Viewport)
5372 RenderDimmedBackgroundBehindWindow(g.NavWindowingListWindow, GetColorU32(ImGuiCol_NavWindowingDimBg, g.DimBgRatio));
5373 viewports_already_dimmed[0] = g.NavWindowingTargetAnim->Viewport;
5374 viewports_already_dimmed[1] = g.NavWindowingListWindow ? g.NavWindowingListWindow->Viewport : NULL;
5375
5376 // Draw border around CTRL+Tab target window
5377 ImGuiWindow* window = g.NavWindowingTargetAnim;
5378 ImGuiViewport* viewport = window->Viewport;
5379 float distance = g.FontSize;
5380 ImRect bb = window->Rect();
5381 bb.Expand(distance);
5382 if (bb.GetWidth() >= viewport->Size.x && bb.GetHeight() >= viewport->Size.y)
5383 bb.Expand(-distance - 1.0f); // If a window fits the entire viewport, adjust its highlight inward
5384 window->DrawList->ChannelsMerge();
5385 if (window->DrawList->CmdBuffer.Size == 0)
5386 window->DrawList->AddDrawCmd();
5387 window->DrawList->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size);
5388 window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), window->WindowRounding, 0, 3.0f);
5389 window->DrawList->PopClipRect();
5390 }
5391
5392 // Draw dimming background on _other_ viewports than the ones our windows are in
5393 for (ImGuiViewportP* viewport : g.Viewports)
5394 {
5395 if (viewport == viewports_already_dimmed[0] || viewport == viewports_already_dimmed[1])
5396 continue;
5397 if (modal_window && viewport->Window && IsWindowAbove(viewport->Window, modal_window))
5398 continue;
5399 ImDrawList* draw_list = GetForegroundDrawList(viewport);
5400 const ImU32 dim_bg_col = GetColorU32(dim_bg_for_modal ? ImGuiCol_ModalWindowDimBg : ImGuiCol_NavWindowingDimBg, g.DimBgRatio);
5401 draw_list->AddRectFilled(viewport->Pos, viewport->Pos + viewport->Size, dim_bg_col);
5402 }
5403}
5404
5405// 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.
5406void ImGui::EndFrame()
5407{
5408 ImGuiContext& g = *GImGui;
5409 IM_ASSERT(g.Initialized);
5410
5411 // Don't process EndFrame() multiple times.
5412 if (g.FrameCountEnded == g.FrameCount)
5413 return;
5414 IM_ASSERT(g.WithinFrameScope && "Forgot to call ImGui::NewFrame()?");
5415
5416 CallContextHooks(&g, ImGuiContextHookType_EndFramePre);
5417
5418 ErrorCheckEndFrameSanityChecks();
5419
5420 // Notify Platform/OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME)
5421 ImGuiPlatformIme