1bf215546Sopenharmony_ci// dear imgui, v1.68 WIP 2bf215546Sopenharmony_ci// (main code and documentation) 3bf215546Sopenharmony_ci 4bf215546Sopenharmony_ci// Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp for demo code. 5bf215546Sopenharmony_ci// Newcomers, read 'Programmer guide' below for notes on how to setup Dear ImGui in your codebase. 6bf215546Sopenharmony_ci// Get latest version at https://github.com/ocornut/imgui 7bf215546Sopenharmony_ci// Releases change-log at https://github.com/ocornut/imgui/releases 8bf215546Sopenharmony_ci// Technical Support for Getting Started https://discourse.dearimgui.org/c/getting-started 9bf215546Sopenharmony_ci// Gallery (please post your screenshots/video there!): https://github.com/ocornut/imgui/issues/1269 10bf215546Sopenharmony_ci 11bf215546Sopenharmony_ci// Developed by Omar Cornut and every direct or indirect contributors to the GitHub. 12bf215546Sopenharmony_ci// See LICENSE.txt for copyright and licensing details (standard MIT License). 13bf215546Sopenharmony_ci// This library is free but I need your support to sustain development and maintenance. 14bf215546Sopenharmony_ci// Businesses: you can support continued maintenance and development via support contracts or sponsoring, see docs/README. 15bf215546Sopenharmony_ci// Individuals: you can support continued maintenance and development via donations or Patreon https://www.patreon.com/imgui. 16bf215546Sopenharmony_ci 17bf215546Sopenharmony_ci// It is recommended that you don't modify imgui.cpp! It will become difficult for you to update the library. 18bf215546Sopenharmony_ci// Note that 'ImGui::' being a namespace, you can add functions into the namespace from your own source files, without 19bf215546Sopenharmony_ci// modifying imgui.h or imgui.cpp. You may include imgui_internal.h to access internal data structures, but it doesn't 20bf215546Sopenharmony_ci// come with any guarantee of forward compatibility. Discussing your changes on the GitHub Issue Tracker may lead you 21bf215546Sopenharmony_ci// to a better solution or official support for them. 22bf215546Sopenharmony_ci 23bf215546Sopenharmony_ci/* 24bf215546Sopenharmony_ci 25bf215546Sopenharmony_ciIndex of this file: 26bf215546Sopenharmony_ci 27bf215546Sopenharmony_ciDOCUMENTATION 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_ci- MISSION STATEMENT 30bf215546Sopenharmony_ci- END-USER GUIDE 31bf215546Sopenharmony_ci- PROGRAMMER GUIDE (read me!) 32bf215546Sopenharmony_ci - Read first. 33bf215546Sopenharmony_ci - How to update to a newer version of Dear ImGui. 34bf215546Sopenharmony_ci - Getting started with integrating Dear ImGui in your code/engine. 35bf215546Sopenharmony_ci - This is how a simple application may look like (2 variations). 36bf215546Sopenharmony_ci - This is how a simple rendering function may look like. 37bf215546Sopenharmony_ci - Using gamepad/keyboard navigation controls. 38bf215546Sopenharmony_ci- API BREAKING CHANGES (read me when you update!) 39bf215546Sopenharmony_ci- FREQUENTLY ASKED QUESTIONS (FAQ), TIPS 40bf215546Sopenharmony_ci - How can I tell whether to dispatch mouse/keyboard to imgui or to my application? 41bf215546Sopenharmony_ci - How can I display an image? What is ImTextureID, how does it works? 42bf215546Sopenharmony_ci - How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack. 43bf215546Sopenharmony_ci - How can I use my own math types instead of ImVec2/ImVec4? 44bf215546Sopenharmony_ci - How can I load a different font than the default? 45bf215546Sopenharmony_ci - How can I easily use icons in my application? 46bf215546Sopenharmony_ci - How can I load multiple fonts? 47bf215546Sopenharmony_ci - How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic? 48bf215546Sopenharmony_ci - How can I interact with standard C++ types (such as std::string and std::vector)? 49bf215546Sopenharmony_ci - How can I use the drawing facilities without an ImGui window? (using ImDrawList API) 50bf215546Sopenharmony_ci - How can I use Dear ImGui on a platform that doesn't have a mouse or a keyboard? (input share, remoting, gamepad) 51bf215546Sopenharmony_ci - I integrated Dear ImGui in my engine and the text or lines are blurry.. 52bf215546Sopenharmony_ci - I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around.. 53bf215546Sopenharmony_ci - How can I help? 54bf215546Sopenharmony_ci 55bf215546Sopenharmony_ciCODE 56bf215546Sopenharmony_ci(search for "[SECTION]" in the code to find them) 57bf215546Sopenharmony_ci 58bf215546Sopenharmony_ci// [SECTION] FORWARD DECLARATIONS 59bf215546Sopenharmony_ci// [SECTION] CONTEXT AND MEMORY ALLOCATORS 60bf215546Sopenharmony_ci// [SECTION] MAIN USER FACING STRUCTURES (ImGuiStyle, ImGuiIO) 61bf215546Sopenharmony_ci// [SECTION] MISC HELPER/UTILITIES (Maths, String, Format, Hash, File functions) 62bf215546Sopenharmony_ci// [SECTION] MISC HELPER/UTILITIES (ImText* functions) 63bf215546Sopenharmony_ci// [SECTION] MISC HELPER/UTILITIES (Color functions) 64bf215546Sopenharmony_ci// [SECTION] ImGuiStorage 65bf215546Sopenharmony_ci// [SECTION] ImGuiTextFilter 66bf215546Sopenharmony_ci// [SECTION] ImGuiTextBuffer 67bf215546Sopenharmony_ci// [SECTION] ImGuiListClipper 68bf215546Sopenharmony_ci// [SECTION] RENDER HELPERS 69bf215546Sopenharmony_ci// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!) 70bf215546Sopenharmony_ci// [SECTION] TOOLTIPS 71bf215546Sopenharmony_ci// [SECTION] POPUPS 72bf215546Sopenharmony_ci// [SECTION] KEYBOARD/GAMEPAD NAVIGATION 73bf215546Sopenharmony_ci// [SECTION] COLUMNS 74bf215546Sopenharmony_ci// [SECTION] DRAG AND DROP 75bf215546Sopenharmony_ci// [SECTION] LOGGING/CAPTURING 76bf215546Sopenharmony_ci// [SECTION] SETTINGS 77bf215546Sopenharmony_ci// [SECTION] PLATFORM DEPENDENT HELPERS 78bf215546Sopenharmony_ci// [SECTION] METRICS/DEBUG WINDOW 79bf215546Sopenharmony_ci 80bf215546Sopenharmony_ci*/ 81bf215546Sopenharmony_ci 82bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 83bf215546Sopenharmony_ci// DOCUMENTATION 84bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 85bf215546Sopenharmony_ci 86bf215546Sopenharmony_ci/* 87bf215546Sopenharmony_ci 88bf215546Sopenharmony_ci MISSION STATEMENT 89bf215546Sopenharmony_ci ================= 90bf215546Sopenharmony_ci 91bf215546Sopenharmony_ci - Easy to use to create code-driven and data-driven tools. 92bf215546Sopenharmony_ci - Easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools. 93bf215546Sopenharmony_ci - Easy to hack and improve. 94bf215546Sopenharmony_ci - Minimize screen real-estate usage. 95bf215546Sopenharmony_ci - Minimize setup and maintenance. 96bf215546Sopenharmony_ci - Minimize state storage on user side. 97bf215546Sopenharmony_ci - Portable, minimize dependencies, run on target (consoles, phones, etc.). 98bf215546Sopenharmony_ci - Efficient runtime and memory consumption (NB- we do allocate when "growing" content e.g. creating a window,. 99bf215546Sopenharmony_ci opening a tree node for the first time, etc. but a typical frame should not allocate anything). 100bf215546Sopenharmony_ci 101bf215546Sopenharmony_ci Designed for developers and content-creators, not the typical end-user! Some of the weaknesses includes: 102bf215546Sopenharmony_ci - Doesn't look fancy, doesn't animate. 103bf215546Sopenharmony_ci - Limited layout features, intricate layouts are typically crafted in code. 104bf215546Sopenharmony_ci 105bf215546Sopenharmony_ci 106bf215546Sopenharmony_ci END-USER GUIDE 107bf215546Sopenharmony_ci ============== 108bf215546Sopenharmony_ci 109bf215546Sopenharmony_ci - Double-click on title bar to collapse window. 110bf215546Sopenharmony_ci - Click upper right corner to close a window, available when 'bool* p_open' is passed to ImGui::Begin(). 111bf215546Sopenharmony_ci - Click and drag on lower right corner to resize window (double-click to auto fit window to its contents). 112bf215546Sopenharmony_ci - Click and drag on any empty space to move window. 113bf215546Sopenharmony_ci - TAB/SHIFT+TAB to cycle through keyboard editable fields. 114bf215546Sopenharmony_ci - CTRL+Click on a slider or drag box to input value as text. 115bf215546Sopenharmony_ci - Use mouse wheel to scroll. 116bf215546Sopenharmony_ci - Text editor: 117bf215546Sopenharmony_ci - Hold SHIFT or use mouse to select text. 118bf215546Sopenharmony_ci - CTRL+Left/Right to word jump. 119bf215546Sopenharmony_ci - CTRL+Shift+Left/Right to select words. 120bf215546Sopenharmony_ci - CTRL+A our Double-Click to select all. 121bf215546Sopenharmony_ci - CTRL+X,CTRL+C,CTRL+V to use OS clipboard/ 122bf215546Sopenharmony_ci - CTRL+Z,CTRL+Y to undo/redo. 123bf215546Sopenharmony_ci - ESCAPE to revert text to its original value. 124bf215546Sopenharmony_ci - You can apply arithmetic operators +,*,/ on numerical values. Use +- to subtract (because - would set a negative value!) 125bf215546Sopenharmony_ci - Controls are automatically adjusted for OSX to match standard OSX text editing operations. 126bf215546Sopenharmony_ci - General Keyboard controls: enable with ImGuiConfigFlags_NavEnableKeyboard. 127bf215546Sopenharmony_ci - General Gamepad controls: enable with ImGuiConfigFlags_NavEnableGamepad. See suggested mappings in imgui.h ImGuiNavInput_ + download PNG/PSD at http://goo.gl/9LgVZW 128bf215546Sopenharmony_ci 129bf215546Sopenharmony_ci 130bf215546Sopenharmony_ci PROGRAMMER GUIDE 131bf215546Sopenharmony_ci ================ 132bf215546Sopenharmony_ci 133bf215546Sopenharmony_ci READ FIRST: 134bf215546Sopenharmony_ci 135bf215546Sopenharmony_ci - Read the FAQ below this section! 136bf215546Sopenharmony_ci - Your code creates the UI, if your code doesn't run the UI is gone! The UI can be highly dynamic, there are no construction 137bf215546Sopenharmony_ci or destruction steps, less superfluous data retention on your side, less state duplication, less state synchronization, less bugs. 138bf215546Sopenharmony_ci - Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features. 139bf215546Sopenharmony_ci - The library is designed to be built from sources. Avoid pre-compiled binaries and packaged versions. See imconfig.h to configure your build. 140bf215546Sopenharmony_ci - Dear ImGui is an implementation of the IMGUI paradigm (immediate-mode graphical user interface, a term coined by Casey Muratori). 141bf215546Sopenharmony_ci You can learn about IMGUI principles at http://www.johno.se/book/imgui.html, http://mollyrocket.com/861 & more links docs/README.md. 142bf215546Sopenharmony_ci - Dear ImGui is a "single pass" rasterizing implementation of the IMGUI paradigm, aimed at ease of use and high-performances. 143bf215546Sopenharmony_ci For every application frame your UI code will be called only once. This is in contrast to e.g. Unity's own implementation of an IMGUI, 144bf215546Sopenharmony_ci where the UI code is called multiple times ("multiple passes") from a single entry point. There are pros and cons to both approaches. 145bf215546Sopenharmony_ci - Our origin are on the top-left. In axis aligned bounding boxes, Min = top-left, Max = bottom-right. 146bf215546Sopenharmony_ci - This codebase is also optimized to yield decent performances with typical "Debug" builds settings. 147bf215546Sopenharmony_ci - Please make sure you have asserts enabled (IM_ASSERT redirects to assert() by default, but can be redirected). 148bf215546Sopenharmony_ci If you get an assert, read the messages and comments around the assert. 149bf215546Sopenharmony_ci - C++: this is a very C-ish codebase: we don't rely on C++11, we don't include any C++ headers, and ImGui:: is a namespace. 150bf215546Sopenharmony_ci - C++: ImVec2/ImVec4 do not expose math operators by default, because it is expected that you use your own math types. 151bf215546Sopenharmony_ci See FAQ "How can I use my own math types instead of ImVec2/ImVec4?" for details about setting up imconfig.h for that. 152bf215546Sopenharmony_ci However, imgui_internal.h can optionally export math operators for ImVec2/ImVec4, which we use in this codebase. 153bf215546Sopenharmony_ci - C++: pay attention that ImVector<> manipulates plain-old-data and does not honor construction/destruction (avoid using it in your code!). 154bf215546Sopenharmony_ci 155bf215546Sopenharmony_ci HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI: 156bf215546Sopenharmony_ci 157bf215546Sopenharmony_ci - Overwrite all the sources files except for imconfig.h (if you have made modification to your copy of imconfig.h) 158bf215546Sopenharmony_ci - Or maintain your own branch where you have imconfig.h modified. 159bf215546Sopenharmony_ci - Read the "API BREAKING CHANGES" section (below). This is where we list occasional API breaking changes. 160bf215546Sopenharmony_ci If a function/type has been renamed / or marked obsolete, try to fix the name in your code before it is permanently removed 161bf215546Sopenharmony_ci from the public API. If you have a problem with a missing function/symbols, search for its name in the code, there will 162bf215546Sopenharmony_ci likely be a comment about it. Please report any issue to the GitHub page! 163bf215546Sopenharmony_ci - Try to keep your copy of dear imgui reasonably up to date. 164bf215546Sopenharmony_ci 165bf215546Sopenharmony_ci GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE: 166bf215546Sopenharmony_ci 167bf215546Sopenharmony_ci - Run and study the examples and demo in imgui_demo.cpp to get acquainted with the library. 168bf215546Sopenharmony_ci - Add the Dear ImGui source files to your projects or using your preferred build system. 169bf215546Sopenharmony_ci It is recommended you build and statically link the .cpp files as part of your project and not as shared library (DLL). 170bf215546Sopenharmony_ci - You can later customize the imconfig.h file to tweak some compile-time behavior, such as integrating imgui types with your own maths types. 171bf215546Sopenharmony_ci - When using Dear ImGui, your programming IDE is your friend: follow the declaration of variables, functions and types to find comments about them. 172bf215546Sopenharmony_ci - Dear ImGui never touches or knows about your GPU state. The only function that knows about GPU is the draw function that you provide. 173bf215546Sopenharmony_ci Effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render" 174bf215546Sopenharmony_ci phases of your own application. All rendering informatioe are stored into command-lists that you will retrieve after calling ImGui::Render(). 175bf215546Sopenharmony_ci - Refer to the bindings and demo applications in the examples/ folder for instruction on how to setup your code. 176bf215546Sopenharmony_ci - 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. 177bf215546Sopenharmony_ci 178bf215546Sopenharmony_ci HOW A SIMPLE APPLICATION MAY LOOK LIKE: 179bf215546Sopenharmony_ci EXHIBIT 1: USING THE EXAMPLE BINDINGS (imgui_impl_XXX.cpp files from the examples/ folder). 180bf215546Sopenharmony_ci 181bf215546Sopenharmony_ci // Application init: create a dear imgui context, setup some options, load fonts 182bf215546Sopenharmony_ci ImGui::CreateContext(); 183bf215546Sopenharmony_ci ImGuiIO& io = ImGui::GetIO(); 184bf215546Sopenharmony_ci // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls. 185bf215546Sopenharmony_ci // TODO: Fill optional fields of the io structure later. 186bf215546Sopenharmony_ci // TODO: Load TTF/OTF fonts if you don't want to use the default font. 187bf215546Sopenharmony_ci 188bf215546Sopenharmony_ci // Initialize helper Platform and Renderer bindings (here we are using imgui_impl_win32 and imgui_impl_dx11) 189bf215546Sopenharmony_ci ImGui_ImplWin32_Init(hwnd); 190bf215546Sopenharmony_ci ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext); 191bf215546Sopenharmony_ci 192bf215546Sopenharmony_ci // Application main loop 193bf215546Sopenharmony_ci while (true) 194bf215546Sopenharmony_ci { 195bf215546Sopenharmony_ci // Feed inputs to dear imgui, start new frame 196bf215546Sopenharmony_ci ImGui_ImplDX11_NewFrame(); 197bf215546Sopenharmony_ci ImGui_ImplWin32_NewFrame(); 198bf215546Sopenharmony_ci ImGui::NewFrame(); 199bf215546Sopenharmony_ci 200bf215546Sopenharmony_ci // Any application code here 201bf215546Sopenharmony_ci ImGui::Text("Hello, world!"); 202bf215546Sopenharmony_ci 203bf215546Sopenharmony_ci // Render dear imgui into screen 204bf215546Sopenharmony_ci ImGui::Render(); 205bf215546Sopenharmony_ci ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); 206bf215546Sopenharmony_ci g_pSwapChain->Present(1, 0); 207bf215546Sopenharmony_ci } 208bf215546Sopenharmony_ci 209bf215546Sopenharmony_ci // Shutdown 210bf215546Sopenharmony_ci ImGui_ImplDX11_Shutdown(); 211bf215546Sopenharmony_ci ImGui_ImplWin32_Shutdown(); 212bf215546Sopenharmony_ci ImGui::DestroyContext(); 213bf215546Sopenharmony_ci 214bf215546Sopenharmony_ci HOW A SIMPLE APPLICATION MAY LOOK LIKE: 215bf215546Sopenharmony_ci EXHIBIT 2: IMPLEMENTING CUSTOM BINDING / CUSTOM ENGINE. 216bf215546Sopenharmony_ci 217bf215546Sopenharmony_ci // Application init: create a dear imgui context, setup some options, load fonts 218bf215546Sopenharmony_ci ImGui::CreateContext(); 219bf215546Sopenharmony_ci ImGuiIO& io = ImGui::GetIO(); 220bf215546Sopenharmony_ci // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls. 221bf215546Sopenharmony_ci // TODO: Fill optional fields of the io structure later. 222bf215546Sopenharmony_ci // TODO: Load TTF/OTF fonts if you don't want to use the default font. 223bf215546Sopenharmony_ci 224bf215546Sopenharmony_ci // Build and load the texture atlas into a texture 225bf215546Sopenharmony_ci // (In the examples/ app this is usually done within the ImGui_ImplXXX_Init() function from one of the demo Renderer) 226bf215546Sopenharmony_ci int width, height; 227bf215546Sopenharmony_ci unsigned char* pixels = NULL; 228bf215546Sopenharmony_ci io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); 229bf215546Sopenharmony_ci 230bf215546Sopenharmony_ci // At this point you've got the texture data and you need to upload that your your graphic system: 231bf215546Sopenharmony_ci // After we have created the texture, store its pointer/identifier (_in whichever format your engine uses_) in 'io.Fonts->TexID'. 232bf215546Sopenharmony_ci // This will be passed back to your via the renderer. Basically ImTextureID == void*. Read FAQ below for details about ImTextureID. 233bf215546Sopenharmony_ci MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA32) 234bf215546Sopenharmony_ci io.Fonts->TexID = (void*)texture; 235bf215546Sopenharmony_ci 236bf215546Sopenharmony_ci // Application main loop 237bf215546Sopenharmony_ci while (true) 238bf215546Sopenharmony_ci { 239bf215546Sopenharmony_ci // Setup low-level inputs, e.g. on Win32: calling GetKeyboardState(), or write to those fields from your Windows message handlers, etc. 240bf215546Sopenharmony_ci // (In the examples/ app this is usually done within the ImGui_ImplXXX_NewFrame() function from one of the demo Platform bindings) 241bf215546Sopenharmony_ci io.DeltaTime = 1.0f/60.0f; // set the time elapsed since the previous frame (in seconds) 242bf215546Sopenharmony_ci io.DisplaySize.x = 1920.0f; // set the current display width 243bf215546Sopenharmony_ci io.DisplaySize.y = 1280.0f; // set the current display height here 244bf215546Sopenharmony_ci io.MousePos = my_mouse_pos; // set the mouse position 245bf215546Sopenharmony_ci io.MouseDown[0] = my_mouse_buttons[0]; // set the mouse button states 246bf215546Sopenharmony_ci io.MouseDown[1] = my_mouse_buttons[1]; 247bf215546Sopenharmony_ci 248bf215546Sopenharmony_ci // Call NewFrame(), after this point you can use ImGui::* functions anytime 249bf215546Sopenharmony_ci // (So you want to try calling NewFrame() as early as you can in your mainloop to be able to use imgui everywhere) 250bf215546Sopenharmony_ci ImGui::NewFrame(); 251bf215546Sopenharmony_ci 252bf215546Sopenharmony_ci // Most of your application code here 253bf215546Sopenharmony_ci ImGui::Text("Hello, world!"); 254bf215546Sopenharmony_ci MyGameUpdate(); // may use any ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End(); 255bf215546Sopenharmony_ci MyGameRender(); // may use any ImGui functions as well! 256bf215546Sopenharmony_ci 257bf215546Sopenharmony_ci // Render imgui, swap buffers 258bf215546Sopenharmony_ci // (You want to try calling EndFrame/Render as late as you can, to be able to use imgui in your own game rendering code) 259bf215546Sopenharmony_ci ImGui::EndFrame(); 260bf215546Sopenharmony_ci ImGui::Render(); 261bf215546Sopenharmony_ci ImDrawData* draw_data = ImGui::GetDrawData(); 262bf215546Sopenharmony_ci MyImGuiRenderFunction(draw_data); 263bf215546Sopenharmony_ci SwapBuffers(); 264bf215546Sopenharmony_ci } 265bf215546Sopenharmony_ci 266bf215546Sopenharmony_ci // Shutdown 267bf215546Sopenharmony_ci ImGui::DestroyContext(); 268bf215546Sopenharmony_ci 269bf215546Sopenharmony_ci HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE: 270bf215546Sopenharmony_ci 271bf215546Sopenharmony_ci void void MyImGuiRenderFunction(ImDrawData* draw_data) 272bf215546Sopenharmony_ci { 273bf215546Sopenharmony_ci // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled 274bf215546Sopenharmony_ci // TODO: Setup viewport covering draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize 275bf215546Sopenharmony_ci // TODO: Setup orthographic projection matrix cover draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize 276bf215546Sopenharmony_ci // TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color. 277bf215546Sopenharmony_ci for (int n = 0; n < draw_data->CmdListsCount; n++) 278bf215546Sopenharmony_ci { 279bf215546Sopenharmony_ci const ImDrawList* cmd_list = draw_data->CmdLists[n]; 280bf215546Sopenharmony_ci const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; // vertex buffer generated by ImGui 281bf215546Sopenharmony_ci const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; // index buffer generated by ImGui 282bf215546Sopenharmony_ci for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) 283bf215546Sopenharmony_ci { 284bf215546Sopenharmony_ci const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; 285bf215546Sopenharmony_ci if (pcmd->UserCallback) 286bf215546Sopenharmony_ci { 287bf215546Sopenharmony_ci pcmd->UserCallback(cmd_list, pcmd); 288bf215546Sopenharmony_ci } 289bf215546Sopenharmony_ci else 290bf215546Sopenharmony_ci { 291bf215546Sopenharmony_ci // The texture for the draw call is specified by pcmd->TextureId. 292bf215546Sopenharmony_ci // The vast majority of draw calls will use the imgui texture atlas, which value you have set yourself during initialization. 293bf215546Sopenharmony_ci MyEngineBindTexture((MyTexture*)pcmd->TextureId); 294bf215546Sopenharmony_ci 295bf215546Sopenharmony_ci // We are using scissoring to clip some objects. All low-level graphics API should supports it. 296bf215546Sopenharmony_ci // - If your engine doesn't support scissoring yet, you may ignore this at first. You will get some small glitches 297bf215546Sopenharmony_ci // (some elements visible outside their bounds) but you can fix that once everything else works! 298bf215546Sopenharmony_ci // - Clipping coordinates are provided in imgui coordinates space (from draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize) 299bf215546Sopenharmony_ci // In a single viewport application, draw_data->DisplayPos will always be (0,0) and draw_data->DisplaySize will always be == io.DisplaySize. 300bf215546Sopenharmony_ci // However, in the interest of supporting multi-viewport applications in the future (see 'viewport' branch on github), 301bf215546Sopenharmony_ci // always subtract draw_data->DisplayPos from clipping bounds to convert them to your viewport space. 302bf215546Sopenharmony_ci // - Note that pcmd->ClipRect contains Min+Max bounds. Some graphics API may use Min+Max, other may use Min+Size (size being Max-Min) 303bf215546Sopenharmony_ci ImVec2 pos = draw_data->DisplayPos; 304bf215546Sopenharmony_ci MyEngineScissor((int)(pcmd->ClipRect.x - pos.x), (int)(pcmd->ClipRect.y - pos.y), (int)(pcmd->ClipRect.z - pos.x), (int)(pcmd->ClipRect.w - pos.y)); 305bf215546Sopenharmony_ci 306bf215546Sopenharmony_ci // Render 'pcmd->ElemCount/3' indexed triangles. 307bf215546Sopenharmony_ci // By default the indices ImDrawIdx are 16-bits, you can change them to 32-bits in imconfig.h if your engine doesn't support 16-bits indices. 308bf215546Sopenharmony_ci MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer, vtx_buffer); 309bf215546Sopenharmony_ci } 310bf215546Sopenharmony_ci idx_buffer += pcmd->ElemCount; 311bf215546Sopenharmony_ci } 312bf215546Sopenharmony_ci } 313bf215546Sopenharmony_ci } 314bf215546Sopenharmony_ci 315bf215546Sopenharmony_ci - The examples/ folders contains many actual implementation of the pseudo-codes above. 316bf215546Sopenharmony_ci - When calling NewFrame(), the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags are updated. 317bf215546Sopenharmony_ci They tell you if Dear ImGui intends to use your inputs. When a flag is set you want to hide the corresponding inputs 318bf215546Sopenharmony_ci from the rest of your application. In every cases you need to pass on the inputs to imgui. Refer to the FAQ for more information. 319bf215546Sopenharmony_ci - Please read the FAQ below!. Amusingly, it is called a FAQ because people frequently run into the same issues! 320bf215546Sopenharmony_ci 321bf215546Sopenharmony_ci USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS 322bf215546Sopenharmony_ci 323bf215546Sopenharmony_ci - The gamepad/keyboard navigation is fairly functional and keeps being improved. 324bf215546Sopenharmony_ci - Gamepad support is particularly useful to use dear imgui on a console system (e.g. PS4, Switch, XB1) without a mouse! 325bf215546Sopenharmony_ci - You can ask questions and report issues at https://github.com/ocornut/imgui/issues/787 326bf215546Sopenharmony_ci - The initial focus was to support game controllers, but keyboard is becoming increasingly and decently usable. 327bf215546Sopenharmony_ci - Gamepad: 328bf215546Sopenharmony_ci - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable. 329bf215546Sopenharmony_ci - Backend: Set io.BackendFlags |= ImGuiBackendFlags_HasGamepad + fill the io.NavInputs[] fields before calling NewFrame(). 330bf215546Sopenharmony_ci Note that io.NavInputs[] is cleared by EndFrame(). 331bf215546Sopenharmony_ci - See 'enum ImGuiNavInput_' in imgui.h for a description of inputs. For each entry of io.NavInputs[], set the following values: 332bf215546Sopenharmony_ci 0.0f= not held. 1.0f= fully held. Pass intermediate 0.0f..1.0f values for analog triggers/sticks. 333bf215546Sopenharmony_ci - We uses a simple >0.0f test for activation testing, and won't attempt to test for a dead-zone. 334bf215546Sopenharmony_ci Your code will probably need to transform your raw inputs (such as e.g. remapping your 0.2..0.9 raw input range to 0.0..1.0 imgui range, etc.). 335bf215546Sopenharmony_ci - You can download PNG/PSD files depicting the gamepad controls for common controllers at: http://goo.gl/9LgVZW. 336bf215546Sopenharmony_ci - If you need to share inputs between your game and the imgui parts, the easiest approach is to go all-or-nothing, with a buttons combo 337bf215546Sopenharmony_ci to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved. 338bf215546Sopenharmony_ci - Keyboard: 339bf215546Sopenharmony_ci - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. 340bf215546Sopenharmony_ci NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays. 341bf215546Sopenharmony_ci - When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard), the io.WantCaptureKeyboard flag 342bf215546Sopenharmony_ci will be set. For more advanced uses, you may want to read from: 343bf215546Sopenharmony_ci - io.NavActive: true when a window is focused and it doesn't have the ImGuiWindowFlags_NoNavInputs flag set. 344bf215546Sopenharmony_ci - io.NavVisible: true when the navigation cursor is visible (and usually goes false when mouse is used). 345bf215546Sopenharmony_ci - or query focus information with e.g. IsWindowFocused(ImGuiFocusedFlags_AnyWindow), IsItemFocused() etc. functions. 346bf215546Sopenharmony_ci Please reach out if you think the game vs navigation input sharing could be improved. 347bf215546Sopenharmony_ci - Mouse: 348bf215546Sopenharmony_ci - PS4 users: Consider emulating a mouse cursor with DualShock4 touch pad or a spare analog stick as a mouse-emulation fallback. 349bf215546Sopenharmony_ci - Consoles/Tablet/Phone users: Consider using a Synergy 1.x server (on your PC) + uSynergy.c (on your console/tablet/phone app) to share your PC mouse/keyboard. 350bf215546Sopenharmony_ci - 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. 351bf215546Sopenharmony_ci Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs dear imgui to move your mouse cursor along with navigation movements. 352bf215546Sopenharmony_ci 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. 353bf215546Sopenharmony_ci When that happens your back-end NEEDS to move the OS or underlying mouse cursor on the next frame. Some of the binding in examples/ do that. 354bf215546Sopenharmony_ci (If you set the NavEnableSetMousePos flag but don't honor 'io.WantSetMousePos' properly, imgui will misbehave as it will see your mouse as moving back and forth!) 355bf215546Sopenharmony_ci (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 356bf215546Sopenharmony_ci to set a boolean to ignore your other external mouse positions until the external source is moved again.) 357bf215546Sopenharmony_ci 358bf215546Sopenharmony_ci 359bf215546Sopenharmony_ci API BREAKING CHANGES 360bf215546Sopenharmony_ci ==================== 361bf215546Sopenharmony_ci 362bf215546Sopenharmony_ci Occasionally introducing changes that are breaking the API. We try to make the breakage minor and easy to fix. 363bf215546Sopenharmony_ci 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. 364bf215546Sopenharmony_ci When you are not sure about a old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. 365bf215546Sopenharmony_ci You can read releases logs https://github.com/ocornut/imgui/releases for more details. 366bf215546Sopenharmony_ci 367bf215546Sopenharmony_ci - 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 a dummy small value! 368bf215546Sopenharmony_ci - 2019/02/01 (1.68) - removed io.DisplayVisibleMin/DisplayVisibleMax (which were marked obsolete and removed from viewport/docking branch already). 369bf215546Sopenharmony_ci - 2019/01/06 (1.67) - renamed io.InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead! 370bf215546Sopenharmony_ci - 2019/01/06 (1.67) - renamed ImFontAtlas::GlyphRangesBuilder to ImFontGlyphRangesBuilder. Keep redirection typedef (will obsolete). 371bf215546Sopenharmony_ci - 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. 372bf215546Sopenharmony_ci - 2018/12/10 (1.67) - renamed io.ConfigResizeWindowsFromEdges to io.ConfigWindowsResizeFromEdges as we are doing a large pass on configuration flags. 373bf215546Sopenharmony_ci - 2018/10/12 (1.66) - renamed misc/stl/imgui_stl.* to misc/cpp/imgui_stdlib.* in prevision for other C++ helper files. 374bf215546Sopenharmony_ci - 2018/09/28 (1.66) - renamed SetScrollHere() to SetScrollHereY(). Kept redirection function (will obsolete). 375bf215546Sopenharmony_ci - 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. 376bf215546Sopenharmony_ci If you were conveniently using the imgui copy of those STB headers in your project you will have to update your include paths. 377bf215546Sopenharmony_ci - 2018/09/05 (1.65) - renamed io.OptCursorBlink/io.ConfigCursorBlink to io.ConfigInputTextCursorBlink. (#1427) 378bf215546Sopenharmony_ci - 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. 379bf215546Sopenharmony_ci NONE OF THE FUNCTIONS HAVE CHANGED. THE CODE IS SEMANTICALLY 100% IDENTICAL, BUT _EVERY_ FUNCTION HAS BEEN MOVED. 380bf215546Sopenharmony_ci Because of this, any local modifications to imgui.cpp will likely conflict when you update. Read docs/CHANGELOG.txt for suggestions. 381bf215546Sopenharmony_ci - 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). 382bf215546Sopenharmony_ci - 2018/08/21 (1.63) - renamed ImGuiTextEditCallback to ImGuiInputTextCallback, ImGuiTextEditCallbackData to ImGuiInputTextCallbackData for consistency. Kept redirection types (will obsolete). 383bf215546Sopenharmony_ci - 2018/08/21 (1.63) - removed ImGuiInputTextCallbackData::ReadOnly since it is a duplication of (ImGuiInputTextCallbackData::Flags & ImGuiInputTextFlags_ReadOnly). 384bf215546Sopenharmony_ci - 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. 385bf215546Sopenharmony_ci - 2018/08/01 (1.63) - renamed io.OptCursorBlink to io.ConfigCursorBlink [-> io.ConfigInputTextCursorBlink in 1.65], io.OptMacOSXBehaviors to ConfigMacOSXBehaviors for consistency. 386bf215546Sopenharmony_ci - 2018/07/22 (1.63) - changed ImGui::GetTime() return value from float to double to avoid accumulating floating point imprecisions over time. 387bf215546Sopenharmony_ci - 2018/07/08 (1.63) - style: renamed ImGuiCol_ModalWindowDarkening to ImGuiCol_ModalWindowDimBg for consistency with other features. Kept redirection enum (will obsolete). 388bf215546Sopenharmony_ci - 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.). 389bf215546Sopenharmony_ci old binding will still work as is, however prefer using the separated bindings as they will be updated to be multi-viewport conformant. 390bf215546Sopenharmony_ci when adopting new bindings follow the main.cpp code of your preferred examples/ folder to know which functions to call. 391bf215546Sopenharmony_ci - 2018/06/06 (1.62) - renamed GetGlyphRangesChinese() to GetGlyphRangesChineseFull() to distinguish other variants and discourage using the full set. 392bf215546Sopenharmony_ci - 2018/06/06 (1.62) - TreeNodeEx()/TreeNodeBehavior(): the ImGuiTreeNodeFlags_CollapsingHeader helper now include the ImGuiTreeNodeFlags_NoTreePushOnOpen flag. See Changelog for details. 393bf215546Sopenharmony_ci - 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. 394bf215546Sopenharmony_ci If you used DragInt() with custom format strings, make sure you change them to use %d or an integer-compatible format. 395bf215546Sopenharmony_ci 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. 396bf215546Sopenharmony_ci 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. 397bf215546Sopenharmony_ci - 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", 398bf215546Sopenharmony_ci consistent with other functions. Kept redirection functions (will obsolete). 399bf215546Sopenharmony_ci - 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. 400bf215546Sopenharmony_ci - 2018/03/20 (1.60) - renamed io.WantMoveMouse to io.WantSetMousePos for consistency and ease of understanding (was added in 1.52, _not_ used by core and only honored by some binding ahead of merging the Nav branch). 401bf215546Sopenharmony_ci - 2018/03/12 (1.60) - removed ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered as the closing cross uses regular button colors now. 402bf215546Sopenharmony_ci - 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. 403bf215546Sopenharmony_ci - 2018/03/03 (1.60) - renamed ImGuiStyleVar_Count_ to ImGuiStyleVar_COUNT and ImGuiMouseCursor_Count_ to ImGuiMouseCursor_COUNT for consistency with other public enums. 404bf215546Sopenharmony_ci - 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. 405bf215546Sopenharmony_ci - 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. 406bf215546Sopenharmony_ci - 2018/02/07 (1.60) - reorganized context handling to be more explicit, 407bf215546Sopenharmony_ci - YOU NOW NEED TO CALL ImGui::CreateContext() AT THE BEGINNING OF YOUR APP, AND CALL ImGui::DestroyContext() AT THE END. 408bf215546Sopenharmony_ci - removed Shutdown() function, as DestroyContext() serve this purpose. 409bf215546Sopenharmony_ci - you may pass a ImFontAtlas* pointer to CreateContext() to share a font atlas between contexts. Otherwise CreateContext() will create its own font atlas instance. 410bf215546Sopenharmony_ci - removed allocator parameters from CreateContext(), they are now setup with SetAllocatorFunctions(), and shared by all contexts. 411bf215546Sopenharmony_ci - removed the default global context and font atlas instance, which were confusing for users of DLL reloading and users of multiple contexts. 412bf215546Sopenharmony_ci - 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. 413bf215546Sopenharmony_ci - 2018/01/11 (1.60) - obsoleted IsAnyWindowHovered() in favor of IsWindowHovered(ImGuiHoveredFlags_AnyWindow). Kept redirection function (will obsolete). 414bf215546Sopenharmony_ci - 2018/01/11 (1.60) - obsoleted IsAnyWindowFocused() in favor of IsWindowFocused(ImGuiFocusedFlags_AnyWindow). Kept redirection function (will obsolete). 415bf215546Sopenharmony_ci - 2018/01/03 (1.60) - renamed ImGuiSizeConstraintCallback to ImGuiSizeCallback, ImGuiSizeConstraintCallbackData to ImGuiSizeCallbackData. 416bf215546Sopenharmony_ci - 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. 417bf215546Sopenharmony_ci - 2017/12/24 (1.53) - renamed the emblematic ShowTestWindow() function to ShowDemoWindow(). Kept redirection function (will obsolete). 418bf215546Sopenharmony_ci - 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 419bf215546Sopenharmony_ci - 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. 420bf215546Sopenharmony_ci - 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. 421bf215546Sopenharmony_ci - 2017/12/13 (1.53) - renamed GetItemsLineHeightWithSpacing() to GetFrameHeightWithSpacing(). Kept redirection function (will obsolete). 422bf215546Sopenharmony_ci - 2017/12/13 (1.53) - obsoleted IsRootWindowFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootWindow). Kept redirection function (will obsolete). 423bf215546Sopenharmony_ci - obsoleted IsRootWindowOrAnyChildFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows). Kept redirection function (will obsolete). 424bf215546Sopenharmony_ci - 2017/12/12 (1.53) - renamed ImGuiTreeNodeFlags_AllowOverlapMode to ImGuiTreeNodeFlags_AllowItemOverlap. Kept redirection enum (will obsolete). 425bf215546Sopenharmony_ci - 2017/12/10 (1.53) - removed SetNextWindowContentWidth(), prefer using SetNextWindowContentSize(). Kept redirection function (will obsolete). 426bf215546Sopenharmony_ci - 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. 427bf215546Sopenharmony_ci - 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. 428bf215546Sopenharmony_ci 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. 429bf215546Sopenharmony_ci - 2017/11/18 (1.53) - Style: removed ImGuiCol_ComboBg in favor of combo boxes using ImGuiCol_PopupBg for consistency. 430bf215546Sopenharmony_ci - 2017/11/18 (1.53) - Style: renamed ImGuiCol_ChildWindowBg to ImGuiCol_ChildBg. 431bf215546Sopenharmony_ci - 2017/11/18 (1.53) - Style: renamed style.ChildWindowRounding to style.ChildRounding, ImGuiStyleVar_ChildWindowRounding to ImGuiStyleVar_ChildRounding. 432bf215546Sopenharmony_ci - 2017/11/02 (1.53) - obsoleted IsRootWindowOrAnyChildHovered() in favor of using IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows); 433bf215546Sopenharmony_ci - 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. 434bf215546Sopenharmony_ci - 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. 435bf215546Sopenharmony_ci - 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. 436bf215546Sopenharmony_ci removed the IsItemRectHovered()/IsWindowRectHovered() names introduced in 1.51 since they were merely more consistent names for the two functions we are now obsoleting. 437bf215546Sopenharmony_ci - 2017/10/17 (1.52) - marked the old 5-parameters version of Begin() as obsolete (still available). Use SetNextWindowSize()+Begin() instead! 438bf215546Sopenharmony_ci - 2017/10/11 (1.52) - renamed AlignFirstTextHeightToWidgets() to AlignTextToFramePadding(). Kept inline redirection function (will obsolete). 439bf215546Sopenharmony_ci - 2017/09/26 (1.52) - renamed ImFont::Glyph to ImFontGlyph. Keep redirection typedef (will obsolete). 440bf215546Sopenharmony_ci - 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). 441bf215546Sopenharmony_ci - 2017/08/25 (1.52) - io.MousePos needs to be set to ImVec2(-FLT_MAX,-FLT_MAX) when mouse is unavailable/missing. Previously ImVec2(-1,-1) was enough but we now accept negative mouse coordinates. In your binding if you need to support unavailable mouse, make sure to replace "io.MousePos = ImVec2(-1,-1)" with "io.MousePos = ImVec2(-FLT_MAX,-FLT_MAX)". 442bf215546Sopenharmony_ci - 2017/08/22 (1.51) - renamed IsItemHoveredRect() to IsItemRectHovered(). Kept inline redirection function (will obsolete). -> (1.52) use IsItemHovered(ImGuiHoveredFlags_RectOnly)! 443bf215546Sopenharmony_ci - renamed IsMouseHoveringAnyWindow() to IsAnyWindowHovered() for consistency. Kept inline redirection function (will obsolete). 444bf215546Sopenharmony_ci - renamed IsMouseHoveringWindow() to IsWindowRectHovered() for consistency. Kept inline redirection function (will obsolete). 445bf215546Sopenharmony_ci - 2017/08/20 (1.51) - renamed GetStyleColName() to GetStyleColorName() for consistency. 446bf215546Sopenharmony_ci - 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. 447bf215546Sopenharmony_ci - 2017/08/15 (1.51) - marked the weird IMGUI_ONCE_UPON_A_FRAME helper macro as obsolete. prefer using the more explicit ImGuiOnceUponAFrame. 448bf215546Sopenharmony_ci - 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. 449bf215546Sopenharmony_ci - 2017/08/13 (1.51) - renamed ImGuiCol_Columns*** to ImGuiCol_Separator***. Kept redirection enums (will obsolete). 450bf215546Sopenharmony_ci - 2017/08/11 (1.51) - renamed ImGuiSetCond_*** types and flags to ImGuiCond_***. Kept redirection enums (will obsolete). 451bf215546Sopenharmony_ci - 2017/08/09 (1.51) - removed ValueColor() helpers, they are equivalent to calling Text(label) + SameLine() + ColorButton(). 452bf215546Sopenharmony_ci - 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. 453bf215546Sopenharmony_ci - 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. 454bf215546Sopenharmony_ci - 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))' 455bf215546Sopenharmony_ci - 2017/07/20 (1.51) - removed IsPosHoveringAnyWindow(ImVec2), which was partly broken and misleading. ASSERT + redirect user to io.WantCaptureMouse 456bf215546Sopenharmony_ci - 2017/05/26 (1.50) - removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset. 457bf215546Sopenharmony_ci - 2017/05/01 (1.50) - renamed ImDrawList::PathFill() (rarely used directly) to ImDrawList::PathFillConvex() for clarity. 458bf215546Sopenharmony_ci - 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(). 459bf215546Sopenharmony_ci - 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it. 460bf215546Sopenharmony_ci - 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. 461bf215546Sopenharmony_ci - 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. 462bf215546Sopenharmony_ci - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore. 463bf215546Sopenharmony_ci If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you. 464bf215546Sopenharmony_ci If your TitleBg/TitleBgActive alpha was <1.0f you need to tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar. 465bf215546Sopenharmony_ci 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. 466bf215546Sopenharmony_ci ImVec4 ConvertTitleBgCol(const ImVec4& win_bg_col, const ImVec4& title_bg_col) 467bf215546Sopenharmony_ci { 468bf215546Sopenharmony_ci float new_a = 1.0f - ((1.0f - win_bg_col.w) * (1.0f - title_bg_col.w)), k = title_bg_col.w / new_a; 469bf215546Sopenharmony_ci 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); 470bf215546Sopenharmony_ci } 471bf215546Sopenharmony_ci 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. 472bf215546Sopenharmony_ci - 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext(). 473bf215546Sopenharmony_ci - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection. 474bf215546Sopenharmony_ci - 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). 475bf215546Sopenharmony_ci - 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. 476bf215546Sopenharmony_ci - 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). 477bf215546Sopenharmony_ci - 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) 478bf215546Sopenharmony_ci - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete). 479bf215546Sopenharmony_ci - 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. 480bf215546Sopenharmony_ci - 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. 481bf215546Sopenharmony_ci - 2015/12/27 (1.48) - fixed ImDrawList::AddRect() which used to render a rectangle 1 px too large on each axis. 482bf215546Sopenharmony_ci - 2015/12/04 (1.47) - renamed Color() helpers to ValueColor() - dangerously named, rarely used and probably to be made obsolete. 483bf215546Sopenharmony_ci - 2015/08/29 (1.45) - with the addition of horizontal scrollbar we made various fixes to inconsistencies with dealing with cursor position. 484bf215546Sopenharmony_ci 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. 485bf215546Sopenharmony_ci 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! 486bf215546Sopenharmony_ci - 2015/08/29 (1.45) - renamed style.ScrollbarWidth to style.ScrollbarSize 487bf215546Sopenharmony_ci - 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. 488bf215546Sopenharmony_ci - 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 489bf215546Sopenharmony_ci - 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. 490bf215546Sopenharmony_ci you need to render your textured triangles with bilinear filtering to benefit from sub-pixel positioning of text. 491bf215546Sopenharmony_ci - 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. 492bf215546Sopenharmony_ci this necessary change will break your rendering function! the fix should be very easy. sorry for that :( 493bf215546Sopenharmony_ci - if you are using a vanilla copy of one of the imgui_impl_XXXX.cpp provided in the example, you just need to update your copy and you can ignore the rest. 494bf215546Sopenharmony_ci - the signature of the io.RenderDrawListsFn handler has changed! 495bf215546Sopenharmony_ci old: ImGui_XXXX_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count) 496bf215546Sopenharmony_ci new: ImGui_XXXX_RenderDrawLists(ImDrawData* draw_data). 497bf215546Sopenharmony_ci parameters: 'cmd_lists' becomes 'draw_data->CmdLists', 'cmd_lists_count' becomes 'draw_data->CmdListsCount' 498bf215546Sopenharmony_ci ImDrawList: 'commands' becomes 'CmdBuffer', 'vtx_buffer' becomes 'VtxBuffer', 'IdxBuffer' is new. 499bf215546Sopenharmony_ci ImDrawCmd: 'vtx_count' becomes 'ElemCount', 'clip_rect' becomes 'ClipRect', 'user_callback' becomes 'UserCallback', 'texture_id' becomes 'TextureId'. 500bf215546Sopenharmony_ci - 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. 501bf215546Sopenharmony_ci - 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! 502bf215546Sopenharmony_ci - refer to code in the examples/ folder or ask on the GitHub if you are unsure of how to upgrade. please upgrade! 503bf215546Sopenharmony_ci - 2015/07/10 (1.43) - changed SameLine() parameters from int to float. 504bf215546Sopenharmony_ci - 2015/07/02 (1.42) - renamed SetScrollPosHere() to SetScrollFromCursorPos(). Kept inline redirection function (will obsolete). 505bf215546Sopenharmony_ci - 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. 506bf215546Sopenharmony_ci - 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 507bf215546Sopenharmony_ci - 2015/06/14 (1.41) - changed Selectable() API from (label, selected, size) to (label, selected, flags, size). Size override should have been rarely be used. Sorry! 508bf215546Sopenharmony_ci - 2015/05/31 (1.40) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete). 509bf215546Sopenharmony_ci - 2015/05/31 (1.40) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete). 510bf215546Sopenharmony_ci - 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. 511bf215546Sopenharmony_ci - 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. 512bf215546Sopenharmony_ci - 2015/05/03 (1.40) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same). 513bf215546Sopenharmony_ci - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function until 1.50. 514bf215546Sopenharmony_ci - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API 515bf215546Sopenharmony_ci - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive. 516bf215546Sopenharmony_ci - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead. 517bf215546Sopenharmony_ci - 2015/03/17 (1.36) - renamed GetItemBoxMin()/GetItemBoxMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function until 1.50. 518bf215546Sopenharmony_ci - 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing 519bf215546Sopenharmony_ci - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function until 1.50. 520bf215546Sopenharmony_ci - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth (casing) 521bf215546Sopenharmony_ci - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function until 1.50. 522bf215546Sopenharmony_ci - 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once. 523bf215546Sopenharmony_ci - 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now. 524bf215546Sopenharmony_ci - 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior 525bf215546Sopenharmony_ci - 2015/02/08 (1.31) - renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing() 526bf215546Sopenharmony_ci - 2015/02/01 (1.31) - removed IO.MemReallocFn (unused) 527bf215546Sopenharmony_ci - 2015/01/19 (1.30) - renamed ImGuiStorage::GetIntPtr()/GetFloatPtr() to GetIntRef()/GetIntRef() because Ptr was conflicting with actual pointer storage functions. 528bf215546Sopenharmony_ci - 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader. 529bf215546Sopenharmony_ci (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels. 530bf215546Sopenharmony_ci font init: { const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); <..Upload texture to GPU..>; } 531bf215546Sopenharmony_ci became: { unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); <..Upload texture to GPU>; io.Fonts->TexId = YourTextureIdentifier; } 532bf215546Sopenharmony_ci you now have more flexibility to load multiple TTF fonts and manage the texture buffer for internal needs. 533bf215546Sopenharmony_ci it is now recommended that you sample the font texture with bilinear interpolation. 534bf215546Sopenharmony_ci (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to set io.Fonts->TexID. 535bf215546Sopenharmony_ci (1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix) 536bf215546Sopenharmony_ci (1.30) - removed ImGui::IsItemFocused() in favor of ImGui::IsItemActive() which handles all widgets 537bf215546Sopenharmony_ci - 2014/12/10 (1.18) - removed SetNewWindowDefaultPos() in favor of new generic API SetNextWindowPos(pos, ImGuiSetCondition_FirstUseEver) 538bf215546Sopenharmony_ci - 2014/11/28 (1.17) - moved IO.Font*** options to inside the IO.Font-> structure (FontYOffset, FontTexUvForWhite, FontBaseScale, FontFallbackGlyph) 539bf215546Sopenharmony_ci - 2014/11/26 (1.17) - reworked syntax of IMGUI_ONCE_UPON_A_FRAME helper macro to increase compiler compatibility 540bf215546Sopenharmony_ci - 2014/11/07 (1.15) - renamed IsHovered() to IsItemHovered() 541bf215546Sopenharmony_ci - 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) 542bf215546Sopenharmony_ci - 2014/09/25 (1.13) - removed 'text_end' parameter from IO.SetClipboardTextFn (the string is now always zero-terminated for simplicity) 543bf215546Sopenharmony_ci - 2014/09/24 (1.12) - renamed SetFontScale() to SetWindowFontScale() 544bf215546Sopenharmony_ci - 2014/09/24 (1.12) - moved IM_MALLOC/IM_REALLOC/IM_FREE preprocessor defines to IO.MemAllocFn/IO.MemReallocFn/IO.MemFreeFn 545bf215546Sopenharmony_ci - 2014/08/30 (1.09) - removed IO.FontHeight (now computed automatically) 546bf215546Sopenharmony_ci - 2014/08/30 (1.09) - moved IMGUI_FONT_TEX_UV_FOR_WHITE preprocessor define to IO.FontTexUvForWhite 547bf215546Sopenharmony_ci - 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes 548bf215546Sopenharmony_ci 549bf215546Sopenharmony_ci 550bf215546Sopenharmony_ci FREQUENTLY ASKED QUESTIONS (FAQ), TIPS 551bf215546Sopenharmony_ci ====================================== 552bf215546Sopenharmony_ci 553bf215546Sopenharmony_ci Q: How can I tell whether to dispatch mouse/keyboard to imgui or to my application? 554bf215546Sopenharmony_ci A: You can read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags from the ImGuiIO structure (e.g. if (ImGui::GetIO().WantCaptureMouse) { ... } ) 555bf215546Sopenharmony_ci - When 'io.WantCaptureMouse' is set, imgui wants to use your mouse state, and you may want to discard/hide the inputs from the rest of your application. 556bf215546Sopenharmony_ci - When 'io.WantCaptureKeyboard' is set, imgui wants to use your keyboard state, and you may want to discard/hide the inputs from the rest of your application. 557bf215546Sopenharmony_ci - When 'io.WantTextInput' is set to may want to notify your OS to popup an on-screen keyboard, if available (e.g. on a mobile phone, or console OS). 558bf215546Sopenharmony_ci Note: you should always pass your mouse/keyboard inputs to imgui, even when the io.WantCaptureXXX flag are set false. 559bf215546Sopenharmony_ci This is because imgui needs to detect that you clicked in the void to unfocus its own windows. 560bf215546Sopenharmony_ci Note: The 'io.WantCaptureMouse' is more accurate that any attempt to "check if the mouse is hovering a window" (don't do that!). 561bf215546Sopenharmony_ci It handle mouse dragging correctly (both dragging that started over your application or over an imgui window) and handle e.g. modal windows blocking inputs. 562bf215546Sopenharmony_ci Those flags are updated by ImGui::NewFrame(). Preferably read the flags after calling NewFrame() if you can afford it, but reading them before is also 563bf215546Sopenharmony_ci perfectly fine, as the bool toggle fairly rarely. If you have on a touch device, you might find use for an early call to UpdateHoveredWindowAndCaptureFlags(). 564bf215546Sopenharmony_ci Note: Text input widget releases focus on "Return KeyDown", so the subsequent "Return KeyUp" event that your application receive will typically 565bf215546Sopenharmony_ci have 'io.WantCaptureKeyboard=false'. Depending on your application logic it may or not be inconvenient. You might want to track which key-downs 566bf215546Sopenharmony_ci were targeted for Dear ImGui, e.g. with an array of bool, and filter out the corresponding key-ups.) 567bf215546Sopenharmony_ci 568bf215546Sopenharmony_ci Q: How can I display an image? What is ImTextureID, how does it works? 569bf215546Sopenharmony_ci A: Short explanation: 570bf215546Sopenharmony_ci - You may use functions such as ImGui::Image(), ImGui::ImageButton() or lower-level ImDrawList::AddImage() to emit draw calls that will use your own textures. 571bf215546Sopenharmony_ci - Actual textures are identified in a way that is up to the user/engine. Those identifiers are stored and passed as ImTextureID (void*) value. 572bf215546Sopenharmony_ci - Loading image files from the disk and turning them into a texture is not within the scope of Dear ImGui (for a good reason). 573bf215546Sopenharmony_ci Please read documentations or tutorials on your graphics API to understand how to display textures on the screen before moving onward. 574bf215546Sopenharmony_ci 575bf215546Sopenharmony_ci Long explanation: 576bf215546Sopenharmony_ci - Dear ImGui's job is to create "meshes", defined in a renderer-agnostic format made of draw commands and vertices. 577bf215546Sopenharmony_ci At the end of the frame those meshes (ImDrawList) will be displayed by your rendering function. They are made up of textured polygons and the code 578bf215546Sopenharmony_ci to render them is generally fairly short (a few dozen lines). In the examples/ folder we provide functions for popular graphics API (OpenGL, DirectX, etc.). 579bf215546Sopenharmony_ci - Each rendering function decides on a data type to represent "textures". The concept of what is a "texture" is entirely tied to your underlying engine/graphics API. 580bf215546Sopenharmony_ci We carry the information to identify a "texture" in the ImTextureID type. 581bf215546Sopenharmony_ci ImTextureID is nothing more that a void*, aka 4/8 bytes worth of data: just enough to store 1 pointer or 1 integer of your choice. 582bf215546Sopenharmony_ci Dear ImGui doesn't know or understand what you are storing in ImTextureID, it merely pass ImTextureID values until they reach your rendering function. 583bf215546Sopenharmony_ci - In the examples/ bindings, for each graphics API binding we decided on a type that is likely to be a good representation for specifying 584bf215546Sopenharmony_ci an image from the end-user perspective. This is what the _examples_ rendering functions are using: 585bf215546Sopenharmony_ci 586bf215546Sopenharmony_ci OpenGL: ImTextureID = GLuint (see ImGui_ImplGlfwGL3_RenderDrawData() function in imgui_impl_glfw_gl3.cpp) 587bf215546Sopenharmony_ci DirectX9: ImTextureID = LPDIRECT3DTEXTURE9 (see ImGui_ImplDX9_RenderDrawData() function in imgui_impl_dx9.cpp) 588bf215546Sopenharmony_ci DirectX11: ImTextureID = ID3D11ShaderResourceView* (see ImGui_ImplDX11_RenderDrawData() function in imgui_impl_dx11.cpp) 589bf215546Sopenharmony_ci DirectX12: ImTextureID = D3D12_GPU_DESCRIPTOR_HANDLE (see ImGui_ImplDX12_RenderDrawData() function in imgui_impl_dx12.cpp) 590bf215546Sopenharmony_ci 591bf215546Sopenharmony_ci For example, in the OpenGL example binding we store raw OpenGL texture identifier (GLuint) inside ImTextureID. 592bf215546Sopenharmony_ci Whereas in the DirectX11 example binding we store a pointer to ID3D11ShaderResourceView inside ImTextureID, which is a higher-level structure 593bf215546Sopenharmony_ci tying together both the texture and information about its format and how to read it. 594bf215546Sopenharmony_ci - If you have a custom engine built over e.g. OpenGL, instead of passing GLuint around you may decide to use a high-level data type to carry information about 595bf215546Sopenharmony_ci the texture as well as how to display it (shaders, etc.). The decision of what to use as ImTextureID can always be made better knowing how your codebase 596bf215546Sopenharmony_ci is designed. If your engine has high-level data types for "textures" and "material" then you may want to use them. 597bf215546Sopenharmony_ci If you are starting with OpenGL or DirectX or Vulkan and haven't built much of a rendering engine over them, keeping the default ImTextureID 598bf215546Sopenharmony_ci representation suggested by the example bindings is probably the best choice. 599bf215546Sopenharmony_ci (Advanced users may also decide to keep a low-level type in ImTextureID, and use ImDrawList callback and pass information to their renderer) 600bf215546Sopenharmony_ci 601bf215546Sopenharmony_ci User code may do: 602bf215546Sopenharmony_ci 603bf215546Sopenharmony_ci // Cast our texture type to ImTextureID / void* 604bf215546Sopenharmony_ci MyTexture* texture = g_CoffeeTableTexture; 605bf215546Sopenharmony_ci ImGui::Image((void*)texture, ImVec2(texture->Width, texture->Height)); 606bf215546Sopenharmony_ci 607bf215546Sopenharmony_ci The renderer function called after ImGui::Render() will receive that same value that the user code passed: 608bf215546Sopenharmony_ci 609bf215546Sopenharmony_ci // Cast ImTextureID / void* stored in the draw command as our texture type 610bf215546Sopenharmony_ci MyTexture* texture = (MyTexture*)pcmd->TextureId; 611bf215546Sopenharmony_ci MyEngineBindTexture2D(texture); 612bf215546Sopenharmony_ci 613bf215546Sopenharmony_ci Once you understand this design you will understand that loading image files and turning them into displayable textures is not within the scope of Dear ImGui. 614bf215546Sopenharmony_ci This is by design and is actually a good thing, because it means your code has full control over your data types and how you display them. 615bf215546Sopenharmony_ci If you want to display an image file (e.g. PNG file) into the screen, please refer to documentation and tutorials for the graphics API you are using. 616bf215546Sopenharmony_ci 617bf215546Sopenharmony_ci Here's a simplified OpenGL example using stb_image.h: 618bf215546Sopenharmony_ci 619bf215546Sopenharmony_ci // Use stb_image.h to load a PNG from disk and turn it into raw RGBA pixel data: 620bf215546Sopenharmony_ci #define STB_IMAGE_IMPLEMENTATION 621bf215546Sopenharmony_ci #include <stb_image.h> 622bf215546Sopenharmony_ci [...] 623bf215546Sopenharmony_ci int my_image_width, my_image_height; 624bf215546Sopenharmony_ci unsigned char* my_image_data = stbi_load("my_image.png", &my_image_width, &my_image_height, NULL, 4); 625bf215546Sopenharmony_ci 626bf215546Sopenharmony_ci // Turn the RGBA pixel data into an OpenGL texture: 627bf215546Sopenharmony_ci GLuint my_opengl_texture; 628bf215546Sopenharmony_ci glGenTextures(1, &my_opengl_texture); 629bf215546Sopenharmony_ci glBindTexture(GL_TEXTURE_2D, my_opengl_texture); 630bf215546Sopenharmony_ci glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 631bf215546Sopenharmony_ci glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 632bf215546Sopenharmony_ci glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 633bf215546Sopenharmony_ci glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image_width, image_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data); 634bf215546Sopenharmony_ci 635bf215546Sopenharmony_ci // Now that we have an OpenGL texture, assuming our imgui rendering function (imgui_impl_xxx.cpp file) takes GLuint as ImTextureID, we can display it: 636bf215546Sopenharmony_ci ImGui::Image((void*)(intptr_t)my_opengl_texture, ImVec2(my_image_width, my_image_height)); 637bf215546Sopenharmony_ci 638bf215546Sopenharmony_ci C/C++ tip: a void* is pointer-sized storage. You may safely store any pointer or integer into it by casting your value to ImTexture / void*, and vice-versa. 639bf215546Sopenharmony_ci Because both end-points (user code and rendering function) are under your control, you know exactly what is stored inside the ImTexture / void*. 640bf215546Sopenharmony_ci Examples: 641bf215546Sopenharmony_ci 642bf215546Sopenharmony_ci GLuint my_tex = XXX; 643bf215546Sopenharmony_ci void* my_void_ptr; 644bf215546Sopenharmony_ci my_void_ptr = (void*)(intptr_t)my_tex; // cast a GLuint into a void* (we don't take its address! we literally store the value inside the pointer) 645bf215546Sopenharmony_ci my_tex = (GLuint)(intptr_t)my_void_ptr; // cast a void* into a GLuint 646bf215546Sopenharmony_ci 647bf215546Sopenharmony_ci ID3D11ShaderResourceView* my_dx11_srv = XXX; 648bf215546Sopenharmony_ci void* my_void_ptr; 649bf215546Sopenharmony_ci my_void_ptr = (void*)my_dx11_srv; // cast a ID3D11ShaderResourceView* into an opaque void* 650bf215546Sopenharmony_ci my_dx11_srv = (ID3D11ShaderResourceView*)my_void_ptr; // cast a void* into a ID3D11ShaderResourceView* 651bf215546Sopenharmony_ci 652bf215546Sopenharmony_ci Finally, you may call ImGui::ShowMetricsWindow() to explore/visualize/understand how the ImDrawList are generated. 653bf215546Sopenharmony_ci 654bf215546Sopenharmony_ci Q: How can I have multiple widgets with the same label or with an empty label? 655bf215546Sopenharmony_ci Q: I have multiple widgets with the same label, and only the first one works. Why is that? 656bf215546Sopenharmony_ci A: A primer on labels and the ID Stack... 657bf215546Sopenharmony_ci 658bf215546Sopenharmony_ci Dear ImGui internally need to uniquely identify UI elements. 659bf215546Sopenharmony_ci Elements that are typically not clickable (such as calls to the Text functions) don't need an ID. 660bf215546Sopenharmony_ci Interactive widgets (such as calls to Button buttons) need a unique ID. 661bf215546Sopenharmony_ci Unique ID are used internally to track active widgets and occasionally associate state to widgets. 662bf215546Sopenharmony_ci Unique ID are implicitly built from the hash of multiple elements that identify the "path" to the UI element. 663bf215546Sopenharmony_ci 664bf215546Sopenharmony_ci - Unique ID are often derived from a string label: 665bf215546Sopenharmony_ci 666bf215546Sopenharmony_ci Button("OK"); // Label = "OK", ID = hash of (..., "OK") 667bf215546Sopenharmony_ci Button("Cancel"); // Label = "Cancel", ID = hash of (..., "Cancel") 668bf215546Sopenharmony_ci 669bf215546Sopenharmony_ci - ID are uniquely scoped within windows, tree nodes, etc. which all pushes to the ID stack. Having 670bf215546Sopenharmony_ci two buttons labeled "OK" in different windows or different tree locations is fine. 671bf215546Sopenharmony_ci We used "..." above to signify whatever was already pushed to the ID stack previously: 672bf215546Sopenharmony_ci 673bf215546Sopenharmony_ci Begin("MyWindow"); 674bf215546Sopenharmony_ci Button("OK"); // Label = "OK", ID = hash of ("MyWindow", "OK") 675bf215546Sopenharmony_ci End(); 676bf215546Sopenharmony_ci Begin("MyOtherWindow"); 677bf215546Sopenharmony_ci Button("OK"); // Label = "OK", ID = hash of ("MyOtherWindow", "OK") 678bf215546Sopenharmony_ci End(); 679bf215546Sopenharmony_ci 680bf215546Sopenharmony_ci - If you have a same ID twice in the same location, you'll have a conflict: 681bf215546Sopenharmony_ci 682bf215546Sopenharmony_ci Button("OK"); 683bf215546Sopenharmony_ci Button("OK"); // ID collision! Interacting with either button will trigger the first one. 684bf215546Sopenharmony_ci 685bf215546Sopenharmony_ci Fear not! this is easy to solve and there are many ways to solve it! 686bf215546Sopenharmony_ci 687bf215546Sopenharmony_ci - Solving ID conflict in a simple/local context: 688bf215546Sopenharmony_ci When passing a label you can optionally specify extra ID information within string itself. 689bf215546Sopenharmony_ci Use "##" to pass a complement to the ID that won't be visible to the end-user. 690bf215546Sopenharmony_ci This helps solving the simple collision cases when you know e.g. at compilation time which items 691bf215546Sopenharmony_ci are going to be created: 692bf215546Sopenharmony_ci 693bf215546Sopenharmony_ci Begin("MyWindow"); 694bf215546Sopenharmony_ci Button("Play"); // Label = "Play", ID = hash of ("MyWindow", "Play") 695bf215546Sopenharmony_ci Button("Play##foo1"); // Label = "Play", ID = hash of ("MyWindow", "Play##foo1") // Different from above 696bf215546Sopenharmony_ci Button("Play##foo2"); // Label = "Play", ID = hash of ("MyWindow", "Play##foo2") // Different from above 697bf215546Sopenharmony_ci End(); 698bf215546Sopenharmony_ci 699bf215546Sopenharmony_ci - If you want to completely hide the label, but still need an ID: 700bf215546Sopenharmony_ci 701bf215546Sopenharmony_ci Checkbox("##On", &b); // Label = "", ID = hash of (..., "##On") // No visible label, just a checkbox! 702bf215546Sopenharmony_ci 703bf215546Sopenharmony_ci - Occasionally/rarely you might want change a label while preserving a constant ID. This allows 704bf215546Sopenharmony_ci you to animate labels. For example you may want to include varying information in a window title bar, 705bf215546Sopenharmony_ci but windows are uniquely identified by their ID. Use "###" to pass a label that isn't part of ID: 706bf215546Sopenharmony_ci 707bf215546Sopenharmony_ci Button("Hello###ID"); // Label = "Hello", ID = hash of (..., "###ID") 708bf215546Sopenharmony_ci Button("World###ID"); // Label = "World", ID = hash of (..., "###ID") // Same as above, even though the label looks different 709bf215546Sopenharmony_ci 710bf215546Sopenharmony_ci sprintf(buf, "My game (%f FPS)###MyGame", fps); 711bf215546Sopenharmony_ci Begin(buf); // Variable title, ID = hash of "MyGame" 712bf215546Sopenharmony_ci 713bf215546Sopenharmony_ci - Solving ID conflict in a more general manner: 714bf215546Sopenharmony_ci Use PushID() / PopID() to create scopes and manipulate the ID stack, as to avoid ID conflicts 715bf215546Sopenharmony_ci within the same window. This is the most convenient way of distinguishing ID when iterating and 716bf215546Sopenharmony_ci creating many UI elements programmatically. 717bf215546Sopenharmony_ci You can push a pointer, a string or an integer value into the ID stack. 718bf215546Sopenharmony_ci Remember that ID are formed from the concatenation of _everything_ pushed into the ID stack. 719bf215546Sopenharmony_ci At each level of the stack we store the seed used for items at this level of the ID stack. 720bf215546Sopenharmony_ci 721bf215546Sopenharmony_ci Begin("Window"); 722bf215546Sopenharmony_ci for (int i = 0; i < 100; i++) 723bf215546Sopenharmony_ci { 724bf215546Sopenharmony_ci PushID(i); // Push i to the id tack 725bf215546Sopenharmony_ci Button("Click"); // Label = "Click", ID = hash of ("Window", i, "Click") 726bf215546Sopenharmony_ci PopID(); 727bf215546Sopenharmony_ci } 728bf215546Sopenharmony_ci for (int i = 0; i < 100; i++) 729bf215546Sopenharmony_ci { 730bf215546Sopenharmony_ci MyObject* obj = Objects[i]; 731bf215546Sopenharmony_ci PushID(obj); 732bf215546Sopenharmony_ci Button("Click"); // Label = "Click", ID = hash of ("Window", obj pointer, "Click") 733bf215546Sopenharmony_ci PopID(); 734bf215546Sopenharmony_ci } 735bf215546Sopenharmony_ci for (int i = 0; i < 100; i++) 736bf215546Sopenharmony_ci { 737bf215546Sopenharmony_ci MyObject* obj = Objects[i]; 738bf215546Sopenharmony_ci PushID(obj->Name); 739bf215546Sopenharmony_ci Button("Click"); // Label = "Click", ID = hash of ("Window", obj->Name, "Click") 740bf215546Sopenharmony_ci PopID(); 741bf215546Sopenharmony_ci } 742bf215546Sopenharmony_ci End(); 743bf215546Sopenharmony_ci 744bf215546Sopenharmony_ci - You can stack multiple prefixes into the ID stack: 745bf215546Sopenharmony_ci 746bf215546Sopenharmony_ci Button("Click"); // Label = "Click", ID = hash of (..., "Click") 747bf215546Sopenharmony_ci PushID("node"); 748bf215546Sopenharmony_ci Button("Click"); // Label = "Click", ID = hash of (..., "node", "Click") 749bf215546Sopenharmony_ci PushID(my_ptr); 750bf215546Sopenharmony_ci Button("Click"); // Label = "Click", ID = hash of (..., "node", my_ptr, "Click") 751bf215546Sopenharmony_ci PopID(); 752bf215546Sopenharmony_ci PopID(); 753bf215546Sopenharmony_ci 754bf215546Sopenharmony_ci - Tree nodes implicitly creates a scope for you by calling PushID(). 755bf215546Sopenharmony_ci 756bf215546Sopenharmony_ci Button("Click"); // Label = "Click", ID = hash of (..., "Click") 757bf215546Sopenharmony_ci if (TreeNode("node")) // <-- this function call will do a PushID() for you (unless instructed not to, with a special flag) 758bf215546Sopenharmony_ci { 759bf215546Sopenharmony_ci Button("Click"); // Label = "Click", ID = hash of (..., "node", "Click") 760bf215546Sopenharmony_ci TreePop(); 761bf215546Sopenharmony_ci } 762bf215546Sopenharmony_ci 763bf215546Sopenharmony_ci - When working with trees, ID are used to preserve the open/close state of each tree node. 764bf215546Sopenharmony_ci Depending on your use cases you may want to use strings, indices or pointers as ID. 765bf215546Sopenharmony_ci e.g. when following a single pointer that may change over time, using a static string as ID 766bf215546Sopenharmony_ci will preserve your node open/closed state when the targeted object change. 767bf215546Sopenharmony_ci e.g. when displaying a list of objects, using indices or pointers as ID will preserve the 768bf215546Sopenharmony_ci node open/closed state differently. See what makes more sense in your situation! 769bf215546Sopenharmony_ci 770bf215546Sopenharmony_ci Q: How can I use my own math types instead of ImVec2/ImVec4? 771bf215546Sopenharmony_ci A: You can edit imconfig.h and setup the IM_VEC2_CLASS_EXTRA/IM_VEC4_CLASS_EXTRA macros to add implicit type conversions. 772bf215546Sopenharmony_ci This way you'll be able to use your own types everywhere, e.g. passsing glm::vec2 to ImGui functions instead of ImVec2. 773bf215546Sopenharmony_ci 774bf215546Sopenharmony_ci Q: How can I load a different font than the default? 775bf215546Sopenharmony_ci A: Use the font atlas to load the TTF/OTF file you want: 776bf215546Sopenharmony_ci ImGuiIO& io = ImGui::GetIO(); 777bf215546Sopenharmony_ci io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels); 778bf215546Sopenharmony_ci io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8() 779bf215546Sopenharmony_ci Default is ProggyClean.ttf, monospace, rendered at size 13, embedded in dear imgui's source code. 780bf215546Sopenharmony_ci (Tip: monospace fonts are convenient because they allow to facilitate horizontal alignment directly at the string level.) 781bf215546Sopenharmony_ci (Read the 'misc/fonts/README.txt' file for more details about font loading.) 782bf215546Sopenharmony_ci 783bf215546Sopenharmony_ci New programmers: remember that in C/C++ and most programming languages if you want to use a 784bf215546Sopenharmony_ci backslash \ within a string literal, you need to write it double backslash "\\": 785bf215546Sopenharmony_ci io.Fonts->AddFontFromFileTTF("MyDataFolder\MyFontFile.ttf", size_in_pixels); // WRONG (you are escape the M here!) 786bf215546Sopenharmony_ci io.Fonts->AddFontFromFileTTF("MyDataFolder\\MyFontFile.ttf", size_in_pixels); // CORRECT 787bf215546Sopenharmony_ci io.Fonts->AddFontFromFileTTF("MyDataFolder/MyFontFile.ttf", size_in_pixels); // ALSO CORRECT 788bf215546Sopenharmony_ci 789bf215546Sopenharmony_ci Q: How can I easily use icons in my application? 790bf215546Sopenharmony_ci A: The most convenient and practical way is to merge an icon font such as FontAwesome inside you 791bf215546Sopenharmony_ci main font. Then you can refer to icons within your strings. 792bf215546Sopenharmony_ci You may want to see ImFontConfig::GlyphMinAdvanceX to make your icon look monospace to facilitate alignment. 793bf215546Sopenharmony_ci (Read the 'misc/fonts/README.txt' file for more details about icons font loading.) 794bf215546Sopenharmony_ci 795bf215546Sopenharmony_ci Q: How can I load multiple fonts? 796bf215546Sopenharmony_ci A: Use the font atlas to pack them into a single texture: 797bf215546Sopenharmony_ci (Read the 'misc/fonts/README.txt' file and the code in ImFontAtlas for more details.) 798bf215546Sopenharmony_ci 799bf215546Sopenharmony_ci ImGuiIO& io = ImGui::GetIO(); 800bf215546Sopenharmony_ci ImFont* font0 = io.Fonts->AddFontDefault(); 801bf215546Sopenharmony_ci ImFont* font1 = io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels); 802bf215546Sopenharmony_ci ImFont* font2 = io.Fonts->AddFontFromFileTTF("myfontfile2.ttf", size_in_pixels); 803bf215546Sopenharmony_ci io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8() 804bf215546Sopenharmony_ci // the first loaded font gets used by default 805bf215546Sopenharmony_ci // use ImGui::PushFont()/ImGui::PopFont() to change the font at runtime 806bf215546Sopenharmony_ci 807bf215546Sopenharmony_ci // Options 808bf215546Sopenharmony_ci ImFontConfig config; 809bf215546Sopenharmony_ci config.OversampleH = 2; 810bf215546Sopenharmony_ci config.OversampleV = 1; 811bf215546Sopenharmony_ci config.GlyphOffset.y -= 1.0f; // Move everything by 1 pixels up 812bf215546Sopenharmony_ci config.GlyphExtraSpacing.x = 1.0f; // Increase spacing between characters 813bf215546Sopenharmony_ci io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_pixels, &config); 814bf215546Sopenharmony_ci 815bf215546Sopenharmony_ci // Combine multiple fonts into one (e.g. for icon fonts) 816bf215546Sopenharmony_ci static ImWchar ranges[] = { 0xf000, 0xf3ff, 0 }; 817bf215546Sopenharmony_ci ImFontConfig config; 818bf215546Sopenharmony_ci config.MergeMode = true; 819bf215546Sopenharmony_ci io.Fonts->AddFontDefault(); 820bf215546Sopenharmony_ci io.Fonts->AddFontFromFileTTF("fontawesome-webfont.ttf", 16.0f, &config, ranges); // Merge icon font 821bf215546Sopenharmony_ci io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_pixels, NULL, &config, io.Fonts->GetGlyphRangesJapanese()); // Merge japanese glyphs 822bf215546Sopenharmony_ci 823bf215546Sopenharmony_ci Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic? 824bf215546Sopenharmony_ci A: When loading a font, pass custom Unicode ranges to specify the glyphs to load. 825bf215546Sopenharmony_ci 826bf215546Sopenharmony_ci // Add default Japanese ranges 827bf215546Sopenharmony_ci io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, io.Fonts->GetGlyphRangesJapanese()); 828bf215546Sopenharmony_ci 829bf215546Sopenharmony_ci // Or create your own custom ranges (e.g. for a game you can feed your entire game script and only build the characters the game need) 830bf215546Sopenharmony_ci ImVector<ImWchar> ranges; 831bf215546Sopenharmony_ci ImFontGlyphRangesBuilder builder; 832bf215546Sopenharmony_ci builder.AddText("Hello world"); // Add a string (here "Hello world" contains 7 unique characters) 833bf215546Sopenharmony_ci builder.AddChar(0x7262); // Add a specific character 834bf215546Sopenharmony_ci builder.AddRanges(io.Fonts->GetGlyphRangesJapanese()); // Add one of the default ranges 835bf215546Sopenharmony_ci builder.BuildRanges(&ranges); // Build the final result (ordered ranges with all the unique characters submitted) 836bf215546Sopenharmony_ci io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, ranges.Data); 837bf215546Sopenharmony_ci 838bf215546Sopenharmony_ci All your strings needs to use UTF-8 encoding. In C++11 you can encode a string literal in UTF-8 839bf215546Sopenharmony_ci by using the u8"hello" syntax. Specifying literal in your source code using a local code page 840bf215546Sopenharmony_ci (such as CP-923 for Japanese or CP-1251 for Cyrillic) will NOT work! 841bf215546Sopenharmony_ci Otherwise you can convert yourself to UTF-8 or load text data from file already saved as UTF-8. 842bf215546Sopenharmony_ci 843bf215546Sopenharmony_ci Text input: it is up to your application to pass the right character code by calling io.AddInputCharacter(). 844bf215546Sopenharmony_ci The applications in examples/ are doing that. 845bf215546Sopenharmony_ci Windows: you can use the WM_CHAR or WM_UNICHAR or WM_IME_CHAR message (depending if your app is built using Unicode or MultiByte mode). 846bf215546Sopenharmony_ci You may also use MultiByteToWideChar() or ToUnicode() to retrieve Unicode codepoints from MultiByte characters or keyboard state. 847bf215546Sopenharmony_ci Windows: if your language is relying on an Input Method Editor (IME), you copy the HWND of your window to io.ImeWindowHandle in order for 848bf215546Sopenharmony_ci the default implementation of io.ImeSetInputScreenPosFn() to set your Microsoft IME position correctly. 849bf215546Sopenharmony_ci 850bf215546Sopenharmony_ci Q: How can I interact with standard C++ types (such as std::string and std::vector)? 851bf215546Sopenharmony_ci A: - Being highly portable (bindings for several languages, frameworks, programming style, obscure or older platforms/compilers), 852bf215546Sopenharmony_ci and aiming for compatibility & performance suitable for every modern real-time game engines, dear imgui does not use 853bf215546Sopenharmony_ci any of std C++ types. We use raw types (e.g. char* instead of std::string) because they adapt to more use cases. 854bf215546Sopenharmony_ci - To use ImGui::InputText() with a std::string or any resizable string class, see misc/cpp/imgui_stdlib.h. 855bf215546Sopenharmony_ci - To use combo boxes and list boxes with std::vector or any other data structure: the BeginCombo()/EndCombo() API 856bf215546Sopenharmony_ci lets you iterate and submit items yourself, so does the ListBoxHeader()/ListBoxFooter() API. 857bf215546Sopenharmony_ci Prefer using them over the old and awkward Combo()/ListBox() api. 858bf215546Sopenharmony_ci - Generally for most high-level types you should be able to access the underlying data type. 859bf215546Sopenharmony_ci You may write your own one-liner wrappers to facilitate user code (tip: add new functions in ImGui:: namespace from your code). 860bf215546Sopenharmony_ci - Dear ImGui applications often need to make intensive use of strings. It is expected that many of the strings you will pass 861bf215546Sopenharmony_ci to the API are raw literals (free in C/C++) or allocated in a manner that won't incur a large cost on your application. 862bf215546Sopenharmony_ci Please bear in mind that using std::string on applications with large amount of UI may incur unsatisfactory performances. 863bf215546Sopenharmony_ci Modern implementations of std::string often include small-string optimization (which is often a local buffer) but those 864bf215546Sopenharmony_ci are not configurable and not the same across implementations. 865bf215546Sopenharmony_ci - If you are finding your UI traversal cost to be too large, make sure your string usage is not leading to excessive amount 866bf215546Sopenharmony_ci of heap allocations. Consider using literals, statically sized buffers and your own helper functions. A common pattern 867bf215546Sopenharmony_ci is that you will need to build lots of strings on the fly, and their maximum length can be easily be scoped ahead. 868bf215546Sopenharmony_ci One possible implementation of a helper to facilitate printf-style building of strings: https://github.com/ocornut/Str 869bf215546Sopenharmony_ci This is a small helper where you can instance strings with configurable local buffers length. Many game engines will 870bf215546Sopenharmony_ci provide similar or better string helpers. 871bf215546Sopenharmony_ci 872bf215546Sopenharmony_ci Q: How can I use the drawing facilities without an ImGui window? (using ImDrawList API) 873bf215546Sopenharmony_ci A: - You can create a dummy window. Call Begin() with the NoBackground | NoDecoration | NoSavedSettings | NoInputs flags. 874bf215546Sopenharmony_ci (The ImGuiWindowFlags_NoDecoration flag itself is a shortcut for NoTitleBar | NoResize | NoScrollbar | NoCollapse) 875bf215546Sopenharmony_ci Then you can retrieve the ImDrawList* via GetWindowDrawList() and draw to it in any way you like. 876bf215546Sopenharmony_ci - You can call ImGui::GetOverlayDrawList() and use this draw list to display contents over every other imgui windows. 877bf215546Sopenharmony_ci - You can create your own ImDrawList instance. You'll need to initialize them ImGui::GetDrawListSharedData(), or create 878bf215546Sopenharmony_ci your own ImDrawListSharedData, and then call your rendered code with your own ImDrawList or ImDrawData data. 879bf215546Sopenharmony_ci 880bf215546Sopenharmony_ci Q: How can I use this without a mouse, without a keyboard or without a screen? (gamepad, input share, remote display) 881bf215546Sopenharmony_ci A: - You can control Dear ImGui with a gamepad. Read about navigation in "Using gamepad/keyboard navigation controls". 882bf215546Sopenharmony_ci (short version: map gamepad inputs into the io.NavInputs[] array + set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad) 883bf215546Sopenharmony_ci - You can share your computer mouse seamlessly with your console/tablet/phone using Synergy (https://symless.com/synergy) 884bf215546Sopenharmony_ci This is the preferred solution for developer productivity. 885bf215546Sopenharmony_ci In particular, the "micro-synergy-client" repository (https://github.com/symless/micro-synergy-client) has simple 886bf215546Sopenharmony_ci and portable source code (uSynergy.c/.h) for a small embeddable client that you can use on any platform to connect 887bf215546Sopenharmony_ci to your host computer, based on the Synergy 1.x protocol. Make sure you download the Synergy 1 server on your computer. 888bf215546Sopenharmony_ci Console SDK also sometimes provide equivalent tooling or wrapper for Synergy-like protocols. 889bf215546Sopenharmony_ci - You may also use a third party solution such as Remote ImGui (https://github.com/JordiRos/remoteimgui) which sends 890bf215546Sopenharmony_ci the vertices to render over the local network, allowing you to use Dear ImGui even on a screen-less machine. 891bf215546Sopenharmony_ci - For touch inputs, you can increase the hit box of widgets (via the style.TouchPadding setting) to accommodate 892bf215546Sopenharmony_ci for the lack of precision of touch inputs, but it is recommended you use a mouse or gamepad to allow optimizing 893bf215546Sopenharmony_ci for screen real-estate and precision. 894bf215546Sopenharmony_ci 895bf215546Sopenharmony_ci Q: I integrated Dear ImGui in my engine and the text or lines are blurry.. 896bf215546Sopenharmony_ci A: In your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f). 897bf215546Sopenharmony_ci Also make sure your orthographic projection matrix and io.DisplaySize matches your actual framebuffer dimension. 898bf215546Sopenharmony_ci 899bf215546Sopenharmony_ci Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around.. 900bf215546Sopenharmony_ci A: You are probably mishandling the clipping rectangles in your render function. 901bf215546Sopenharmony_ci Rectangles provided by ImGui are defined as (x1=left,y1=top,x2=right,y2=bottom) and NOT as (x1,y1,width,height). 902bf215546Sopenharmony_ci 903bf215546Sopenharmony_ci Q: How can I help? 904bf215546Sopenharmony_ci A: - If you are experienced with Dear ImGui and C++, look at the github issues, look at the Wiki, read docs/TODO.txt 905bf215546Sopenharmony_ci and see how you want to help and can help! 906bf215546Sopenharmony_ci - Businesses: convince your company to fund development via support contracts/sponsoring! This is among the most useful thing you can do for dear imgui. 907bf215546Sopenharmony_ci - Individuals: you can also become a Patron (http://www.patreon.com/imgui) or donate on PayPal! See README. 908bf215546Sopenharmony_ci - Disclose your usage of dear imgui via a dev blog post, a tweet, a screenshot, a mention somewhere etc. 909bf215546Sopenharmony_ci You may post screenshot or links in the gallery threads (github.com/ocornut/imgui/issues/1902). Visuals are ideal as they inspire other programmers. 910bf215546Sopenharmony_ci But even without visuals, disclosing your use of dear imgui help the library grow credibility, and help other teams and programmers with taking decisions. 911bf215546Sopenharmony_ci - 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). 912bf215546Sopenharmony_ci 913bf215546Sopenharmony_ci - tip: you can call Begin() multiple times with the same name during the same frame, it will keep appending to the same window. 914bf215546Sopenharmony_ci this is also useful to set yourself in the context of another window (to get/set other settings) 915bf215546Sopenharmony_ci - tip: you can create widgets without a Begin()/End() block, they will go in an implicit window called "Debug". 916bf215546Sopenharmony_ci - tip: the ImGuiOnceUponAFrame helper will allow run the block of code only once a frame. You can use it to quickly add custom UI in the middle 917bf215546Sopenharmony_ci of a deep nested inner loop in your code. 918bf215546Sopenharmony_ci - tip: you can call Render() multiple times (e.g for VR renders). 919bf215546Sopenharmony_ci - tip: call and read the ShowDemoWindow() code in imgui_demo.cpp for more example of how to use ImGui! 920bf215546Sopenharmony_ci 921bf215546Sopenharmony_ci*/ 922bf215546Sopenharmony_ci 923bf215546Sopenharmony_ci#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) 924bf215546Sopenharmony_ci#define _CRT_SECURE_NO_WARNINGS 925bf215546Sopenharmony_ci#endif 926bf215546Sopenharmony_ci 927bf215546Sopenharmony_ci#include "imgui.h" 928bf215546Sopenharmony_ci#ifndef IMGUI_DEFINE_MATH_OPERATORS 929bf215546Sopenharmony_ci#define IMGUI_DEFINE_MATH_OPERATORS 930bf215546Sopenharmony_ci#endif 931bf215546Sopenharmony_ci#include "imgui_internal.h" 932bf215546Sopenharmony_ci 933bf215546Sopenharmony_ci#include <ctype.h> // toupper, isprint 934bf215546Sopenharmony_ci#include <stdio.h> // vsnprintf, sscanf, printf 935bf215546Sopenharmony_ci#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier 936bf215546Sopenharmony_ci#include <stddef.h> // intptr_t 937bf215546Sopenharmony_ci#else 938bf215546Sopenharmony_ci#include <stdint.h> // intptr_t 939bf215546Sopenharmony_ci#endif 940bf215546Sopenharmony_ci 941bf215546Sopenharmony_ci// Debug options 942bf215546Sopenharmony_ci#define IMGUI_DEBUG_NAV_SCORING 0 // Display navigation scoring preview when hovering items. Display last moving direction matches when holding CTRL 943bf215546Sopenharmony_ci#define IMGUI_DEBUG_NAV_RECTS 0 // Display the reference navigation rectangle for each window 944bf215546Sopenharmony_ci 945bf215546Sopenharmony_ci// Visual Studio warnings 946bf215546Sopenharmony_ci#ifdef _MSC_VER 947bf215546Sopenharmony_ci#pragma warning (disable: 4127) // condition expression is constant 948bf215546Sopenharmony_ci#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen 949bf215546Sopenharmony_ci#endif 950bf215546Sopenharmony_ci 951bf215546Sopenharmony_ci// Clang/GCC warnings with -Weverything 952bf215546Sopenharmony_ci#ifdef __clang__ 953bf215546Sopenharmony_ci#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning : unknown warning group '-Wformat-pedantic *' // not all warnings are known by all clang versions.. so ignoring warnings triggers new warnings on some configuration. great! 954bf215546Sopenharmony_ci#pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse. 955bf215546Sopenharmony_ci#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. 956bf215546Sopenharmony_ci#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. 957bf215546Sopenharmony_ci#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. 958bf215546Sopenharmony_ci#pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it. 959bf215546Sopenharmony_ci#pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness // 960bf215546Sopenharmony_ci#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. 961bf215546Sopenharmony_ci#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int' 962bf215546Sopenharmony_ci#if __has_warning("-Wzero-as-null-pointer-constant") 963bf215546Sopenharmony_ci#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0 964bf215546Sopenharmony_ci#endif 965bf215546Sopenharmony_ci#if __has_warning("-Wdouble-promotion") 966bf215546Sopenharmony_ci#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. 967bf215546Sopenharmony_ci#endif 968bf215546Sopenharmony_ci#elif defined(__GNUC__) 969bf215546Sopenharmony_ci#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used 970bf215546Sopenharmony_ci#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size 971bf215546Sopenharmony_ci#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'void*', but argument 6 has type 'ImGuiWindow*' 972bf215546Sopenharmony_ci#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function 973bf215546Sopenharmony_ci#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value 974bf215546Sopenharmony_ci#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked 975bf215546Sopenharmony_ci#pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when assuming that (X - c) > X is always false 976bf215546Sopenharmony_ci#if __GNUC__ >= 8 977bf215546Sopenharmony_ci#pragma GCC diagnostic ignored "-Wclass-memaccess" // warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead 978bf215546Sopenharmony_ci#endif 979bf215546Sopenharmony_ci#endif 980bf215546Sopenharmony_ci 981bf215546Sopenharmony_ci// 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. 982bf215546Sopenharmony_cistatic const float NAV_WINDOWING_HIGHLIGHT_DELAY = 0.20f; // Time before the highlight and screen dimming starts fading in 983bf215546Sopenharmony_cistatic const float NAV_WINDOWING_LIST_APPEAR_DELAY = 0.15f; // Time before the window list starts to appear 984bf215546Sopenharmony_ci 985bf215546Sopenharmony_ci// Window resizing from edges (when io.ConfigWindowsResizeFromEdges = true and ImGuiBackendFlags_HasMouseCursors is set in io.BackendFlags by back-end) 986bf215546Sopenharmony_cistatic const float WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS = 4.0f; // Extend outside and inside windows. Affect FindHoveredWindow(). 987bf215546Sopenharmony_cistatic const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04f; // Reduce visual noise by only highlighting the border after a certain time. 988bf215546Sopenharmony_ci 989bf215546Sopenharmony_ci//------------------------------------------------------------------------- 990bf215546Sopenharmony_ci// [SECTION] FORWARD DECLARATIONS 991bf215546Sopenharmony_ci//------------------------------------------------------------------------- 992bf215546Sopenharmony_ci 993bf215546Sopenharmony_cistatic void SetCurrentWindow(ImGuiWindow* window); 994bf215546Sopenharmony_cistatic void FindHoveredWindow(); 995bf215546Sopenharmony_cistatic ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFlags flags); 996bf215546Sopenharmony_cistatic void CheckStacksSize(ImGuiWindow* window, bool write); 997bf215546Sopenharmony_cistatic ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool snap_on_edges); 998bf215546Sopenharmony_ci 999bf215546Sopenharmony_cistatic void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* draw_list); 1000bf215546Sopenharmony_cistatic void AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window); 1001bf215546Sopenharmony_ci 1002bf215546Sopenharmony_cistatic ImRect GetViewportRect(); 1003bf215546Sopenharmony_ci 1004bf215546Sopenharmony_ci// Settings 1005bf215546Sopenharmony_cistatic void* SettingsHandlerWindow_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name); 1006bf215546Sopenharmony_cistatic void SettingsHandlerWindow_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line); 1007bf215546Sopenharmony_cistatic void SettingsHandlerWindow_WriteAll(ImGuiContext* imgui_ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf); 1008bf215546Sopenharmony_ci 1009bf215546Sopenharmony_ci// Platform Dependents default implementation for IO functions 1010bf215546Sopenharmony_cistatic const char* GetClipboardTextFn_DefaultImpl(void* user_data); 1011bf215546Sopenharmony_cistatic void SetClipboardTextFn_DefaultImpl(void* user_data, const char* text); 1012bf215546Sopenharmony_cistatic void ImeSetInputScreenPosFn_DefaultImpl(int x, int y); 1013bf215546Sopenharmony_ci 1014bf215546Sopenharmony_cinamespace ImGui 1015bf215546Sopenharmony_ci{ 1016bf215546Sopenharmony_cistatic bool BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags); 1017bf215546Sopenharmony_ci 1018bf215546Sopenharmony_ci// Navigation 1019bf215546Sopenharmony_cistatic void NavUpdate(); 1020bf215546Sopenharmony_cistatic void NavUpdateWindowing(); 1021bf215546Sopenharmony_cistatic void NavUpdateWindowingList(); 1022bf215546Sopenharmony_cistatic void NavUpdateMoveResult(); 1023bf215546Sopenharmony_cistatic float NavUpdatePageUpPageDown(int allowed_dir_flags); 1024bf215546Sopenharmony_cistatic inline void NavUpdateAnyRequestFlag(); 1025bf215546Sopenharmony_cistatic void NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, const ImGuiID id); 1026bf215546Sopenharmony_cistatic ImVec2 NavCalcPreferredRefPos(); 1027bf215546Sopenharmony_cistatic void NavSaveLastChildNavWindow(ImGuiWindow* nav_window); 1028bf215546Sopenharmony_cistatic ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window); 1029bf215546Sopenharmony_ci 1030bf215546Sopenharmony_ci// Misc 1031bf215546Sopenharmony_cistatic void UpdateMouseInputs(); 1032bf215546Sopenharmony_cistatic void UpdateMouseWheel(); 1033bf215546Sopenharmony_cistatic void UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]); 1034bf215546Sopenharmony_cistatic void RenderOuterBorders(ImGuiWindow* window); 1035bf215546Sopenharmony_ci 1036bf215546Sopenharmony_ci} 1037bf215546Sopenharmony_ci 1038bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 1039bf215546Sopenharmony_ci// [SECTION] CONTEXT AND MEMORY ALLOCATORS 1040bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 1041bf215546Sopenharmony_ci 1042bf215546Sopenharmony_ci// Current context pointer. Implicitly used by all Dear ImGui functions. Always assumed to be != NULL. 1043bf215546Sopenharmony_ci// ImGui::CreateContext() will automatically set this pointer if it is NULL. Change to a different context by calling ImGui::SetCurrentContext(). 1044bf215546Sopenharmony_ci// 1) Important: globals are not shared across DLL boundaries! If you use DLLs or any form of hot-reloading: you will need to call 1045bf215546Sopenharmony_ci// SetCurrentContext() (with the pointer you got from CreateContext) from each unique static/DLL boundary, and after each hot-reloading. 1046bf215546Sopenharmony_ci// In your debugger, add GImGui to your watch window and notice how its value changes depending on which location you are currently stepping into. 1047bf215546Sopenharmony_ci// 2) Important: Dear ImGui functions are not thread-safe because of this pointer. 1048bf215546Sopenharmony_ci// If you want thread-safety to allow N threads to access N different contexts, you can: 1049bf215546Sopenharmony_ci// - Change this variable to use thread local storage so each thread can refer to a different context, in imconfig.h: 1050bf215546Sopenharmony_ci// struct ImGuiContext; 1051bf215546Sopenharmony_ci// extern thread_local ImGuiContext* MyImGuiTLS; 1052bf215546Sopenharmony_ci// #define GImGui MyImGuiTLS 1053bf215546Sopenharmony_ci// And then define MyImGuiTLS in one of your cpp file. Note that thread_local is a C++11 keyword, earlier C++ uses compiler-specific keyword. 1054bf215546Sopenharmony_ci// - Future development aim to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586 1055bf215546Sopenharmony_ci// - If you need a finite number of contexts, you may compile and use multiple instances of the ImGui code from different namespace. 1056bf215546Sopenharmony_ci#ifndef GImGui 1057bf215546Sopenharmony_ciImGuiContext* GImGui = NULL; 1058bf215546Sopenharmony_ci#endif 1059bf215546Sopenharmony_ci 1060bf215546Sopenharmony_ci// Memory Allocator functions. Use SetAllocatorFunctions() to change them. 1061bf215546Sopenharmony_ci// If you use DLL hotreloading you might need to call SetAllocatorFunctions() after reloading code from this file. 1062bf215546Sopenharmony_ci// Otherwise, you probably don't want to modify them mid-program, and if you use global/static e.g. ImVector<> instances you may need to keep them accessible during program destruction. 1063bf215546Sopenharmony_ci#ifndef IMGUI_DISABLE_DEFAULT_ALLOCATORS 1064bf215546Sopenharmony_cistatic void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); return malloc(size); } 1065bf215546Sopenharmony_cistatic void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); free(ptr); } 1066bf215546Sopenharmony_ci#else 1067bf215546Sopenharmony_cistatic void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); IM_UNUSED(size); IM_ASSERT(0); return NULL; } 1068bf215546Sopenharmony_cistatic void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); IM_UNUSED(ptr); IM_ASSERT(0); } 1069bf215546Sopenharmony_ci#endif 1070bf215546Sopenharmony_ci 1071bf215546Sopenharmony_cistatic void* (*GImAllocatorAllocFunc)(size_t size, void* user_data) = MallocWrapper; 1072bf215546Sopenharmony_cistatic void (*GImAllocatorFreeFunc)(void* ptr, void* user_data) = FreeWrapper; 1073bf215546Sopenharmony_cistatic void* GImAllocatorUserData = NULL; 1074bf215546Sopenharmony_ci 1075bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 1076bf215546Sopenharmony_ci// [SECTION] MAIN USER FACING STRUCTURES (ImGuiStyle, ImGuiIO) 1077bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 1078bf215546Sopenharmony_ci 1079bf215546Sopenharmony_ciImGuiStyle::ImGuiStyle() 1080bf215546Sopenharmony_ci{ 1081bf215546Sopenharmony_ci Alpha = 1.0f; // Global alpha applies to everything in ImGui 1082bf215546Sopenharmony_ci WindowPadding = ImVec2(8,8); // Padding within a window 1083bf215546Sopenharmony_ci WindowRounding = 7.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows 1084bf215546Sopenharmony_ci WindowBorderSize = 1.0f; // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested. 1085bf215546Sopenharmony_ci WindowMinSize = ImVec2(32,32); // Minimum window size 1086bf215546Sopenharmony_ci WindowTitleAlign = ImVec2(0.0f,0.5f);// Alignment for title bar text 1087bf215546Sopenharmony_ci ChildRounding = 0.0f; // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows 1088bf215546Sopenharmony_ci ChildBorderSize = 1.0f; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. Other values not well tested. 1089bf215546Sopenharmony_ci PopupRounding = 0.0f; // Radius of popup window corners rounding. Set to 0.0f to have rectangular child windows 1090bf215546Sopenharmony_ci PopupBorderSize = 1.0f; // Thickness of border around popup or tooltip windows. Generally set to 0.0f or 1.0f. Other values not well tested. 1091bf215546Sopenharmony_ci FramePadding = ImVec2(4,3); // Padding within a framed rectangle (used by most widgets) 1092bf215546Sopenharmony_ci FrameRounding = 0.0f; // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets). 1093bf215546Sopenharmony_ci FrameBorderSize = 0.0f; // Thickness of border around frames. Generally set to 0.0f or 1.0f. Other values not well tested. 1094bf215546Sopenharmony_ci ItemSpacing = ImVec2(8,4); // Horizontal and vertical spacing between widgets/lines 1095bf215546Sopenharmony_ci ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label) 1096bf215546Sopenharmony_ci 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! 1097bf215546Sopenharmony_ci IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). 1098bf215546Sopenharmony_ci ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns 1099bf215546Sopenharmony_ci ScrollbarSize = 16.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar 1100bf215546Sopenharmony_ci ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar 1101bf215546Sopenharmony_ci GrabMinSize = 10.0f; // Minimum width/height of a grab box for slider/scrollbar 1102bf215546Sopenharmony_ci GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. 1103bf215546Sopenharmony_ci TabRounding = 4.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. 1104bf215546Sopenharmony_ci TabBorderSize = 0.0f; // Thickness of border around tabs. 1105bf215546Sopenharmony_ci ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text. 1106bf215546Sopenharmony_ci SelectableTextAlign = ImVec2(0.0f,0.0f);// Alignment of selectable text when button is larger than text. 1107bf215546Sopenharmony_ci DisplayWindowPadding = ImVec2(19,19); // Window position are clamped to be visible within the display area by at least this amount. Only applies to regular windows. 1108bf215546Sopenharmony_ci 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. 1109bf215546Sopenharmony_ci MouseCursorScale = 1.0f; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later. 1110bf215546Sopenharmony_ci AntiAliasedLines = true; // Enable anti-aliasing on lines/borders. Disable if you are really short on CPU/GPU. 1111bf215546Sopenharmony_ci AntiAliasedFill = true; // Enable anti-aliasing on filled shapes (rounded rectangles, circles, etc.) 1112bf215546Sopenharmony_ci 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. 1113bf215546Sopenharmony_ci 1114bf215546Sopenharmony_ci // Default theme 1115bf215546Sopenharmony_ci ImGui::StyleColorsDark(this); 1116bf215546Sopenharmony_ci} 1117bf215546Sopenharmony_ci 1118bf215546Sopenharmony_ci// 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. 1119bf215546Sopenharmony_ci// 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. 1120bf215546Sopenharmony_civoid ImGuiStyle::ScaleAllSizes(float scale_factor) 1121bf215546Sopenharmony_ci{ 1122bf215546Sopenharmony_ci WindowPadding = ImFloor(WindowPadding * scale_factor); 1123bf215546Sopenharmony_ci WindowRounding = ImFloor(WindowRounding * scale_factor); 1124bf215546Sopenharmony_ci WindowMinSize = ImFloor(WindowMinSize * scale_factor); 1125bf215546Sopenharmony_ci ChildRounding = ImFloor(ChildRounding * scale_factor); 1126bf215546Sopenharmony_ci PopupRounding = ImFloor(PopupRounding * scale_factor); 1127bf215546Sopenharmony_ci FramePadding = ImFloor(FramePadding * scale_factor); 1128bf215546Sopenharmony_ci FrameRounding = ImFloor(FrameRounding * scale_factor); 1129bf215546Sopenharmony_ci ItemSpacing = ImFloor(ItemSpacing * scale_factor); 1130bf215546Sopenharmony_ci ItemInnerSpacing = ImFloor(ItemInnerSpacing * scale_factor); 1131bf215546Sopenharmony_ci TouchExtraPadding = ImFloor(TouchExtraPadding * scale_factor); 1132bf215546Sopenharmony_ci IndentSpacing = ImFloor(IndentSpacing * scale_factor); 1133bf215546Sopenharmony_ci ColumnsMinSpacing = ImFloor(ColumnsMinSpacing * scale_factor); 1134bf215546Sopenharmony_ci ScrollbarSize = ImFloor(ScrollbarSize * scale_factor); 1135bf215546Sopenharmony_ci ScrollbarRounding = ImFloor(ScrollbarRounding * scale_factor); 1136bf215546Sopenharmony_ci GrabMinSize = ImFloor(GrabMinSize * scale_factor); 1137bf215546Sopenharmony_ci GrabRounding = ImFloor(GrabRounding * scale_factor); 1138bf215546Sopenharmony_ci TabRounding = ImFloor(TabRounding * scale_factor); 1139bf215546Sopenharmony_ci DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor); 1140bf215546Sopenharmony_ci DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor); 1141bf215546Sopenharmony_ci MouseCursorScale = ImFloor(MouseCursorScale * scale_factor); 1142bf215546Sopenharmony_ci} 1143bf215546Sopenharmony_ci 1144bf215546Sopenharmony_ciImGuiIO::ImGuiIO() 1145bf215546Sopenharmony_ci{ 1146bf215546Sopenharmony_ci // Most fields are initialized with zero 1147bf215546Sopenharmony_ci memset(this, 0, sizeof(*this)); 1148bf215546Sopenharmony_ci 1149bf215546Sopenharmony_ci // Settings 1150bf215546Sopenharmony_ci ConfigFlags = ImGuiConfigFlags_None; 1151bf215546Sopenharmony_ci BackendFlags = ImGuiBackendFlags_None; 1152bf215546Sopenharmony_ci DisplaySize = ImVec2(-1.0f, -1.0f); 1153bf215546Sopenharmony_ci DeltaTime = 1.0f/60.0f; 1154bf215546Sopenharmony_ci IniSavingRate = 5.0f; 1155bf215546Sopenharmony_ci IniFilename = "imgui.ini"; 1156bf215546Sopenharmony_ci LogFilename = "imgui_log.txt"; 1157bf215546Sopenharmony_ci MouseDoubleClickTime = 0.30f; 1158bf215546Sopenharmony_ci MouseDoubleClickMaxDist = 6.0f; 1159bf215546Sopenharmony_ci for (int i = 0; i < ImGuiKey_COUNT; i++) 1160bf215546Sopenharmony_ci KeyMap[i] = -1; 1161bf215546Sopenharmony_ci KeyRepeatDelay = 0.250f; 1162bf215546Sopenharmony_ci KeyRepeatRate = 0.050f; 1163bf215546Sopenharmony_ci UserData = NULL; 1164bf215546Sopenharmony_ci 1165bf215546Sopenharmony_ci Fonts = NULL; 1166bf215546Sopenharmony_ci FontGlobalScale = 1.0f; 1167bf215546Sopenharmony_ci FontDefault = NULL; 1168bf215546Sopenharmony_ci FontAllowUserScaling = false; 1169bf215546Sopenharmony_ci DisplayFramebufferScale = ImVec2(1.0f, 1.0f); 1170bf215546Sopenharmony_ci 1171bf215546Sopenharmony_ci // Miscellaneous options 1172bf215546Sopenharmony_ci MouseDrawCursor = false; 1173bf215546Sopenharmony_ci#ifdef __APPLE__ 1174bf215546Sopenharmony_ci ConfigMacOSXBehaviors = true; // Set Mac OS X style defaults based on __APPLE__ compile time flag 1175bf215546Sopenharmony_ci#else 1176bf215546Sopenharmony_ci ConfigMacOSXBehaviors = false; 1177bf215546Sopenharmony_ci#endif 1178bf215546Sopenharmony_ci ConfigInputTextCursorBlink = true; 1179bf215546Sopenharmony_ci ConfigWindowsResizeFromEdges = true; 1180bf215546Sopenharmony_ci ConfigWindowsMoveFromTitleBarOnly = false; 1181bf215546Sopenharmony_ci 1182bf215546Sopenharmony_ci // Platform Functions 1183bf215546Sopenharmony_ci BackendPlatformName = BackendRendererName = NULL; 1184bf215546Sopenharmony_ci BackendPlatformUserData = BackendRendererUserData = BackendLanguageUserData = NULL; 1185bf215546Sopenharmony_ci GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations 1186bf215546Sopenharmony_ci SetClipboardTextFn = SetClipboardTextFn_DefaultImpl; 1187bf215546Sopenharmony_ci ClipboardUserData = NULL; 1188bf215546Sopenharmony_ci ImeSetInputScreenPosFn = ImeSetInputScreenPosFn_DefaultImpl; 1189bf215546Sopenharmony_ci ImeWindowHandle = NULL; 1190bf215546Sopenharmony_ci 1191bf215546Sopenharmony_ci#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS 1192bf215546Sopenharmony_ci RenderDrawListsFn = NULL; 1193bf215546Sopenharmony_ci#endif 1194bf215546Sopenharmony_ci 1195bf215546Sopenharmony_ci // Input (NB: we already have memset zero the entire structure!) 1196bf215546Sopenharmony_ci MousePos = ImVec2(-FLT_MAX, -FLT_MAX); 1197bf215546Sopenharmony_ci MousePosPrev = ImVec2(-FLT_MAX, -FLT_MAX); 1198bf215546Sopenharmony_ci MouseDragThreshold = 6.0f; 1199bf215546Sopenharmony_ci for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[i] = MouseDownDurationPrev[i] = -1.0f; 1200bf215546Sopenharmony_ci for (int i = 0; i < IM_ARRAYSIZE(KeysDownDuration); i++) KeysDownDuration[i] = KeysDownDurationPrev[i] = -1.0f; 1201bf215546Sopenharmony_ci for (int i = 0; i < IM_ARRAYSIZE(NavInputsDownDuration); i++) NavInputsDownDuration[i] = -1.0f; 1202bf215546Sopenharmony_ci} 1203bf215546Sopenharmony_ci 1204bf215546Sopenharmony_ci// Pass in translated ASCII characters for text input. 1205bf215546Sopenharmony_ci// - with glfw you can get those from the callback set in glfwSetCharCallback() 1206bf215546Sopenharmony_ci// - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message 1207bf215546Sopenharmony_civoid ImGuiIO::AddInputCharacter(ImWchar c) 1208bf215546Sopenharmony_ci{ 1209bf215546Sopenharmony_ci InputQueueCharacters.push_back(c); 1210bf215546Sopenharmony_ci} 1211bf215546Sopenharmony_ci 1212bf215546Sopenharmony_civoid ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars) 1213bf215546Sopenharmony_ci{ 1214bf215546Sopenharmony_ci while (*utf8_chars != 0) 1215bf215546Sopenharmony_ci { 1216bf215546Sopenharmony_ci unsigned int c = 0; 1217bf215546Sopenharmony_ci utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL); 1218bf215546Sopenharmony_ci if (c > 0 && c <= 0xFFFF) 1219bf215546Sopenharmony_ci InputQueueCharacters.push_back((ImWchar)c); 1220bf215546Sopenharmony_ci } 1221bf215546Sopenharmony_ci} 1222bf215546Sopenharmony_ci 1223bf215546Sopenharmony_civoid ImGuiIO::ClearInputCharacters() 1224bf215546Sopenharmony_ci{ 1225bf215546Sopenharmony_ci InputQueueCharacters.resize(0); 1226bf215546Sopenharmony_ci} 1227bf215546Sopenharmony_ci 1228bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 1229bf215546Sopenharmony_ci// [SECTION] MISC HELPER/UTILITIES (Maths, String, Format, Hash, File functions) 1230bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 1231bf215546Sopenharmony_ci 1232bf215546Sopenharmony_ciImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p) 1233bf215546Sopenharmony_ci{ 1234bf215546Sopenharmony_ci ImVec2 ap = p - a; 1235bf215546Sopenharmony_ci ImVec2 ab_dir = b - a; 1236bf215546Sopenharmony_ci float dot = ap.x * ab_dir.x + ap.y * ab_dir.y; 1237bf215546Sopenharmony_ci if (dot < 0.0f) 1238bf215546Sopenharmony_ci return a; 1239bf215546Sopenharmony_ci float ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y; 1240bf215546Sopenharmony_ci if (dot > ab_len_sqr) 1241bf215546Sopenharmony_ci return b; 1242bf215546Sopenharmony_ci return a + ab_dir * dot / ab_len_sqr; 1243bf215546Sopenharmony_ci} 1244bf215546Sopenharmony_ci 1245bf215546Sopenharmony_cibool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p) 1246bf215546Sopenharmony_ci{ 1247bf215546Sopenharmony_ci bool b1 = ((p.x - b.x) * (a.y - b.y) - (p.y - b.y) * (a.x - b.x)) < 0.0f; 1248bf215546Sopenharmony_ci bool b2 = ((p.x - c.x) * (b.y - c.y) - (p.y - c.y) * (b.x - c.x)) < 0.0f; 1249bf215546Sopenharmony_ci bool b3 = ((p.x - a.x) * (c.y - a.y) - (p.y - a.y) * (c.x - a.x)) < 0.0f; 1250bf215546Sopenharmony_ci return ((b1 == b2) && (b2 == b3)); 1251bf215546Sopenharmony_ci} 1252bf215546Sopenharmony_ci 1253bf215546Sopenharmony_civoid ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w) 1254bf215546Sopenharmony_ci{ 1255bf215546Sopenharmony_ci ImVec2 v0 = b - a; 1256bf215546Sopenharmony_ci ImVec2 v1 = c - a; 1257bf215546Sopenharmony_ci ImVec2 v2 = p - a; 1258bf215546Sopenharmony_ci const float denom = v0.x * v1.y - v1.x * v0.y; 1259bf215546Sopenharmony_ci out_v = (v2.x * v1.y - v1.x * v2.y) / denom; 1260bf215546Sopenharmony_ci out_w = (v0.x * v2.y - v2.x * v0.y) / denom; 1261bf215546Sopenharmony_ci out_u = 1.0f - out_v - out_w; 1262bf215546Sopenharmony_ci} 1263bf215546Sopenharmony_ci 1264bf215546Sopenharmony_ciImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p) 1265bf215546Sopenharmony_ci{ 1266bf215546Sopenharmony_ci ImVec2 proj_ab = ImLineClosestPoint(a, b, p); 1267bf215546Sopenharmony_ci ImVec2 proj_bc = ImLineClosestPoint(b, c, p); 1268bf215546Sopenharmony_ci ImVec2 proj_ca = ImLineClosestPoint(c, a, p); 1269bf215546Sopenharmony_ci float dist2_ab = ImLengthSqr(p - proj_ab); 1270bf215546Sopenharmony_ci float dist2_bc = ImLengthSqr(p - proj_bc); 1271bf215546Sopenharmony_ci float dist2_ca = ImLengthSqr(p - proj_ca); 1272bf215546Sopenharmony_ci float m = ImMin(dist2_ab, ImMin(dist2_bc, dist2_ca)); 1273bf215546Sopenharmony_ci if (m == dist2_ab) 1274bf215546Sopenharmony_ci return proj_ab; 1275bf215546Sopenharmony_ci if (m == dist2_bc) 1276bf215546Sopenharmony_ci return proj_bc; 1277bf215546Sopenharmony_ci return proj_ca; 1278bf215546Sopenharmony_ci} 1279bf215546Sopenharmony_ci 1280bf215546Sopenharmony_ci// Consider using _stricmp/_strnicmp under Windows or strcasecmp/strncasecmp. We don't actually use either ImStricmp/ImStrnicmp in the codebase any more. 1281bf215546Sopenharmony_ciint ImStricmp(const char* str1, const char* str2) 1282bf215546Sopenharmony_ci{ 1283bf215546Sopenharmony_ci int d; 1284bf215546Sopenharmony_ci while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; } 1285bf215546Sopenharmony_ci return d; 1286bf215546Sopenharmony_ci} 1287bf215546Sopenharmony_ci 1288bf215546Sopenharmony_ciint ImStrnicmp(const char* str1, const char* str2, size_t count) 1289bf215546Sopenharmony_ci{ 1290bf215546Sopenharmony_ci int d = 0; 1291bf215546Sopenharmony_ci while (count > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; count--; } 1292bf215546Sopenharmony_ci return d; 1293bf215546Sopenharmony_ci} 1294bf215546Sopenharmony_ci 1295bf215546Sopenharmony_civoid ImStrncpy(char* dst, const char* src, size_t count) 1296bf215546Sopenharmony_ci{ 1297bf215546Sopenharmony_ci if (count < 1) 1298bf215546Sopenharmony_ci return; 1299bf215546Sopenharmony_ci if (count > 1) 1300bf215546Sopenharmony_ci strncpy(dst, src, count - 1); 1301bf215546Sopenharmony_ci dst[count - 1] = 0; 1302bf215546Sopenharmony_ci} 1303bf215546Sopenharmony_ci 1304bf215546Sopenharmony_cichar* ImStrdup(const char* str) 1305bf215546Sopenharmony_ci{ 1306bf215546Sopenharmony_ci size_t len = strlen(str); 1307bf215546Sopenharmony_ci void* buf = ImGui::MemAlloc(len + 1); 1308bf215546Sopenharmony_ci return (char*)memcpy(buf, (const void*)str, len + 1); 1309bf215546Sopenharmony_ci} 1310bf215546Sopenharmony_ci 1311bf215546Sopenharmony_cichar* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* src) 1312bf215546Sopenharmony_ci{ 1313bf215546Sopenharmony_ci size_t dst_buf_size = p_dst_size ? *p_dst_size : strlen(dst) + 1; 1314bf215546Sopenharmony_ci size_t src_size = strlen(src) + 1; 1315bf215546Sopenharmony_ci if (dst_buf_size < src_size) 1316bf215546Sopenharmony_ci { 1317bf215546Sopenharmony_ci ImGui::MemFree(dst); 1318bf215546Sopenharmony_ci dst = (char*)ImGui::MemAlloc(src_size); 1319bf215546Sopenharmony_ci if (p_dst_size) 1320bf215546Sopenharmony_ci *p_dst_size = src_size; 1321bf215546Sopenharmony_ci } 1322bf215546Sopenharmony_ci return (char*)memcpy(dst, (const void*)src, src_size); 1323bf215546Sopenharmony_ci} 1324bf215546Sopenharmony_ci 1325bf215546Sopenharmony_ciconst char* ImStrchrRange(const char* str, const char* str_end, char c) 1326bf215546Sopenharmony_ci{ 1327bf215546Sopenharmony_ci const char* p = (const char*)memchr(str, (int)c, str_end - str); 1328bf215546Sopenharmony_ci return p; 1329bf215546Sopenharmony_ci} 1330bf215546Sopenharmony_ci 1331bf215546Sopenharmony_ciint ImStrlenW(const ImWchar* str) 1332bf215546Sopenharmony_ci{ 1333bf215546Sopenharmony_ci //return (int)wcslen((const wchar_t*)str); // FIXME-OPT: Could use this when wchar_t are 16-bits 1334bf215546Sopenharmony_ci int n = 0; 1335bf215546Sopenharmony_ci while (*str++) n++; 1336bf215546Sopenharmony_ci return n; 1337bf215546Sopenharmony_ci} 1338bf215546Sopenharmony_ci 1339bf215546Sopenharmony_ci// Find end-of-line. Return pointer will point to either first \n, either str_end. 1340bf215546Sopenharmony_ciconst char* ImStreolRange(const char* str, const char* str_end) 1341bf215546Sopenharmony_ci{ 1342bf215546Sopenharmony_ci const char* p = (const char*)memchr(str, '\n', str_end - str); 1343bf215546Sopenharmony_ci return p ? p : str_end; 1344bf215546Sopenharmony_ci} 1345bf215546Sopenharmony_ci 1346bf215546Sopenharmony_ciconst ImWchar* ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin) // find beginning-of-line 1347bf215546Sopenharmony_ci{ 1348bf215546Sopenharmony_ci while (buf_mid_line > buf_begin && buf_mid_line[-1] != '\n') 1349bf215546Sopenharmony_ci buf_mid_line--; 1350bf215546Sopenharmony_ci return buf_mid_line; 1351bf215546Sopenharmony_ci} 1352bf215546Sopenharmony_ci 1353bf215546Sopenharmony_ciconst char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end) 1354bf215546Sopenharmony_ci{ 1355bf215546Sopenharmony_ci if (!needle_end) 1356bf215546Sopenharmony_ci needle_end = needle + strlen(needle); 1357bf215546Sopenharmony_ci 1358bf215546Sopenharmony_ci const char un0 = (char)toupper(*needle); 1359bf215546Sopenharmony_ci while ((!haystack_end && *haystack) || (haystack_end && haystack < haystack_end)) 1360bf215546Sopenharmony_ci { 1361bf215546Sopenharmony_ci if (toupper(*haystack) == un0) 1362bf215546Sopenharmony_ci { 1363bf215546Sopenharmony_ci const char* b = needle + 1; 1364bf215546Sopenharmony_ci for (const char* a = haystack + 1; b < needle_end; a++, b++) 1365bf215546Sopenharmony_ci if (toupper(*a) != toupper(*b)) 1366bf215546Sopenharmony_ci break; 1367bf215546Sopenharmony_ci if (b == needle_end) 1368bf215546Sopenharmony_ci return haystack; 1369bf215546Sopenharmony_ci } 1370bf215546Sopenharmony_ci haystack++; 1371bf215546Sopenharmony_ci } 1372bf215546Sopenharmony_ci return NULL; 1373bf215546Sopenharmony_ci} 1374bf215546Sopenharmony_ci 1375bf215546Sopenharmony_ci// 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. 1376bf215546Sopenharmony_civoid ImStrTrimBlanks(char* buf) 1377bf215546Sopenharmony_ci{ 1378bf215546Sopenharmony_ci char* p = buf; 1379bf215546Sopenharmony_ci while (p[0] == ' ' || p[0] == '\t') // Leading blanks 1380bf215546Sopenharmony_ci p++; 1381bf215546Sopenharmony_ci char* p_start = p; 1382bf215546Sopenharmony_ci while (*p != 0) // Find end of string 1383bf215546Sopenharmony_ci p++; 1384bf215546Sopenharmony_ci while (p > p_start && (p[-1] == ' ' || p[-1] == '\t')) // Trailing blanks 1385bf215546Sopenharmony_ci p--; 1386bf215546Sopenharmony_ci if (p_start != buf) // Copy memory if we had leading blanks 1387bf215546Sopenharmony_ci memmove(buf, p_start, p - p_start); 1388bf215546Sopenharmony_ci buf[p - p_start] = 0; // Zero terminate 1389bf215546Sopenharmony_ci} 1390bf215546Sopenharmony_ci 1391bf215546Sopenharmony_ci// A) MSVC version appears to return -1 on overflow, whereas glibc appears to return total count (which may be >= buf_size). 1392bf215546Sopenharmony_ci// 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. 1393bf215546Sopenharmony_ci// B) When buf==NULL vsnprintf() will return the output size. 1394bf215546Sopenharmony_ci#ifndef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS 1395bf215546Sopenharmony_ci 1396bf215546Sopenharmony_ci//#define IMGUI_USE_STB_SPRINTF 1397bf215546Sopenharmony_ci#ifdef IMGUI_USE_STB_SPRINTF 1398bf215546Sopenharmony_ci#define STB_SPRINTF_IMPLEMENTATION 1399bf215546Sopenharmony_ci#include "imstb_sprintf.h" 1400bf215546Sopenharmony_ci#endif 1401bf215546Sopenharmony_ci 1402bf215546Sopenharmony_ci#if defined(_MSC_VER) && !defined(vsnprintf) 1403bf215546Sopenharmony_ci#define vsnprintf _vsnprintf 1404bf215546Sopenharmony_ci#endif 1405bf215546Sopenharmony_ci 1406bf215546Sopenharmony_ciint ImFormatString(char* buf, size_t buf_size, const char* fmt, ...) 1407bf215546Sopenharmony_ci{ 1408bf215546Sopenharmony_ci va_list args; 1409bf215546Sopenharmony_ci va_start(args, fmt); 1410bf215546Sopenharmony_ci#ifdef IMGUI_USE_STB_SPRINTF 1411bf215546Sopenharmony_ci int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args); 1412bf215546Sopenharmony_ci#else 1413bf215546Sopenharmony_ci int w = vsnprintf(buf, buf_size, fmt, args); 1414bf215546Sopenharmony_ci#endif 1415bf215546Sopenharmony_ci va_end(args); 1416bf215546Sopenharmony_ci if (buf == NULL) 1417bf215546Sopenharmony_ci return w; 1418bf215546Sopenharmony_ci if (w == -1 || w >= (int)buf_size) 1419bf215546Sopenharmony_ci w = (int)buf_size - 1; 1420bf215546Sopenharmony_ci buf[w] = 0; 1421bf215546Sopenharmony_ci return w; 1422bf215546Sopenharmony_ci} 1423bf215546Sopenharmony_ci 1424bf215546Sopenharmony_ciint ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) 1425bf215546Sopenharmony_ci{ 1426bf215546Sopenharmony_ci#ifdef IMGUI_USE_STB_SPRINTF 1427bf215546Sopenharmony_ci int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args); 1428bf215546Sopenharmony_ci#else 1429bf215546Sopenharmony_ci int w = vsnprintf(buf, buf_size, fmt, args); 1430bf215546Sopenharmony_ci#endif 1431bf215546Sopenharmony_ci if (buf == NULL) 1432bf215546Sopenharmony_ci return w; 1433bf215546Sopenharmony_ci if (w == -1 || w >= (int)buf_size) 1434bf215546Sopenharmony_ci w = (int)buf_size - 1; 1435bf215546Sopenharmony_ci buf[w] = 0; 1436bf215546Sopenharmony_ci return w; 1437bf215546Sopenharmony_ci} 1438bf215546Sopenharmony_ci#endif // #ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS 1439bf215546Sopenharmony_ci 1440bf215546Sopenharmony_ci// CRC32 needs a 1KB lookup table (not cache friendly) 1441bf215546Sopenharmony_ci// Although the code to generate the table is simple and shorter than the table itself, using a const table allows us to easily: 1442bf215546Sopenharmony_ci// - avoid an unnecessary branch/memory tap, - keep the ImHashXXX functions usable by static constructors, - make it thread-safe. 1443bf215546Sopenharmony_cistatic const ImU32 GCrc32LookupTable[256] = 1444bf215546Sopenharmony_ci{ 1445bf215546Sopenharmony_ci 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91, 1446bf215546Sopenharmony_ci 0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5, 1447bf215546Sopenharmony_ci 0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59, 1448bf215546Sopenharmony_ci 0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F,0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D, 1449bf215546Sopenharmony_ci 0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01, 1450bf215546Sopenharmony_ci 0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65, 1451bf215546Sopenharmony_ci 0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9, 1452bf215546Sopenharmony_ci 0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD, 1453bf215546Sopenharmony_ci 0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1, 1454bf215546Sopenharmony_ci 0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5, 1455bf215546Sopenharmony_ci 0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79, 1456bf215546Sopenharmony_ci 0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D, 1457bf215546Sopenharmony_ci 0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21, 1458bf215546Sopenharmony_ci 0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45, 1459bf215546Sopenharmony_ci 0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9, 1460bf215546Sopenharmony_ci 0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D, 1461bf215546Sopenharmony_ci}; 1462bf215546Sopenharmony_ci 1463bf215546Sopenharmony_ci// Known size hash 1464bf215546Sopenharmony_ci// It is ok to call ImHashData on a string with known length but the ### operator won't be supported. 1465bf215546Sopenharmony_ci// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements. 1466bf215546Sopenharmony_ciImU32 ImHashData(const void* data_p, size_t data_size, ImU32 seed) 1467bf215546Sopenharmony_ci{ 1468bf215546Sopenharmony_ci ImU32 crc = ~seed; 1469bf215546Sopenharmony_ci const unsigned char* data = (const unsigned char*)data_p; 1470bf215546Sopenharmony_ci const ImU32* crc32_lut = GCrc32LookupTable; 1471bf215546Sopenharmony_ci while (data_size-- != 0) 1472bf215546Sopenharmony_ci crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *data++]; 1473bf215546Sopenharmony_ci return ~crc; 1474bf215546Sopenharmony_ci} 1475bf215546Sopenharmony_ci 1476bf215546Sopenharmony_ci// Zero-terminated string hash, with support for ### to reset back to seed value 1477bf215546Sopenharmony_ci// We support a syntax of "label###id" where only "###id" is included in the hash, and only "label" gets displayed. 1478bf215546Sopenharmony_ci// Because this syntax is rarely used we are optimizing for the common case. 1479bf215546Sopenharmony_ci// - If we reach ### in the string we discard the hash so far and reset to the seed. 1480bf215546Sopenharmony_ci// - We don't do 'current += 2; continue;' after handling ### to keep the code smaller/faster (measured ~10% diff in Debug build) 1481bf215546Sopenharmony_ci// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements. 1482bf215546Sopenharmony_ciImU32 ImHashStr(const char* data, size_t data_size, ImU32 seed) 1483bf215546Sopenharmony_ci{ 1484bf215546Sopenharmony_ci seed = ~seed; 1485bf215546Sopenharmony_ci ImU32 crc = seed; 1486bf215546Sopenharmony_ci const unsigned char* src = (const unsigned char*)data; 1487bf215546Sopenharmony_ci const ImU32* crc32_lut = GCrc32LookupTable; 1488bf215546Sopenharmony_ci if (data_size != 0) 1489bf215546Sopenharmony_ci { 1490bf215546Sopenharmony_ci while (data_size-- != 0) 1491bf215546Sopenharmony_ci { 1492bf215546Sopenharmony_ci unsigned char c = *src++; 1493bf215546Sopenharmony_ci if (c == '#' && src[0] == '#' && src[1] == '#') 1494bf215546Sopenharmony_ci crc = seed; 1495bf215546Sopenharmony_ci crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c]; 1496bf215546Sopenharmony_ci } 1497bf215546Sopenharmony_ci } 1498bf215546Sopenharmony_ci else 1499bf215546Sopenharmony_ci { 1500bf215546Sopenharmony_ci while (unsigned char c = *src++) 1501bf215546Sopenharmony_ci { 1502bf215546Sopenharmony_ci if (c == '#' && src[0] == '#' && src[1] == '#') 1503bf215546Sopenharmony_ci crc = seed; 1504bf215546Sopenharmony_ci crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c]; 1505bf215546Sopenharmony_ci } 1506bf215546Sopenharmony_ci } 1507bf215546Sopenharmony_ci return ~crc; 1508bf215546Sopenharmony_ci} 1509bf215546Sopenharmony_ci 1510bf215546Sopenharmony_ciFILE* ImFileOpen(const char* filename, const char* mode) 1511bf215546Sopenharmony_ci{ 1512bf215546Sopenharmony_ci#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__GNUC__) 1513bf215546Sopenharmony_ci // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames. Converting both strings from UTF-8 to wchar format (using a single allocation, because we can) 1514bf215546Sopenharmony_ci const int filename_wsize = ImTextCountCharsFromUtf8(filename, NULL) + 1; 1515bf215546Sopenharmony_ci const int mode_wsize = ImTextCountCharsFromUtf8(mode, NULL) + 1; 1516bf215546Sopenharmony_ci ImVector<ImWchar> buf; 1517bf215546Sopenharmony_ci buf.resize(filename_wsize + mode_wsize); 1518bf215546Sopenharmony_ci ImTextStrFromUtf8(&buf[0], filename_wsize, filename, NULL); 1519bf215546Sopenharmony_ci ImTextStrFromUtf8(&buf[filename_wsize], mode_wsize, mode, NULL); 1520bf215546Sopenharmony_ci return _wfopen((wchar_t*)&buf[0], (wchar_t*)&buf[filename_wsize]); 1521bf215546Sopenharmony_ci#else 1522bf215546Sopenharmony_ci return fopen(filename, mode); 1523bf215546Sopenharmony_ci#endif 1524bf215546Sopenharmony_ci} 1525bf215546Sopenharmony_ci 1526bf215546Sopenharmony_ci// Load file content into memory 1527bf215546Sopenharmony_ci// Memory allocated with ImGui::MemAlloc(), must be freed by user using ImGui::MemFree() 1528bf215546Sopenharmony_civoid* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_t* out_file_size, int padding_bytes) 1529bf215546Sopenharmony_ci{ 1530bf215546Sopenharmony_ci IM_ASSERT(filename && file_open_mode); 1531bf215546Sopenharmony_ci if (out_file_size) 1532bf215546Sopenharmony_ci *out_file_size = 0; 1533bf215546Sopenharmony_ci 1534bf215546Sopenharmony_ci FILE* f; 1535bf215546Sopenharmony_ci if ((f = ImFileOpen(filename, file_open_mode)) == NULL) 1536bf215546Sopenharmony_ci return NULL; 1537bf215546Sopenharmony_ci 1538bf215546Sopenharmony_ci long file_size_signed; 1539bf215546Sopenharmony_ci if (fseek(f, 0, SEEK_END) || (file_size_signed = ftell(f)) == -1 || fseek(f, 0, SEEK_SET)) 1540bf215546Sopenharmony_ci { 1541bf215546Sopenharmony_ci fclose(f); 1542bf215546Sopenharmony_ci return NULL; 1543bf215546Sopenharmony_ci } 1544bf215546Sopenharmony_ci 1545bf215546Sopenharmony_ci size_t file_size = (size_t)file_size_signed; 1546bf215546Sopenharmony_ci void* file_data = ImGui::MemAlloc(file_size + padding_bytes); 1547bf215546Sopenharmony_ci if (file_data == NULL) 1548bf215546Sopenharmony_ci { 1549bf215546Sopenharmony_ci fclose(f); 1550bf215546Sopenharmony_ci return NULL; 1551bf215546Sopenharmony_ci } 1552bf215546Sopenharmony_ci if (fread(file_data, 1, file_size, f) != file_size) 1553bf215546Sopenharmony_ci { 1554bf215546Sopenharmony_ci fclose(f); 1555bf215546Sopenharmony_ci ImGui::MemFree(file_data); 1556bf215546Sopenharmony_ci return NULL; 1557bf215546Sopenharmony_ci } 1558bf215546Sopenharmony_ci if (padding_bytes > 0) 1559bf215546Sopenharmony_ci memset((void*)(((char*)file_data) + file_size), 0, (size_t)padding_bytes); 1560bf215546Sopenharmony_ci 1561bf215546Sopenharmony_ci fclose(f); 1562bf215546Sopenharmony_ci if (out_file_size) 1563bf215546Sopenharmony_ci *out_file_size = file_size; 1564bf215546Sopenharmony_ci 1565bf215546Sopenharmony_ci return file_data; 1566bf215546Sopenharmony_ci} 1567bf215546Sopenharmony_ci 1568bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 1569bf215546Sopenharmony_ci// [SECTION] MISC HELPERS/UTILITIES (ImText* functions) 1570bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 1571bf215546Sopenharmony_ci 1572bf215546Sopenharmony_ci// Convert UTF-8 to 32-bits character, process single character input. 1573bf215546Sopenharmony_ci// Based on stb_from_utf8() from github.com/nothings/stb/ 1574bf215546Sopenharmony_ci// We handle UTF-8 decoding error by skipping forward. 1575bf215546Sopenharmony_ciint ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end) 1576bf215546Sopenharmony_ci{ 1577bf215546Sopenharmony_ci unsigned int c = (unsigned int)-1; 1578bf215546Sopenharmony_ci const unsigned char* str = (const unsigned char*)in_text; 1579bf215546Sopenharmony_ci if (!(*str & 0x80)) 1580bf215546Sopenharmony_ci { 1581bf215546Sopenharmony_ci c = (unsigned int)(*str++); 1582bf215546Sopenharmony_ci *out_char = c; 1583bf215546Sopenharmony_ci return 1; 1584bf215546Sopenharmony_ci } 1585bf215546Sopenharmony_ci if ((*str & 0xe0) == 0xc0) 1586bf215546Sopenharmony_ci { 1587bf215546Sopenharmony_ci *out_char = 0xFFFD; // will be invalid but not end of string 1588bf215546Sopenharmony_ci if (in_text_end && in_text_end - (const char*)str < 2) return 1; 1589bf215546Sopenharmony_ci if (*str < 0xc2) return 2; 1590bf215546Sopenharmony_ci c = (unsigned int)((*str++ & 0x1f) << 6); 1591bf215546Sopenharmony_ci if ((*str & 0xc0) != 0x80) return 2; 1592bf215546Sopenharmony_ci c += (*str++ & 0x3f); 1593bf215546Sopenharmony_ci *out_char = c; 1594bf215546Sopenharmony_ci return 2; 1595bf215546Sopenharmony_ci } 1596bf215546Sopenharmony_ci if ((*str & 0xf0) == 0xe0) 1597bf215546Sopenharmony_ci { 1598bf215546Sopenharmony_ci *out_char = 0xFFFD; // will be invalid but not end of string 1599bf215546Sopenharmony_ci if (in_text_end && in_text_end - (const char*)str < 3) return 1; 1600bf215546Sopenharmony_ci if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return 3; 1601bf215546Sopenharmony_ci if (*str == 0xed && str[1] > 0x9f) return 3; // str[1] < 0x80 is checked below 1602bf215546Sopenharmony_ci c = (unsigned int)((*str++ & 0x0f) << 12); 1603bf215546Sopenharmony_ci if ((*str & 0xc0) != 0x80) return 3; 1604bf215546Sopenharmony_ci c += (unsigned int)((*str++ & 0x3f) << 6); 1605bf215546Sopenharmony_ci if ((*str & 0xc0) != 0x80) return 3; 1606bf215546Sopenharmony_ci c += (*str++ & 0x3f); 1607bf215546Sopenharmony_ci *out_char = c; 1608bf215546Sopenharmony_ci return 3; 1609bf215546Sopenharmony_ci } 1610bf215546Sopenharmony_ci if ((*str & 0xf8) == 0xf0) 1611bf215546Sopenharmony_ci { 1612bf215546Sopenharmony_ci *out_char = 0xFFFD; // will be invalid but not end of string 1613bf215546Sopenharmony_ci if (in_text_end && in_text_end - (const char*)str < 4) return 1; 1614bf215546Sopenharmony_ci if (*str > 0xf4) return 4; 1615bf215546Sopenharmony_ci if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return 4; 1616bf215546Sopenharmony_ci if (*str == 0xf4 && str[1] > 0x8f) return 4; // str[1] < 0x80 is checked below 1617bf215546Sopenharmony_ci c = (unsigned int)((*str++ & 0x07) << 18); 1618bf215546Sopenharmony_ci if ((*str & 0xc0) != 0x80) return 4; 1619bf215546Sopenharmony_ci c += (unsigned int)((*str++ & 0x3f) << 12); 1620bf215546Sopenharmony_ci if ((*str & 0xc0) != 0x80) return 4; 1621bf215546Sopenharmony_ci c += (unsigned int)((*str++ & 0x3f) << 6); 1622bf215546Sopenharmony_ci if ((*str & 0xc0) != 0x80) return 4; 1623bf215546Sopenharmony_ci c += (*str++ & 0x3f); 1624bf215546Sopenharmony_ci // utf-8 encodings of values used in surrogate pairs are invalid 1625bf215546Sopenharmony_ci if ((c & 0xFFFFF800) == 0xD800) return 4; 1626bf215546Sopenharmony_ci *out_char = c; 1627bf215546Sopenharmony_ci return 4; 1628bf215546Sopenharmony_ci } 1629bf215546Sopenharmony_ci *out_char = 0; 1630bf215546Sopenharmony_ci return 0; 1631bf215546Sopenharmony_ci} 1632bf215546Sopenharmony_ci 1633bf215546Sopenharmony_ciint ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_text_remaining) 1634bf215546Sopenharmony_ci{ 1635bf215546Sopenharmony_ci ImWchar* buf_out = buf; 1636bf215546Sopenharmony_ci ImWchar* buf_end = buf + buf_size; 1637bf215546Sopenharmony_ci while (buf_out < buf_end-1 && (!in_text_end || in_text < in_text_end) && *in_text) 1638bf215546Sopenharmony_ci { 1639bf215546Sopenharmony_ci unsigned int c; 1640bf215546Sopenharmony_ci in_text += ImTextCharFromUtf8(&c, in_text, in_text_end); 1641bf215546Sopenharmony_ci if (c == 0) 1642bf215546Sopenharmony_ci break; 1643bf215546Sopenharmony_ci if (c < 0x10000) // FIXME: Losing characters that don't fit in 2 bytes 1644bf215546Sopenharmony_ci *buf_out++ = (ImWchar)c; 1645bf215546Sopenharmony_ci } 1646bf215546Sopenharmony_ci *buf_out = 0; 1647bf215546Sopenharmony_ci if (in_text_remaining) 1648bf215546Sopenharmony_ci *in_text_remaining = in_text; 1649bf215546Sopenharmony_ci return (int)(buf_out - buf); 1650bf215546Sopenharmony_ci} 1651bf215546Sopenharmony_ci 1652bf215546Sopenharmony_ciint ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end) 1653bf215546Sopenharmony_ci{ 1654bf215546Sopenharmony_ci int char_count = 0; 1655bf215546Sopenharmony_ci while ((!in_text_end || in_text < in_text_end) && *in_text) 1656bf215546Sopenharmony_ci { 1657bf215546Sopenharmony_ci unsigned int c; 1658bf215546Sopenharmony_ci in_text += ImTextCharFromUtf8(&c, in_text, in_text_end); 1659bf215546Sopenharmony_ci if (c == 0) 1660bf215546Sopenharmony_ci break; 1661bf215546Sopenharmony_ci if (c < 0x10000) 1662bf215546Sopenharmony_ci char_count++; 1663bf215546Sopenharmony_ci } 1664bf215546Sopenharmony_ci return char_count; 1665bf215546Sopenharmony_ci} 1666bf215546Sopenharmony_ci 1667bf215546Sopenharmony_ci// Based on stb_to_utf8() from github.com/nothings/stb/ 1668bf215546Sopenharmony_cistatic inline int ImTextCharToUtf8(char* buf, int buf_size, unsigned int c) 1669bf215546Sopenharmony_ci{ 1670bf215546Sopenharmony_ci if (c < 0x80) 1671bf215546Sopenharmony_ci { 1672bf215546Sopenharmony_ci buf[0] = (char)c; 1673bf215546Sopenharmony_ci return 1; 1674bf215546Sopenharmony_ci } 1675bf215546Sopenharmony_ci if (c < 0x800) 1676bf215546Sopenharmony_ci { 1677bf215546Sopenharmony_ci if (buf_size < 2) return 0; 1678bf215546Sopenharmony_ci buf[0] = (char)(0xc0 + (c >> 6)); 1679bf215546Sopenharmony_ci buf[1] = (char)(0x80 + (c & 0x3f)); 1680bf215546Sopenharmony_ci return 2; 1681bf215546Sopenharmony_ci } 1682bf215546Sopenharmony_ci if (c >= 0xdc00 && c < 0xe000) 1683bf215546Sopenharmony_ci { 1684bf215546Sopenharmony_ci return 0; 1685bf215546Sopenharmony_ci } 1686bf215546Sopenharmony_ci if (c >= 0xd800 && c < 0xdc00) 1687bf215546Sopenharmony_ci { 1688bf215546Sopenharmony_ci if (buf_size < 4) return 0; 1689bf215546Sopenharmony_ci buf[0] = (char)(0xf0 + (c >> 18)); 1690bf215546Sopenharmony_ci buf[1] = (char)(0x80 + ((c >> 12) & 0x3f)); 1691bf215546Sopenharmony_ci buf[2] = (char)(0x80 + ((c >> 6) & 0x3f)); 1692bf215546Sopenharmony_ci buf[3] = (char)(0x80 + ((c ) & 0x3f)); 1693bf215546Sopenharmony_ci return 4; 1694bf215546Sopenharmony_ci } 1695bf215546Sopenharmony_ci //else if (c < 0x10000) 1696bf215546Sopenharmony_ci { 1697bf215546Sopenharmony_ci if (buf_size < 3) return 0; 1698bf215546Sopenharmony_ci buf[0] = (char)(0xe0 + (c >> 12)); 1699bf215546Sopenharmony_ci buf[1] = (char)(0x80 + ((c>> 6) & 0x3f)); 1700bf215546Sopenharmony_ci buf[2] = (char)(0x80 + ((c ) & 0x3f)); 1701bf215546Sopenharmony_ci return 3; 1702bf215546Sopenharmony_ci } 1703bf215546Sopenharmony_ci} 1704bf215546Sopenharmony_ci 1705bf215546Sopenharmony_ci// Not optimal but we very rarely use this function. 1706bf215546Sopenharmony_ciint ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end) 1707bf215546Sopenharmony_ci{ 1708bf215546Sopenharmony_ci unsigned int dummy = 0; 1709bf215546Sopenharmony_ci return ImTextCharFromUtf8(&dummy, in_text, in_text_end); 1710bf215546Sopenharmony_ci} 1711bf215546Sopenharmony_ci 1712bf215546Sopenharmony_cistatic inline int ImTextCountUtf8BytesFromChar(unsigned int c) 1713bf215546Sopenharmony_ci{ 1714bf215546Sopenharmony_ci if (c < 0x80) return 1; 1715bf215546Sopenharmony_ci if (c < 0x800) return 2; 1716bf215546Sopenharmony_ci if (c >= 0xdc00 && c < 0xe000) return 0; 1717bf215546Sopenharmony_ci if (c >= 0xd800 && c < 0xdc00) return 4; 1718bf215546Sopenharmony_ci return 3; 1719bf215546Sopenharmony_ci} 1720bf215546Sopenharmony_ci 1721bf215546Sopenharmony_ciint ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end) 1722bf215546Sopenharmony_ci{ 1723bf215546Sopenharmony_ci char* buf_out = buf; 1724bf215546Sopenharmony_ci const char* buf_end = buf + buf_size; 1725bf215546Sopenharmony_ci while (buf_out < buf_end-1 && (!in_text_end || in_text < in_text_end) && *in_text) 1726bf215546Sopenharmony_ci { 1727bf215546Sopenharmony_ci unsigned int c = (unsigned int)(*in_text++); 1728bf215546Sopenharmony_ci if (c < 0x80) 1729bf215546Sopenharmony_ci *buf_out++ = (char)c; 1730bf215546Sopenharmony_ci else 1731bf215546Sopenharmony_ci buf_out += ImTextCharToUtf8(buf_out, (int)(buf_end-buf_out-1), c); 1732bf215546Sopenharmony_ci } 1733bf215546Sopenharmony_ci *buf_out = 0; 1734bf215546Sopenharmony_ci return (int)(buf_out - buf); 1735bf215546Sopenharmony_ci} 1736bf215546Sopenharmony_ci 1737bf215546Sopenharmony_ciint ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end) 1738bf215546Sopenharmony_ci{ 1739bf215546Sopenharmony_ci int bytes_count = 0; 1740bf215546Sopenharmony_ci while ((!in_text_end || in_text < in_text_end) && *in_text) 1741bf215546Sopenharmony_ci { 1742bf215546Sopenharmony_ci unsigned int c = (unsigned int)(*in_text++); 1743bf215546Sopenharmony_ci if (c < 0x80) 1744bf215546Sopenharmony_ci bytes_count++; 1745bf215546Sopenharmony_ci else 1746bf215546Sopenharmony_ci bytes_count += ImTextCountUtf8BytesFromChar(c); 1747bf215546Sopenharmony_ci } 1748bf215546Sopenharmony_ci return bytes_count; 1749bf215546Sopenharmony_ci} 1750bf215546Sopenharmony_ci 1751bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 1752bf215546Sopenharmony_ci// [SECTION] MISC HELPER/UTILTIES (Color functions) 1753bf215546Sopenharmony_ci// Note: The Convert functions are early design which are not consistent with other API. 1754bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 1755bf215546Sopenharmony_ci 1756bf215546Sopenharmony_ciImVec4 ImGui::ColorConvertU32ToFloat4(ImU32 in) 1757bf215546Sopenharmony_ci{ 1758bf215546Sopenharmony_ci float s = 1.0f/255.0f; 1759bf215546Sopenharmony_ci return ImVec4( 1760bf215546Sopenharmony_ci ((in >> IM_COL32_R_SHIFT) & 0xFF) * s, 1761bf215546Sopenharmony_ci ((in >> IM_COL32_G_SHIFT) & 0xFF) * s, 1762bf215546Sopenharmony_ci ((in >> IM_COL32_B_SHIFT) & 0xFF) * s, 1763bf215546Sopenharmony_ci ((in >> IM_COL32_A_SHIFT) & 0xFF) * s); 1764bf215546Sopenharmony_ci} 1765bf215546Sopenharmony_ci 1766bf215546Sopenharmony_ciImU32 ImGui::ColorConvertFloat4ToU32(const ImVec4& in) 1767bf215546Sopenharmony_ci{ 1768bf215546Sopenharmony_ci ImU32 out; 1769bf215546Sopenharmony_ci out = ((ImU32)IM_F32_TO_INT8_SAT(in.x)) << IM_COL32_R_SHIFT; 1770bf215546Sopenharmony_ci out |= ((ImU32)IM_F32_TO_INT8_SAT(in.y)) << IM_COL32_G_SHIFT; 1771bf215546Sopenharmony_ci out |= ((ImU32)IM_F32_TO_INT8_SAT(in.z)) << IM_COL32_B_SHIFT; 1772bf215546Sopenharmony_ci out |= ((ImU32)IM_F32_TO_INT8_SAT(in.w)) << IM_COL32_A_SHIFT; 1773bf215546Sopenharmony_ci return out; 1774bf215546Sopenharmony_ci} 1775bf215546Sopenharmony_ci 1776bf215546Sopenharmony_ci// Convert rgb floats ([0-1],[0-1],[0-1]) to hsv floats ([0-1],[0-1],[0-1]), from Foley & van Dam p592 1777bf215546Sopenharmony_ci// Optimized http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv 1778bf215546Sopenharmony_civoid ImGui::ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v) 1779bf215546Sopenharmony_ci{ 1780bf215546Sopenharmony_ci float K = 0.f; 1781bf215546Sopenharmony_ci if (g < b) 1782bf215546Sopenharmony_ci { 1783bf215546Sopenharmony_ci ImSwap(g, b); 1784bf215546Sopenharmony_ci K = -1.f; 1785bf215546Sopenharmony_ci } 1786bf215546Sopenharmony_ci if (r < g) 1787bf215546Sopenharmony_ci { 1788bf215546Sopenharmony_ci ImSwap(r, g); 1789bf215546Sopenharmony_ci K = -2.f / 6.f - K; 1790bf215546Sopenharmony_ci } 1791bf215546Sopenharmony_ci 1792bf215546Sopenharmony_ci const float chroma = r - (g < b ? g : b); 1793bf215546Sopenharmony_ci out_h = ImFabs(K + (g - b) / (6.f * chroma + 1e-20f)); 1794bf215546Sopenharmony_ci out_s = chroma / (r + 1e-20f); 1795bf215546Sopenharmony_ci out_v = r; 1796bf215546Sopenharmony_ci} 1797bf215546Sopenharmony_ci 1798bf215546Sopenharmony_ci// Convert hsv floats ([0-1],[0-1],[0-1]) to rgb floats ([0-1],[0-1],[0-1]), from Foley & van Dam p593 1799bf215546Sopenharmony_ci// also http://en.wikipedia.org/wiki/HSL_and_HSV 1800bf215546Sopenharmony_civoid ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b) 1801bf215546Sopenharmony_ci{ 1802bf215546Sopenharmony_ci if (s == 0.0f) 1803bf215546Sopenharmony_ci { 1804bf215546Sopenharmony_ci // gray 1805bf215546Sopenharmony_ci out_r = out_g = out_b = v; 1806bf215546Sopenharmony_ci return; 1807bf215546Sopenharmony_ci } 1808bf215546Sopenharmony_ci 1809bf215546Sopenharmony_ci h = ImFmod(h, 1.0f) / (60.0f/360.0f); 1810bf215546Sopenharmony_ci int i = (int)h; 1811bf215546Sopenharmony_ci float f = h - (float)i; 1812bf215546Sopenharmony_ci float p = v * (1.0f - s); 1813bf215546Sopenharmony_ci float q = v * (1.0f - s * f); 1814bf215546Sopenharmony_ci float t = v * (1.0f - s * (1.0f - f)); 1815bf215546Sopenharmony_ci 1816bf215546Sopenharmony_ci switch (i) 1817bf215546Sopenharmony_ci { 1818bf215546Sopenharmony_ci case 0: out_r = v; out_g = t; out_b = p; break; 1819bf215546Sopenharmony_ci case 1: out_r = q; out_g = v; out_b = p; break; 1820bf215546Sopenharmony_ci case 2: out_r = p; out_g = v; out_b = t; break; 1821bf215546Sopenharmony_ci case 3: out_r = p; out_g = q; out_b = v; break; 1822bf215546Sopenharmony_ci case 4: out_r = t; out_g = p; out_b = v; break; 1823bf215546Sopenharmony_ci case 5: default: out_r = v; out_g = p; out_b = q; break; 1824bf215546Sopenharmony_ci } 1825bf215546Sopenharmony_ci} 1826bf215546Sopenharmony_ci 1827bf215546Sopenharmony_ciImU32 ImGui::GetColorU32(ImGuiCol idx, float alpha_mul) 1828bf215546Sopenharmony_ci{ 1829bf215546Sopenharmony_ci ImGuiStyle& style = GImGui->Style; 1830bf215546Sopenharmony_ci ImVec4 c = style.Colors[idx]; 1831bf215546Sopenharmony_ci c.w *= style.Alpha * alpha_mul; 1832bf215546Sopenharmony_ci return ColorConvertFloat4ToU32(c); 1833bf215546Sopenharmony_ci} 1834bf215546Sopenharmony_ci 1835bf215546Sopenharmony_ciImU32 ImGui::GetColorU32(const ImVec4& col) 1836bf215546Sopenharmony_ci{ 1837bf215546Sopenharmony_ci ImGuiStyle& style = GImGui->Style; 1838bf215546Sopenharmony_ci ImVec4 c = col; 1839bf215546Sopenharmony_ci c.w *= style.Alpha; 1840bf215546Sopenharmony_ci return ColorConvertFloat4ToU32(c); 1841bf215546Sopenharmony_ci} 1842bf215546Sopenharmony_ci 1843bf215546Sopenharmony_ciconst ImVec4& ImGui::GetStyleColorVec4(ImGuiCol idx) 1844bf215546Sopenharmony_ci{ 1845bf215546Sopenharmony_ci ImGuiStyle& style = GImGui->Style; 1846bf215546Sopenharmony_ci return style.Colors[idx]; 1847bf215546Sopenharmony_ci} 1848bf215546Sopenharmony_ci 1849bf215546Sopenharmony_ciImU32 ImGui::GetColorU32(ImU32 col) 1850bf215546Sopenharmony_ci{ 1851bf215546Sopenharmony_ci float style_alpha = GImGui->Style.Alpha; 1852bf215546Sopenharmony_ci if (style_alpha >= 1.0f) 1853bf215546Sopenharmony_ci return col; 1854bf215546Sopenharmony_ci ImU32 a = (col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT; 1855bf215546Sopenharmony_ci a = (ImU32)(a * style_alpha); // We don't need to clamp 0..255 because Style.Alpha is in 0..1 range. 1856bf215546Sopenharmony_ci return (col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT); 1857bf215546Sopenharmony_ci} 1858bf215546Sopenharmony_ci 1859bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 1860bf215546Sopenharmony_ci// [SECTION] ImGuiStorage 1861bf215546Sopenharmony_ci// Helper: Key->value storage 1862bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 1863bf215546Sopenharmony_ci 1864bf215546Sopenharmony_ci// std::lower_bound but without the bullshit 1865bf215546Sopenharmony_cistatic ImGuiStorage::Pair* LowerBound(ImVector<ImGuiStorage::Pair>& data, ImGuiID key) 1866bf215546Sopenharmony_ci{ 1867bf215546Sopenharmony_ci ImGuiStorage::Pair* first = data.Data; 1868bf215546Sopenharmony_ci ImGuiStorage::Pair* last = data.Data + data.Size; 1869bf215546Sopenharmony_ci size_t count = (size_t)(last - first); 1870bf215546Sopenharmony_ci while (count > 0) 1871bf215546Sopenharmony_ci { 1872bf215546Sopenharmony_ci size_t count2 = count >> 1; 1873bf215546Sopenharmony_ci ImGuiStorage::Pair* mid = first + count2; 1874bf215546Sopenharmony_ci if (mid->key < key) 1875bf215546Sopenharmony_ci { 1876bf215546Sopenharmony_ci first = ++mid; 1877bf215546Sopenharmony_ci count -= count2 + 1; 1878bf215546Sopenharmony_ci } 1879bf215546Sopenharmony_ci else 1880bf215546Sopenharmony_ci { 1881bf215546Sopenharmony_ci count = count2; 1882bf215546Sopenharmony_ci } 1883bf215546Sopenharmony_ci } 1884bf215546Sopenharmony_ci return first; 1885bf215546Sopenharmony_ci} 1886bf215546Sopenharmony_ci 1887bf215546Sopenharmony_ci// For quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once. 1888bf215546Sopenharmony_civoid ImGuiStorage::BuildSortByKey() 1889bf215546Sopenharmony_ci{ 1890bf215546Sopenharmony_ci struct StaticFunc 1891bf215546Sopenharmony_ci { 1892bf215546Sopenharmony_ci static int IMGUI_CDECL PairCompareByID(const void* lhs, const void* rhs) 1893bf215546Sopenharmony_ci { 1894bf215546Sopenharmony_ci // We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that. 1895bf215546Sopenharmony_ci if (((const Pair*)lhs)->key > ((const Pair*)rhs)->key) return +1; 1896bf215546Sopenharmony_ci if (((const Pair*)lhs)->key < ((const Pair*)rhs)->key) return -1; 1897bf215546Sopenharmony_ci return 0; 1898bf215546Sopenharmony_ci } 1899bf215546Sopenharmony_ci }; 1900bf215546Sopenharmony_ci if (Data.Size > 1) 1901bf215546Sopenharmony_ci ImQsort(Data.Data, (size_t)Data.Size, sizeof(Pair), StaticFunc::PairCompareByID); 1902bf215546Sopenharmony_ci} 1903bf215546Sopenharmony_ci 1904bf215546Sopenharmony_ciint ImGuiStorage::GetInt(ImGuiID key, int default_val) const 1905bf215546Sopenharmony_ci{ 1906bf215546Sopenharmony_ci ImGuiStorage::Pair* it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key); 1907bf215546Sopenharmony_ci if (it == Data.end() || it->key != key) 1908bf215546Sopenharmony_ci return default_val; 1909bf215546Sopenharmony_ci return it->val_i; 1910bf215546Sopenharmony_ci} 1911bf215546Sopenharmony_ci 1912bf215546Sopenharmony_cibool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const 1913bf215546Sopenharmony_ci{ 1914bf215546Sopenharmony_ci return GetInt(key, default_val ? 1 : 0) != 0; 1915bf215546Sopenharmony_ci} 1916bf215546Sopenharmony_ci 1917bf215546Sopenharmony_cifloat ImGuiStorage::GetFloat(ImGuiID key, float default_val) const 1918bf215546Sopenharmony_ci{ 1919bf215546Sopenharmony_ci ImGuiStorage::Pair* it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key); 1920bf215546Sopenharmony_ci if (it == Data.end() || it->key != key) 1921bf215546Sopenharmony_ci return default_val; 1922bf215546Sopenharmony_ci return it->val_f; 1923bf215546Sopenharmony_ci} 1924bf215546Sopenharmony_ci 1925bf215546Sopenharmony_civoid* ImGuiStorage::GetVoidPtr(ImGuiID key) const 1926bf215546Sopenharmony_ci{ 1927bf215546Sopenharmony_ci ImGuiStorage::Pair* it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key); 1928bf215546Sopenharmony_ci if (it == Data.end() || it->key != key) 1929bf215546Sopenharmony_ci return NULL; 1930bf215546Sopenharmony_ci return it->val_p; 1931bf215546Sopenharmony_ci} 1932bf215546Sopenharmony_ci 1933bf215546Sopenharmony_ci// 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. 1934bf215546Sopenharmony_ciint* ImGuiStorage::GetIntRef(ImGuiID key, int default_val) 1935bf215546Sopenharmony_ci{ 1936bf215546Sopenharmony_ci ImGuiStorage::Pair* it = LowerBound(Data, key); 1937bf215546Sopenharmony_ci if (it == Data.end() || it->key != key) 1938bf215546Sopenharmony_ci it = Data.insert(it, Pair(key, default_val)); 1939bf215546Sopenharmony_ci return &it->val_i; 1940bf215546Sopenharmony_ci} 1941bf215546Sopenharmony_ci 1942bf215546Sopenharmony_cibool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val) 1943bf215546Sopenharmony_ci{ 1944bf215546Sopenharmony_ci return (bool*)GetIntRef(key, default_val ? 1 : 0); 1945bf215546Sopenharmony_ci} 1946bf215546Sopenharmony_ci 1947bf215546Sopenharmony_cifloat* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val) 1948bf215546Sopenharmony_ci{ 1949bf215546Sopenharmony_ci ImGuiStorage::Pair* it = LowerBound(Data, key); 1950bf215546Sopenharmony_ci if (it == Data.end() || it->key != key) 1951bf215546Sopenharmony_ci it = Data.insert(it, Pair(key, default_val)); 1952bf215546Sopenharmony_ci return &it->val_f; 1953bf215546Sopenharmony_ci} 1954bf215546Sopenharmony_ci 1955bf215546Sopenharmony_civoid** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val) 1956bf215546Sopenharmony_ci{ 1957bf215546Sopenharmony_ci ImGuiStorage::Pair* it = LowerBound(Data, key); 1958bf215546Sopenharmony_ci if (it == Data.end() || it->key != key) 1959bf215546Sopenharmony_ci it = Data.insert(it, Pair(key, default_val)); 1960bf215546Sopenharmony_ci return &it->val_p; 1961bf215546Sopenharmony_ci} 1962bf215546Sopenharmony_ci 1963bf215546Sopenharmony_ci// 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) 1964bf215546Sopenharmony_civoid ImGuiStorage::SetInt(ImGuiID key, int val) 1965bf215546Sopenharmony_ci{ 1966bf215546Sopenharmony_ci ImGuiStorage::Pair* it = LowerBound(Data, key); 1967bf215546Sopenharmony_ci if (it == Data.end() || it->key != key) 1968bf215546Sopenharmony_ci { 1969bf215546Sopenharmony_ci Data.insert(it, Pair(key, val)); 1970bf215546Sopenharmony_ci return; 1971bf215546Sopenharmony_ci } 1972bf215546Sopenharmony_ci it->val_i = val; 1973bf215546Sopenharmony_ci} 1974bf215546Sopenharmony_ci 1975bf215546Sopenharmony_civoid ImGuiStorage::SetBool(ImGuiID key, bool val) 1976bf215546Sopenharmony_ci{ 1977bf215546Sopenharmony_ci SetInt(key, val ? 1 : 0); 1978bf215546Sopenharmony_ci} 1979bf215546Sopenharmony_ci 1980bf215546Sopenharmony_civoid ImGuiStorage::SetFloat(ImGuiID key, float val) 1981bf215546Sopenharmony_ci{ 1982bf215546Sopenharmony_ci ImGuiStorage::Pair* it = LowerBound(Data, key); 1983bf215546Sopenharmony_ci if (it == Data.end() || it->key != key) 1984bf215546Sopenharmony_ci { 1985bf215546Sopenharmony_ci Data.insert(it, Pair(key, val)); 1986bf215546Sopenharmony_ci return; 1987bf215546Sopenharmony_ci } 1988bf215546Sopenharmony_ci it->val_f = val; 1989bf215546Sopenharmony_ci} 1990bf215546Sopenharmony_ci 1991bf215546Sopenharmony_civoid ImGuiStorage::SetVoidPtr(ImGuiID key, void* val) 1992bf215546Sopenharmony_ci{ 1993bf215546Sopenharmony_ci ImGuiStorage::Pair* it = LowerBound(Data, key); 1994bf215546Sopenharmony_ci if (it == Data.end() || it->key != key) 1995bf215546Sopenharmony_ci { 1996bf215546Sopenharmony_ci Data.insert(it, Pair(key, val)); 1997bf215546Sopenharmony_ci return; 1998bf215546Sopenharmony_ci } 1999bf215546Sopenharmony_ci it->val_p = val; 2000bf215546Sopenharmony_ci} 2001bf215546Sopenharmony_ci 2002bf215546Sopenharmony_civoid ImGuiStorage::SetAllInt(int v) 2003bf215546Sopenharmony_ci{ 2004bf215546Sopenharmony_ci for (int i = 0; i < Data.Size; i++) 2005bf215546Sopenharmony_ci Data[i].val_i = v; 2006bf215546Sopenharmony_ci} 2007bf215546Sopenharmony_ci 2008bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 2009bf215546Sopenharmony_ci// [SECTION] ImGuiTextFilter 2010bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 2011bf215546Sopenharmony_ci 2012bf215546Sopenharmony_ci// Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]" 2013bf215546Sopenharmony_ciImGuiTextFilter::ImGuiTextFilter(const char* default_filter) 2014bf215546Sopenharmony_ci{ 2015bf215546Sopenharmony_ci if (default_filter) 2016bf215546Sopenharmony_ci { 2017bf215546Sopenharmony_ci ImStrncpy(InputBuf, default_filter, IM_ARRAYSIZE(InputBuf)); 2018bf215546Sopenharmony_ci Build(); 2019bf215546Sopenharmony_ci } 2020bf215546Sopenharmony_ci else 2021bf215546Sopenharmony_ci { 2022bf215546Sopenharmony_ci InputBuf[0] = 0; 2023bf215546Sopenharmony_ci CountGrep = 0; 2024bf215546Sopenharmony_ci } 2025bf215546Sopenharmony_ci} 2026bf215546Sopenharmony_ci 2027bf215546Sopenharmony_cibool ImGuiTextFilter::Draw(const char* label, float width) 2028bf215546Sopenharmony_ci{ 2029bf215546Sopenharmony_ci if (width != 0.0f) 2030bf215546Sopenharmony_ci ImGui::PushItemWidth(width); 2031bf215546Sopenharmony_ci bool value_changed = ImGui::InputText(label, InputBuf, IM_ARRAYSIZE(InputBuf)); 2032bf215546Sopenharmony_ci if (width != 0.0f) 2033bf215546Sopenharmony_ci ImGui::PopItemWidth(); 2034bf215546Sopenharmony_ci if (value_changed) 2035bf215546Sopenharmony_ci Build(); 2036bf215546Sopenharmony_ci return value_changed; 2037bf215546Sopenharmony_ci} 2038bf215546Sopenharmony_ci 2039bf215546Sopenharmony_civoid ImGuiTextFilter::TextRange::split(char separator, ImVector<TextRange>* out) const 2040bf215546Sopenharmony_ci{ 2041bf215546Sopenharmony_ci out->resize(0); 2042bf215546Sopenharmony_ci const char* wb = b; 2043bf215546Sopenharmony_ci const char* we = wb; 2044bf215546Sopenharmony_ci while (we < e) 2045bf215546Sopenharmony_ci { 2046bf215546Sopenharmony_ci if (*we == separator) 2047bf215546Sopenharmony_ci { 2048bf215546Sopenharmony_ci out->push_back(TextRange(wb, we)); 2049bf215546Sopenharmony_ci wb = we + 1; 2050bf215546Sopenharmony_ci } 2051bf215546Sopenharmony_ci we++; 2052bf215546Sopenharmony_ci } 2053bf215546Sopenharmony_ci if (wb != we) 2054bf215546Sopenharmony_ci out->push_back(TextRange(wb, we)); 2055bf215546Sopenharmony_ci} 2056bf215546Sopenharmony_ci 2057bf215546Sopenharmony_civoid ImGuiTextFilter::Build() 2058bf215546Sopenharmony_ci{ 2059bf215546Sopenharmony_ci Filters.resize(0); 2060bf215546Sopenharmony_ci TextRange input_range(InputBuf, InputBuf+strlen(InputBuf)); 2061bf215546Sopenharmony_ci input_range.split(',', &Filters); 2062bf215546Sopenharmony_ci 2063bf215546Sopenharmony_ci CountGrep = 0; 2064bf215546Sopenharmony_ci for (int i = 0; i != Filters.Size; i++) 2065bf215546Sopenharmony_ci { 2066bf215546Sopenharmony_ci TextRange& f = Filters[i]; 2067bf215546Sopenharmony_ci while (f.b < f.e && ImCharIsBlankA(f.b[0])) 2068bf215546Sopenharmony_ci f.b++; 2069bf215546Sopenharmony_ci while (f.e > f.b && ImCharIsBlankA(f.e[-1])) 2070bf215546Sopenharmony_ci f.e--; 2071bf215546Sopenharmony_ci if (f.empty()) 2072bf215546Sopenharmony_ci continue; 2073bf215546Sopenharmony_ci if (Filters[i].b[0] != '-') 2074bf215546Sopenharmony_ci CountGrep += 1; 2075bf215546Sopenharmony_ci } 2076bf215546Sopenharmony_ci} 2077bf215546Sopenharmony_ci 2078bf215546Sopenharmony_cibool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const 2079bf215546Sopenharmony_ci{ 2080bf215546Sopenharmony_ci if (Filters.empty()) 2081bf215546Sopenharmony_ci return true; 2082bf215546Sopenharmony_ci 2083bf215546Sopenharmony_ci if (text == NULL) 2084bf215546Sopenharmony_ci text = ""; 2085bf215546Sopenharmony_ci 2086bf215546Sopenharmony_ci for (int i = 0; i != Filters.Size; i++) 2087bf215546Sopenharmony_ci { 2088bf215546Sopenharmony_ci const TextRange& f = Filters[i]; 2089bf215546Sopenharmony_ci if (f.empty()) 2090bf215546Sopenharmony_ci continue; 2091bf215546Sopenharmony_ci if (f.b[0] == '-') 2092bf215546Sopenharmony_ci { 2093bf215546Sopenharmony_ci // Subtract 2094bf215546Sopenharmony_ci if (ImStristr(text, text_end, f.begin()+1, f.end()) != NULL) 2095bf215546Sopenharmony_ci return false; 2096bf215546Sopenharmony_ci } 2097bf215546Sopenharmony_ci else 2098bf215546Sopenharmony_ci { 2099bf215546Sopenharmony_ci // Grep 2100bf215546Sopenharmony_ci if (ImStristr(text, text_end, f.begin(), f.end()) != NULL) 2101bf215546Sopenharmony_ci return true; 2102bf215546Sopenharmony_ci } 2103bf215546Sopenharmony_ci } 2104bf215546Sopenharmony_ci 2105bf215546Sopenharmony_ci // Implicit * grep 2106bf215546Sopenharmony_ci if (CountGrep == 0) 2107bf215546Sopenharmony_ci return true; 2108bf215546Sopenharmony_ci 2109bf215546Sopenharmony_ci return false; 2110bf215546Sopenharmony_ci} 2111bf215546Sopenharmony_ci 2112bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 2113bf215546Sopenharmony_ci// [SECTION] ImGuiTextBuffer 2114bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 2115bf215546Sopenharmony_ci 2116bf215546Sopenharmony_ci// On some platform vsnprintf() takes va_list by reference and modifies it. 2117bf215546Sopenharmony_ci// va_copy is the 'correct' way to copy a va_list but Visual Studio prior to 2013 doesn't have it. 2118bf215546Sopenharmony_ci#ifndef va_copy 2119bf215546Sopenharmony_ci#if defined(__GNUC__) || defined(__clang__) 2120bf215546Sopenharmony_ci#define va_copy(dest, src) __builtin_va_copy(dest, src) 2121bf215546Sopenharmony_ci#else 2122bf215546Sopenharmony_ci#define va_copy(dest, src) (dest = src) 2123bf215546Sopenharmony_ci#endif 2124bf215546Sopenharmony_ci#endif 2125bf215546Sopenharmony_ci 2126bf215546Sopenharmony_cichar ImGuiTextBuffer::EmptyString[1] = { 0 }; 2127bf215546Sopenharmony_ci 2128bf215546Sopenharmony_civoid ImGuiTextBuffer::append(const char* str, const char* str_end) 2129bf215546Sopenharmony_ci{ 2130bf215546Sopenharmony_ci int len = str_end ? (int)(str_end - str) : (int)strlen(str); 2131bf215546Sopenharmony_ci 2132bf215546Sopenharmony_ci // Add zero-terminator the first time 2133bf215546Sopenharmony_ci const int write_off = (Buf.Size != 0) ? Buf.Size : 1; 2134bf215546Sopenharmony_ci const int needed_sz = write_off + len; 2135bf215546Sopenharmony_ci if (write_off + len >= Buf.Capacity) 2136bf215546Sopenharmony_ci { 2137bf215546Sopenharmony_ci int new_capacity = Buf.Capacity * 2; 2138bf215546Sopenharmony_ci Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity); 2139bf215546Sopenharmony_ci } 2140bf215546Sopenharmony_ci 2141bf215546Sopenharmony_ci Buf.resize(needed_sz); 2142bf215546Sopenharmony_ci memcpy(&Buf[write_off - 1], str, (size_t)len); 2143bf215546Sopenharmony_ci Buf[write_off - 1 + len] = 0; 2144bf215546Sopenharmony_ci} 2145bf215546Sopenharmony_ci 2146bf215546Sopenharmony_civoid ImGuiTextBuffer::appendf(const char* fmt, ...) 2147bf215546Sopenharmony_ci{ 2148bf215546Sopenharmony_ci va_list args; 2149bf215546Sopenharmony_ci va_start(args, fmt); 2150bf215546Sopenharmony_ci appendfv(fmt, args); 2151bf215546Sopenharmony_ci va_end(args); 2152bf215546Sopenharmony_ci} 2153bf215546Sopenharmony_ci 2154bf215546Sopenharmony_ci// Helper: Text buffer for logging/accumulating text 2155bf215546Sopenharmony_civoid ImGuiTextBuffer::appendfv(const char* fmt, va_list args) 2156bf215546Sopenharmony_ci{ 2157bf215546Sopenharmony_ci va_list args_copy; 2158bf215546Sopenharmony_ci va_copy(args_copy, args); 2159bf215546Sopenharmony_ci 2160bf215546Sopenharmony_ci int len = ImFormatStringV(NULL, 0, fmt, args); // FIXME-OPT: could do a first pass write attempt, likely successful on first pass. 2161bf215546Sopenharmony_ci if (len <= 0) 2162bf215546Sopenharmony_ci { 2163bf215546Sopenharmony_ci va_end(args_copy); 2164bf215546Sopenharmony_ci return; 2165bf215546Sopenharmony_ci } 2166bf215546Sopenharmony_ci 2167bf215546Sopenharmony_ci // Add zero-terminator the first time 2168bf215546Sopenharmony_ci const int write_off = (Buf.Size != 0) ? Buf.Size : 1; 2169bf215546Sopenharmony_ci const int needed_sz = write_off + len; 2170bf215546Sopenharmony_ci if (write_off + len >= Buf.Capacity) 2171bf215546Sopenharmony_ci { 2172bf215546Sopenharmony_ci int new_capacity = Buf.Capacity * 2; 2173bf215546Sopenharmony_ci Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity); 2174bf215546Sopenharmony_ci } 2175bf215546Sopenharmony_ci 2176bf215546Sopenharmony_ci Buf.resize(needed_sz); 2177bf215546Sopenharmony_ci ImFormatStringV(&Buf[write_off - 1], (size_t)len + 1, fmt, args_copy); 2178bf215546Sopenharmony_ci va_end(args_copy); 2179bf215546Sopenharmony_ci} 2180bf215546Sopenharmony_ci 2181bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 2182bf215546Sopenharmony_ci// [SECTION] ImGuiListClipper 2183bf215546Sopenharmony_ci// This is currently not as flexible/powerful as it should be, needs some rework (see TODO) 2184bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 2185bf215546Sopenharmony_ci 2186bf215546Sopenharmony_cistatic void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height) 2187bf215546Sopenharmony_ci{ 2188bf215546Sopenharmony_ci // Set cursor position and a few other things so that SetScrollHereY() and Columns() can work when seeking cursor. 2189bf215546Sopenharmony_ci // FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue. 2190bf215546Sopenharmony_ci // The clipper should probably have a 4th step to display the last item in a regular manner. 2191bf215546Sopenharmony_ci ImGui::SetCursorPosY(pos_y); 2192bf215546Sopenharmony_ci ImGuiWindow* window = ImGui::GetCurrentWindow(); 2193bf215546Sopenharmony_ci 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. 2194bf215546Sopenharmony_ci window->DC.PrevLineSize.y = (line_height - GImGui->Style.ItemSpacing.y); // If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list. 2195bf215546Sopenharmony_ci if (window->DC.ColumnsSet) 2196bf215546Sopenharmony_ci window->DC.ColumnsSet->LineMinY = window->DC.CursorPos.y; // Setting this so that cell Y position are set properly 2197bf215546Sopenharmony_ci} 2198bf215546Sopenharmony_ci 2199bf215546Sopenharmony_ci// Use case A: Begin() called from constructor with items_height<0, then called again from Sync() in StepNo 1 2200bf215546Sopenharmony_ci// Use case B: Begin() called from constructor with items_height>0 2201bf215546Sopenharmony_ci// FIXME-LEGACY: Ideally we should remove the Begin/End functions but they are part of the legacy API we still support. This is why some of the code in Step() calling Begin() and reassign some fields, spaghetti style. 2202bf215546Sopenharmony_civoid ImGuiListClipper::Begin(int count, float items_height) 2203bf215546Sopenharmony_ci{ 2204bf215546Sopenharmony_ci StartPosY = ImGui::GetCursorPosY(); 2205bf215546Sopenharmony_ci ItemsHeight = items_height; 2206bf215546Sopenharmony_ci ItemsCount = count; 2207bf215546Sopenharmony_ci StepNo = 0; 2208bf215546Sopenharmony_ci DisplayEnd = DisplayStart = -1; 2209bf215546Sopenharmony_ci if (ItemsHeight > 0.0f) 2210bf215546Sopenharmony_ci { 2211bf215546Sopenharmony_ci ImGui::CalcListClipping(ItemsCount, ItemsHeight, &DisplayStart, &DisplayEnd); // calculate how many to clip/display 2212bf215546Sopenharmony_ci if (DisplayStart > 0) 2213bf215546Sopenharmony_ci SetCursorPosYAndSetupDummyPrevLine(StartPosY + DisplayStart * ItemsHeight, ItemsHeight); // advance cursor 2214bf215546Sopenharmony_ci StepNo = 2; 2215bf215546Sopenharmony_ci } 2216bf215546Sopenharmony_ci} 2217bf215546Sopenharmony_ci 2218bf215546Sopenharmony_civoid ImGuiListClipper::End() 2219bf215546Sopenharmony_ci{ 2220bf215546Sopenharmony_ci if (ItemsCount < 0) 2221bf215546Sopenharmony_ci return; 2222bf215546Sopenharmony_ci // In theory here we should assert that ImGui::GetCursorPosY() == StartPosY + DisplayEnd * ItemsHeight, but it feels saner to just seek at the end and not assert/crash the user. 2223bf215546Sopenharmony_ci if (ItemsCount < INT_MAX) 2224bf215546Sopenharmony_ci SetCursorPosYAndSetupDummyPrevLine(StartPosY + ItemsCount * ItemsHeight, ItemsHeight); // advance cursor 2225bf215546Sopenharmony_ci ItemsCount = -1; 2226bf215546Sopenharmony_ci StepNo = 3; 2227bf215546Sopenharmony_ci} 2228bf215546Sopenharmony_ci 2229bf215546Sopenharmony_cibool ImGuiListClipper::Step() 2230bf215546Sopenharmony_ci{ 2231bf215546Sopenharmony_ci if (ItemsCount == 0 || ImGui::GetCurrentWindowRead()->SkipItems) 2232bf215546Sopenharmony_ci { 2233bf215546Sopenharmony_ci ItemsCount = -1; 2234bf215546Sopenharmony_ci return false; 2235bf215546Sopenharmony_ci } 2236bf215546Sopenharmony_ci if (StepNo == 0) // Step 0: the clipper let you process the first element, regardless of it being visible or not, so we can measure the element height. 2237bf215546Sopenharmony_ci { 2238bf215546Sopenharmony_ci DisplayStart = 0; 2239bf215546Sopenharmony_ci DisplayEnd = 1; 2240bf215546Sopenharmony_ci StartPosY = ImGui::GetCursorPosY(); 2241bf215546Sopenharmony_ci StepNo = 1; 2242bf215546Sopenharmony_ci return true; 2243bf215546Sopenharmony_ci } 2244bf215546Sopenharmony_ci if (StepNo == 1) // Step 1: the clipper infer height from first element, calculate the actual range of elements to display, and position the cursor before the first element. 2245bf215546Sopenharmony_ci { 2246bf215546Sopenharmony_ci if (ItemsCount == 1) { ItemsCount = -1; return false; } 2247bf215546Sopenharmony_ci float items_height = ImGui::GetCursorPosY() - StartPosY; 2248bf215546Sopenharmony_ci IM_ASSERT(items_height > 0.0f); // If this triggers, it means Item 0 hasn't moved the cursor vertically 2249bf215546Sopenharmony_ci Begin(ItemsCount-1, items_height); 2250bf215546Sopenharmony_ci DisplayStart++; 2251bf215546Sopenharmony_ci DisplayEnd++; 2252bf215546Sopenharmony_ci StepNo = 3; 2253bf215546Sopenharmony_ci return true; 2254bf215546Sopenharmony_ci } 2255bf215546Sopenharmony_ci if (StepNo == 2) // Step 2: dummy step only required if an explicit items_height was passed to constructor or Begin() and user still call Step(). Does nothing and switch to Step 3. 2256bf215546Sopenharmony_ci { 2257bf215546Sopenharmony_ci IM_ASSERT(DisplayStart >= 0 && DisplayEnd >= 0); 2258bf215546Sopenharmony_ci StepNo = 3; 2259bf215546Sopenharmony_ci return true; 2260bf215546Sopenharmony_ci } 2261bf215546Sopenharmony_ci if (StepNo == 3) // Step 3: the clipper validate that we have reached the expected Y position (corresponding to element DisplayEnd), advance the cursor to the end of the list and then returns 'false' to end the loop. 2262bf215546Sopenharmony_ci End(); 2263bf215546Sopenharmony_ci return false; 2264bf215546Sopenharmony_ci} 2265bf215546Sopenharmony_ci 2266bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 2267bf215546Sopenharmony_ci// [SECTION] RENDER HELPERS 2268bf215546Sopenharmony_ci// Those (internal) functions are currently quite a legacy mess - their signature and behavior will change. 2269bf215546Sopenharmony_ci// Also see imgui_draw.cpp for some more which have been reworked to not rely on ImGui:: state. 2270bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 2271bf215546Sopenharmony_ci 2272bf215546Sopenharmony_ciconst char* ImGui::FindRenderedTextEnd(const char* text, const char* text_end) 2273bf215546Sopenharmony_ci{ 2274bf215546Sopenharmony_ci const char* text_display_end = text; 2275bf215546Sopenharmony_ci if (!text_end) 2276bf215546Sopenharmony_ci text_end = (const char*)-1; 2277bf215546Sopenharmony_ci 2278bf215546Sopenharmony_ci while (text_display_end < text_end && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#')) 2279bf215546Sopenharmony_ci text_display_end++; 2280bf215546Sopenharmony_ci return text_display_end; 2281bf215546Sopenharmony_ci} 2282bf215546Sopenharmony_ci 2283bf215546Sopenharmony_ci// Internal ImGui functions to render text 2284bf215546Sopenharmony_ci// RenderText***() functions calls ImDrawList::AddText() calls ImBitmapFont::RenderText() 2285bf215546Sopenharmony_civoid ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool hide_text_after_hash) 2286bf215546Sopenharmony_ci{ 2287bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 2288bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 2289bf215546Sopenharmony_ci 2290bf215546Sopenharmony_ci // Hide anything after a '##' string 2291bf215546Sopenharmony_ci const char* text_display_end; 2292bf215546Sopenharmony_ci if (hide_text_after_hash) 2293bf215546Sopenharmony_ci { 2294bf215546Sopenharmony_ci text_display_end = FindRenderedTextEnd(text, text_end); 2295bf215546Sopenharmony_ci } 2296bf215546Sopenharmony_ci else 2297bf215546Sopenharmony_ci { 2298bf215546Sopenharmony_ci if (!text_end) 2299bf215546Sopenharmony_ci text_end = text + strlen(text); // FIXME-OPT 2300bf215546Sopenharmony_ci text_display_end = text_end; 2301bf215546Sopenharmony_ci } 2302bf215546Sopenharmony_ci 2303bf215546Sopenharmony_ci if (text != text_display_end) 2304bf215546Sopenharmony_ci { 2305bf215546Sopenharmony_ci window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end); 2306bf215546Sopenharmony_ci if (g.LogEnabled) 2307bf215546Sopenharmony_ci LogRenderedText(&pos, text, text_display_end); 2308bf215546Sopenharmony_ci } 2309bf215546Sopenharmony_ci} 2310bf215546Sopenharmony_ci 2311bf215546Sopenharmony_civoid ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width) 2312bf215546Sopenharmony_ci{ 2313bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 2314bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 2315bf215546Sopenharmony_ci 2316bf215546Sopenharmony_ci if (!text_end) 2317bf215546Sopenharmony_ci text_end = text + strlen(text); // FIXME-OPT 2318bf215546Sopenharmony_ci 2319bf215546Sopenharmony_ci if (text != text_end) 2320bf215546Sopenharmony_ci { 2321bf215546Sopenharmony_ci window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_end, wrap_width); 2322bf215546Sopenharmony_ci if (g.LogEnabled) 2323bf215546Sopenharmony_ci LogRenderedText(&pos, text, text_end); 2324bf215546Sopenharmony_ci } 2325bf215546Sopenharmony_ci} 2326bf215546Sopenharmony_ci 2327bf215546Sopenharmony_ci// Default clip_rect uses (pos_min,pos_max) 2328bf215546Sopenharmony_ci// Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges) 2329bf215546Sopenharmony_civoid 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) 2330bf215546Sopenharmony_ci{ 2331bf215546Sopenharmony_ci // Perform CPU side clipping for single clipped element to avoid using scissor state 2332bf215546Sopenharmony_ci ImVec2 pos = pos_min; 2333bf215546Sopenharmony_ci const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_display_end, false, 0.0f); 2334bf215546Sopenharmony_ci 2335bf215546Sopenharmony_ci const ImVec2* clip_min = clip_rect ? &clip_rect->Min : &pos_min; 2336bf215546Sopenharmony_ci const ImVec2* clip_max = clip_rect ? &clip_rect->Max : &pos_max; 2337bf215546Sopenharmony_ci bool need_clipping = (pos.x + text_size.x >= clip_max->x) || (pos.y + text_size.y >= clip_max->y); 2338bf215546Sopenharmony_ci if (clip_rect) // If we had no explicit clipping rectangle then pos==clip_min 2339bf215546Sopenharmony_ci need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y); 2340bf215546Sopenharmony_ci 2341bf215546Sopenharmony_ci // Align whole block. We should defer that to the better rendering function when we'll have support for individual line alignment. 2342bf215546Sopenharmony_ci if (align.x > 0.0f) pos.x = ImMax(pos.x, pos.x + (pos_max.x - pos.x - text_size.x) * align.x); 2343bf215546Sopenharmony_ci if (align.y > 0.0f) pos.y = ImMax(pos.y, pos.y + (pos_max.y - pos.y - text_size.y) * align.y); 2344bf215546Sopenharmony_ci 2345bf215546Sopenharmony_ci // Render 2346bf215546Sopenharmony_ci if (need_clipping) 2347bf215546Sopenharmony_ci { 2348bf215546Sopenharmony_ci ImVec4 fine_clip_rect(clip_min->x, clip_min->y, clip_max->x, clip_max->y); 2349bf215546Sopenharmony_ci draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, &fine_clip_rect); 2350bf215546Sopenharmony_ci } 2351bf215546Sopenharmony_ci else 2352bf215546Sopenharmony_ci { 2353bf215546Sopenharmony_ci draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL); 2354bf215546Sopenharmony_ci } 2355bf215546Sopenharmony_ci} 2356bf215546Sopenharmony_ci 2357bf215546Sopenharmony_civoid 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) 2358bf215546Sopenharmony_ci{ 2359bf215546Sopenharmony_ci // Hide anything after a '##' string 2360bf215546Sopenharmony_ci const char* text_display_end = FindRenderedTextEnd(text, text_end); 2361bf215546Sopenharmony_ci const int text_len = (int)(text_display_end - text); 2362bf215546Sopenharmony_ci if (text_len == 0) 2363bf215546Sopenharmony_ci return; 2364bf215546Sopenharmony_ci 2365bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 2366bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 2367bf215546Sopenharmony_ci RenderTextClippedEx(window->DrawList, pos_min, pos_max, text, text_display_end, text_size_if_known, align, clip_rect); 2368bf215546Sopenharmony_ci if (g.LogEnabled) 2369bf215546Sopenharmony_ci LogRenderedText(&pos_min, text, text_display_end); 2370bf215546Sopenharmony_ci} 2371bf215546Sopenharmony_ci 2372bf215546Sopenharmony_ci// Render a rectangle shaped with optional rounding and borders 2373bf215546Sopenharmony_civoid ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, float rounding) 2374bf215546Sopenharmony_ci{ 2375bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 2376bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 2377bf215546Sopenharmony_ci window->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding); 2378bf215546Sopenharmony_ci const float border_size = g.Style.FrameBorderSize; 2379bf215546Sopenharmony_ci if (border && border_size > 0.0f) 2380bf215546Sopenharmony_ci { 2381bf215546Sopenharmony_ci window->DrawList->AddRect(p_min+ImVec2(1,1), p_max+ImVec2(1,1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size); 2382bf215546Sopenharmony_ci window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size); 2383bf215546Sopenharmony_ci } 2384bf215546Sopenharmony_ci} 2385bf215546Sopenharmony_ci 2386bf215546Sopenharmony_civoid ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding) 2387bf215546Sopenharmony_ci{ 2388bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 2389bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 2390bf215546Sopenharmony_ci const float border_size = g.Style.FrameBorderSize; 2391bf215546Sopenharmony_ci if (border_size > 0.0f) 2392bf215546Sopenharmony_ci { 2393bf215546Sopenharmony_ci window->DrawList->AddRect(p_min+ImVec2(1,1), p_max+ImVec2(1,1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size); 2394bf215546Sopenharmony_ci window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size); 2395bf215546Sopenharmony_ci } 2396bf215546Sopenharmony_ci} 2397bf215546Sopenharmony_ci 2398bf215546Sopenharmony_ci// Render an arrow aimed to be aligned with text (p_min is a position in the same space text would be positioned). To e.g. denote expanded/collapsed state 2399bf215546Sopenharmony_civoid ImGui::RenderArrow(ImVec2 p_min, ImGuiDir dir, float scale) 2400bf215546Sopenharmony_ci{ 2401bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 2402bf215546Sopenharmony_ci 2403bf215546Sopenharmony_ci const float h = g.FontSize * 1.00f; 2404bf215546Sopenharmony_ci float r = h * 0.40f * scale; 2405bf215546Sopenharmony_ci ImVec2 center = p_min + ImVec2(h * 0.50f, h * 0.50f * scale); 2406bf215546Sopenharmony_ci 2407bf215546Sopenharmony_ci ImVec2 a, b, c; 2408bf215546Sopenharmony_ci switch (dir) 2409bf215546Sopenharmony_ci { 2410bf215546Sopenharmony_ci case ImGuiDir_Up: 2411bf215546Sopenharmony_ci case ImGuiDir_Down: 2412bf215546Sopenharmony_ci if (dir == ImGuiDir_Up) r = -r; 2413bf215546Sopenharmony_ci a = ImVec2(+0.000f,+0.750f) * r; 2414bf215546Sopenharmony_ci b = ImVec2(-0.866f,-0.750f) * r; 2415bf215546Sopenharmony_ci c = ImVec2(+0.866f,-0.750f) * r; 2416bf215546Sopenharmony_ci break; 2417bf215546Sopenharmony_ci case ImGuiDir_Left: 2418bf215546Sopenharmony_ci case ImGuiDir_Right: 2419bf215546Sopenharmony_ci if (dir == ImGuiDir_Left) r = -r; 2420bf215546Sopenharmony_ci a = ImVec2(+0.750f,+0.000f) * r; 2421bf215546Sopenharmony_ci b = ImVec2(-0.750f,+0.866f) * r; 2422bf215546Sopenharmony_ci c = ImVec2(-0.750f,-0.866f) * r; 2423bf215546Sopenharmony_ci break; 2424bf215546Sopenharmony_ci case ImGuiDir_None: 2425bf215546Sopenharmony_ci case ImGuiDir_COUNT: 2426bf215546Sopenharmony_ci IM_ASSERT(0); 2427bf215546Sopenharmony_ci break; 2428bf215546Sopenharmony_ci } 2429bf215546Sopenharmony_ci 2430bf215546Sopenharmony_ci g.CurrentWindow->DrawList->AddTriangleFilled(center + a, center + b, center + c, GetColorU32(ImGuiCol_Text)); 2431bf215546Sopenharmony_ci} 2432bf215546Sopenharmony_ci 2433bf215546Sopenharmony_civoid ImGui::RenderBullet(ImVec2 pos) 2434bf215546Sopenharmony_ci{ 2435bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 2436bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 2437bf215546Sopenharmony_ci window->DrawList->AddCircleFilled(pos, g.FontSize*0.20f, GetColorU32(ImGuiCol_Text), 8); 2438bf215546Sopenharmony_ci} 2439bf215546Sopenharmony_ci 2440bf215546Sopenharmony_civoid ImGui::RenderCheckMark(ImVec2 pos, ImU32 col, float sz) 2441bf215546Sopenharmony_ci{ 2442bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 2443bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 2444bf215546Sopenharmony_ci 2445bf215546Sopenharmony_ci float thickness = ImMax(sz / 5.0f, 1.0f); 2446bf215546Sopenharmony_ci sz -= thickness*0.5f; 2447bf215546Sopenharmony_ci pos += ImVec2(thickness*0.25f, thickness*0.25f); 2448bf215546Sopenharmony_ci 2449bf215546Sopenharmony_ci float third = sz / 3.0f; 2450bf215546Sopenharmony_ci float bx = pos.x + third; 2451bf215546Sopenharmony_ci float by = pos.y + sz - third*0.5f; 2452bf215546Sopenharmony_ci window->DrawList->PathLineTo(ImVec2(bx - third, by - third)); 2453bf215546Sopenharmony_ci window->DrawList->PathLineTo(ImVec2(bx, by)); 2454bf215546Sopenharmony_ci window->DrawList->PathLineTo(ImVec2(bx + third*2, by - third*2)); 2455bf215546Sopenharmony_ci window->DrawList->PathStroke(col, false, thickness); 2456bf215546Sopenharmony_ci} 2457bf215546Sopenharmony_ci 2458bf215546Sopenharmony_civoid ImGui::RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags) 2459bf215546Sopenharmony_ci{ 2460bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 2461bf215546Sopenharmony_ci if (id != g.NavId) 2462bf215546Sopenharmony_ci return; 2463bf215546Sopenharmony_ci if (g.NavDisableHighlight && !(flags & ImGuiNavHighlightFlags_AlwaysDraw)) 2464bf215546Sopenharmony_ci return; 2465bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 2466bf215546Sopenharmony_ci if (window->DC.NavHideHighlightOneFrame) 2467bf215546Sopenharmony_ci return; 2468bf215546Sopenharmony_ci 2469bf215546Sopenharmony_ci float rounding = (flags & ImGuiNavHighlightFlags_NoRounding) ? 0.0f : g.Style.FrameRounding; 2470bf215546Sopenharmony_ci ImRect display_rect = bb; 2471bf215546Sopenharmony_ci display_rect.ClipWith(window->ClipRect); 2472bf215546Sopenharmony_ci if (flags & ImGuiNavHighlightFlags_TypeDefault) 2473bf215546Sopenharmony_ci { 2474bf215546Sopenharmony_ci const float THICKNESS = 2.0f; 2475bf215546Sopenharmony_ci const float DISTANCE = 3.0f + THICKNESS * 0.5f; 2476bf215546Sopenharmony_ci display_rect.Expand(ImVec2(DISTANCE,DISTANCE)); 2477bf215546Sopenharmony_ci bool fully_visible = window->ClipRect.Contains(display_rect); 2478bf215546Sopenharmony_ci if (!fully_visible) 2479bf215546Sopenharmony_ci window->DrawList->PushClipRect(display_rect.Min, display_rect.Max); 2480bf215546Sopenharmony_ci window->DrawList->AddRect(display_rect.Min + ImVec2(THICKNESS*0.5f,THICKNESS*0.5f), display_rect.Max - ImVec2(THICKNESS*0.5f,THICKNESS*0.5f), GetColorU32(ImGuiCol_NavHighlight), rounding, ImDrawCornerFlags_All, THICKNESS); 2481bf215546Sopenharmony_ci if (!fully_visible) 2482bf215546Sopenharmony_ci window->DrawList->PopClipRect(); 2483bf215546Sopenharmony_ci } 2484bf215546Sopenharmony_ci if (flags & ImGuiNavHighlightFlags_TypeThin) 2485bf215546Sopenharmony_ci { 2486bf215546Sopenharmony_ci window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavHighlight), rounding, ~0, 1.0f); 2487bf215546Sopenharmony_ci } 2488bf215546Sopenharmony_ci} 2489bf215546Sopenharmony_ci 2490bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 2491bf215546Sopenharmony_ci// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!) 2492bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 2493bf215546Sopenharmony_ci 2494bf215546Sopenharmony_ci// ImGuiWindow is mostly a dumb struct. It merely has a constructor and a few helper methods 2495bf215546Sopenharmony_ciImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name) 2496bf215546Sopenharmony_ci : DrawListInst(&context->DrawListSharedData) 2497bf215546Sopenharmony_ci{ 2498bf215546Sopenharmony_ci Name = ImStrdup(name); 2499bf215546Sopenharmony_ci ID = ImHashStr(name, 0); 2500bf215546Sopenharmony_ci IDStack.push_back(ID); 2501bf215546Sopenharmony_ci Flags = ImGuiWindowFlags_None; 2502bf215546Sopenharmony_ci Pos = ImVec2(0.0f, 0.0f); 2503bf215546Sopenharmony_ci Size = SizeFull = ImVec2(0.0f, 0.0f); 2504bf215546Sopenharmony_ci SizeContents = SizeContentsExplicit = ImVec2(0.0f, 0.0f); 2505bf215546Sopenharmony_ci WindowPadding = ImVec2(0.0f, 0.0f); 2506bf215546Sopenharmony_ci WindowRounding = 0.0f; 2507bf215546Sopenharmony_ci WindowBorderSize = 0.0f; 2508bf215546Sopenharmony_ci NameBufLen = (int)strlen(name) + 1; 2509bf215546Sopenharmony_ci MoveId = GetID("#MOVE"); 2510bf215546Sopenharmony_ci ChildId = 0; 2511bf215546Sopenharmony_ci Scroll = ImVec2(0.0f, 0.0f); 2512bf215546Sopenharmony_ci ScrollTarget = ImVec2(FLT_MAX, FLT_MAX); 2513bf215546Sopenharmony_ci ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f); 2514bf215546Sopenharmony_ci ScrollbarSizes = ImVec2(0.0f, 0.0f); 2515bf215546Sopenharmony_ci ScrollbarX = ScrollbarY = false; 2516bf215546Sopenharmony_ci Active = WasActive = false; 2517bf215546Sopenharmony_ci WriteAccessed = false; 2518bf215546Sopenharmony_ci Collapsed = false; 2519bf215546Sopenharmony_ci WantCollapseToggle = false; 2520bf215546Sopenharmony_ci SkipItems = false; 2521bf215546Sopenharmony_ci Appearing = false; 2522bf215546Sopenharmony_ci Hidden = false; 2523bf215546Sopenharmony_ci HasCloseButton = false; 2524bf215546Sopenharmony_ci ResizeBorderHeld = -1; 2525bf215546Sopenharmony_ci BeginCount = 0; 2526bf215546Sopenharmony_ci BeginOrderWithinParent = -1; 2527bf215546Sopenharmony_ci BeginOrderWithinContext = -1; 2528bf215546Sopenharmony_ci PopupId = 0; 2529bf215546Sopenharmony_ci AutoFitFramesX = AutoFitFramesY = -1; 2530bf215546Sopenharmony_ci AutoFitOnlyGrows = false; 2531bf215546Sopenharmony_ci AutoFitChildAxises = 0x00; 2532bf215546Sopenharmony_ci AutoPosLastDirection = ImGuiDir_None; 2533bf215546Sopenharmony_ci HiddenFramesRegular = HiddenFramesForResize = 0; 2534bf215546Sopenharmony_ci SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing; 2535bf215546Sopenharmony_ci SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX); 2536bf215546Sopenharmony_ci 2537bf215546Sopenharmony_ci LastFrameActive = -1; 2538bf215546Sopenharmony_ci ItemWidthDefault = 0.0f; 2539bf215546Sopenharmony_ci FontWindowScale = 1.0f; 2540bf215546Sopenharmony_ci SettingsIdx = -1; 2541bf215546Sopenharmony_ci 2542bf215546Sopenharmony_ci DrawList = &DrawListInst; 2543bf215546Sopenharmony_ci DrawList->_OwnerName = Name; 2544bf215546Sopenharmony_ci ParentWindow = NULL; 2545bf215546Sopenharmony_ci RootWindow = NULL; 2546bf215546Sopenharmony_ci RootWindowForTitleBarHighlight = NULL; 2547bf215546Sopenharmony_ci RootWindowForNav = NULL; 2548bf215546Sopenharmony_ci 2549bf215546Sopenharmony_ci NavLastIds[0] = NavLastIds[1] = 0; 2550bf215546Sopenharmony_ci NavRectRel[0] = NavRectRel[1] = ImRect(); 2551bf215546Sopenharmony_ci NavLastChildNavWindow = NULL; 2552bf215546Sopenharmony_ci 2553bf215546Sopenharmony_ci FocusIdxAllCounter = FocusIdxTabCounter = -1; 2554bf215546Sopenharmony_ci FocusIdxAllRequestCurrent = FocusIdxTabRequestCurrent = INT_MAX; 2555bf215546Sopenharmony_ci FocusIdxAllRequestNext = FocusIdxTabRequestNext = INT_MAX; 2556bf215546Sopenharmony_ci} 2557bf215546Sopenharmony_ci 2558bf215546Sopenharmony_ciImGuiWindow::~ImGuiWindow() 2559bf215546Sopenharmony_ci{ 2560bf215546Sopenharmony_ci IM_ASSERT(DrawList == &DrawListInst); 2561bf215546Sopenharmony_ci IM_DELETE(Name); 2562bf215546Sopenharmony_ci for (int i = 0; i != ColumnsStorage.Size; i++) 2563bf215546Sopenharmony_ci ColumnsStorage[i].~ImGuiColumnsSet(); 2564bf215546Sopenharmony_ci} 2565bf215546Sopenharmony_ci 2566bf215546Sopenharmony_ciImGuiID ImGuiWindow::GetID(const char* str, const char* str_end) 2567bf215546Sopenharmony_ci{ 2568bf215546Sopenharmony_ci ImGuiID seed = IDStack.back(); 2569bf215546Sopenharmony_ci ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed); 2570bf215546Sopenharmony_ci ImGui::KeepAliveID(id); 2571bf215546Sopenharmony_ci return id; 2572bf215546Sopenharmony_ci} 2573bf215546Sopenharmony_ci 2574bf215546Sopenharmony_ciImGuiID ImGuiWindow::GetID(const void* ptr) 2575bf215546Sopenharmony_ci{ 2576bf215546Sopenharmony_ci ImGuiID seed = IDStack.back(); 2577bf215546Sopenharmony_ci ImGuiID id = ImHashData(&ptr, sizeof(void*), seed); 2578bf215546Sopenharmony_ci ImGui::KeepAliveID(id); 2579bf215546Sopenharmony_ci return id; 2580bf215546Sopenharmony_ci} 2581bf215546Sopenharmony_ci 2582bf215546Sopenharmony_ciImGuiID ImGuiWindow::GetIDNoKeepAlive(const char* str, const char* str_end) 2583bf215546Sopenharmony_ci{ 2584bf215546Sopenharmony_ci ImGuiID seed = IDStack.back(); 2585bf215546Sopenharmony_ci return ImHashStr(str, str_end ? (str_end - str) : 0, seed); 2586bf215546Sopenharmony_ci} 2587bf215546Sopenharmony_ci 2588bf215546Sopenharmony_ciImGuiID ImGuiWindow::GetIDNoKeepAlive(const void* ptr) 2589bf215546Sopenharmony_ci{ 2590bf215546Sopenharmony_ci ImGuiID seed = IDStack.back(); 2591bf215546Sopenharmony_ci return ImHashData(&ptr, sizeof(void*), seed); 2592bf215546Sopenharmony_ci} 2593bf215546Sopenharmony_ci 2594bf215546Sopenharmony_ci// This is only used in rare/specific situations to manufacture an ID out of nowhere. 2595bf215546Sopenharmony_ciImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs) 2596bf215546Sopenharmony_ci{ 2597bf215546Sopenharmony_ci ImGuiID seed = IDStack.back(); 2598bf215546Sopenharmony_ci const int r_rel[4] = { (int)(r_abs.Min.x - Pos.x), (int)(r_abs.Min.y - Pos.y), (int)(r_abs.Max.x - Pos.x), (int)(r_abs.Max.y - Pos.y) }; 2599bf215546Sopenharmony_ci ImGuiID id = ImHashData(&r_rel, sizeof(r_rel), seed); 2600bf215546Sopenharmony_ci ImGui::KeepAliveID(id); 2601bf215546Sopenharmony_ci return id; 2602bf215546Sopenharmony_ci} 2603bf215546Sopenharmony_ci 2604bf215546Sopenharmony_cistatic void SetCurrentWindow(ImGuiWindow* window) 2605bf215546Sopenharmony_ci{ 2606bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 2607bf215546Sopenharmony_ci g.CurrentWindow = window; 2608bf215546Sopenharmony_ci if (window) 2609bf215546Sopenharmony_ci g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize(); 2610bf215546Sopenharmony_ci} 2611bf215546Sopenharmony_ci 2612bf215546Sopenharmony_civoid ImGui::SetNavID(ImGuiID id, int nav_layer) 2613bf215546Sopenharmony_ci{ 2614bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 2615bf215546Sopenharmony_ci IM_ASSERT(g.NavWindow); 2616bf215546Sopenharmony_ci IM_ASSERT(nav_layer == 0 || nav_layer == 1); 2617bf215546Sopenharmony_ci g.NavId = id; 2618bf215546Sopenharmony_ci g.NavWindow->NavLastIds[nav_layer] = id; 2619bf215546Sopenharmony_ci} 2620bf215546Sopenharmony_ci 2621bf215546Sopenharmony_civoid ImGui::SetNavIDWithRectRel(ImGuiID id, int nav_layer, const ImRect& rect_rel) 2622bf215546Sopenharmony_ci{ 2623bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 2624bf215546Sopenharmony_ci SetNavID(id, nav_layer); 2625bf215546Sopenharmony_ci g.NavWindow->NavRectRel[nav_layer] = rect_rel; 2626bf215546Sopenharmony_ci g.NavMousePosDirty = true; 2627bf215546Sopenharmony_ci g.NavDisableHighlight = false; 2628bf215546Sopenharmony_ci g.NavDisableMouseHover = true; 2629bf215546Sopenharmony_ci} 2630bf215546Sopenharmony_ci 2631bf215546Sopenharmony_civoid ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window) 2632bf215546Sopenharmony_ci{ 2633bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 2634bf215546Sopenharmony_ci g.ActiveIdIsJustActivated = (g.ActiveId != id); 2635bf215546Sopenharmony_ci if (g.ActiveIdIsJustActivated) 2636bf215546Sopenharmony_ci { 2637bf215546Sopenharmony_ci g.ActiveIdTimer = 0.0f; 2638bf215546Sopenharmony_ci g.ActiveIdHasBeenPressed = false; 2639bf215546Sopenharmony_ci g.ActiveIdHasBeenEdited = false; 2640bf215546Sopenharmony_ci if (id != 0) 2641bf215546Sopenharmony_ci { 2642bf215546Sopenharmony_ci g.LastActiveId = id; 2643bf215546Sopenharmony_ci g.LastActiveIdTimer = 0.0f; 2644bf215546Sopenharmony_ci } 2645bf215546Sopenharmony_ci } 2646bf215546Sopenharmony_ci g.ActiveId = id; 2647bf215546Sopenharmony_ci g.ActiveIdAllowNavDirFlags = 0; 2648bf215546Sopenharmony_ci g.ActiveIdBlockNavInputFlags = 0; 2649bf215546Sopenharmony_ci g.ActiveIdAllowOverlap = false; 2650bf215546Sopenharmony_ci g.ActiveIdWindow = window; 2651bf215546Sopenharmony_ci if (id) 2652bf215546Sopenharmony_ci { 2653bf215546Sopenharmony_ci g.ActiveIdIsAlive = id; 2654bf215546Sopenharmony_ci g.ActiveIdSource = (g.NavActivateId == id || g.NavInputId == id || g.NavJustTabbedId == id || g.NavJustMovedToId == id) ? ImGuiInputSource_Nav : ImGuiInputSource_Mouse; 2655bf215546Sopenharmony_ci } 2656bf215546Sopenharmony_ci} 2657bf215546Sopenharmony_ci 2658bf215546Sopenharmony_ci// FIXME-NAV: The existence of SetNavID/SetNavIDWithRectRel/SetFocusID is incredibly messy and confusing and needs some explanation or refactoring. 2659bf215546Sopenharmony_civoid ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window) 2660bf215546Sopenharmony_ci{ 2661bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 2662bf215546Sopenharmony_ci IM_ASSERT(id != 0); 2663bf215546Sopenharmony_ci 2664bf215546Sopenharmony_ci // Assume that SetFocusID() is called in the context where its NavLayer is the current layer, which is the case everywhere we call it. 2665bf215546Sopenharmony_ci const ImGuiNavLayer nav_layer = window->DC.NavLayerCurrent; 2666bf215546Sopenharmony_ci if (g.NavWindow != window) 2667bf215546Sopenharmony_ci g.NavInitRequest = false; 2668bf215546Sopenharmony_ci g.NavId = id; 2669bf215546Sopenharmony_ci g.NavWindow = window; 2670bf215546Sopenharmony_ci g.NavLayer = nav_layer; 2671bf215546Sopenharmony_ci window->NavLastIds[nav_layer] = id; 2672bf215546Sopenharmony_ci if (window->DC.LastItemId == id) 2673bf215546Sopenharmony_ci window->NavRectRel[nav_layer] = ImRect(window->DC.LastItemRect.Min - window->Pos, window->DC.LastItemRect.Max - window->Pos); 2674bf215546Sopenharmony_ci 2675bf215546Sopenharmony_ci if (g.ActiveIdSource == ImGuiInputSource_Nav) 2676bf215546Sopenharmony_ci g.NavDisableMouseHover = true; 2677bf215546Sopenharmony_ci else 2678bf215546Sopenharmony_ci g.NavDisableHighlight = true; 2679bf215546Sopenharmony_ci} 2680bf215546Sopenharmony_ci 2681bf215546Sopenharmony_civoid ImGui::ClearActiveID() 2682bf215546Sopenharmony_ci{ 2683bf215546Sopenharmony_ci SetActiveID(0, NULL); 2684bf215546Sopenharmony_ci} 2685bf215546Sopenharmony_ci 2686bf215546Sopenharmony_civoid ImGui::SetHoveredID(ImGuiID id) 2687bf215546Sopenharmony_ci{ 2688bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 2689bf215546Sopenharmony_ci g.HoveredId = id; 2690bf215546Sopenharmony_ci g.HoveredIdAllowOverlap = false; 2691bf215546Sopenharmony_ci if (id != 0 && g.HoveredIdPreviousFrame != id) 2692bf215546Sopenharmony_ci g.HoveredIdTimer = g.HoveredIdNotActiveTimer = 0.0f; 2693bf215546Sopenharmony_ci} 2694bf215546Sopenharmony_ci 2695bf215546Sopenharmony_ciImGuiID ImGui::GetHoveredID() 2696bf215546Sopenharmony_ci{ 2697bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 2698bf215546Sopenharmony_ci return g.HoveredId ? g.HoveredId : g.HoveredIdPreviousFrame; 2699bf215546Sopenharmony_ci} 2700bf215546Sopenharmony_ci 2701bf215546Sopenharmony_civoid ImGui::KeepAliveID(ImGuiID id) 2702bf215546Sopenharmony_ci{ 2703bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 2704bf215546Sopenharmony_ci if (g.ActiveId == id) 2705bf215546Sopenharmony_ci g.ActiveIdIsAlive = id; 2706bf215546Sopenharmony_ci if (g.ActiveIdPreviousFrame == id) 2707bf215546Sopenharmony_ci g.ActiveIdPreviousFrameIsAlive = true; 2708bf215546Sopenharmony_ci} 2709bf215546Sopenharmony_ci 2710bf215546Sopenharmony_civoid ImGui::MarkItemEdited(ImGuiID id) 2711bf215546Sopenharmony_ci{ 2712bf215546Sopenharmony_ci // This marking is solely to be able to provide info for IsItemDeactivatedAfterEdit(). 2713bf215546Sopenharmony_ci // ActiveId might have been released by the time we call this (as in the typical press/release button behavior) but still need need to fill the data. 2714bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 2715bf215546Sopenharmony_ci IM_ASSERT(g.ActiveId == id || g.ActiveId == 0 || g.DragDropActive); 2716bf215546Sopenharmony_ci IM_UNUSED(id); // Avoid unused variable warnings when asserts are compiled out. 2717bf215546Sopenharmony_ci //IM_ASSERT(g.CurrentWindow->DC.LastItemId == id); 2718bf215546Sopenharmony_ci g.ActiveIdHasBeenEdited = true; 2719bf215546Sopenharmony_ci g.CurrentWindow->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited; 2720bf215546Sopenharmony_ci} 2721bf215546Sopenharmony_ci 2722bf215546Sopenharmony_cistatic inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags) 2723bf215546Sopenharmony_ci{ 2724bf215546Sopenharmony_ci // An active popup disable hovering on other windows (apart from its own children) 2725bf215546Sopenharmony_ci // FIXME-OPT: This could be cached/stored within the window. 2726bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 2727bf215546Sopenharmony_ci if (g.NavWindow) 2728bf215546Sopenharmony_ci if (ImGuiWindow* focused_root_window = g.NavWindow->RootWindow) 2729bf215546Sopenharmony_ci if (focused_root_window->WasActive && focused_root_window != window->RootWindow) 2730bf215546Sopenharmony_ci { 2731bf215546Sopenharmony_ci // For the purpose of those flags we differentiate "standard popup" from "modal popup" 2732bf215546Sopenharmony_ci // NB: The order of those two tests is important because Modal windows are also Popups. 2733bf215546Sopenharmony_ci if (focused_root_window->Flags & ImGuiWindowFlags_Modal) 2734bf215546Sopenharmony_ci return false; 2735bf215546Sopenharmony_ci if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiHoveredFlags_AllowWhenBlockedByPopup)) 2736bf215546Sopenharmony_ci return false; 2737bf215546Sopenharmony_ci } 2738bf215546Sopenharmony_ci 2739bf215546Sopenharmony_ci return true; 2740bf215546Sopenharmony_ci} 2741bf215546Sopenharmony_ci 2742bf215546Sopenharmony_ci// Advance cursor given item size for layout. 2743bf215546Sopenharmony_civoid ImGui::ItemSize(const ImVec2& size, float text_offset_y) 2744bf215546Sopenharmony_ci{ 2745bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 2746bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 2747bf215546Sopenharmony_ci if (window->SkipItems) 2748bf215546Sopenharmony_ci return; 2749bf215546Sopenharmony_ci 2750bf215546Sopenharmony_ci // Always align ourselves on pixel boundaries 2751bf215546Sopenharmony_ci const float line_height = ImMax(window->DC.CurrentLineSize.y, size.y); 2752bf215546Sopenharmony_ci const float text_base_offset = ImMax(window->DC.CurrentLineTextBaseOffset, text_offset_y); 2753bf215546Sopenharmony_ci //if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG] 2754bf215546Sopenharmony_ci window->DC.CursorPosPrevLine = ImVec2(window->DC.CursorPos.x + size.x, window->DC.CursorPos.y); 2755bf215546Sopenharmony_ci window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); 2756bf215546Sopenharmony_ci window->DC.CursorPos.y = (float)(int)(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y); 2757bf215546Sopenharmony_ci window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x); 2758bf215546Sopenharmony_ci window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y); 2759bf215546Sopenharmony_ci //if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG] 2760bf215546Sopenharmony_ci 2761bf215546Sopenharmony_ci window->DC.PrevLineSize.y = line_height; 2762bf215546Sopenharmony_ci window->DC.PrevLineTextBaseOffset = text_base_offset; 2763bf215546Sopenharmony_ci window->DC.CurrentLineSize.y = window->DC.CurrentLineTextBaseOffset = 0.0f; 2764bf215546Sopenharmony_ci 2765bf215546Sopenharmony_ci // Horizontal layout mode 2766bf215546Sopenharmony_ci if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) 2767bf215546Sopenharmony_ci SameLine(); 2768bf215546Sopenharmony_ci} 2769bf215546Sopenharmony_ci 2770bf215546Sopenharmony_civoid ImGui::ItemSize(const ImRect& bb, float text_offset_y) 2771bf215546Sopenharmony_ci{ 2772bf215546Sopenharmony_ci ItemSize(bb.GetSize(), text_offset_y); 2773bf215546Sopenharmony_ci} 2774bf215546Sopenharmony_ci 2775bf215546Sopenharmony_ci// Declare item bounding box for clipping and interaction. 2776bf215546Sopenharmony_ci// Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface 2777bf215546Sopenharmony_ci// declare their minimum size requirement to ItemSize() and then use a larger region for drawing/interaction, which is passed to ItemAdd(). 2778bf215546Sopenharmony_cibool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg) 2779bf215546Sopenharmony_ci{ 2780bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 2781bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 2782bf215546Sopenharmony_ci 2783bf215546Sopenharmony_ci if (id != 0) 2784bf215546Sopenharmony_ci { 2785bf215546Sopenharmony_ci // Navigation processing runs prior to clipping early-out 2786bf215546Sopenharmony_ci // (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget 2787bf215546Sopenharmony_ci // (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests unfortunately, but it is still limited to one window. 2788bf215546Sopenharmony_ci // it may not scale very well for windows with ten of thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame. 2789bf215546Sopenharmony_ci // We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick) 2790bf215546Sopenharmony_ci window->DC.NavLayerActiveMaskNext |= window->DC.NavLayerCurrentMask; 2791bf215546Sopenharmony_ci if (g.NavId == id || g.NavAnyRequest) 2792bf215546Sopenharmony_ci if (g.NavWindow->RootWindowForNav == window->RootWindowForNav) 2793bf215546Sopenharmony_ci if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened)) 2794bf215546Sopenharmony_ci NavProcessItem(window, nav_bb_arg ? *nav_bb_arg : bb, id); 2795bf215546Sopenharmony_ci } 2796bf215546Sopenharmony_ci 2797bf215546Sopenharmony_ci window->DC.LastItemId = id; 2798bf215546Sopenharmony_ci window->DC.LastItemRect = bb; 2799bf215546Sopenharmony_ci window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None; 2800bf215546Sopenharmony_ci 2801bf215546Sopenharmony_ci#ifdef IMGUI_ENABLE_TEST_ENGINE 2802bf215546Sopenharmony_ci if (id != 0) 2803bf215546Sopenharmony_ci ImGuiTestEngineHook_ItemAdd(&g, nav_bb_arg ? *nav_bb_arg : bb, id); 2804bf215546Sopenharmony_ci#endif 2805bf215546Sopenharmony_ci 2806bf215546Sopenharmony_ci // Clipping test 2807bf215546Sopenharmony_ci const bool is_clipped = IsClippedEx(bb, id, false); 2808bf215546Sopenharmony_ci if (is_clipped) 2809bf215546Sopenharmony_ci return false; 2810bf215546Sopenharmony_ci //if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG] 2811bf215546Sopenharmony_ci 2812bf215546Sopenharmony_ci // We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them) 2813bf215546Sopenharmony_ci if (IsMouseHoveringRect(bb.Min, bb.Max)) 2814bf215546Sopenharmony_ci window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredRect; 2815bf215546Sopenharmony_ci return true; 2816bf215546Sopenharmony_ci} 2817bf215546Sopenharmony_ci 2818bf215546Sopenharmony_ci// This is roughly matching the behavior of internal-facing ItemHoverable() 2819bf215546Sopenharmony_ci// - 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() 2820bf215546Sopenharmony_ci// - this should work even for non-interactive items that have no ID, so we cannot use LastItemId 2821bf215546Sopenharmony_cibool ImGui::IsItemHovered(ImGuiHoveredFlags flags) 2822bf215546Sopenharmony_ci{ 2823bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 2824bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 2825bf215546Sopenharmony_ci if (g.NavDisableMouseHover && !g.NavDisableHighlight) 2826bf215546Sopenharmony_ci return IsItemFocused(); 2827bf215546Sopenharmony_ci 2828bf215546Sopenharmony_ci // Test for bounding box overlap, as updated as ItemAdd() 2829bf215546Sopenharmony_ci if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect)) 2830bf215546Sopenharmony_ci return false; 2831bf215546Sopenharmony_ci IM_ASSERT((flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) == 0); // Flags not supported by this function 2832bf215546Sopenharmony_ci 2833bf215546Sopenharmony_ci // Test if we are hovering the right window (our window could be behind another window) 2834bf215546Sopenharmony_ci // [2017/10/16] Reverted commit 344d48be3 and testing RootWindow instead. I believe it is correct to NOT test for RootWindow but this leaves us unable to use IsItemHovered() after EndChild() itself. 2835bf215546Sopenharmony_ci // Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was the test that has been running for a long while. 2836bf215546Sopenharmony_ci //if (g.HoveredWindow != window) 2837bf215546Sopenharmony_ci // return false; 2838bf215546Sopenharmony_ci if (g.HoveredRootWindow != window->RootWindow && !(flags & ImGuiHoveredFlags_AllowWhenOverlapped)) 2839bf215546Sopenharmony_ci return false; 2840bf215546Sopenharmony_ci 2841bf215546Sopenharmony_ci // Test if another item is active (e.g. being dragged) 2842bf215546Sopenharmony_ci if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) 2843bf215546Sopenharmony_ci if (g.ActiveId != 0 && g.ActiveId != window->DC.LastItemId && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId) 2844bf215546Sopenharmony_ci return false; 2845bf215546Sopenharmony_ci 2846bf215546Sopenharmony_ci // Test if interactions on this window are blocked by an active popup or modal 2847bf215546Sopenharmony_ci if (!IsWindowContentHoverable(window, flags)) 2848bf215546Sopenharmony_ci return false; 2849bf215546Sopenharmony_ci 2850bf215546Sopenharmony_ci // Test if the item is disabled 2851bf215546Sopenharmony_ci if ((window->DC.ItemFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled)) 2852bf215546Sopenharmony_ci return false; 2853bf215546Sopenharmony_ci 2854bf215546Sopenharmony_ci // Special handling for the dummy item after Begin() which represent the title bar or tab. 2855bf215546Sopenharmony_ci // When the window is collapsed (SkipItems==true) that last item will never be overwritten so we need to detect the case. 2856bf215546Sopenharmony_ci if (window->DC.LastItemId == window->MoveId && window->WriteAccessed) 2857bf215546Sopenharmony_ci return false; 2858bf215546Sopenharmony_ci return true; 2859bf215546Sopenharmony_ci} 2860bf215546Sopenharmony_ci 2861bf215546Sopenharmony_ci// Internal facing ItemHoverable() used when submitting widgets. Differs slightly from IsItemHovered(). 2862bf215546Sopenharmony_cibool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id) 2863bf215546Sopenharmony_ci{ 2864bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 2865bf215546Sopenharmony_ci if (g.HoveredId != 0 && g.HoveredId != id && !g.HoveredIdAllowOverlap) 2866bf215546Sopenharmony_ci return false; 2867bf215546Sopenharmony_ci 2868bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 2869bf215546Sopenharmony_ci if (g.HoveredWindow != window) 2870bf215546Sopenharmony_ci return false; 2871bf215546Sopenharmony_ci if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap) 2872bf215546Sopenharmony_ci return false; 2873bf215546Sopenharmony_ci if (!IsMouseHoveringRect(bb.Min, bb.Max)) 2874bf215546Sopenharmony_ci return false; 2875bf215546Sopenharmony_ci if (g.NavDisableMouseHover || !IsWindowContentHoverable(window, ImGuiHoveredFlags_None)) 2876bf215546Sopenharmony_ci return false; 2877bf215546Sopenharmony_ci if (window->DC.ItemFlags & ImGuiItemFlags_Disabled) 2878bf215546Sopenharmony_ci return false; 2879bf215546Sopenharmony_ci 2880bf215546Sopenharmony_ci SetHoveredID(id); 2881bf215546Sopenharmony_ci return true; 2882bf215546Sopenharmony_ci} 2883bf215546Sopenharmony_ci 2884bf215546Sopenharmony_cibool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged) 2885bf215546Sopenharmony_ci{ 2886bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 2887bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 2888bf215546Sopenharmony_ci if (!bb.Overlaps(window->ClipRect)) 2889bf215546Sopenharmony_ci if (id == 0 || id != g.ActiveId) 2890bf215546Sopenharmony_ci if (clip_even_when_logged || !g.LogEnabled) 2891bf215546Sopenharmony_ci return true; 2892bf215546Sopenharmony_ci return false; 2893bf215546Sopenharmony_ci} 2894bf215546Sopenharmony_ci 2895bf215546Sopenharmony_cibool ImGui::FocusableItemRegister(ImGuiWindow* window, ImGuiID id, bool tab_stop) 2896bf215546Sopenharmony_ci{ 2897bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 2898bf215546Sopenharmony_ci 2899bf215546Sopenharmony_ci const bool is_tab_stop = (window->DC.ItemFlags & (ImGuiItemFlags_NoTabStop | ImGuiItemFlags_Disabled)) == 0; 2900bf215546Sopenharmony_ci window->FocusIdxAllCounter++; 2901bf215546Sopenharmony_ci if (is_tab_stop) 2902bf215546Sopenharmony_ci window->FocusIdxTabCounter++; 2903bf215546Sopenharmony_ci 2904bf215546Sopenharmony_ci // Process keyboard input at this point: TAB/Shift-TAB to tab out of the currently focused item. 2905bf215546Sopenharmony_ci // Note that we can always TAB out of a widget that doesn't allow tabbing in. 2906bf215546Sopenharmony_ci if (tab_stop && (g.ActiveId == id) && window->FocusIdxAllRequestNext == INT_MAX && window->FocusIdxTabRequestNext == INT_MAX && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab)) 2907bf215546Sopenharmony_ci window->FocusIdxTabRequestNext = window->FocusIdxTabCounter + (g.IO.KeyShift ? (is_tab_stop ? -1 : 0) : +1); // Modulo on index will be applied at the end of frame once we've got the total counter of items. 2908bf215546Sopenharmony_ci 2909bf215546Sopenharmony_ci if (window->FocusIdxAllCounter == window->FocusIdxAllRequestCurrent) 2910bf215546Sopenharmony_ci return true; 2911bf215546Sopenharmony_ci if (is_tab_stop && window->FocusIdxTabCounter == window->FocusIdxTabRequestCurrent) 2912bf215546Sopenharmony_ci { 2913bf215546Sopenharmony_ci g.NavJustTabbedId = id; 2914bf215546Sopenharmony_ci return true; 2915bf215546Sopenharmony_ci } 2916bf215546Sopenharmony_ci 2917bf215546Sopenharmony_ci return false; 2918bf215546Sopenharmony_ci} 2919bf215546Sopenharmony_ci 2920bf215546Sopenharmony_civoid ImGui::FocusableItemUnregister(ImGuiWindow* window) 2921bf215546Sopenharmony_ci{ 2922bf215546Sopenharmony_ci window->FocusIdxAllCounter--; 2923bf215546Sopenharmony_ci window->FocusIdxTabCounter--; 2924bf215546Sopenharmony_ci} 2925bf215546Sopenharmony_ci 2926bf215546Sopenharmony_ciImVec2 ImGui::CalcItemSize(ImVec2 size, float default_x, float default_y) 2927bf215546Sopenharmony_ci{ 2928bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 2929bf215546Sopenharmony_ci ImVec2 content_max; 2930bf215546Sopenharmony_ci if (size.x < 0.0f || size.y < 0.0f) 2931bf215546Sopenharmony_ci content_max = g.CurrentWindow->Pos + GetContentRegionMax(); 2932bf215546Sopenharmony_ci if (size.x <= 0.0f) 2933bf215546Sopenharmony_ci size.x = (size.x == 0.0f) ? default_x : ImMax(content_max.x - g.CurrentWindow->DC.CursorPos.x, 4.0f) + size.x; 2934bf215546Sopenharmony_ci if (size.y <= 0.0f) 2935bf215546Sopenharmony_ci size.y = (size.y == 0.0f) ? default_y : ImMax(content_max.y - g.CurrentWindow->DC.CursorPos.y, 4.0f) + size.y; 2936bf215546Sopenharmony_ci return size; 2937bf215546Sopenharmony_ci} 2938bf215546Sopenharmony_ci 2939bf215546Sopenharmony_cifloat ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x) 2940bf215546Sopenharmony_ci{ 2941bf215546Sopenharmony_ci if (wrap_pos_x < 0.0f) 2942bf215546Sopenharmony_ci return 0.0f; 2943bf215546Sopenharmony_ci 2944bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindowRead(); 2945bf215546Sopenharmony_ci if (wrap_pos_x == 0.0f) 2946bf215546Sopenharmony_ci wrap_pos_x = GetContentRegionMax().x + window->Pos.x; 2947bf215546Sopenharmony_ci else if (wrap_pos_x > 0.0f) 2948bf215546Sopenharmony_ci wrap_pos_x += window->Pos.x - window->Scroll.x; // wrap_pos_x is provided is window local space 2949bf215546Sopenharmony_ci 2950bf215546Sopenharmony_ci return ImMax(wrap_pos_x - pos.x, 1.0f); 2951bf215546Sopenharmony_ci} 2952bf215546Sopenharmony_ci 2953bf215546Sopenharmony_civoid* ImGui::MemAlloc(size_t size) 2954bf215546Sopenharmony_ci{ 2955bf215546Sopenharmony_ci if (ImGuiContext* ctx = GImGui) 2956bf215546Sopenharmony_ci ctx->IO.MetricsActiveAllocations++; 2957bf215546Sopenharmony_ci return GImAllocatorAllocFunc(size, GImAllocatorUserData); 2958bf215546Sopenharmony_ci} 2959bf215546Sopenharmony_ci 2960bf215546Sopenharmony_civoid ImGui::MemFree(void* ptr) 2961bf215546Sopenharmony_ci{ 2962bf215546Sopenharmony_ci if (ptr) 2963bf215546Sopenharmony_ci if (ImGuiContext* ctx = GImGui) 2964bf215546Sopenharmony_ci ctx->IO.MetricsActiveAllocations--; 2965bf215546Sopenharmony_ci return GImAllocatorFreeFunc(ptr, GImAllocatorUserData); 2966bf215546Sopenharmony_ci} 2967bf215546Sopenharmony_ci 2968bf215546Sopenharmony_ciconst char* ImGui::GetClipboardText() 2969bf215546Sopenharmony_ci{ 2970bf215546Sopenharmony_ci return GImGui->IO.GetClipboardTextFn ? GImGui->IO.GetClipboardTextFn(GImGui->IO.ClipboardUserData) : ""; 2971bf215546Sopenharmony_ci} 2972bf215546Sopenharmony_ci 2973bf215546Sopenharmony_civoid ImGui::SetClipboardText(const char* text) 2974bf215546Sopenharmony_ci{ 2975bf215546Sopenharmony_ci if (GImGui->IO.SetClipboardTextFn) 2976bf215546Sopenharmony_ci GImGui->IO.SetClipboardTextFn(GImGui->IO.ClipboardUserData, text); 2977bf215546Sopenharmony_ci} 2978bf215546Sopenharmony_ci 2979bf215546Sopenharmony_ciconst char* ImGui::GetVersion() 2980bf215546Sopenharmony_ci{ 2981bf215546Sopenharmony_ci return IMGUI_VERSION; 2982bf215546Sopenharmony_ci} 2983bf215546Sopenharmony_ci 2984bf215546Sopenharmony_ci// Internal state access - if you want to share ImGui state between modules (e.g. DLL) or allocate it yourself 2985bf215546Sopenharmony_ci// 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 2986bf215546Sopenharmony_ciImGuiContext* ImGui::GetCurrentContext() 2987bf215546Sopenharmony_ci{ 2988bf215546Sopenharmony_ci return GImGui; 2989bf215546Sopenharmony_ci} 2990bf215546Sopenharmony_ci 2991bf215546Sopenharmony_civoid ImGui::SetCurrentContext(ImGuiContext* ctx) 2992bf215546Sopenharmony_ci{ 2993bf215546Sopenharmony_ci#ifdef IMGUI_SET_CURRENT_CONTEXT_FUNC 2994bf215546Sopenharmony_ci IMGUI_SET_CURRENT_CONTEXT_FUNC(ctx); // For custom thread-based hackery you may want to have control over this. 2995bf215546Sopenharmony_ci#else 2996bf215546Sopenharmony_ci GImGui = ctx; 2997bf215546Sopenharmony_ci#endif 2998bf215546Sopenharmony_ci} 2999bf215546Sopenharmony_ci 3000bf215546Sopenharmony_ci// Helper function to verify that the type sizes are matching between the calling file's compilation unit and imgui.cpp's compilation unit 3001bf215546Sopenharmony_ci// If the user has inconsistent compilation settings, imgui configuration #define, packing pragma, etc. you may see different structures from what imgui.cpp sees which is highly problematic. 3002bf215546Sopenharmony_cibool ImGui::DebugCheckVersionAndDataLayout(const char* version, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_vert) 3003bf215546Sopenharmony_ci{ 3004bf215546Sopenharmony_ci bool error = false; 3005bf215546Sopenharmony_ci if (strcmp(version, IMGUI_VERSION)!=0) { error = true; IM_ASSERT(strcmp(version,IMGUI_VERSION)==0 && "Mismatched version string!"); } 3006bf215546Sopenharmony_ci if (sz_io != sizeof(ImGuiIO)) { error = true; IM_ASSERT(sz_io == sizeof(ImGuiIO) && "Mismatched struct layout!"); } 3007bf215546Sopenharmony_ci if (sz_style != sizeof(ImGuiStyle)) { error = true; IM_ASSERT(sz_style == sizeof(ImGuiStyle) && "Mismatched struct layout!"); } 3008bf215546Sopenharmony_ci if (sz_vec2 != sizeof(ImVec2)) { error = true; IM_ASSERT(sz_vec2 == sizeof(ImVec2) && "Mismatched struct layout!"); } 3009bf215546Sopenharmony_ci if (sz_vec4 != sizeof(ImVec4)) { error = true; IM_ASSERT(sz_vec4 == sizeof(ImVec4) && "Mismatched struct layout!"); } 3010bf215546Sopenharmony_ci if (sz_vert != sizeof(ImDrawVert)) { error = true; IM_ASSERT(sz_vert == sizeof(ImDrawVert) && "Mismatched struct layout!"); } 3011bf215546Sopenharmony_ci return !error; 3012bf215546Sopenharmony_ci} 3013bf215546Sopenharmony_ci 3014bf215546Sopenharmony_civoid ImGui::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data) 3015bf215546Sopenharmony_ci{ 3016bf215546Sopenharmony_ci GImAllocatorAllocFunc = alloc_func; 3017bf215546Sopenharmony_ci GImAllocatorFreeFunc = free_func; 3018bf215546Sopenharmony_ci GImAllocatorUserData = user_data; 3019bf215546Sopenharmony_ci} 3020bf215546Sopenharmony_ci 3021bf215546Sopenharmony_ciImGuiContext* ImGui::CreateContext(ImFontAtlas* shared_font_atlas) 3022bf215546Sopenharmony_ci{ 3023bf215546Sopenharmony_ci ImGuiContext* ctx = IM_NEW(ImGuiContext)(shared_font_atlas); 3024bf215546Sopenharmony_ci if (GImGui == NULL) 3025bf215546Sopenharmony_ci SetCurrentContext(ctx); 3026bf215546Sopenharmony_ci Initialize(ctx); 3027bf215546Sopenharmony_ci return ctx; 3028bf215546Sopenharmony_ci} 3029bf215546Sopenharmony_ci 3030bf215546Sopenharmony_civoid ImGui::DestroyContext(ImGuiContext* ctx) 3031bf215546Sopenharmony_ci{ 3032bf215546Sopenharmony_ci if (ctx == NULL) 3033bf215546Sopenharmony_ci ctx = GImGui; 3034bf215546Sopenharmony_ci Shutdown(ctx); 3035bf215546Sopenharmony_ci if (GImGui == ctx) 3036bf215546Sopenharmony_ci SetCurrentContext(NULL); 3037bf215546Sopenharmony_ci IM_DELETE(ctx); 3038bf215546Sopenharmony_ci} 3039bf215546Sopenharmony_ci 3040bf215546Sopenharmony_ciImGuiIO& ImGui::GetIO() 3041bf215546Sopenharmony_ci{ 3042bf215546Sopenharmony_ci IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?"); 3043bf215546Sopenharmony_ci return GImGui->IO; 3044bf215546Sopenharmony_ci} 3045bf215546Sopenharmony_ci 3046bf215546Sopenharmony_ciImGuiStyle& ImGui::GetStyle() 3047bf215546Sopenharmony_ci{ 3048bf215546Sopenharmony_ci IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?"); 3049bf215546Sopenharmony_ci return GImGui->Style; 3050bf215546Sopenharmony_ci} 3051bf215546Sopenharmony_ci 3052bf215546Sopenharmony_ci// Same value as passed to the old io.RenderDrawListsFn function. Valid after Render() and until the next call to NewFrame() 3053bf215546Sopenharmony_ciImDrawData* ImGui::GetDrawData() 3054bf215546Sopenharmony_ci{ 3055bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 3056bf215546Sopenharmony_ci return g.DrawData.Valid ? &g.DrawData : NULL; 3057bf215546Sopenharmony_ci} 3058bf215546Sopenharmony_ci 3059bf215546Sopenharmony_cidouble ImGui::GetTime() 3060bf215546Sopenharmony_ci{ 3061bf215546Sopenharmony_ci return GImGui->Time; 3062bf215546Sopenharmony_ci} 3063bf215546Sopenharmony_ci 3064bf215546Sopenharmony_ciint ImGui::GetFrameCount() 3065bf215546Sopenharmony_ci{ 3066bf215546Sopenharmony_ci return GImGui->FrameCount; 3067bf215546Sopenharmony_ci} 3068bf215546Sopenharmony_ci 3069bf215546Sopenharmony_cistatic ImDrawList* GetOverlayDrawList(ImGuiWindow*) 3070bf215546Sopenharmony_ci{ 3071bf215546Sopenharmony_ci // This seemingly unnecessary wrapper simplifies compatibility between the 'master' and 'viewport' branches. 3072bf215546Sopenharmony_ci return &GImGui->OverlayDrawList; 3073bf215546Sopenharmony_ci} 3074bf215546Sopenharmony_ci 3075bf215546Sopenharmony_ciImDrawList* ImGui::GetOverlayDrawList() 3076bf215546Sopenharmony_ci{ 3077bf215546Sopenharmony_ci return &GImGui->OverlayDrawList; 3078bf215546Sopenharmony_ci} 3079bf215546Sopenharmony_ci 3080bf215546Sopenharmony_ciImDrawListSharedData* ImGui::GetDrawListSharedData() 3081bf215546Sopenharmony_ci{ 3082bf215546Sopenharmony_ci return &GImGui->DrawListSharedData; 3083bf215546Sopenharmony_ci} 3084bf215546Sopenharmony_ci 3085bf215546Sopenharmony_civoid ImGui::StartMouseMovingWindow(ImGuiWindow* window) 3086bf215546Sopenharmony_ci{ 3087bf215546Sopenharmony_ci // Set ActiveId even if the _NoMove flag is set. Without it, dragging away from a window with _NoMove would activate hover on other windows. 3088bf215546Sopenharmony_ci // We _also_ call this when clicking in a window empty space when io.ConfigWindowsMoveFromTitleBarOnly is set, but clear g.MovingWindow afterward. 3089bf215546Sopenharmony_ci // This is because we want ActiveId to be set even when the window is not permitted to move. 3090bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 3091bf215546Sopenharmony_ci FocusWindow(window); 3092bf215546Sopenharmony_ci SetActiveID(window->MoveId, window); 3093bf215546Sopenharmony_ci g.NavDisableHighlight = true; 3094bf215546Sopenharmony_ci g.ActiveIdClickOffset = g.IO.MousePos - window->RootWindow->Pos; 3095bf215546Sopenharmony_ci 3096bf215546Sopenharmony_ci bool can_move_window = true; 3097bf215546Sopenharmony_ci if ((window->Flags & ImGuiWindowFlags_NoMove) || (window->RootWindow->Flags & ImGuiWindowFlags_NoMove)) 3098bf215546Sopenharmony_ci can_move_window = false; 3099bf215546Sopenharmony_ci if (can_move_window) 3100bf215546Sopenharmony_ci g.MovingWindow = window; 3101bf215546Sopenharmony_ci} 3102bf215546Sopenharmony_ci 3103bf215546Sopenharmony_ci// Handle mouse moving window 3104bf215546Sopenharmony_ci// Note: moving window with the navigation keys (Square + d-pad / CTRL+TAB + Arrows) are processed in NavUpdateWindowing() 3105bf215546Sopenharmony_civoid ImGui::UpdateMouseMovingWindowNewFrame() 3106bf215546Sopenharmony_ci{ 3107bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 3108bf215546Sopenharmony_ci if (g.MovingWindow != NULL) 3109bf215546Sopenharmony_ci { 3110bf215546Sopenharmony_ci // We actually want to move the root window. g.MovingWindow == window we clicked on (could be a child window). 3111bf215546Sopenharmony_ci // We track it to preserve Focus and so that generally ActiveIdWindow == MovingWindow and ActiveId == MovingWindow->MoveId for consistency. 3112bf215546Sopenharmony_ci KeepAliveID(g.ActiveId); 3113bf215546Sopenharmony_ci IM_ASSERT(g.MovingWindow && g.MovingWindow->RootWindow); 3114bf215546Sopenharmony_ci ImGuiWindow* moving_window = g.MovingWindow->RootWindow; 3115bf215546Sopenharmony_ci if (g.IO.MouseDown[0] && IsMousePosValid(&g.IO.MousePos)) 3116bf215546Sopenharmony_ci { 3117bf215546Sopenharmony_ci ImVec2 pos = g.IO.MousePos - g.ActiveIdClickOffset; 3118bf215546Sopenharmony_ci if (moving_window->Pos.x != pos.x || moving_window->Pos.y != pos.y) 3119bf215546Sopenharmony_ci { 3120bf215546Sopenharmony_ci MarkIniSettingsDirty(moving_window); 3121bf215546Sopenharmony_ci SetWindowPos(moving_window, pos, ImGuiCond_Always); 3122bf215546Sopenharmony_ci } 3123bf215546Sopenharmony_ci FocusWindow(g.MovingWindow); 3124bf215546Sopenharmony_ci } 3125bf215546Sopenharmony_ci else 3126bf215546Sopenharmony_ci { 3127bf215546Sopenharmony_ci ClearActiveID(); 3128bf215546Sopenharmony_ci g.MovingWindow = NULL; 3129bf215546Sopenharmony_ci } 3130bf215546Sopenharmony_ci } 3131bf215546Sopenharmony_ci else 3132bf215546Sopenharmony_ci { 3133bf215546Sopenharmony_ci // When clicking/dragging from a window that has the _NoMove flag, we still set the ActiveId in order to prevent hovering others. 3134bf215546Sopenharmony_ci if (g.ActiveIdWindow && g.ActiveIdWindow->MoveId == g.ActiveId) 3135bf215546Sopenharmony_ci { 3136bf215546Sopenharmony_ci KeepAliveID(g.ActiveId); 3137bf215546Sopenharmony_ci if (!g.IO.MouseDown[0]) 3138bf215546Sopenharmony_ci ClearActiveID(); 3139bf215546Sopenharmony_ci } 3140bf215546Sopenharmony_ci } 3141bf215546Sopenharmony_ci} 3142bf215546Sopenharmony_ci 3143bf215546Sopenharmony_ci// Initiate moving window, handle left-click and right-click focus 3144bf215546Sopenharmony_civoid ImGui::UpdateMouseMovingWindowEndFrame() 3145bf215546Sopenharmony_ci{ 3146bf215546Sopenharmony_ci // Initiate moving window 3147bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 3148bf215546Sopenharmony_ci if (g.ActiveId != 0 || g.HoveredId != 0) 3149bf215546Sopenharmony_ci return; 3150bf215546Sopenharmony_ci 3151bf215546Sopenharmony_ci // Unless we just made a window/popup appear 3152bf215546Sopenharmony_ci if (g.NavWindow && g.NavWindow->Appearing) 3153bf215546Sopenharmony_ci return; 3154bf215546Sopenharmony_ci 3155bf215546Sopenharmony_ci // Click to focus window and start moving (after we're done with all our widgets) 3156bf215546Sopenharmony_ci if (g.IO.MouseClicked[0]) 3157bf215546Sopenharmony_ci { 3158bf215546Sopenharmony_ci if (g.HoveredRootWindow != NULL) 3159bf215546Sopenharmony_ci { 3160bf215546Sopenharmony_ci StartMouseMovingWindow(g.HoveredWindow); 3161bf215546Sopenharmony_ci if (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(g.HoveredRootWindow->Flags & ImGuiWindowFlags_NoTitleBar)) 3162bf215546Sopenharmony_ci if (!g.HoveredRootWindow->TitleBarRect().Contains(g.IO.MouseClickedPos[0])) 3163bf215546Sopenharmony_ci g.MovingWindow = NULL; 3164bf215546Sopenharmony_ci } 3165bf215546Sopenharmony_ci else if (g.NavWindow != NULL && GetFrontMostPopupModal() == NULL) 3166bf215546Sopenharmony_ci { 3167bf215546Sopenharmony_ci // Clicking on void disable focus 3168bf215546Sopenharmony_ci FocusWindow(NULL); 3169bf215546Sopenharmony_ci } 3170bf215546Sopenharmony_ci } 3171bf215546Sopenharmony_ci 3172bf215546Sopenharmony_ci // With right mouse button we close popups without changing focus 3173bf215546Sopenharmony_ci // (The left mouse button path calls FocusWindow which will lead NewFrame->ClosePopupsOverWindow to trigger) 3174bf215546Sopenharmony_ci if (g.IO.MouseClicked[1]) 3175bf215546Sopenharmony_ci { 3176bf215546Sopenharmony_ci // Find the top-most window between HoveredWindow and the front most Modal Window. 3177bf215546Sopenharmony_ci // This is where we can trim the popup stack. 3178bf215546Sopenharmony_ci ImGuiWindow* modal = GetFrontMostPopupModal(); 3179bf215546Sopenharmony_ci bool hovered_window_above_modal = false; 3180bf215546Sopenharmony_ci if (modal == NULL) 3181bf215546Sopenharmony_ci hovered_window_above_modal = true; 3182bf215546Sopenharmony_ci for (int i = g.Windows.Size - 1; i >= 0 && hovered_window_above_modal == false; i--) 3183bf215546Sopenharmony_ci { 3184bf215546Sopenharmony_ci ImGuiWindow* window = g.Windows[i]; 3185bf215546Sopenharmony_ci if (window == modal) 3186bf215546Sopenharmony_ci break; 3187bf215546Sopenharmony_ci if (window == g.HoveredWindow) 3188bf215546Sopenharmony_ci hovered_window_above_modal = true; 3189bf215546Sopenharmony_ci } 3190bf215546Sopenharmony_ci ClosePopupsOverWindow(hovered_window_above_modal ? g.HoveredWindow : modal); 3191bf215546Sopenharmony_ci } 3192bf215546Sopenharmony_ci} 3193bf215546Sopenharmony_ci 3194bf215546Sopenharmony_cistatic bool IsWindowActiveAndVisible(ImGuiWindow* window) 3195bf215546Sopenharmony_ci{ 3196bf215546Sopenharmony_ci return (window->Active) && (!window->Hidden); 3197bf215546Sopenharmony_ci} 3198bf215546Sopenharmony_ci 3199bf215546Sopenharmony_cistatic void ImGui::UpdateMouseInputs() 3200bf215546Sopenharmony_ci{ 3201bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 3202bf215546Sopenharmony_ci 3203bf215546Sopenharmony_ci // Round mouse position to avoid spreading non-rounded position (e.g. UpdateManualResize doesn't support them well) 3204bf215546Sopenharmony_ci if (IsMousePosValid(&g.IO.MousePos)) 3205bf215546Sopenharmony_ci g.IO.MousePos = g.LastValidMousePos = ImFloor(g.IO.MousePos); 3206bf215546Sopenharmony_ci 3207bf215546Sopenharmony_ci // If mouse just appeared or disappeared (usually denoted by -FLT_MAX components) we cancel out movement in MouseDelta 3208bf215546Sopenharmony_ci if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MousePosPrev)) 3209bf215546Sopenharmony_ci g.IO.MouseDelta = g.IO.MousePos - g.IO.MousePosPrev; 3210bf215546Sopenharmony_ci else 3211bf215546Sopenharmony_ci g.IO.MouseDelta = ImVec2(0.0f, 0.0f); 3212bf215546Sopenharmony_ci if (g.IO.MouseDelta.x != 0.0f || g.IO.MouseDelta.y != 0.0f) 3213bf215546Sopenharmony_ci g.NavDisableMouseHover = false; 3214bf215546Sopenharmony_ci 3215bf215546Sopenharmony_ci g.IO.MousePosPrev = g.IO.MousePos; 3216bf215546Sopenharmony_ci for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++) 3217bf215546Sopenharmony_ci { 3218bf215546Sopenharmony_ci g.IO.MouseClicked[i] = g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] < 0.0f; 3219bf215546Sopenharmony_ci g.IO.MouseReleased[i] = !g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] >= 0.0f; 3220bf215546Sopenharmony_ci g.IO.MouseDownDurationPrev[i] = g.IO.MouseDownDuration[i]; 3221bf215546Sopenharmony_ci g.IO.MouseDownDuration[i] = g.IO.MouseDown[i] ? (g.IO.MouseDownDuration[i] < 0.0f ? 0.0f : g.IO.MouseDownDuration[i] + g.IO.DeltaTime) : -1.0f; 3222bf215546Sopenharmony_ci g.IO.MouseDoubleClicked[i] = false; 3223bf215546Sopenharmony_ci if (g.IO.MouseClicked[i]) 3224bf215546Sopenharmony_ci { 3225bf215546Sopenharmony_ci if ((float)(g.Time - g.IO.MouseClickedTime[i]) < g.IO.MouseDoubleClickTime) 3226bf215546Sopenharmony_ci { 3227bf215546Sopenharmony_ci ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f); 3228bf215546Sopenharmony_ci if (ImLengthSqr(delta_from_click_pos) < g.IO.MouseDoubleClickMaxDist * g.IO.MouseDoubleClickMaxDist) 3229bf215546Sopenharmony_ci g.IO.MouseDoubleClicked[i] = true; 3230bf215546Sopenharmony_ci g.IO.MouseClickedTime[i] = -FLT_MAX; // so the third click isn't turned into a double-click 3231bf215546Sopenharmony_ci } 3232bf215546Sopenharmony_ci else 3233bf215546Sopenharmony_ci { 3234bf215546Sopenharmony_ci g.IO.MouseClickedTime[i] = g.Time; 3235bf215546Sopenharmony_ci } 3236bf215546Sopenharmony_ci g.IO.MouseClickedPos[i] = g.IO.MousePos; 3237bf215546Sopenharmony_ci g.IO.MouseDragMaxDistanceAbs[i] = ImVec2(0.0f, 0.0f); 3238bf215546Sopenharmony_ci g.IO.MouseDragMaxDistanceSqr[i] = 0.0f; 3239bf215546Sopenharmony_ci } 3240bf215546Sopenharmony_ci else if (g.IO.MouseDown[i]) 3241bf215546Sopenharmony_ci { 3242bf215546Sopenharmony_ci // Maintain the maximum distance we reaching from the initial click position, which is used with dragging threshold 3243bf215546Sopenharmony_ci ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f); 3244bf215546Sopenharmony_ci g.IO.MouseDragMaxDistanceSqr[i] = ImMax(g.IO.MouseDragMaxDistanceSqr[i], ImLengthSqr(delta_from_click_pos)); 3245bf215546Sopenharmony_ci g.IO.MouseDragMaxDistanceAbs[i].x = ImMax(g.IO.MouseDragMaxDistanceAbs[i].x, delta_from_click_pos.x < 0.0f ? -delta_from_click_pos.x : delta_from_click_pos.x); 3246bf215546Sopenharmony_ci g.IO.MouseDragMaxDistanceAbs[i].y = ImMax(g.IO.MouseDragMaxDistanceAbs[i].y, delta_from_click_pos.y < 0.0f ? -delta_from_click_pos.y : delta_from_click_pos.y); 3247bf215546Sopenharmony_ci } 3248bf215546Sopenharmony_ci if (g.IO.MouseClicked[i]) // Clicking any mouse button reactivate mouse hovering which may have been deactivated by gamepad/keyboard navigation 3249bf215546Sopenharmony_ci g.NavDisableMouseHover = false; 3250bf215546Sopenharmony_ci } 3251bf215546Sopenharmony_ci} 3252bf215546Sopenharmony_ci 3253bf215546Sopenharmony_civoid ImGui::UpdateMouseWheel() 3254bf215546Sopenharmony_ci{ 3255bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 3256bf215546Sopenharmony_ci if (!g.HoveredWindow || g.HoveredWindow->Collapsed) 3257bf215546Sopenharmony_ci return; 3258bf215546Sopenharmony_ci if (g.IO.MouseWheel == 0.0f && g.IO.MouseWheelH == 0.0f) 3259bf215546Sopenharmony_ci return; 3260bf215546Sopenharmony_ci 3261bf215546Sopenharmony_ci // If a child window has the ImGuiWindowFlags_NoScrollWithMouse flag, we give a chance to scroll its parent (unless either ImGuiWindowFlags_NoInputs or ImGuiWindowFlags_NoScrollbar are also set). 3262bf215546Sopenharmony_ci ImGuiWindow* window = g.HoveredWindow; 3263bf215546Sopenharmony_ci ImGuiWindow* scroll_window = window; 3264bf215546Sopenharmony_ci while ((scroll_window->Flags & ImGuiWindowFlags_ChildWindow) && (scroll_window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(scroll_window->Flags & ImGuiWindowFlags_NoScrollbar) && !(scroll_window->Flags & ImGuiWindowFlags_NoMouseInputs) && scroll_window->ParentWindow) 3265bf215546Sopenharmony_ci scroll_window = scroll_window->ParentWindow; 3266bf215546Sopenharmony_ci const bool scroll_allowed = !(scroll_window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(scroll_window->Flags & ImGuiWindowFlags_NoMouseInputs); 3267bf215546Sopenharmony_ci 3268bf215546Sopenharmony_ci if (g.IO.MouseWheel != 0.0f) 3269bf215546Sopenharmony_ci { 3270bf215546Sopenharmony_ci if (g.IO.KeyCtrl && g.IO.FontAllowUserScaling) 3271bf215546Sopenharmony_ci { 3272bf215546Sopenharmony_ci // Zoom / Scale window 3273bf215546Sopenharmony_ci const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f); 3274bf215546Sopenharmony_ci const float scale = new_font_scale / window->FontWindowScale; 3275bf215546Sopenharmony_ci window->FontWindowScale = new_font_scale; 3276bf215546Sopenharmony_ci 3277bf215546Sopenharmony_ci const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size; 3278bf215546Sopenharmony_ci window->Pos += offset; 3279bf215546Sopenharmony_ci window->Size *= scale; 3280bf215546Sopenharmony_ci window->SizeFull *= scale; 3281bf215546Sopenharmony_ci } 3282bf215546Sopenharmony_ci else if (!g.IO.KeyCtrl && scroll_allowed) 3283bf215546Sopenharmony_ci { 3284bf215546Sopenharmony_ci // Mouse wheel vertical scrolling 3285bf215546Sopenharmony_ci float scroll_amount = 5 * scroll_window->CalcFontSize(); 3286bf215546Sopenharmony_ci scroll_amount = (float)(int)ImMin(scroll_amount, (scroll_window->ContentsRegionRect.GetHeight() + scroll_window->WindowPadding.y * 2.0f) * 0.67f); 3287bf215546Sopenharmony_ci SetWindowScrollY(scroll_window, scroll_window->Scroll.y - g.IO.MouseWheel * scroll_amount); 3288bf215546Sopenharmony_ci } 3289bf215546Sopenharmony_ci } 3290bf215546Sopenharmony_ci if (g.IO.MouseWheelH != 0.0f && scroll_allowed && !g.IO.KeyCtrl) 3291bf215546Sopenharmony_ci { 3292bf215546Sopenharmony_ci // Mouse wheel horizontal scrolling (for hardware that supports it) 3293bf215546Sopenharmony_ci float scroll_amount = scroll_window->CalcFontSize(); 3294bf215546Sopenharmony_ci SetWindowScrollX(scroll_window, scroll_window->Scroll.x - g.IO.MouseWheelH * scroll_amount); 3295bf215546Sopenharmony_ci } 3296bf215546Sopenharmony_ci} 3297bf215546Sopenharmony_ci 3298bf215546Sopenharmony_ci// 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) 3299bf215546Sopenharmony_civoid ImGui::UpdateHoveredWindowAndCaptureFlags() 3300bf215546Sopenharmony_ci{ 3301bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 3302bf215546Sopenharmony_ci 3303bf215546Sopenharmony_ci // Find the window hovered by mouse: 3304bf215546Sopenharmony_ci // - Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow. 3305bf215546Sopenharmony_ci // - 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. 3306bf215546Sopenharmony_ci // - 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. 3307bf215546Sopenharmony_ci FindHoveredWindow(); 3308bf215546Sopenharmony_ci 3309bf215546Sopenharmony_ci // Modal windows prevents cursor from hovering behind them. 3310bf215546Sopenharmony_ci ImGuiWindow* modal_window = GetFrontMostPopupModal(); 3311bf215546Sopenharmony_ci if (modal_window) 3312bf215546Sopenharmony_ci if (g.HoveredRootWindow && !IsWindowChildOf(g.HoveredRootWindow, modal_window)) 3313bf215546Sopenharmony_ci g.HoveredRootWindow = g.HoveredWindow = NULL; 3314bf215546Sopenharmony_ci 3315bf215546Sopenharmony_ci // Disabled mouse? 3316bf215546Sopenharmony_ci if (g.IO.ConfigFlags & ImGuiConfigFlags_NoMouse) 3317bf215546Sopenharmony_ci g.HoveredWindow = g.HoveredRootWindow = NULL; 3318bf215546Sopenharmony_ci 3319bf215546Sopenharmony_ci // We track click ownership. When clicked outside of a window the click is owned by the application and won't report hovering nor request capture even while dragging over our windows afterward. 3320bf215546Sopenharmony_ci int mouse_earliest_button_down = -1; 3321bf215546Sopenharmony_ci bool mouse_any_down = false; 3322bf215546Sopenharmony_ci for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++) 3323bf215546Sopenharmony_ci { 3324bf215546Sopenharmony_ci if (g.IO.MouseClicked[i]) 3325bf215546Sopenharmony_ci g.IO.MouseDownOwned[i] = (g.HoveredWindow != NULL) || (!g.OpenPopupStack.empty()); 3326bf215546Sopenharmony_ci mouse_any_down |= g.IO.MouseDown[i]; 3327bf215546Sopenharmony_ci if (g.IO.MouseDown[i]) 3328bf215546Sopenharmony_ci if (mouse_earliest_button_down == -1 || g.IO.MouseClickedTime[i] < g.IO.MouseClickedTime[mouse_earliest_button_down]) 3329bf215546Sopenharmony_ci mouse_earliest_button_down = i; 3330bf215546Sopenharmony_ci } 3331bf215546Sopenharmony_ci const bool mouse_avail_to_imgui = (mouse_earliest_button_down == -1) || g.IO.MouseDownOwned[mouse_earliest_button_down]; 3332bf215546Sopenharmony_ci 3333bf215546Sopenharmony_ci // If mouse was first clicked outside of ImGui bounds we also cancel out hovering. 3334bf215546Sopenharmony_ci // FIXME: For patterns of drag and drop across OS windows, we may need to rework/remove this test (first committed 311c0ca9 on 2015/02) 3335bf215546Sopenharmony_ci const bool mouse_dragging_extern_payload = g.DragDropActive && (g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) != 0; 3336bf215546Sopenharmony_ci if (!mouse_avail_to_imgui && !mouse_dragging_extern_payload) 3337bf215546Sopenharmony_ci g.HoveredWindow = g.HoveredRootWindow = NULL; 3338bf215546Sopenharmony_ci 3339bf215546Sopenharmony_ci // Update io.WantCaptureMouse for the user application (true = dispatch mouse info to imgui, false = dispatch mouse info to imgui + app) 3340bf215546Sopenharmony_ci if (g.WantCaptureMouseNextFrame != -1) 3341bf215546Sopenharmony_ci g.IO.WantCaptureMouse = (g.WantCaptureMouseNextFrame != 0); 3342bf215546Sopenharmony_ci else 3343bf215546Sopenharmony_ci g.IO.WantCaptureMouse = (mouse_avail_to_imgui && (g.HoveredWindow != NULL || mouse_any_down)) || (!g.OpenPopupStack.empty()); 3344bf215546Sopenharmony_ci 3345bf215546Sopenharmony_ci // Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to imgui, false = dispatch keyboard info to imgui + app) 3346bf215546Sopenharmony_ci if (g.WantCaptureKeyboardNextFrame != -1) 3347bf215546Sopenharmony_ci g.IO.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != 0); 3348bf215546Sopenharmony_ci else 3349bf215546Sopenharmony_ci g.IO.WantCaptureKeyboard = (g.ActiveId != 0) || (modal_window != NULL); 3350bf215546Sopenharmony_ci if (g.IO.NavActive && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard)) 3351bf215546Sopenharmony_ci g.IO.WantCaptureKeyboard = true; 3352bf215546Sopenharmony_ci 3353bf215546Sopenharmony_ci // Update io.WantTextInput flag, this is to allow systems without a keyboard (e.g. mobile, hand-held) to show a software keyboard if possible 3354bf215546Sopenharmony_ci g.IO.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false; 3355bf215546Sopenharmony_ci} 3356bf215546Sopenharmony_ci 3357bf215546Sopenharmony_civoid ImGui::NewFrame() 3358bf215546Sopenharmony_ci{ 3359bf215546Sopenharmony_ci IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?"); 3360bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 3361bf215546Sopenharmony_ci 3362bf215546Sopenharmony_ci#ifdef IMGUI_ENABLE_TEST_ENGINE 3363bf215546Sopenharmony_ci ImGuiTestEngineHook_PreNewFrame(&g); 3364bf215546Sopenharmony_ci#endif 3365bf215546Sopenharmony_ci 3366bf215546Sopenharmony_ci // Check user data 3367bf215546Sopenharmony_ci // (We pass an error message in the assert expression to make it visible to programmers who are not using a debugger, as most assert handlers display their argument) 3368bf215546Sopenharmony_ci IM_ASSERT(g.Initialized); 3369bf215546Sopenharmony_ci IM_ASSERT((g.IO.DeltaTime > 0.0f || g.FrameCount == 0) && "Need a positive DeltaTime!"); 3370bf215546Sopenharmony_ci IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f && "Invalid DisplaySize value!"); 3371bf215546Sopenharmony_ci IM_ASSERT(g.IO.Fonts->Fonts.Size > 0 && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8() ?"); 3372bf215546Sopenharmony_ci IM_ASSERT(g.IO.Fonts->Fonts[0]->IsLoaded() && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8() ?"); 3373bf215546Sopenharmony_ci IM_ASSERT(g.Style.CurveTessellationTol > 0.0f && "Invalid style setting!"); 3374bf215546Sopenharmony_ci IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f && "Invalid style setting. Alpha cannot be negative (allows us to avoid a few clamps in color computations)!"); 3375bf215546Sopenharmony_ci IM_ASSERT((g.FrameCount == 0 || g.FrameCountEnded == g.FrameCount) && "Forgot to call Render() or EndFrame() at the end of the previous frame?"); 3376bf215546Sopenharmony_ci for (int n = 0; n < ImGuiKey_COUNT; n++) 3377bf215546Sopenharmony_ci IM_ASSERT(g.IO.KeyMap[n] >= -1 && g.IO.KeyMap[n] < IM_ARRAYSIZE(g.IO.KeysDown) && "io.KeyMap[] contains an out of bound value (need to be 0..512, or -1 for unmapped key)"); 3378bf215546Sopenharmony_ci 3379bf215546Sopenharmony_ci // Perform simple check: required key mapping (we intentionally do NOT check all keys to not pressure user into setting up everything, but Space is required and was only recently added in 1.60 WIP) 3380bf215546Sopenharmony_ci if (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) 3381bf215546Sopenharmony_ci IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation."); 3382bf215546Sopenharmony_ci 3383bf215546Sopenharmony_ci // Perform simple check: the beta io.ConfigWindowsResizeFromEdges option requires back-end to honor mouse cursor changes and set the ImGuiBackendFlags_HasMouseCursors flag accordingly. 3384bf215546Sopenharmony_ci if (g.IO.ConfigWindowsResizeFromEdges && !(g.IO.BackendFlags & ImGuiBackendFlags_HasMouseCursors)) 3385bf215546Sopenharmony_ci g.IO.ConfigWindowsResizeFromEdges = false; 3386bf215546Sopenharmony_ci 3387bf215546Sopenharmony_ci // Load settings on first frame (if not explicitly loaded manually before) 3388bf215546Sopenharmony_ci if (!g.SettingsLoaded) 3389bf215546Sopenharmony_ci { 3390bf215546Sopenharmony_ci IM_ASSERT(g.SettingsWindows.empty()); 3391bf215546Sopenharmony_ci if (g.IO.IniFilename) 3392bf215546Sopenharmony_ci LoadIniSettingsFromDisk(g.IO.IniFilename); 3393bf215546Sopenharmony_ci g.SettingsLoaded = true; 3394bf215546Sopenharmony_ci } 3395bf215546Sopenharmony_ci 3396bf215546Sopenharmony_ci // Save settings (with a delay after the last modification, so we don't spam disk too much) 3397bf215546Sopenharmony_ci if (g.SettingsDirtyTimer > 0.0f) 3398bf215546Sopenharmony_ci { 3399bf215546Sopenharmony_ci g.SettingsDirtyTimer -= g.IO.DeltaTime; 3400bf215546Sopenharmony_ci if (g.SettingsDirtyTimer <= 0.0f) 3401bf215546Sopenharmony_ci { 3402bf215546Sopenharmony_ci if (g.IO.IniFilename != NULL) 3403bf215546Sopenharmony_ci SaveIniSettingsToDisk(g.IO.IniFilename); 3404bf215546Sopenharmony_ci else 3405bf215546Sopenharmony_ci g.IO.WantSaveIniSettings = true; // Let user know they can call SaveIniSettingsToMemory(). user will need to clear io.WantSaveIniSettings themselves. 3406bf215546Sopenharmony_ci g.SettingsDirtyTimer = 0.0f; 3407bf215546Sopenharmony_ci } 3408bf215546Sopenharmony_ci } 3409bf215546Sopenharmony_ci 3410bf215546Sopenharmony_ci g.Time += g.IO.DeltaTime; 3411bf215546Sopenharmony_ci g.FrameScopeActive = true; 3412bf215546Sopenharmony_ci g.FrameCount += 1; 3413bf215546Sopenharmony_ci g.TooltipOverrideCount = 0; 3414bf215546Sopenharmony_ci g.WindowsActiveCount = 0; 3415bf215546Sopenharmony_ci 3416bf215546Sopenharmony_ci // Setup current font and draw list shared data 3417bf215546Sopenharmony_ci g.IO.Fonts->Locked = true; 3418bf215546Sopenharmony_ci SetCurrentFont(GetDefaultFont()); 3419bf215546Sopenharmony_ci IM_ASSERT(g.Font->IsLoaded()); 3420bf215546Sopenharmony_ci g.DrawListSharedData.ClipRectFullscreen = ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y); 3421bf215546Sopenharmony_ci g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol; 3422bf215546Sopenharmony_ci 3423bf215546Sopenharmony_ci g.OverlayDrawList.Clear(); 3424bf215546Sopenharmony_ci g.OverlayDrawList.PushTextureID(g.IO.Fonts->TexID); 3425bf215546Sopenharmony_ci g.OverlayDrawList.PushClipRectFullScreen(); 3426bf215546Sopenharmony_ci g.OverlayDrawList.Flags = (g.Style.AntiAliasedLines ? ImDrawListFlags_AntiAliasedLines : 0) | (g.Style.AntiAliasedFill ? ImDrawListFlags_AntiAliasedFill : 0); 3427bf215546Sopenharmony_ci 3428bf215546Sopenharmony_ci // Mark rendering data as invalid to prevent user who may have a handle on it to use it. 3429bf215546Sopenharmony_ci g.DrawData.Clear(); 3430bf215546Sopenharmony_ci 3431bf215546Sopenharmony_ci // Drag and drop keep the source ID alive so even if the source disappear our state is consistent 3432bf215546Sopenharmony_ci if (g.DragDropActive && g.DragDropPayload.SourceId == g.ActiveId) 3433bf215546Sopenharmony_ci KeepAliveID(g.DragDropPayload.SourceId); 3434bf215546Sopenharmony_ci 3435bf215546Sopenharmony_ci // Clear reference to active widget if the widget isn't alive anymore 3436bf215546Sopenharmony_ci if (!g.HoveredIdPreviousFrame) 3437bf215546Sopenharmony_ci g.HoveredIdTimer = 0.0f; 3438bf215546Sopenharmony_ci if (!g.HoveredIdPreviousFrame || (g.HoveredId && g.ActiveId == g.HoveredId)) 3439bf215546Sopenharmony_ci g.HoveredIdNotActiveTimer = 0.0f; 3440bf215546Sopenharmony_ci if (g.HoveredId) 3441bf215546Sopenharmony_ci g.HoveredIdTimer += g.IO.DeltaTime; 3442bf215546Sopenharmony_ci if (g.HoveredId && g.ActiveId != g.HoveredId) 3443bf215546Sopenharmony_ci g.HoveredIdNotActiveTimer += g.IO.DeltaTime; 3444bf215546Sopenharmony_ci g.HoveredIdPreviousFrame = g.HoveredId; 3445bf215546Sopenharmony_ci g.HoveredId = 0; 3446bf215546Sopenharmony_ci g.HoveredIdAllowOverlap = false; 3447bf215546Sopenharmony_ci if (g.ActiveIdIsAlive != g.ActiveId && g.ActiveIdPreviousFrame == g.ActiveId && g.ActiveId != 0) 3448bf215546Sopenharmony_ci ClearActiveID(); 3449bf215546Sopenharmony_ci if (g.ActiveId) 3450bf215546Sopenharmony_ci g.ActiveIdTimer += g.IO.DeltaTime; 3451bf215546Sopenharmony_ci g.LastActiveIdTimer += g.IO.DeltaTime; 3452bf215546Sopenharmony_ci g.ActiveIdPreviousFrame = g.ActiveId; 3453bf215546Sopenharmony_ci g.ActiveIdPreviousFrameWindow = g.ActiveIdWindow; 3454bf215546Sopenharmony_ci g.ActiveIdPreviousFrameHasBeenEdited = g.ActiveIdHasBeenEdited; 3455bf215546Sopenharmony_ci g.ActiveIdIsAlive = 0; 3456bf215546Sopenharmony_ci g.ActiveIdPreviousFrameIsAlive = false; 3457bf215546Sopenharmony_ci g.ActiveIdIsJustActivated = false; 3458bf215546Sopenharmony_ci if (g.ScalarAsInputTextId && g.ActiveId != g.ScalarAsInputTextId) 3459bf215546Sopenharmony_ci g.ScalarAsInputTextId = 0; 3460bf215546Sopenharmony_ci 3461bf215546Sopenharmony_ci // Drag and drop 3462bf215546Sopenharmony_ci g.DragDropAcceptIdPrev = g.DragDropAcceptIdCurr; 3463bf215546Sopenharmony_ci g.DragDropAcceptIdCurr = 0; 3464bf215546Sopenharmony_ci g.DragDropAcceptIdCurrRectSurface = FLT_MAX; 3465bf215546Sopenharmony_ci g.DragDropWithinSourceOrTarget = false; 3466bf215546Sopenharmony_ci 3467bf215546Sopenharmony_ci // Update keyboard input state 3468bf215546Sopenharmony_ci memcpy(g.IO.KeysDownDurationPrev, g.IO.KeysDownDuration, sizeof(g.IO.KeysDownDuration)); 3469bf215546Sopenharmony_ci for (int i = 0; i < IM_ARRAYSIZE(g.IO.KeysDown); i++) 3470bf215546Sopenharmony_ci g.IO.KeysDownDuration[i] = g.IO.KeysDown[i] ? (g.IO.KeysDownDuration[i] < 0.0f ? 0.0f : g.IO.KeysDownDuration[i] + g.IO.DeltaTime) : -1.0f; 3471bf215546Sopenharmony_ci 3472bf215546Sopenharmony_ci // Update gamepad/keyboard directional navigation 3473bf215546Sopenharmony_ci NavUpdate(); 3474bf215546Sopenharmony_ci 3475bf215546Sopenharmony_ci // Update mouse input state 3476bf215546Sopenharmony_ci UpdateMouseInputs(); 3477bf215546Sopenharmony_ci 3478bf215546Sopenharmony_ci // Calculate frame-rate for the user, as a purely luxurious feature 3479bf215546Sopenharmony_ci g.FramerateSecPerFrameAccum += g.IO.DeltaTime - g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx]; 3480bf215546Sopenharmony_ci g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx] = g.IO.DeltaTime; 3481bf215546Sopenharmony_ci g.FramerateSecPerFrameIdx = (g.FramerateSecPerFrameIdx + 1) % IM_ARRAYSIZE(g.FramerateSecPerFrame); 3482bf215546Sopenharmony_ci g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)IM_ARRAYSIZE(g.FramerateSecPerFrame))) : FLT_MAX; 3483bf215546Sopenharmony_ci 3484bf215546Sopenharmony_ci // Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering) 3485bf215546Sopenharmony_ci UpdateMouseMovingWindowNewFrame(); 3486bf215546Sopenharmony_ci UpdateHoveredWindowAndCaptureFlags(); 3487bf215546Sopenharmony_ci 3488bf215546Sopenharmony_ci // Background darkening/whitening 3489bf215546Sopenharmony_ci if (GetFrontMostPopupModal() != NULL || (g.NavWindowingTarget != NULL && g.NavWindowingHighlightAlpha > 0.0f)) 3490bf215546Sopenharmony_ci g.DimBgRatio = ImMin(g.DimBgRatio + g.IO.DeltaTime * 6.0f, 1.0f); 3491bf215546Sopenharmony_ci else 3492bf215546Sopenharmony_ci g.DimBgRatio = ImMax(g.DimBgRatio - g.IO.DeltaTime * 10.0f, 0.0f); 3493bf215546Sopenharmony_ci 3494bf215546Sopenharmony_ci g.MouseCursor = ImGuiMouseCursor_Arrow; 3495bf215546Sopenharmony_ci g.WantCaptureMouseNextFrame = g.WantCaptureKeyboardNextFrame = g.WantTextInputNextFrame = -1; 3496bf215546Sopenharmony_ci g.PlatformImePos = ImVec2(1.0f, 1.0f); // OS Input Method Editor showing on top-left of our window by default 3497bf215546Sopenharmony_ci 3498bf215546Sopenharmony_ci // Mouse wheel scrolling, scale 3499bf215546Sopenharmony_ci UpdateMouseWheel(); 3500bf215546Sopenharmony_ci 3501bf215546Sopenharmony_ci // Pressing TAB activate widget focus 3502bf215546Sopenharmony_ci if (g.ActiveId == 0 && g.NavWindow != NULL && g.NavWindow->Active && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab, false)) 3503bf215546Sopenharmony_ci { 3504bf215546Sopenharmony_ci if (g.NavId != 0 && g.NavIdTabCounter != INT_MAX) 3505bf215546Sopenharmony_ci g.NavWindow->FocusIdxTabRequestNext = g.NavIdTabCounter + 1 + (g.IO.KeyShift ? -1 : 1); 3506bf215546Sopenharmony_ci else 3507bf215546Sopenharmony_ci g.NavWindow->FocusIdxTabRequestNext = g.IO.KeyShift ? -1 : 0; 3508bf215546Sopenharmony_ci } 3509bf215546Sopenharmony_ci g.NavIdTabCounter = INT_MAX; 3510bf215546Sopenharmony_ci 3511bf215546Sopenharmony_ci // Mark all windows as not visible 3512bf215546Sopenharmony_ci IM_ASSERT(g.WindowsFocusOrder.Size == g.Windows.Size); 3513bf215546Sopenharmony_ci for (int i = 0; i != g.Windows.Size; i++) 3514bf215546Sopenharmony_ci { 3515bf215546Sopenharmony_ci ImGuiWindow* window = g.Windows[i]; 3516bf215546Sopenharmony_ci window->WasActive = window->Active; 3517bf215546Sopenharmony_ci window->Active = false; 3518bf215546Sopenharmony_ci window->WriteAccessed = false; 3519bf215546Sopenharmony_ci } 3520bf215546Sopenharmony_ci 3521bf215546Sopenharmony_ci // Closing the focused window restore focus to the first active root window in descending z-order 3522bf215546Sopenharmony_ci if (g.NavWindow && !g.NavWindow->WasActive) 3523bf215546Sopenharmony_ci FocusPreviousWindowIgnoringOne(NULL); 3524bf215546Sopenharmony_ci 3525bf215546Sopenharmony_ci // No window should be open at the beginning of the frame. 3526bf215546Sopenharmony_ci // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear. 3527bf215546Sopenharmony_ci g.CurrentWindowStack.resize(0); 3528bf215546Sopenharmony_ci g.BeginPopupStack.resize(0); 3529bf215546Sopenharmony_ci ClosePopupsOverWindow(g.NavWindow); 3530bf215546Sopenharmony_ci 3531bf215546Sopenharmony_ci // Create implicit/fallback window - which we will only render it if the user has added something to it. 3532bf215546Sopenharmony_ci // We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags. 3533bf215546Sopenharmony_ci // This fallback is particularly important as it avoid ImGui:: calls from crashing. 3534bf215546Sopenharmony_ci SetNextWindowSize(ImVec2(400,400), ImGuiCond_FirstUseEver); 3535bf215546Sopenharmony_ci Begin("Debug##Default"); 3536bf215546Sopenharmony_ci g.FrameScopePushedImplicitWindow = true; 3537bf215546Sopenharmony_ci 3538bf215546Sopenharmony_ci#ifdef IMGUI_ENABLE_TEST_ENGINE 3539bf215546Sopenharmony_ci ImGuiTestEngineHook_PostNewFrame(&g); 3540bf215546Sopenharmony_ci#endif 3541bf215546Sopenharmony_ci} 3542bf215546Sopenharmony_ci 3543bf215546Sopenharmony_civoid ImGui::Initialize(ImGuiContext* context) 3544bf215546Sopenharmony_ci{ 3545bf215546Sopenharmony_ci ImGuiContext& g = *context; 3546bf215546Sopenharmony_ci IM_ASSERT(!g.Initialized && !g.SettingsLoaded); 3547bf215546Sopenharmony_ci 3548bf215546Sopenharmony_ci // Add .ini handle for ImGuiWindow type 3549bf215546Sopenharmony_ci ImGuiSettingsHandler ini_handler; 3550bf215546Sopenharmony_ci ini_handler.TypeName = "Window"; 3551bf215546Sopenharmony_ci ini_handler.TypeHash = ImHashStr("Window", 0); 3552bf215546Sopenharmony_ci ini_handler.ReadOpenFn = SettingsHandlerWindow_ReadOpen; 3553bf215546Sopenharmony_ci ini_handler.ReadLineFn = SettingsHandlerWindow_ReadLine; 3554bf215546Sopenharmony_ci ini_handler.WriteAllFn = SettingsHandlerWindow_WriteAll; 3555bf215546Sopenharmony_ci g.SettingsHandlers.push_back(ini_handler); 3556bf215546Sopenharmony_ci 3557bf215546Sopenharmony_ci g.Initialized = true; 3558bf215546Sopenharmony_ci} 3559bf215546Sopenharmony_ci 3560bf215546Sopenharmony_ci// This function is merely here to free heap allocations. 3561bf215546Sopenharmony_civoid ImGui::Shutdown(ImGuiContext* context) 3562bf215546Sopenharmony_ci{ 3563bf215546Sopenharmony_ci // 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) 3564bf215546Sopenharmony_ci ImGuiContext& g = *context; 3565bf215546Sopenharmony_ci if (g.IO.Fonts && g.FontAtlasOwnedByContext) 3566bf215546Sopenharmony_ci { 3567bf215546Sopenharmony_ci g.IO.Fonts->Locked = false; 3568bf215546Sopenharmony_ci IM_DELETE(g.IO.Fonts); 3569bf215546Sopenharmony_ci } 3570bf215546Sopenharmony_ci g.IO.Fonts = NULL; 3571bf215546Sopenharmony_ci 3572bf215546Sopenharmony_ci // Cleanup of other data are conditional on actually having initialized ImGui. 3573bf215546Sopenharmony_ci if (!g.Initialized) 3574bf215546Sopenharmony_ci return; 3575bf215546Sopenharmony_ci 3576bf215546Sopenharmony_ci // Save settings (unless we haven't attempted to load them: CreateContext/DestroyContext without a call to NewFrame shouldn't save an empty file) 3577bf215546Sopenharmony_ci if (g.SettingsLoaded && g.IO.IniFilename != NULL) 3578bf215546Sopenharmony_ci { 3579bf215546Sopenharmony_ci ImGuiContext* backup_context = GImGui; 3580bf215546Sopenharmony_ci SetCurrentContext(context); 3581bf215546Sopenharmony_ci SaveIniSettingsToDisk(g.IO.IniFilename); 3582bf215546Sopenharmony_ci SetCurrentContext(backup_context); 3583bf215546Sopenharmony_ci } 3584bf215546Sopenharmony_ci 3585bf215546Sopenharmony_ci // Clear everything else 3586bf215546Sopenharmony_ci for (int i = 0; i < g.Windows.Size; i++) 3587bf215546Sopenharmony_ci IM_DELETE(g.Windows[i]); 3588bf215546Sopenharmony_ci g.Windows.clear(); 3589bf215546Sopenharmony_ci g.WindowsFocusOrder.clear(); 3590bf215546Sopenharmony_ci g.WindowsSortBuffer.clear(); 3591bf215546Sopenharmony_ci g.CurrentWindow = NULL; 3592bf215546Sopenharmony_ci g.CurrentWindowStack.clear(); 3593bf215546Sopenharmony_ci g.WindowsById.Clear(); 3594bf215546Sopenharmony_ci g.NavWindow = NULL; 3595bf215546Sopenharmony_ci g.HoveredWindow = g.HoveredRootWindow = NULL; 3596bf215546Sopenharmony_ci g.ActiveIdWindow = g.ActiveIdPreviousFrameWindow = NULL; 3597bf215546Sopenharmony_ci g.MovingWindow = NULL; 3598bf215546Sopenharmony_ci g.ColorModifiers.clear(); 3599bf215546Sopenharmony_ci g.StyleModifiers.clear(); 3600bf215546Sopenharmony_ci g.FontStack.clear(); 3601bf215546Sopenharmony_ci g.OpenPopupStack.clear(); 3602bf215546Sopenharmony_ci g.BeginPopupStack.clear(); 3603bf215546Sopenharmony_ci g.DrawDataBuilder.ClearFreeMemory(); 3604bf215546Sopenharmony_ci g.OverlayDrawList.ClearFreeMemory(); 3605bf215546Sopenharmony_ci g.PrivateClipboard.clear(); 3606bf215546Sopenharmony_ci g.InputTextState.TextW.clear(); 3607bf215546Sopenharmony_ci g.InputTextState.InitialText.clear(); 3608bf215546Sopenharmony_ci g.InputTextState.TempBuffer.clear(); 3609bf215546Sopenharmony_ci 3610bf215546Sopenharmony_ci for (int i = 0; i < g.SettingsWindows.Size; i++) 3611bf215546Sopenharmony_ci IM_DELETE(g.SettingsWindows[i].Name); 3612bf215546Sopenharmony_ci g.SettingsWindows.clear(); 3613bf215546Sopenharmony_ci g.SettingsHandlers.clear(); 3614bf215546Sopenharmony_ci 3615bf215546Sopenharmony_ci if (g.LogFile && g.LogFile != stdout) 3616bf215546Sopenharmony_ci { 3617bf215546Sopenharmony_ci fclose(g.LogFile); 3618bf215546Sopenharmony_ci g.LogFile = NULL; 3619bf215546Sopenharmony_ci } 3620bf215546Sopenharmony_ci g.LogClipboard.clear(); 3621bf215546Sopenharmony_ci 3622bf215546Sopenharmony_ci g.Initialized = false; 3623bf215546Sopenharmony_ci} 3624bf215546Sopenharmony_ci 3625bf215546Sopenharmony_ci// FIXME: Add a more explicit sort order in the window structure. 3626bf215546Sopenharmony_cistatic int IMGUI_CDECL ChildWindowComparer(const void* lhs, const void* rhs) 3627bf215546Sopenharmony_ci{ 3628bf215546Sopenharmony_ci const ImGuiWindow* const a = *(const ImGuiWindow* const *)lhs; 3629bf215546Sopenharmony_ci const ImGuiWindow* const b = *(const ImGuiWindow* const *)rhs; 3630bf215546Sopenharmony_ci if (int d = (a->Flags & ImGuiWindowFlags_Popup) - (b->Flags & ImGuiWindowFlags_Popup)) 3631bf215546Sopenharmony_ci return d; 3632bf215546Sopenharmony_ci if (int d = (a->Flags & ImGuiWindowFlags_Tooltip) - (b->Flags & ImGuiWindowFlags_Tooltip)) 3633bf215546Sopenharmony_ci return d; 3634bf215546Sopenharmony_ci return (a->BeginOrderWithinParent - b->BeginOrderWithinParent); 3635bf215546Sopenharmony_ci} 3636bf215546Sopenharmony_ci 3637bf215546Sopenharmony_cistatic void AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window) 3638bf215546Sopenharmony_ci{ 3639bf215546Sopenharmony_ci out_sorted_windows->push_back(window); 3640bf215546Sopenharmony_ci if (window->Active) 3641bf215546Sopenharmony_ci { 3642bf215546Sopenharmony_ci int count = window->DC.ChildWindows.Size; 3643bf215546Sopenharmony_ci if (count > 1) 3644bf215546Sopenharmony_ci ImQsort(window->DC.ChildWindows.begin(), (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer); 3645bf215546Sopenharmony_ci for (int i = 0; i < count; i++) 3646bf215546Sopenharmony_ci { 3647bf215546Sopenharmony_ci ImGuiWindow* child = window->DC.ChildWindows[i]; 3648bf215546Sopenharmony_ci if (child->Active) 3649bf215546Sopenharmony_ci AddWindowToSortBuffer(out_sorted_windows, child); 3650bf215546Sopenharmony_ci } 3651bf215546Sopenharmony_ci } 3652bf215546Sopenharmony_ci} 3653bf215546Sopenharmony_ci 3654bf215546Sopenharmony_cistatic void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* draw_list) 3655bf215546Sopenharmony_ci{ 3656bf215546Sopenharmony_ci if (draw_list->CmdBuffer.empty()) 3657bf215546Sopenharmony_ci return; 3658bf215546Sopenharmony_ci 3659bf215546Sopenharmony_ci // Remove trailing command if unused 3660bf215546Sopenharmony_ci ImDrawCmd& last_cmd = draw_list->CmdBuffer.back(); 3661bf215546Sopenharmony_ci if (last_cmd.ElemCount == 0 && last_cmd.UserCallback == NULL) 3662bf215546Sopenharmony_ci { 3663bf215546Sopenharmony_ci draw_list->CmdBuffer.pop_back(); 3664bf215546Sopenharmony_ci if (draw_list->CmdBuffer.empty()) 3665bf215546Sopenharmony_ci return; 3666bf215546Sopenharmony_ci } 3667bf215546Sopenharmony_ci 3668bf215546Sopenharmony_ci // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc. May trigger for you if you are using PrimXXX functions incorrectly. 3669bf215546Sopenharmony_ci IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size); 3670bf215546Sopenharmony_ci IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size); 3671bf215546Sopenharmony_ci IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size); 3672bf215546Sopenharmony_ci 3673bf215546Sopenharmony_ci // Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window) 3674bf215546Sopenharmony_ci // If this assert triggers because you are drawing lots of stuff manually: 3675bf215546Sopenharmony_ci // A) Make sure you are coarse clipping, because ImDrawList let all your vertices pass. You can use the Metrics window to inspect draw list contents. 3676bf215546Sopenharmony_ci // B) If you need/want meshes with more than 64K vertices, uncomment the '#define ImDrawIdx unsigned int' line in imconfig.h to set the index size to 4 bytes. 3677bf215546Sopenharmony_ci // You'll need to handle the 4-bytes indices to your renderer. For example, the OpenGL example code detect index size at compile-time by doing: 3678bf215546Sopenharmony_ci // glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset); 3679bf215546Sopenharmony_ci // Your own engine or render API may use different parameters or function calls to specify index sizes. 2 and 4 bytes indices are generally supported by most API. 3680bf215546Sopenharmony_ci // C) If for some reason you cannot use 4 bytes indices or don't want to, a workaround is to call BeginChild()/EndChild() before reaching the 64K limit to split your draw commands in multiple draw lists. 3681bf215546Sopenharmony_ci if (sizeof(ImDrawIdx) == 2) 3682bf215546Sopenharmony_ci IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above"); 3683bf215546Sopenharmony_ci 3684bf215546Sopenharmony_ci out_list->push_back(draw_list); 3685bf215546Sopenharmony_ci} 3686bf215546Sopenharmony_ci 3687bf215546Sopenharmony_cistatic void AddWindowToDrawData(ImVector<ImDrawList*>* out_render_list, ImGuiWindow* window) 3688bf215546Sopenharmony_ci{ 3689bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 3690bf215546Sopenharmony_ci g.IO.MetricsRenderWindows++; 3691bf215546Sopenharmony_ci AddDrawListToDrawData(out_render_list, window->DrawList); 3692bf215546Sopenharmony_ci for (int i = 0; i < window->DC.ChildWindows.Size; i++) 3693bf215546Sopenharmony_ci { 3694bf215546Sopenharmony_ci ImGuiWindow* child = window->DC.ChildWindows[i]; 3695bf215546Sopenharmony_ci if (IsWindowActiveAndVisible(child)) // clipped children may have been marked not active 3696bf215546Sopenharmony_ci AddWindowToDrawData(out_render_list, child); 3697bf215546Sopenharmony_ci } 3698bf215546Sopenharmony_ci} 3699bf215546Sopenharmony_ci 3700bf215546Sopenharmony_cistatic void AddRootWindowToDrawData(ImGuiWindow* window) 3701bf215546Sopenharmony_ci{ 3702bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 3703bf215546Sopenharmony_ci if (window->Flags & ImGuiWindowFlags_Tooltip) 3704bf215546Sopenharmony_ci AddWindowToDrawData(&g.DrawDataBuilder.Layers[1], window); 3705bf215546Sopenharmony_ci else 3706bf215546Sopenharmony_ci AddWindowToDrawData(&g.DrawDataBuilder.Layers[0], window); 3707bf215546Sopenharmony_ci} 3708bf215546Sopenharmony_ci 3709bf215546Sopenharmony_civoid ImDrawDataBuilder::FlattenIntoSingleLayer() 3710bf215546Sopenharmony_ci{ 3711bf215546Sopenharmony_ci int n = Layers[0].Size; 3712bf215546Sopenharmony_ci int size = n; 3713bf215546Sopenharmony_ci for (int i = 1; i < IM_ARRAYSIZE(Layers); i++) 3714bf215546Sopenharmony_ci size += Layers[i].Size; 3715bf215546Sopenharmony_ci Layers[0].resize(size); 3716bf215546Sopenharmony_ci for (int layer_n = 1; layer_n < IM_ARRAYSIZE(Layers); layer_n++) 3717bf215546Sopenharmony_ci { 3718bf215546Sopenharmony_ci ImVector<ImDrawList*>& layer = Layers[layer_n]; 3719bf215546Sopenharmony_ci if (layer.empty()) 3720bf215546Sopenharmony_ci continue; 3721bf215546Sopenharmony_ci memcpy(&Layers[0][n], &layer[0], layer.Size * sizeof(ImDrawList*)); 3722bf215546Sopenharmony_ci n += layer.Size; 3723bf215546Sopenharmony_ci layer.resize(0); 3724bf215546Sopenharmony_ci } 3725bf215546Sopenharmony_ci} 3726bf215546Sopenharmony_ci 3727bf215546Sopenharmony_cistatic void SetupDrawData(ImVector<ImDrawList*>* draw_lists, ImDrawData* draw_data) 3728bf215546Sopenharmony_ci{ 3729bf215546Sopenharmony_ci ImGuiIO& io = ImGui::GetIO(); 3730bf215546Sopenharmony_ci draw_data->Valid = true; 3731bf215546Sopenharmony_ci draw_data->CmdLists = (draw_lists->Size > 0) ? draw_lists->Data : NULL; 3732bf215546Sopenharmony_ci draw_data->CmdListsCount = draw_lists->Size; 3733bf215546Sopenharmony_ci draw_data->TotalVtxCount = draw_data->TotalIdxCount = 0; 3734bf215546Sopenharmony_ci draw_data->DisplayPos = ImVec2(0.0f, 0.0f); 3735bf215546Sopenharmony_ci draw_data->DisplaySize = io.DisplaySize; 3736bf215546Sopenharmony_ci draw_data->FramebufferScale = io.DisplayFramebufferScale; 3737bf215546Sopenharmony_ci for (int n = 0; n < draw_lists->Size; n++) 3738bf215546Sopenharmony_ci { 3739bf215546Sopenharmony_ci draw_data->TotalVtxCount += draw_lists->Data[n]->VtxBuffer.Size; 3740bf215546Sopenharmony_ci draw_data->TotalIdxCount += draw_lists->Data[n]->IdxBuffer.Size; 3741bf215546Sopenharmony_ci } 3742bf215546Sopenharmony_ci} 3743bf215546Sopenharmony_ci 3744bf215546Sopenharmony_ci// When using this function it is sane to ensure that float are perfectly rounded to integer values, to that e.g. (int)(max.x-min.x) in user's render produce correct result. 3745bf215546Sopenharmony_civoid ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect) 3746bf215546Sopenharmony_ci{ 3747bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindow(); 3748bf215546Sopenharmony_ci window->DrawList->PushClipRect(clip_rect_min, clip_rect_max, intersect_with_current_clip_rect); 3749bf215546Sopenharmony_ci window->ClipRect = window->DrawList->_ClipRectStack.back(); 3750bf215546Sopenharmony_ci} 3751bf215546Sopenharmony_ci 3752bf215546Sopenharmony_civoid ImGui::PopClipRect() 3753bf215546Sopenharmony_ci{ 3754bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindow(); 3755bf215546Sopenharmony_ci window->DrawList->PopClipRect(); 3756bf215546Sopenharmony_ci window->ClipRect = window->DrawList->_ClipRectStack.back(); 3757bf215546Sopenharmony_ci} 3758bf215546Sopenharmony_ci 3759bf215546Sopenharmony_ci// 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. 3760bf215546Sopenharmony_civoid ImGui::EndFrame() 3761bf215546Sopenharmony_ci{ 3762bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 3763bf215546Sopenharmony_ci IM_ASSERT(g.Initialized); 3764bf215546Sopenharmony_ci if (g.FrameCountEnded == g.FrameCount) // Don't process EndFrame() multiple times. 3765bf215546Sopenharmony_ci return; 3766bf215546Sopenharmony_ci IM_ASSERT(g.FrameScopeActive && "Forgot to call ImGui::NewFrame()?"); 3767bf215546Sopenharmony_ci 3768bf215546Sopenharmony_ci // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME) 3769bf215546Sopenharmony_ci if (g.IO.ImeSetInputScreenPosFn && (g.PlatformImeLastPos.x == FLT_MAX || ImLengthSqr(g.PlatformImeLastPos - g.PlatformImePos) > 0.0001f)) 3770bf215546Sopenharmony_ci { 3771bf215546Sopenharmony_ci g.IO.ImeSetInputScreenPosFn((int)g.PlatformImePos.x, (int)g.PlatformImePos.y); 3772bf215546Sopenharmony_ci g.PlatformImeLastPos = g.PlatformImePos; 3773bf215546Sopenharmony_ci } 3774bf215546Sopenharmony_ci 3775bf215546Sopenharmony_ci // Report when there is a mismatch of Begin/BeginChild vs End/EndChild calls. Important: Remember that the Begin/BeginChild API requires you 3776bf215546Sopenharmony_ci // to always call End/EndChild even if Begin/BeginChild returns false! (this is unfortunately inconsistent with most other Begin* API). 3777bf215546Sopenharmony_ci if (g.CurrentWindowStack.Size != 1) 3778bf215546Sopenharmony_ci { 3779bf215546Sopenharmony_ci if (g.CurrentWindowStack.Size > 1) 3780bf215546Sopenharmony_ci { 3781bf215546Sopenharmony_ci IM_ASSERT(g.CurrentWindowStack.Size == 1 && "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?"); 3782bf215546Sopenharmony_ci while (g.CurrentWindowStack.Size > 1) // FIXME-ERRORHANDLING 3783bf215546Sopenharmony_ci End(); 3784bf215546Sopenharmony_ci } 3785bf215546Sopenharmony_ci else 3786bf215546Sopenharmony_ci { 3787bf215546Sopenharmony_ci IM_ASSERT(g.CurrentWindowStack.Size == 1 && "Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?"); 3788bf215546Sopenharmony_ci } 3789bf215546Sopenharmony_ci } 3790bf215546Sopenharmony_ci 3791bf215546Sopenharmony_ci // Hide implicit/fallback "Debug" window if it hasn't been used 3792bf215546Sopenharmony_ci g.FrameScopePushedImplicitWindow = false; 3793bf215546Sopenharmony_ci if (g.CurrentWindow && !g.CurrentWindow->WriteAccessed) 3794bf215546Sopenharmony_ci g.CurrentWindow->Active = false; 3795bf215546Sopenharmony_ci End(); 3796bf215546Sopenharmony_ci 3797bf215546Sopenharmony_ci // Show CTRL+TAB list window 3798bf215546Sopenharmony_ci if (g.NavWindowingTarget) 3799bf215546Sopenharmony_ci NavUpdateWindowingList(); 3800bf215546Sopenharmony_ci 3801bf215546Sopenharmony_ci // Drag and Drop: Elapse payload (if delivered, or if source stops being submitted) 3802bf215546Sopenharmony_ci if (g.DragDropActive) 3803bf215546Sopenharmony_ci { 3804bf215546Sopenharmony_ci bool is_delivered = g.DragDropPayload.Delivery; 3805bf215546Sopenharmony_ci bool is_elapsed = (g.DragDropPayload.DataFrameCount + 1 < g.FrameCount) && ((g.DragDropSourceFlags & ImGuiDragDropFlags_SourceAutoExpirePayload) || !IsMouseDown(g.DragDropMouseButton)); 3806bf215546Sopenharmony_ci if (is_delivered || is_elapsed) 3807bf215546Sopenharmony_ci ClearDragDrop(); 3808bf215546Sopenharmony_ci } 3809bf215546Sopenharmony_ci 3810bf215546Sopenharmony_ci // Drag and Drop: Fallback for source tooltip. This is not ideal but better than nothing. 3811bf215546Sopenharmony_ci if (g.DragDropActive && g.DragDropSourceFrameCount < g.FrameCount) 3812bf215546Sopenharmony_ci { 3813bf215546Sopenharmony_ci g.DragDropWithinSourceOrTarget = true; 3814bf215546Sopenharmony_ci SetTooltip("..."); 3815bf215546Sopenharmony_ci g.DragDropWithinSourceOrTarget = false; 3816bf215546Sopenharmony_ci } 3817bf215546Sopenharmony_ci 3818bf215546Sopenharmony_ci // End frame 3819bf215546Sopenharmony_ci g.FrameScopeActive = false; 3820bf215546Sopenharmony_ci g.FrameCountEnded = g.FrameCount; 3821bf215546Sopenharmony_ci 3822bf215546Sopenharmony_ci // Initiate moving window + handle left-click and right-click focus 3823bf215546Sopenharmony_ci UpdateMouseMovingWindowEndFrame(); 3824bf215546Sopenharmony_ci 3825bf215546Sopenharmony_ci // Sort the window list so that all child windows are after their parent 3826bf215546Sopenharmony_ci // We cannot do that on FocusWindow() because childs may not exist yet 3827bf215546Sopenharmony_ci g.WindowsSortBuffer.resize(0); 3828bf215546Sopenharmony_ci g.WindowsSortBuffer.reserve(g.Windows.Size); 3829bf215546Sopenharmony_ci for (int i = 0; i != g.Windows.Size; i++) 3830bf215546Sopenharmony_ci { 3831bf215546Sopenharmony_ci ImGuiWindow* window = g.Windows[i]; 3832bf215546Sopenharmony_ci if (window->Active && (window->Flags & ImGuiWindowFlags_ChildWindow)) // if a child is active its parent will add it 3833bf215546Sopenharmony_ci continue; 3834bf215546Sopenharmony_ci AddWindowToSortBuffer(&g.WindowsSortBuffer, window); 3835bf215546Sopenharmony_ci } 3836bf215546Sopenharmony_ci 3837bf215546Sopenharmony_ci // This usually assert if there is a mismatch between the ImGuiWindowFlags_ChildWindow / ParentWindow values and DC.ChildWindows[] in parents, aka we've done something wrong. 3838bf215546Sopenharmony_ci IM_ASSERT(g.Windows.Size == g.WindowsSortBuffer.Size); 3839bf215546Sopenharmony_ci g.Windows.swap(g.WindowsSortBuffer); 3840bf215546Sopenharmony_ci g.IO.MetricsActiveWindows = g.WindowsActiveCount; 3841bf215546Sopenharmony_ci 3842bf215546Sopenharmony_ci // Unlock font atlas 3843bf215546Sopenharmony_ci g.IO.Fonts->Locked = false; 3844bf215546Sopenharmony_ci 3845bf215546Sopenharmony_ci // Clear Input data for next frame 3846bf215546Sopenharmony_ci g.IO.MouseWheel = g.IO.MouseWheelH = 0.0f; 3847bf215546Sopenharmony_ci g.IO.InputQueueCharacters.resize(0); 3848bf215546Sopenharmony_ci memset(g.IO.NavInputs, 0, sizeof(g.IO.NavInputs)); 3849bf215546Sopenharmony_ci} 3850bf215546Sopenharmony_ci 3851bf215546Sopenharmony_civoid ImGui::Render() 3852bf215546Sopenharmony_ci{ 3853bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 3854bf215546Sopenharmony_ci IM_ASSERT(g.Initialized); 3855bf215546Sopenharmony_ci 3856bf215546Sopenharmony_ci if (g.FrameCountEnded != g.FrameCount) 3857bf215546Sopenharmony_ci EndFrame(); 3858bf215546Sopenharmony_ci g.FrameCountRendered = g.FrameCount; 3859bf215546Sopenharmony_ci 3860bf215546Sopenharmony_ci // Gather ImDrawList to render (for each active window) 3861bf215546Sopenharmony_ci g.IO.MetricsRenderVertices = g.IO.MetricsRenderIndices = g.IO.MetricsRenderWindows = 0; 3862bf215546Sopenharmony_ci g.DrawDataBuilder.Clear(); 3863bf215546Sopenharmony_ci ImGuiWindow* windows_to_render_front_most[2]; 3864bf215546Sopenharmony_ci windows_to_render_front_most[0] = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget->RootWindow : NULL; 3865bf215546Sopenharmony_ci windows_to_render_front_most[1] = g.NavWindowingTarget ? g.NavWindowingList : NULL; 3866bf215546Sopenharmony_ci for (int n = 0; n != g.Windows.Size; n++) 3867bf215546Sopenharmony_ci { 3868bf215546Sopenharmony_ci ImGuiWindow* window = g.Windows[n]; 3869bf215546Sopenharmony_ci if (IsWindowActiveAndVisible(window) && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != windows_to_render_front_most[0] && window != windows_to_render_front_most[1]) 3870bf215546Sopenharmony_ci AddRootWindowToDrawData(window); 3871bf215546Sopenharmony_ci } 3872bf215546Sopenharmony_ci for (int n = 0; n < IM_ARRAYSIZE(windows_to_render_front_most); n++) 3873bf215546Sopenharmony_ci if (windows_to_render_front_most[n] && IsWindowActiveAndVisible(windows_to_render_front_most[n])) // NavWindowingTarget is always temporarily displayed as the front-most window 3874bf215546Sopenharmony_ci AddRootWindowToDrawData(windows_to_render_front_most[n]); 3875bf215546Sopenharmony_ci g.DrawDataBuilder.FlattenIntoSingleLayer(); 3876bf215546Sopenharmony_ci 3877bf215546Sopenharmony_ci // Draw software mouse cursor if requested 3878bf215546Sopenharmony_ci if (g.IO.MouseDrawCursor) 3879bf215546Sopenharmony_ci RenderMouseCursor(&g.OverlayDrawList, g.IO.MousePos, g.Style.MouseCursorScale, g.MouseCursor); 3880bf215546Sopenharmony_ci 3881bf215546Sopenharmony_ci if (!g.OverlayDrawList.VtxBuffer.empty()) 3882bf215546Sopenharmony_ci AddDrawListToDrawData(&g.DrawDataBuilder.Layers[0], &g.OverlayDrawList); 3883bf215546Sopenharmony_ci 3884bf215546Sopenharmony_ci // Setup ImDrawData structure for end-user 3885bf215546Sopenharmony_ci SetupDrawData(&g.DrawDataBuilder.Layers[0], &g.DrawData); 3886bf215546Sopenharmony_ci g.IO.MetricsRenderVertices = g.DrawData.TotalVtxCount; 3887bf215546Sopenharmony_ci g.IO.MetricsRenderIndices = g.DrawData.TotalIdxCount; 3888bf215546Sopenharmony_ci 3889bf215546Sopenharmony_ci // (Legacy) Call the Render callback function. The current prefer way is to let the user retrieve GetDrawData() and call the render function themselves. 3890bf215546Sopenharmony_ci#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS 3891bf215546Sopenharmony_ci if (g.DrawData.CmdListsCount > 0 && g.IO.RenderDrawListsFn != NULL) 3892bf215546Sopenharmony_ci g.IO.RenderDrawListsFn(&g.DrawData); 3893bf215546Sopenharmony_ci#endif 3894bf215546Sopenharmony_ci} 3895bf215546Sopenharmony_ci 3896bf215546Sopenharmony_ci// Calculate text size. Text can be multi-line. Optionally ignore text after a ## marker. 3897bf215546Sopenharmony_ci// CalcTextSize("") should return ImVec2(0.0f, GImGui->FontSize) 3898bf215546Sopenharmony_ciImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_text_after_double_hash, float wrap_width) 3899bf215546Sopenharmony_ci{ 3900bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 3901bf215546Sopenharmony_ci 3902bf215546Sopenharmony_ci const char* text_display_end; 3903bf215546Sopenharmony_ci if (hide_text_after_double_hash) 3904bf215546Sopenharmony_ci text_display_end = FindRenderedTextEnd(text, text_end); // Hide anything after a '##' string 3905bf215546Sopenharmony_ci else 3906bf215546Sopenharmony_ci text_display_end = text_end; 3907bf215546Sopenharmony_ci 3908bf215546Sopenharmony_ci ImFont* font = g.Font; 3909bf215546Sopenharmony_ci const float font_size = g.FontSize; 3910bf215546Sopenharmony_ci if (text == text_display_end) 3911bf215546Sopenharmony_ci return ImVec2(0.0f, font_size); 3912bf215546Sopenharmony_ci ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL); 3913bf215546Sopenharmony_ci 3914bf215546Sopenharmony_ci // Round 3915bf215546Sopenharmony_ci text_size.x = (float)(int)(text_size.x + 0.95f); 3916bf215546Sopenharmony_ci 3917bf215546Sopenharmony_ci return text_size; 3918bf215546Sopenharmony_ci} 3919bf215546Sopenharmony_ci 3920bf215546Sopenharmony_ci// Helper to calculate coarse clipping of large list of evenly sized items. 3921bf215546Sopenharmony_ci// NB: Prefer using the ImGuiListClipper higher-level helper if you can! Read comments and instructions there on how those use this sort of pattern. 3922bf215546Sopenharmony_ci// NB: 'items_count' is only used to clamp the result, if you don't know your count you can use INT_MAX 3923bf215546Sopenharmony_civoid ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end) 3924bf215546Sopenharmony_ci{ 3925bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 3926bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 3927bf215546Sopenharmony_ci if (g.LogEnabled) 3928bf215546Sopenharmony_ci { 3929bf215546Sopenharmony_ci // If logging is active, do not perform any clipping 3930bf215546Sopenharmony_ci *out_items_display_start = 0; 3931bf215546Sopenharmony_ci *out_items_display_end = items_count; 3932bf215546Sopenharmony_ci return; 3933bf215546Sopenharmony_ci } 3934bf215546Sopenharmony_ci if (window->SkipItems) 3935bf215546Sopenharmony_ci { 3936bf215546Sopenharmony_ci *out_items_display_start = *out_items_display_end = 0; 3937bf215546Sopenharmony_ci return; 3938bf215546Sopenharmony_ci } 3939bf215546Sopenharmony_ci 3940bf215546Sopenharmony_ci // We create the union of the ClipRect and the NavScoringRect which at worst should be 1 page away from ClipRect 3941bf215546Sopenharmony_ci ImRect unclipped_rect = window->ClipRect; 3942bf215546Sopenharmony_ci if (g.NavMoveRequest) 3943bf215546Sopenharmony_ci unclipped_rect.Add(g.NavScoringRectScreen); 3944bf215546Sopenharmony_ci 3945bf215546Sopenharmony_ci const ImVec2 pos = window->DC.CursorPos; 3946bf215546Sopenharmony_ci int start = (int)((unclipped_rect.Min.y - pos.y) / items_height); 3947bf215546Sopenharmony_ci int end = (int)((unclipped_rect.Max.y - pos.y) / items_height); 3948bf215546Sopenharmony_ci 3949bf215546Sopenharmony_ci // When performing a navigation request, ensure we have one item extra in the direction we are moving to 3950bf215546Sopenharmony_ci if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Up) 3951bf215546Sopenharmony_ci start--; 3952bf215546Sopenharmony_ci if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Down) 3953bf215546Sopenharmony_ci end++; 3954bf215546Sopenharmony_ci 3955bf215546Sopenharmony_ci start = ImClamp(start, 0, items_count); 3956bf215546Sopenharmony_ci end = ImClamp(end + 1, start, items_count); 3957bf215546Sopenharmony_ci *out_items_display_start = start; 3958bf215546Sopenharmony_ci *out_items_display_end = end; 3959bf215546Sopenharmony_ci} 3960bf215546Sopenharmony_ci 3961bf215546Sopenharmony_ci// Find window given position, search front-to-back 3962bf215546Sopenharmony_ci// FIXME: Note that we have an inconsequential lag here: OuterRectClipped is updated in Begin(), so windows moved programatically 3963bf215546Sopenharmony_ci// with SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is 3964bf215546Sopenharmony_ci// called, aka before the next Begin(). Moving window isn't affected. 3965bf215546Sopenharmony_cistatic void FindHoveredWindow() 3966bf215546Sopenharmony_ci{ 3967bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 3968bf215546Sopenharmony_ci 3969bf215546Sopenharmony_ci ImGuiWindow* hovered_window = NULL; 3970bf215546Sopenharmony_ci if (g.MovingWindow && !(g.MovingWindow->Flags & ImGuiWindowFlags_NoMouseInputs)) 3971bf215546Sopenharmony_ci hovered_window = g.MovingWindow; 3972bf215546Sopenharmony_ci 3973bf215546Sopenharmony_ci ImVec2 padding_regular = g.Style.TouchExtraPadding; 3974bf215546Sopenharmony_ci ImVec2 padding_for_resize_from_edges = g.IO.ConfigWindowsResizeFromEdges ? ImMax(g.Style.TouchExtraPadding, ImVec2(WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS)) : padding_regular; 3975bf215546Sopenharmony_ci for (int i = g.Windows.Size - 1; i >= 0; i--) 3976bf215546Sopenharmony_ci { 3977bf215546Sopenharmony_ci ImGuiWindow* window = g.Windows[i]; 3978bf215546Sopenharmony_ci if (!window->Active || window->Hidden) 3979bf215546Sopenharmony_ci continue; 3980bf215546Sopenharmony_ci if (window->Flags & ImGuiWindowFlags_NoMouseInputs) 3981bf215546Sopenharmony_ci continue; 3982bf215546Sopenharmony_ci 3983bf215546Sopenharmony_ci // Using the clipped AABB, a child window will typically be clipped by its parent (not always) 3984bf215546Sopenharmony_ci ImRect bb(window->OuterRectClipped); 3985bf215546Sopenharmony_ci if ((window->Flags & ImGuiWindowFlags_ChildWindow) || (window->Flags & ImGuiWindowFlags_NoResize)) 3986bf215546Sopenharmony_ci bb.Expand(padding_regular); 3987bf215546Sopenharmony_ci else 3988bf215546Sopenharmony_ci bb.Expand(padding_for_resize_from_edges); 3989bf215546Sopenharmony_ci if (!bb.Contains(g.IO.MousePos)) 3990bf215546Sopenharmony_ci continue; 3991bf215546Sopenharmony_ci 3992bf215546Sopenharmony_ci // Those seemingly unnecessary extra tests are because the code here is a little different in viewport/docking branches. 3993bf215546Sopenharmony_ci if (hovered_window == NULL) 3994bf215546Sopenharmony_ci hovered_window = window; 3995bf215546Sopenharmony_ci if (hovered_window) 3996bf215546Sopenharmony_ci break; 3997bf215546Sopenharmony_ci } 3998bf215546Sopenharmony_ci 3999bf215546Sopenharmony_ci g.HoveredWindow = hovered_window; 4000bf215546Sopenharmony_ci g.HoveredRootWindow = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL; 4001bf215546Sopenharmony_ci 4002bf215546Sopenharmony_ci} 4003bf215546Sopenharmony_ci 4004bf215546Sopenharmony_ci// Test if mouse cursor is hovering given rectangle 4005bf215546Sopenharmony_ci// NB- Rectangle is clipped by our current clip setting 4006bf215546Sopenharmony_ci// NB- Expand the rectangle to be generous on imprecise inputs systems (g.Style.TouchExtraPadding) 4007bf215546Sopenharmony_cibool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip) 4008bf215546Sopenharmony_ci{ 4009bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4010bf215546Sopenharmony_ci 4011bf215546Sopenharmony_ci // Clip 4012bf215546Sopenharmony_ci ImRect rect_clipped(r_min, r_max); 4013bf215546Sopenharmony_ci if (clip) 4014bf215546Sopenharmony_ci rect_clipped.ClipWith(g.CurrentWindow->ClipRect); 4015bf215546Sopenharmony_ci 4016bf215546Sopenharmony_ci // Expand for touch input 4017bf215546Sopenharmony_ci const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, rect_clipped.Max + g.Style.TouchExtraPadding); 4018bf215546Sopenharmony_ci if (!rect_for_touch.Contains(g.IO.MousePos)) 4019bf215546Sopenharmony_ci return false; 4020bf215546Sopenharmony_ci return true; 4021bf215546Sopenharmony_ci} 4022bf215546Sopenharmony_ci 4023bf215546Sopenharmony_ciint ImGui::GetKeyIndex(ImGuiKey imgui_key) 4024bf215546Sopenharmony_ci{ 4025bf215546Sopenharmony_ci IM_ASSERT(imgui_key >= 0 && imgui_key < ImGuiKey_COUNT); 4026bf215546Sopenharmony_ci return GImGui->IO.KeyMap[imgui_key]; 4027bf215546Sopenharmony_ci} 4028bf215546Sopenharmony_ci 4029bf215546Sopenharmony_ci// Note that imgui doesn't know the semantic of each entry of io.KeysDown[]. Use your own indices/enums according to how your back-end/engine stored them into io.KeysDown[]! 4030bf215546Sopenharmony_cibool ImGui::IsKeyDown(int user_key_index) 4031bf215546Sopenharmony_ci{ 4032bf215546Sopenharmony_ci if (user_key_index < 0) return false; 4033bf215546Sopenharmony_ci IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(GImGui->IO.KeysDown)); 4034bf215546Sopenharmony_ci return GImGui->IO.KeysDown[user_key_index]; 4035bf215546Sopenharmony_ci} 4036bf215546Sopenharmony_ci 4037bf215546Sopenharmony_ciint ImGui::CalcTypematicPressedRepeatAmount(float t, float t_prev, float repeat_delay, float repeat_rate) 4038bf215546Sopenharmony_ci{ 4039bf215546Sopenharmony_ci if (t == 0.0f) 4040bf215546Sopenharmony_ci return 1; 4041bf215546Sopenharmony_ci if (t <= repeat_delay || repeat_rate <= 0.0f) 4042bf215546Sopenharmony_ci return 0; 4043bf215546Sopenharmony_ci const int count = (int)((t - repeat_delay) / repeat_rate) - (int)((t_prev - repeat_delay) / repeat_rate); 4044bf215546Sopenharmony_ci return (count > 0) ? count : 0; 4045bf215546Sopenharmony_ci} 4046bf215546Sopenharmony_ci 4047bf215546Sopenharmony_ciint ImGui::GetKeyPressedAmount(int key_index, float repeat_delay, float repeat_rate) 4048bf215546Sopenharmony_ci{ 4049bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4050bf215546Sopenharmony_ci if (key_index < 0) 4051bf215546Sopenharmony_ci return 0; 4052bf215546Sopenharmony_ci IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(g.IO.KeysDown)); 4053bf215546Sopenharmony_ci const float t = g.IO.KeysDownDuration[key_index]; 4054bf215546Sopenharmony_ci return CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, repeat_delay, repeat_rate); 4055bf215546Sopenharmony_ci} 4056bf215546Sopenharmony_ci 4057bf215546Sopenharmony_cibool ImGui::IsKeyPressed(int user_key_index, bool repeat) 4058bf215546Sopenharmony_ci{ 4059bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4060bf215546Sopenharmony_ci if (user_key_index < 0) 4061bf215546Sopenharmony_ci return false; 4062bf215546Sopenharmony_ci IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown)); 4063bf215546Sopenharmony_ci const float t = g.IO.KeysDownDuration[user_key_index]; 4064bf215546Sopenharmony_ci if (t == 0.0f) 4065bf215546Sopenharmony_ci return true; 4066bf215546Sopenharmony_ci if (repeat && t > g.IO.KeyRepeatDelay) 4067bf215546Sopenharmony_ci return GetKeyPressedAmount(user_key_index, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0; 4068bf215546Sopenharmony_ci return false; 4069bf215546Sopenharmony_ci} 4070bf215546Sopenharmony_ci 4071bf215546Sopenharmony_cibool ImGui::IsKeyReleased(int user_key_index) 4072bf215546Sopenharmony_ci{ 4073bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4074bf215546Sopenharmony_ci if (user_key_index < 0) return false; 4075bf215546Sopenharmony_ci IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown)); 4076bf215546Sopenharmony_ci return g.IO.KeysDownDurationPrev[user_key_index] >= 0.0f && !g.IO.KeysDown[user_key_index]; 4077bf215546Sopenharmony_ci} 4078bf215546Sopenharmony_ci 4079bf215546Sopenharmony_cibool ImGui::IsMouseDown(int button) 4080bf215546Sopenharmony_ci{ 4081bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4082bf215546Sopenharmony_ci IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); 4083bf215546Sopenharmony_ci return g.IO.MouseDown[button]; 4084bf215546Sopenharmony_ci} 4085bf215546Sopenharmony_ci 4086bf215546Sopenharmony_cibool ImGui::IsAnyMouseDown() 4087bf215546Sopenharmony_ci{ 4088bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4089bf215546Sopenharmony_ci for (int n = 0; n < IM_ARRAYSIZE(g.IO.MouseDown); n++) 4090bf215546Sopenharmony_ci if (g.IO.MouseDown[n]) 4091bf215546Sopenharmony_ci return true; 4092bf215546Sopenharmony_ci return false; 4093bf215546Sopenharmony_ci} 4094bf215546Sopenharmony_ci 4095bf215546Sopenharmony_cibool ImGui::IsMouseClicked(int button, bool repeat) 4096bf215546Sopenharmony_ci{ 4097bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4098bf215546Sopenharmony_ci IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); 4099bf215546Sopenharmony_ci const float t = g.IO.MouseDownDuration[button]; 4100bf215546Sopenharmony_ci if (t == 0.0f) 4101bf215546Sopenharmony_ci return true; 4102bf215546Sopenharmony_ci 4103bf215546Sopenharmony_ci if (repeat && t > g.IO.KeyRepeatDelay) 4104bf215546Sopenharmony_ci { 4105bf215546Sopenharmony_ci float delay = g.IO.KeyRepeatDelay, rate = g.IO.KeyRepeatRate; 4106bf215546Sopenharmony_ci if ((ImFmod(t - delay, rate) > rate*0.5f) != (ImFmod(t - delay - g.IO.DeltaTime, rate) > rate*0.5f)) 4107bf215546Sopenharmony_ci return true; 4108bf215546Sopenharmony_ci } 4109bf215546Sopenharmony_ci 4110bf215546Sopenharmony_ci return false; 4111bf215546Sopenharmony_ci} 4112bf215546Sopenharmony_ci 4113bf215546Sopenharmony_cibool ImGui::IsMouseReleased(int button) 4114bf215546Sopenharmony_ci{ 4115bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4116bf215546Sopenharmony_ci IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); 4117bf215546Sopenharmony_ci return g.IO.MouseReleased[button]; 4118bf215546Sopenharmony_ci} 4119bf215546Sopenharmony_ci 4120bf215546Sopenharmony_cibool ImGui::IsMouseDoubleClicked(int button) 4121bf215546Sopenharmony_ci{ 4122bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4123bf215546Sopenharmony_ci IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); 4124bf215546Sopenharmony_ci return g.IO.MouseDoubleClicked[button]; 4125bf215546Sopenharmony_ci} 4126bf215546Sopenharmony_ci 4127bf215546Sopenharmony_cibool ImGui::IsMouseDragging(int button, float lock_threshold) 4128bf215546Sopenharmony_ci{ 4129bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4130bf215546Sopenharmony_ci IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); 4131bf215546Sopenharmony_ci if (!g.IO.MouseDown[button]) 4132bf215546Sopenharmony_ci return false; 4133bf215546Sopenharmony_ci if (lock_threshold < 0.0f) 4134bf215546Sopenharmony_ci lock_threshold = g.IO.MouseDragThreshold; 4135bf215546Sopenharmony_ci return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold; 4136bf215546Sopenharmony_ci} 4137bf215546Sopenharmony_ci 4138bf215546Sopenharmony_ciImVec2 ImGui::GetMousePos() 4139bf215546Sopenharmony_ci{ 4140bf215546Sopenharmony_ci return GImGui->IO.MousePos; 4141bf215546Sopenharmony_ci} 4142bf215546Sopenharmony_ci 4143bf215546Sopenharmony_ci// NB: prefer to call right after BeginPopup(). At the time Selectable/MenuItem is activated, the popup is already closed! 4144bf215546Sopenharmony_ciImVec2 ImGui::GetMousePosOnOpeningCurrentPopup() 4145bf215546Sopenharmony_ci{ 4146bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4147bf215546Sopenharmony_ci if (g.BeginPopupStack.Size > 0) 4148bf215546Sopenharmony_ci return g.OpenPopupStack[g.BeginPopupStack.Size-1].OpenMousePos; 4149bf215546Sopenharmony_ci return g.IO.MousePos; 4150bf215546Sopenharmony_ci} 4151bf215546Sopenharmony_ci 4152bf215546Sopenharmony_ci// We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position. 4153bf215546Sopenharmony_cibool ImGui::IsMousePosValid(const ImVec2* mouse_pos) 4154bf215546Sopenharmony_ci{ 4155bf215546Sopenharmony_ci // The assert is only to silence a false-positive in XCode Static Analysis. 4156bf215546Sopenharmony_ci // Because GImGui is not dereferenced in every code path, the static analyzer assume that it may be NULL (which it doesn't for other functions). 4157bf215546Sopenharmony_ci IM_ASSERT(GImGui != NULL); 4158bf215546Sopenharmony_ci const float MOUSE_INVALID = -256000.0f; 4159bf215546Sopenharmony_ci ImVec2 p = mouse_pos ? *mouse_pos : GImGui->IO.MousePos; 4160bf215546Sopenharmony_ci return p.x >= MOUSE_INVALID && p.y >= MOUSE_INVALID; 4161bf215546Sopenharmony_ci} 4162bf215546Sopenharmony_ci 4163bf215546Sopenharmony_ci// Return the delta from the initial clicking position. 4164bf215546Sopenharmony_ci// This is locked and return 0.0f until the mouse moves past a distance threshold at least once. 4165bf215546Sopenharmony_ci// NB: This is only valid if IsMousePosValid(). Back-ends in theory should always keep mouse position valid when dragging even outside the client window. 4166bf215546Sopenharmony_ciImVec2 ImGui::GetMouseDragDelta(int button, float lock_threshold) 4167bf215546Sopenharmony_ci{ 4168bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4169bf215546Sopenharmony_ci IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); 4170bf215546Sopenharmony_ci if (lock_threshold < 0.0f) 4171bf215546Sopenharmony_ci lock_threshold = g.IO.MouseDragThreshold; 4172bf215546Sopenharmony_ci if (g.IO.MouseDown[button]) 4173bf215546Sopenharmony_ci if (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold) 4174bf215546Sopenharmony_ci return g.IO.MousePos - g.IO.MouseClickedPos[button]; // Assume we can only get active with left-mouse button (at the moment). 4175bf215546Sopenharmony_ci return ImVec2(0.0f, 0.0f); 4176bf215546Sopenharmony_ci} 4177bf215546Sopenharmony_ci 4178bf215546Sopenharmony_civoid ImGui::ResetMouseDragDelta(int button) 4179bf215546Sopenharmony_ci{ 4180bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4181bf215546Sopenharmony_ci IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); 4182bf215546Sopenharmony_ci // NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr 4183bf215546Sopenharmony_ci g.IO.MouseClickedPos[button] = g.IO.MousePos; 4184bf215546Sopenharmony_ci} 4185bf215546Sopenharmony_ci 4186bf215546Sopenharmony_ciImGuiMouseCursor ImGui::GetMouseCursor() 4187bf215546Sopenharmony_ci{ 4188bf215546Sopenharmony_ci return GImGui->MouseCursor; 4189bf215546Sopenharmony_ci} 4190bf215546Sopenharmony_ci 4191bf215546Sopenharmony_civoid ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type) 4192bf215546Sopenharmony_ci{ 4193bf215546Sopenharmony_ci GImGui->MouseCursor = cursor_type; 4194bf215546Sopenharmony_ci} 4195bf215546Sopenharmony_ci 4196bf215546Sopenharmony_civoid ImGui::CaptureKeyboardFromApp(bool capture) 4197bf215546Sopenharmony_ci{ 4198bf215546Sopenharmony_ci GImGui->WantCaptureKeyboardNextFrame = capture ? 1 : 0; 4199bf215546Sopenharmony_ci} 4200bf215546Sopenharmony_ci 4201bf215546Sopenharmony_civoid ImGui::CaptureMouseFromApp(bool capture) 4202bf215546Sopenharmony_ci{ 4203bf215546Sopenharmony_ci GImGui->WantCaptureMouseNextFrame = capture ? 1 : 0; 4204bf215546Sopenharmony_ci} 4205bf215546Sopenharmony_ci 4206bf215546Sopenharmony_cibool ImGui::IsItemActive() 4207bf215546Sopenharmony_ci{ 4208bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4209bf215546Sopenharmony_ci if (g.ActiveId) 4210bf215546Sopenharmony_ci { 4211bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 4212bf215546Sopenharmony_ci return g.ActiveId == window->DC.LastItemId; 4213bf215546Sopenharmony_ci } 4214bf215546Sopenharmony_ci return false; 4215bf215546Sopenharmony_ci} 4216bf215546Sopenharmony_ci 4217bf215546Sopenharmony_cibool ImGui::IsItemActivated() 4218bf215546Sopenharmony_ci{ 4219bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4220bf215546Sopenharmony_ci if (g.ActiveId) 4221bf215546Sopenharmony_ci { 4222bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 4223bf215546Sopenharmony_ci if (g.ActiveId == window->DC.LastItemId && g.ActiveIdPreviousFrame != window->DC.LastItemId) 4224bf215546Sopenharmony_ci return true; 4225bf215546Sopenharmony_ci } 4226bf215546Sopenharmony_ci return false; 4227bf215546Sopenharmony_ci} 4228bf215546Sopenharmony_ci 4229bf215546Sopenharmony_cibool ImGui::IsItemDeactivated() 4230bf215546Sopenharmony_ci{ 4231bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4232bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 4233bf215546Sopenharmony_ci return (g.ActiveIdPreviousFrame == window->DC.LastItemId && g.ActiveIdPreviousFrame != 0 && g.ActiveId != window->DC.LastItemId); 4234bf215546Sopenharmony_ci} 4235bf215546Sopenharmony_ci 4236bf215546Sopenharmony_cibool ImGui::IsItemDeactivatedAfterEdit() 4237bf215546Sopenharmony_ci{ 4238bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4239bf215546Sopenharmony_ci return IsItemDeactivated() && (g.ActiveIdPreviousFrameHasBeenEdited || (g.ActiveId == 0 && g.ActiveIdHasBeenEdited)); 4240bf215546Sopenharmony_ci} 4241bf215546Sopenharmony_ci 4242bf215546Sopenharmony_cibool ImGui::IsItemFocused() 4243bf215546Sopenharmony_ci{ 4244bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4245bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 4246bf215546Sopenharmony_ci 4247bf215546Sopenharmony_ci if (g.NavId == 0 || g.NavDisableHighlight || g.NavId != window->DC.LastItemId) 4248bf215546Sopenharmony_ci return false; 4249bf215546Sopenharmony_ci return true; 4250bf215546Sopenharmony_ci} 4251bf215546Sopenharmony_ci 4252bf215546Sopenharmony_cibool ImGui::IsItemClicked(int mouse_button) 4253bf215546Sopenharmony_ci{ 4254bf215546Sopenharmony_ci return IsMouseClicked(mouse_button) && IsItemHovered(ImGuiHoveredFlags_None); 4255bf215546Sopenharmony_ci} 4256bf215546Sopenharmony_ci 4257bf215546Sopenharmony_cibool ImGui::IsAnyItemHovered() 4258bf215546Sopenharmony_ci{ 4259bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4260bf215546Sopenharmony_ci return g.HoveredId != 0 || g.HoveredIdPreviousFrame != 0; 4261bf215546Sopenharmony_ci} 4262bf215546Sopenharmony_ci 4263bf215546Sopenharmony_cibool ImGui::IsAnyItemActive() 4264bf215546Sopenharmony_ci{ 4265bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4266bf215546Sopenharmony_ci return g.ActiveId != 0; 4267bf215546Sopenharmony_ci} 4268bf215546Sopenharmony_ci 4269bf215546Sopenharmony_cibool ImGui::IsAnyItemFocused() 4270bf215546Sopenharmony_ci{ 4271bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4272bf215546Sopenharmony_ci return g.NavId != 0 && !g.NavDisableHighlight; 4273bf215546Sopenharmony_ci} 4274bf215546Sopenharmony_ci 4275bf215546Sopenharmony_cibool ImGui::IsItemVisible() 4276bf215546Sopenharmony_ci{ 4277bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindowRead(); 4278bf215546Sopenharmony_ci return window->ClipRect.Overlaps(window->DC.LastItemRect); 4279bf215546Sopenharmony_ci} 4280bf215546Sopenharmony_ci 4281bf215546Sopenharmony_cibool ImGui::IsItemEdited() 4282bf215546Sopenharmony_ci{ 4283bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindowRead(); 4284bf215546Sopenharmony_ci return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Edited) != 0; 4285bf215546Sopenharmony_ci} 4286bf215546Sopenharmony_ci 4287bf215546Sopenharmony_ci// Allow last item to be overlapped by a subsequent item. Both may be activated during the same frame before the later one takes priority. 4288bf215546Sopenharmony_civoid ImGui::SetItemAllowOverlap() 4289bf215546Sopenharmony_ci{ 4290bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4291bf215546Sopenharmony_ci if (g.HoveredId == g.CurrentWindow->DC.LastItemId) 4292bf215546Sopenharmony_ci g.HoveredIdAllowOverlap = true; 4293bf215546Sopenharmony_ci if (g.ActiveId == g.CurrentWindow->DC.LastItemId) 4294bf215546Sopenharmony_ci g.ActiveIdAllowOverlap = true; 4295bf215546Sopenharmony_ci} 4296bf215546Sopenharmony_ci 4297bf215546Sopenharmony_ciImVec2 ImGui::GetItemRectMin() 4298bf215546Sopenharmony_ci{ 4299bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindowRead(); 4300bf215546Sopenharmony_ci return window->DC.LastItemRect.Min; 4301bf215546Sopenharmony_ci} 4302bf215546Sopenharmony_ci 4303bf215546Sopenharmony_ciImVec2 ImGui::GetItemRectMax() 4304bf215546Sopenharmony_ci{ 4305bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindowRead(); 4306bf215546Sopenharmony_ci return window->DC.LastItemRect.Max; 4307bf215546Sopenharmony_ci} 4308bf215546Sopenharmony_ci 4309bf215546Sopenharmony_ciImVec2 ImGui::GetItemRectSize() 4310bf215546Sopenharmony_ci{ 4311bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindowRead(); 4312bf215546Sopenharmony_ci return window->DC.LastItemRect.GetSize(); 4313bf215546Sopenharmony_ci} 4314bf215546Sopenharmony_ci 4315bf215546Sopenharmony_cistatic ImRect GetViewportRect() 4316bf215546Sopenharmony_ci{ 4317bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4318bf215546Sopenharmony_ci return ImRect(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y); 4319bf215546Sopenharmony_ci} 4320bf215546Sopenharmony_ci 4321bf215546Sopenharmony_cistatic bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags) 4322bf215546Sopenharmony_ci{ 4323bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4324bf215546Sopenharmony_ci ImGuiWindow* parent_window = g.CurrentWindow; 4325bf215546Sopenharmony_ci 4326bf215546Sopenharmony_ci flags |= ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_ChildWindow; 4327bf215546Sopenharmony_ci flags |= (parent_window->Flags & ImGuiWindowFlags_NoMove); // Inherit the NoMove flag 4328bf215546Sopenharmony_ci 4329bf215546Sopenharmony_ci // Size 4330bf215546Sopenharmony_ci const ImVec2 content_avail = GetContentRegionAvail(); 4331bf215546Sopenharmony_ci ImVec2 size = ImFloor(size_arg); 4332bf215546Sopenharmony_ci const int auto_fit_axises = ((size.x == 0.0f) ? (1 << ImGuiAxis_X) : 0x00) | ((size.y == 0.0f) ? (1 << ImGuiAxis_Y) : 0x00); 4333bf215546Sopenharmony_ci if (size.x <= 0.0f) 4334bf215546Sopenharmony_ci size.x = ImMax(content_avail.x + size.x, 4.0f); // Arbitrary minimum child size (0.0f causing too much issues) 4335bf215546Sopenharmony_ci if (size.y <= 0.0f) 4336bf215546Sopenharmony_ci size.y = ImMax(content_avail.y + size.y, 4.0f); 4337bf215546Sopenharmony_ci SetNextWindowSize(size); 4338bf215546Sopenharmony_ci 4339bf215546Sopenharmony_ci // Build up name. If you need to append to a same child from multiple location in the ID stack, use BeginChild(ImGuiID id) with a stable value. 4340bf215546Sopenharmony_ci char title[256]; 4341bf215546Sopenharmony_ci if (name) 4342bf215546Sopenharmony_ci ImFormatString(title, IM_ARRAYSIZE(title), "%s/%s_%08X", parent_window->Name, name, id); 4343bf215546Sopenharmony_ci else 4344bf215546Sopenharmony_ci ImFormatString(title, IM_ARRAYSIZE(title), "%s/%08X", parent_window->Name, id); 4345bf215546Sopenharmony_ci 4346bf215546Sopenharmony_ci const float backup_border_size = g.Style.ChildBorderSize; 4347bf215546Sopenharmony_ci if (!border) 4348bf215546Sopenharmony_ci g.Style.ChildBorderSize = 0.0f; 4349bf215546Sopenharmony_ci bool ret = Begin(title, NULL, flags); 4350bf215546Sopenharmony_ci g.Style.ChildBorderSize = backup_border_size; 4351bf215546Sopenharmony_ci 4352bf215546Sopenharmony_ci ImGuiWindow* child_window = g.CurrentWindow; 4353bf215546Sopenharmony_ci child_window->ChildId = id; 4354bf215546Sopenharmony_ci child_window->AutoFitChildAxises = auto_fit_axises; 4355bf215546Sopenharmony_ci 4356bf215546Sopenharmony_ci // Set the cursor to handle case where the user called SetNextWindowPos()+BeginChild() manually. 4357bf215546Sopenharmony_ci // While this is not really documented/defined, it seems that the expected thing to do. 4358bf215546Sopenharmony_ci if (child_window->BeginCount == 1) 4359bf215546Sopenharmony_ci parent_window->DC.CursorPos = child_window->Pos; 4360bf215546Sopenharmony_ci 4361bf215546Sopenharmony_ci // Process navigation-in immediately so NavInit can run on first frame 4362bf215546Sopenharmony_ci if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayerActiveMask != 0 || child_window->DC.NavHasScroll)) 4363bf215546Sopenharmony_ci { 4364bf215546Sopenharmony_ci FocusWindow(child_window); 4365bf215546Sopenharmony_ci NavInitWindow(child_window, false); 4366bf215546Sopenharmony_ci SetActiveID(id+1, child_window); // Steal ActiveId with a dummy id so that key-press won't activate child item 4367bf215546Sopenharmony_ci g.ActiveIdSource = ImGuiInputSource_Nav; 4368bf215546Sopenharmony_ci } 4369bf215546Sopenharmony_ci return ret; 4370bf215546Sopenharmony_ci} 4371bf215546Sopenharmony_ci 4372bf215546Sopenharmony_cibool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags) 4373bf215546Sopenharmony_ci{ 4374bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindow(); 4375bf215546Sopenharmony_ci return BeginChildEx(str_id, window->GetID(str_id), size_arg, border, extra_flags); 4376bf215546Sopenharmony_ci} 4377bf215546Sopenharmony_ci 4378bf215546Sopenharmony_cibool ImGui::BeginChild(ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags) 4379bf215546Sopenharmony_ci{ 4380bf215546Sopenharmony_ci IM_ASSERT(id != 0); 4381bf215546Sopenharmony_ci return BeginChildEx(NULL, id, size_arg, border, extra_flags); 4382bf215546Sopenharmony_ci} 4383bf215546Sopenharmony_ci 4384bf215546Sopenharmony_civoid ImGui::EndChild() 4385bf215546Sopenharmony_ci{ 4386bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4387bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 4388bf215546Sopenharmony_ci 4389bf215546Sopenharmony_ci IM_ASSERT(window->Flags & ImGuiWindowFlags_ChildWindow); // Mismatched BeginChild()/EndChild() callss 4390bf215546Sopenharmony_ci if (window->BeginCount > 1) 4391bf215546Sopenharmony_ci { 4392bf215546Sopenharmony_ci End(); 4393bf215546Sopenharmony_ci } 4394bf215546Sopenharmony_ci else 4395bf215546Sopenharmony_ci { 4396bf215546Sopenharmony_ci ImVec2 sz = window->Size; 4397bf215546Sopenharmony_ci if (window->AutoFitChildAxises & (1 << ImGuiAxis_X)) // Arbitrary minimum zero-ish child size of 4.0f causes less trouble than a 0.0f 4398bf215546Sopenharmony_ci sz.x = ImMax(4.0f, sz.x); 4399bf215546Sopenharmony_ci if (window->AutoFitChildAxises & (1 << ImGuiAxis_Y)) 4400bf215546Sopenharmony_ci sz.y = ImMax(4.0f, sz.y); 4401bf215546Sopenharmony_ci End(); 4402bf215546Sopenharmony_ci 4403bf215546Sopenharmony_ci ImGuiWindow* parent_window = g.CurrentWindow; 4404bf215546Sopenharmony_ci ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + sz); 4405bf215546Sopenharmony_ci ItemSize(sz); 4406bf215546Sopenharmony_ci if ((window->DC.NavLayerActiveMask != 0 || window->DC.NavHasScroll) && !(window->Flags & ImGuiWindowFlags_NavFlattened)) 4407bf215546Sopenharmony_ci { 4408bf215546Sopenharmony_ci ItemAdd(bb, window->ChildId); 4409bf215546Sopenharmony_ci RenderNavHighlight(bb, window->ChildId); 4410bf215546Sopenharmony_ci 4411bf215546Sopenharmony_ci // When browsing a window that has no activable items (scroll only) we keep a highlight on the child 4412bf215546Sopenharmony_ci if (window->DC.NavLayerActiveMask == 0 && window == g.NavWindow) 4413bf215546Sopenharmony_ci RenderNavHighlight(ImRect(bb.Min - ImVec2(2,2), bb.Max + ImVec2(2,2)), g.NavId, ImGuiNavHighlightFlags_TypeThin); 4414bf215546Sopenharmony_ci } 4415bf215546Sopenharmony_ci else 4416bf215546Sopenharmony_ci { 4417bf215546Sopenharmony_ci // Not navigable into 4418bf215546Sopenharmony_ci ItemAdd(bb, 0); 4419bf215546Sopenharmony_ci } 4420bf215546Sopenharmony_ci } 4421bf215546Sopenharmony_ci} 4422bf215546Sopenharmony_ci 4423bf215546Sopenharmony_ci// Helper to create a child window / scrolling region that looks like a normal widget frame. 4424bf215546Sopenharmony_cibool ImGui::BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags extra_flags) 4425bf215546Sopenharmony_ci{ 4426bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4427bf215546Sopenharmony_ci const ImGuiStyle& style = g.Style; 4428bf215546Sopenharmony_ci PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]); 4429bf215546Sopenharmony_ci PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding); 4430bf215546Sopenharmony_ci PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize); 4431bf215546Sopenharmony_ci PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding); 4432bf215546Sopenharmony_ci bool ret = BeginChild(id, size, true, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysUseWindowPadding | extra_flags); 4433bf215546Sopenharmony_ci PopStyleVar(3); 4434bf215546Sopenharmony_ci PopStyleColor(); 4435bf215546Sopenharmony_ci return ret; 4436bf215546Sopenharmony_ci} 4437bf215546Sopenharmony_ci 4438bf215546Sopenharmony_civoid ImGui::EndChildFrame() 4439bf215546Sopenharmony_ci{ 4440bf215546Sopenharmony_ci EndChild(); 4441bf215546Sopenharmony_ci} 4442bf215546Sopenharmony_ci 4443bf215546Sopenharmony_ci// Save and compare stack sizes on Begin()/End() to detect usage errors 4444bf215546Sopenharmony_cistatic void CheckStacksSize(ImGuiWindow* window, bool write) 4445bf215546Sopenharmony_ci{ 4446bf215546Sopenharmony_ci // NOT checking: DC.ItemWidth, DC.AllowKeyboardFocus, DC.ButtonRepeat, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin) 4447bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4448bf215546Sopenharmony_ci short* p_backup = &window->DC.StackSizesBackup[0]; 4449bf215546Sopenharmony_ci { int current = window->IDStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "PushID/PopID or TreeNode/TreePop Mismatch!"); p_backup++; } // Too few or too many PopID()/TreePop() 4450bf215546Sopenharmony_ci { int current = window->DC.GroupStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "BeginGroup/EndGroup Mismatch!"); p_backup++; } // Too few or too many EndGroup() 4451bf215546Sopenharmony_ci { int current = g.BeginPopupStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch"); p_backup++;}// Too few or too many EndMenu()/EndPopup() 4452bf215546Sopenharmony_ci // For color, style and font stacks there is an incentive to use Push/Begin/Pop/.../End patterns, so we relax our checks a little to allow them. 4453bf215546Sopenharmony_ci { int current = g.ColorModifiers.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup >= current && "PushStyleColor/PopStyleColor Mismatch!"); p_backup++; } // Too few or too many PopStyleColor() 4454bf215546Sopenharmony_ci { int current = g.StyleModifiers.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup >= current && "PushStyleVar/PopStyleVar Mismatch!"); p_backup++; } // Too few or too many PopStyleVar() 4455bf215546Sopenharmony_ci { int current = g.FontStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup >= current && "PushFont/PopFont Mismatch!"); p_backup++; } // Too few or too many PopFont() 4456bf215546Sopenharmony_ci IM_ASSERT(p_backup == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup)); 4457bf215546Sopenharmony_ci} 4458bf215546Sopenharmony_ci 4459bf215546Sopenharmony_cistatic void SetWindowConditionAllowFlags(ImGuiWindow* window, ImGuiCond flags, bool enabled) 4460bf215546Sopenharmony_ci{ 4461bf215546Sopenharmony_ci window->SetWindowPosAllowFlags = enabled ? (window->SetWindowPosAllowFlags | flags) : (window->SetWindowPosAllowFlags & ~flags); 4462bf215546Sopenharmony_ci window->SetWindowSizeAllowFlags = enabled ? (window->SetWindowSizeAllowFlags | flags) : (window->SetWindowSizeAllowFlags & ~flags); 4463bf215546Sopenharmony_ci window->SetWindowCollapsedAllowFlags = enabled ? (window->SetWindowCollapsedAllowFlags | flags) : (window->SetWindowCollapsedAllowFlags & ~flags); 4464bf215546Sopenharmony_ci} 4465bf215546Sopenharmony_ci 4466bf215546Sopenharmony_ciImGuiWindow* ImGui::FindWindowByID(ImGuiID id) 4467bf215546Sopenharmony_ci{ 4468bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4469bf215546Sopenharmony_ci return (ImGuiWindow*)g.WindowsById.GetVoidPtr(id); 4470bf215546Sopenharmony_ci} 4471bf215546Sopenharmony_ci 4472bf215546Sopenharmony_ciImGuiWindow* ImGui::FindWindowByName(const char* name) 4473bf215546Sopenharmony_ci{ 4474bf215546Sopenharmony_ci ImGuiID id = ImHashStr(name, 0); 4475bf215546Sopenharmony_ci return FindWindowByID(id); 4476bf215546Sopenharmony_ci} 4477bf215546Sopenharmony_ci 4478bf215546Sopenharmony_cistatic ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFlags flags) 4479bf215546Sopenharmony_ci{ 4480bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4481bf215546Sopenharmony_ci 4482bf215546Sopenharmony_ci // Create window the first time 4483bf215546Sopenharmony_ci ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name); 4484bf215546Sopenharmony_ci window->Flags = flags; 4485bf215546Sopenharmony_ci g.WindowsById.SetVoidPtr(window->ID, window); 4486bf215546Sopenharmony_ci 4487bf215546Sopenharmony_ci // Default/arbitrary window position. Use SetNextWindowPos() with the appropriate condition flag to change the initial position of a window. 4488bf215546Sopenharmony_ci window->Pos = ImVec2(60, 60); 4489bf215546Sopenharmony_ci 4490bf215546Sopenharmony_ci // User can disable loading and saving of settings. Tooltip and child windows also don't store settings. 4491bf215546Sopenharmony_ci if (!(flags & ImGuiWindowFlags_NoSavedSettings)) 4492bf215546Sopenharmony_ci if (ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID)) 4493bf215546Sopenharmony_ci { 4494bf215546Sopenharmony_ci // Retrieve settings from .ini file 4495bf215546Sopenharmony_ci window->SettingsIdx = g.SettingsWindows.index_from_ptr(settings); 4496bf215546Sopenharmony_ci SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false); 4497bf215546Sopenharmony_ci window->Pos = ImFloor(settings->Pos); 4498bf215546Sopenharmony_ci window->Collapsed = settings->Collapsed; 4499bf215546Sopenharmony_ci if (ImLengthSqr(settings->Size) > 0.00001f) 4500bf215546Sopenharmony_ci size = ImFloor(settings->Size); 4501bf215546Sopenharmony_ci } 4502bf215546Sopenharmony_ci window->Size = window->SizeFull = window->SizeFullAtLastBegin = ImFloor(size); 4503bf215546Sopenharmony_ci window->DC.CursorMaxPos = window->Pos; // So first call to CalcSizeContents() doesn't return crazy values 4504bf215546Sopenharmony_ci 4505bf215546Sopenharmony_ci if ((flags & ImGuiWindowFlags_AlwaysAutoResize) != 0) 4506bf215546Sopenharmony_ci { 4507bf215546Sopenharmony_ci window->AutoFitFramesX = window->AutoFitFramesY = 2; 4508bf215546Sopenharmony_ci window->AutoFitOnlyGrows = false; 4509bf215546Sopenharmony_ci } 4510bf215546Sopenharmony_ci else 4511bf215546Sopenharmony_ci { 4512bf215546Sopenharmony_ci if (window->Size.x <= 0.0f) 4513bf215546Sopenharmony_ci window->AutoFitFramesX = 2; 4514bf215546Sopenharmony_ci if (window->Size.y <= 0.0f) 4515bf215546Sopenharmony_ci window->AutoFitFramesY = 2; 4516bf215546Sopenharmony_ci window->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0); 4517bf215546Sopenharmony_ci } 4518bf215546Sopenharmony_ci 4519bf215546Sopenharmony_ci g.WindowsFocusOrder.push_back(window); 4520bf215546Sopenharmony_ci if (flags & ImGuiWindowFlags_NoBringToFrontOnFocus) 4521bf215546Sopenharmony_ci g.Windows.push_front(window); // Quite slow but rare and only once 4522bf215546Sopenharmony_ci else 4523bf215546Sopenharmony_ci g.Windows.push_back(window); 4524bf215546Sopenharmony_ci return window; 4525bf215546Sopenharmony_ci} 4526bf215546Sopenharmony_ci 4527bf215546Sopenharmony_cistatic ImVec2 CalcSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size) 4528bf215546Sopenharmony_ci{ 4529bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4530bf215546Sopenharmony_ci if (g.NextWindowData.SizeConstraintCond != 0) 4531bf215546Sopenharmony_ci { 4532bf215546Sopenharmony_ci // Using -1,-1 on either X/Y axis to preserve the current size. 4533bf215546Sopenharmony_ci ImRect cr = g.NextWindowData.SizeConstraintRect; 4534bf215546Sopenharmony_ci new_size.x = (cr.Min.x >= 0 && cr.Max.x >= 0) ? ImClamp(new_size.x, cr.Min.x, cr.Max.x) : window->SizeFull.x; 4535bf215546Sopenharmony_ci new_size.y = (cr.Min.y >= 0 && cr.Max.y >= 0) ? ImClamp(new_size.y, cr.Min.y, cr.Max.y) : window->SizeFull.y; 4536bf215546Sopenharmony_ci if (g.NextWindowData.SizeCallback) 4537bf215546Sopenharmony_ci { 4538bf215546Sopenharmony_ci ImGuiSizeCallbackData data; 4539bf215546Sopenharmony_ci data.UserData = g.NextWindowData.SizeCallbackUserData; 4540bf215546Sopenharmony_ci data.Pos = window->Pos; 4541bf215546Sopenharmony_ci data.CurrentSize = window->SizeFull; 4542bf215546Sopenharmony_ci data.DesiredSize = new_size; 4543bf215546Sopenharmony_ci g.NextWindowData.SizeCallback(&data); 4544bf215546Sopenharmony_ci new_size = data.DesiredSize; 4545bf215546Sopenharmony_ci } 4546bf215546Sopenharmony_ci } 4547bf215546Sopenharmony_ci 4548bf215546Sopenharmony_ci // Minimum size 4549bf215546Sopenharmony_ci if (!(window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysAutoResize))) 4550bf215546Sopenharmony_ci { 4551bf215546Sopenharmony_ci new_size = ImMax(new_size, g.Style.WindowMinSize); 4552bf215546Sopenharmony_ci new_size.y = ImMax(new_size.y, window->TitleBarHeight() + window->MenuBarHeight() + ImMax(0.0f, g.Style.WindowRounding - 1.0f)); // Reduce artifacts with very small windows 4553bf215546Sopenharmony_ci } 4554bf215546Sopenharmony_ci return new_size; 4555bf215546Sopenharmony_ci} 4556bf215546Sopenharmony_ci 4557bf215546Sopenharmony_cistatic ImVec2 CalcSizeContents(ImGuiWindow* window) 4558bf215546Sopenharmony_ci{ 4559bf215546Sopenharmony_ci if (window->Collapsed) 4560bf215546Sopenharmony_ci if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) 4561bf215546Sopenharmony_ci return window->SizeContents; 4562bf215546Sopenharmony_ci if (window->Hidden && window->HiddenFramesForResize == 0 && window->HiddenFramesRegular > 0) 4563bf215546Sopenharmony_ci return window->SizeContents; 4564bf215546Sopenharmony_ci 4565bf215546Sopenharmony_ci ImVec2 sz; 4566bf215546Sopenharmony_ci sz.x = (float)(int)((window->SizeContentsExplicit.x != 0.0f) ? window->SizeContentsExplicit.x : (window->DC.CursorMaxPos.x - window->Pos.x + window->Scroll.x)); 4567bf215546Sopenharmony_ci sz.y = (float)(int)((window->SizeContentsExplicit.y != 0.0f) ? window->SizeContentsExplicit.y : (window->DC.CursorMaxPos.y - window->Pos.y + window->Scroll.y)); 4568bf215546Sopenharmony_ci return sz + window->WindowPadding; 4569bf215546Sopenharmony_ci} 4570bf215546Sopenharmony_ci 4571bf215546Sopenharmony_cistatic ImVec2 CalcSizeAutoFit(ImGuiWindow* window, const ImVec2& size_contents) 4572bf215546Sopenharmony_ci{ 4573bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4574bf215546Sopenharmony_ci ImGuiStyle& style = g.Style; 4575bf215546Sopenharmony_ci if (window->Flags & ImGuiWindowFlags_Tooltip) 4576bf215546Sopenharmony_ci { 4577bf215546Sopenharmony_ci // Tooltip always resize 4578bf215546Sopenharmony_ci return size_contents; 4579bf215546Sopenharmony_ci } 4580bf215546Sopenharmony_ci else 4581bf215546Sopenharmony_ci { 4582bf215546Sopenharmony_ci // Maximum window size is determined by the display size 4583bf215546Sopenharmony_ci const bool is_popup = (window->Flags & ImGuiWindowFlags_Popup) != 0; 4584bf215546Sopenharmony_ci const bool is_menu = (window->Flags & ImGuiWindowFlags_ChildMenu) != 0; 4585bf215546Sopenharmony_ci ImVec2 size_min = style.WindowMinSize; 4586bf215546Sopenharmony_ci if (is_popup || is_menu) // Popups and menus bypass style.WindowMinSize by default, but we give then a non-zero minimum size to facilitate understanding problematic cases (e.g. empty popups) 4587bf215546Sopenharmony_ci size_min = ImMin(size_min, ImVec2(4.0f, 4.0f)); 4588bf215546Sopenharmony_ci ImVec2 size_auto_fit = ImClamp(size_contents, size_min, ImMax(size_min, g.IO.DisplaySize - style.DisplaySafeAreaPadding * 2.0f)); 4589bf215546Sopenharmony_ci 4590bf215546Sopenharmony_ci // When the window cannot fit all contents (either because of constraints, either because screen is too small), 4591bf215546Sopenharmony_ci // we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than ViewportSize-WindowPadding. 4592bf215546Sopenharmony_ci ImVec2 size_auto_fit_after_constraint = CalcSizeAfterConstraint(window, size_auto_fit); 4593bf215546Sopenharmony_ci if (size_auto_fit_after_constraint.x < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) 4594bf215546Sopenharmony_ci size_auto_fit.y += style.ScrollbarSize; 4595bf215546Sopenharmony_ci if (size_auto_fit_after_constraint.y < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) 4596bf215546Sopenharmony_ci size_auto_fit.x += style.ScrollbarSize; 4597bf215546Sopenharmony_ci return size_auto_fit; 4598bf215546Sopenharmony_ci } 4599bf215546Sopenharmony_ci} 4600bf215546Sopenharmony_ci 4601bf215546Sopenharmony_ciImVec2 ImGui::CalcWindowExpectedSize(ImGuiWindow* window) 4602bf215546Sopenharmony_ci{ 4603bf215546Sopenharmony_ci ImVec2 size_contents = CalcSizeContents(window); 4604bf215546Sopenharmony_ci return CalcSizeAfterConstraint(window, CalcSizeAutoFit(window, size_contents)); 4605bf215546Sopenharmony_ci} 4606bf215546Sopenharmony_ci 4607bf215546Sopenharmony_cifloat ImGui::GetWindowScrollMaxX(ImGuiWindow* window) 4608bf215546Sopenharmony_ci{ 4609bf215546Sopenharmony_ci return ImMax(0.0f, window->SizeContents.x - (window->SizeFull.x - window->ScrollbarSizes.x)); 4610bf215546Sopenharmony_ci} 4611bf215546Sopenharmony_ci 4612bf215546Sopenharmony_cifloat ImGui::GetWindowScrollMaxY(ImGuiWindow* window) 4613bf215546Sopenharmony_ci{ 4614bf215546Sopenharmony_ci return ImMax(0.0f, window->SizeContents.y - (window->SizeFull.y - window->ScrollbarSizes.y)); 4615bf215546Sopenharmony_ci} 4616bf215546Sopenharmony_ci 4617bf215546Sopenharmony_cistatic ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool snap_on_edges) 4618bf215546Sopenharmony_ci{ 4619bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4620bf215546Sopenharmony_ci ImVec2 scroll = window->Scroll; 4621bf215546Sopenharmony_ci if (window->ScrollTarget.x < FLT_MAX) 4622bf215546Sopenharmony_ci { 4623bf215546Sopenharmony_ci float cr_x = window->ScrollTargetCenterRatio.x; 4624bf215546Sopenharmony_ci scroll.x = window->ScrollTarget.x - cr_x * (window->SizeFull.x - window->ScrollbarSizes.x); 4625bf215546Sopenharmony_ci } 4626bf215546Sopenharmony_ci if (window->ScrollTarget.y < FLT_MAX) 4627bf215546Sopenharmony_ci { 4628bf215546Sopenharmony_ci // 'snap_on_edges' allows for a discontinuity at the edge of scrolling limits to take account of WindowPadding so that scrolling to make the last item visible scroll far enough to see the padding. 4629bf215546Sopenharmony_ci float cr_y = window->ScrollTargetCenterRatio.y; 4630bf215546Sopenharmony_ci float target_y = window->ScrollTarget.y; 4631bf215546Sopenharmony_ci if (snap_on_edges && cr_y <= 0.0f && target_y <= window->WindowPadding.y) 4632bf215546Sopenharmony_ci target_y = 0.0f; 4633bf215546Sopenharmony_ci if (snap_on_edges && cr_y >= 1.0f && target_y >= window->SizeContents.y - window->WindowPadding.y + g.Style.ItemSpacing.y) 4634bf215546Sopenharmony_ci target_y = window->SizeContents.y; 4635bf215546Sopenharmony_ci scroll.y = target_y - (1.0f - cr_y) * (window->TitleBarHeight() + window->MenuBarHeight()) - cr_y * (window->SizeFull.y - window->ScrollbarSizes.y); 4636bf215546Sopenharmony_ci } 4637bf215546Sopenharmony_ci scroll = ImMax(scroll, ImVec2(0.0f, 0.0f)); 4638bf215546Sopenharmony_ci if (!window->Collapsed && !window->SkipItems) 4639bf215546Sopenharmony_ci { 4640bf215546Sopenharmony_ci scroll.x = ImMin(scroll.x, ImGui::GetWindowScrollMaxX(window)); 4641bf215546Sopenharmony_ci scroll.y = ImMin(scroll.y, ImGui::GetWindowScrollMaxY(window)); 4642bf215546Sopenharmony_ci } 4643bf215546Sopenharmony_ci return scroll; 4644bf215546Sopenharmony_ci} 4645bf215546Sopenharmony_ci 4646bf215546Sopenharmony_cistatic ImGuiCol GetWindowBgColorIdxFromFlags(ImGuiWindowFlags flags) 4647bf215546Sopenharmony_ci{ 4648bf215546Sopenharmony_ci if (flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) 4649bf215546Sopenharmony_ci return ImGuiCol_PopupBg; 4650bf215546Sopenharmony_ci if (flags & ImGuiWindowFlags_ChildWindow) 4651bf215546Sopenharmony_ci return ImGuiCol_ChildBg; 4652bf215546Sopenharmony_ci return ImGuiCol_WindowBg; 4653bf215546Sopenharmony_ci} 4654bf215546Sopenharmony_ci 4655bf215546Sopenharmony_cistatic void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& corner_target, const ImVec2& corner_norm, ImVec2* out_pos, ImVec2* out_size) 4656bf215546Sopenharmony_ci{ 4657bf215546Sopenharmony_ci ImVec2 pos_min = ImLerp(corner_target, window->Pos, corner_norm); // Expected window upper-left 4658bf215546Sopenharmony_ci ImVec2 pos_max = ImLerp(window->Pos + window->Size, corner_target, corner_norm); // Expected window lower-right 4659bf215546Sopenharmony_ci ImVec2 size_expected = pos_max - pos_min; 4660bf215546Sopenharmony_ci ImVec2 size_constrained = CalcSizeAfterConstraint(window, size_expected); 4661bf215546Sopenharmony_ci *out_pos = pos_min; 4662bf215546Sopenharmony_ci if (corner_norm.x == 0.0f) 4663bf215546Sopenharmony_ci out_pos->x -= (size_constrained.x - size_expected.x); 4664bf215546Sopenharmony_ci if (corner_norm.y == 0.0f) 4665bf215546Sopenharmony_ci out_pos->y -= (size_constrained.y - size_expected.y); 4666bf215546Sopenharmony_ci *out_size = size_constrained; 4667bf215546Sopenharmony_ci} 4668bf215546Sopenharmony_ci 4669bf215546Sopenharmony_cistruct ImGuiResizeGripDef 4670bf215546Sopenharmony_ci{ 4671bf215546Sopenharmony_ci ImVec2 CornerPosN; 4672bf215546Sopenharmony_ci ImVec2 InnerDir; 4673bf215546Sopenharmony_ci int AngleMin12, AngleMax12; 4674bf215546Sopenharmony_ci}; 4675bf215546Sopenharmony_ci 4676bf215546Sopenharmony_cistatic const ImGuiResizeGripDef resize_grip_def[4] = 4677bf215546Sopenharmony_ci{ 4678bf215546Sopenharmony_ci { ImVec2(1,1), ImVec2(-1,-1), 0, 3 }, // Lower right 4679bf215546Sopenharmony_ci { ImVec2(0,1), ImVec2(+1,-1), 3, 6 }, // Lower left 4680bf215546Sopenharmony_ci { ImVec2(0,0), ImVec2(+1,+1), 6, 9 }, // Upper left 4681bf215546Sopenharmony_ci { ImVec2(1,0), ImVec2(-1,+1), 9,12 }, // Upper right 4682bf215546Sopenharmony_ci}; 4683bf215546Sopenharmony_ci 4684bf215546Sopenharmony_cistatic ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_padding, float thickness) 4685bf215546Sopenharmony_ci{ 4686bf215546Sopenharmony_ci ImRect rect = window->Rect(); 4687bf215546Sopenharmony_ci if (thickness == 0.0f) rect.Max -= ImVec2(1,1); 4688bf215546Sopenharmony_ci if (border_n == 0) return ImRect(rect.Min.x + perp_padding, rect.Min.y - thickness, rect.Max.x - perp_padding, rect.Min.y + thickness); // Top 4689bf215546Sopenharmony_ci if (border_n == 1) return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x + thickness, rect.Max.y - perp_padding); // Right 4690bf215546Sopenharmony_ci if (border_n == 2) return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y + thickness); // Bottom 4691bf215546Sopenharmony_ci if (border_n == 3) return ImRect(rect.Min.x - thickness, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding); // Left 4692bf215546Sopenharmony_ci IM_ASSERT(0); 4693bf215546Sopenharmony_ci return ImRect(); 4694bf215546Sopenharmony_ci} 4695bf215546Sopenharmony_ci 4696bf215546Sopenharmony_ci// Handle resize for: Resize Grips, Borders, Gamepad 4697bf215546Sopenharmony_cistatic void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]) 4698bf215546Sopenharmony_ci{ 4699bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4700bf215546Sopenharmony_ci ImGuiWindowFlags flags = window->Flags; 4701bf215546Sopenharmony_ci if ((flags & ImGuiWindowFlags_NoResize) || (flags & ImGuiWindowFlags_AlwaysAutoResize) || window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0) 4702bf215546Sopenharmony_ci return; 4703bf215546Sopenharmony_ci if (window->WasActive == false) // Early out to avoid running this code for e.g. an hidden implicit/fallback Debug window. 4704bf215546Sopenharmony_ci return; 4705bf215546Sopenharmony_ci 4706bf215546Sopenharmony_ci const int resize_border_count = g.IO.ConfigWindowsResizeFromEdges ? 4 : 0; 4707bf215546Sopenharmony_ci const float grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f); 4708bf215546Sopenharmony_ci const float grip_hover_inner_size = (float)(int)(grip_draw_size * 0.75f); 4709bf215546Sopenharmony_ci const float grip_hover_outer_size = g.IO.ConfigWindowsResizeFromEdges ? WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS : 0.0f; 4710bf215546Sopenharmony_ci 4711bf215546Sopenharmony_ci ImVec2 pos_target(FLT_MAX, FLT_MAX); 4712bf215546Sopenharmony_ci ImVec2 size_target(FLT_MAX, FLT_MAX); 4713bf215546Sopenharmony_ci 4714bf215546Sopenharmony_ci // Manual resize grips 4715bf215546Sopenharmony_ci PushID("#RESIZE"); 4716bf215546Sopenharmony_ci for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++) 4717bf215546Sopenharmony_ci { 4718bf215546Sopenharmony_ci const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n]; 4719bf215546Sopenharmony_ci const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN); 4720bf215546Sopenharmony_ci 4721bf215546Sopenharmony_ci // Using the FlattenChilds button flag we make the resize button accessible even if we are hovering over a child window 4722bf215546Sopenharmony_ci ImRect resize_rect(corner - grip.InnerDir * grip_hover_outer_size, corner + grip.InnerDir * grip_hover_inner_size); 4723bf215546Sopenharmony_ci if (resize_rect.Min.x > resize_rect.Max.x) ImSwap(resize_rect.Min.x, resize_rect.Max.x); 4724bf215546Sopenharmony_ci if (resize_rect.Min.y > resize_rect.Max.y) ImSwap(resize_rect.Min.y, resize_rect.Max.y); 4725bf215546Sopenharmony_ci bool hovered, held; 4726bf215546Sopenharmony_ci ButtonBehavior(resize_rect, window->GetID((void*)(intptr_t)resize_grip_n), &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus); 4727bf215546Sopenharmony_ci //GetOverlayDrawList(window)->AddRect(resize_rect.Min, resize_rect.Max, IM_COL32(255, 255, 0, 255)); 4728bf215546Sopenharmony_ci if (hovered || held) 4729bf215546Sopenharmony_ci g.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE; 4730bf215546Sopenharmony_ci 4731bf215546Sopenharmony_ci if (held && g.IO.MouseDoubleClicked[0] && resize_grip_n == 0) 4732bf215546Sopenharmony_ci { 4733bf215546Sopenharmony_ci // Manual auto-fit when double-clicking 4734bf215546Sopenharmony_ci size_target = CalcSizeAfterConstraint(window, size_auto_fit); 4735bf215546Sopenharmony_ci ClearActiveID(); 4736bf215546Sopenharmony_ci } 4737bf215546Sopenharmony_ci else if (held) 4738bf215546Sopenharmony_ci { 4739bf215546Sopenharmony_ci // Resize from any of the four corners 4740bf215546Sopenharmony_ci // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position 4741bf215546Sopenharmony_ci ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(grip.InnerDir * grip_hover_outer_size, grip.InnerDir * -grip_hover_inner_size, grip.CornerPosN); // Corner of the window corresponding to our corner grip 4742bf215546Sopenharmony_ci CalcResizePosSizeFromAnyCorner(window, corner_target, grip.CornerPosN, &pos_target, &size_target); 4743bf215546Sopenharmony_ci } 4744bf215546Sopenharmony_ci if (resize_grip_n == 0 || held || hovered) 4745bf215546Sopenharmony_ci resize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip); 4746bf215546Sopenharmony_ci } 4747bf215546Sopenharmony_ci for (int border_n = 0; border_n < resize_border_count; border_n++) 4748bf215546Sopenharmony_ci { 4749bf215546Sopenharmony_ci bool hovered, held; 4750bf215546Sopenharmony_ci ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); 4751bf215546Sopenharmony_ci ButtonBehavior(border_rect, window->GetID((void*)(intptr_t)(border_n + 4)), &hovered, &held, ImGuiButtonFlags_FlattenChildren); 4752bf215546Sopenharmony_ci //GetOverlayDrawList(window)->AddRect(border_rect.Min, border_rect.Max, IM_COL32(255, 255, 0, 255)); 4753bf215546Sopenharmony_ci if ((hovered && g.HoveredIdTimer > WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) || held) 4754bf215546Sopenharmony_ci { 4755bf215546Sopenharmony_ci g.MouseCursor = (border_n & 1) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS; 4756bf215546Sopenharmony_ci if (held) 4757bf215546Sopenharmony_ci *border_held = border_n; 4758bf215546Sopenharmony_ci } 4759bf215546Sopenharmony_ci if (held) 4760bf215546Sopenharmony_ci { 4761bf215546Sopenharmony_ci ImVec2 border_target = window->Pos; 4762bf215546Sopenharmony_ci ImVec2 border_posn; 4763bf215546Sopenharmony_ci if (border_n == 0) { border_posn = ImVec2(0, 0); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Top 4764bf215546Sopenharmony_ci if (border_n == 1) { border_posn = ImVec2(1, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Right 4765bf215546Sopenharmony_ci if (border_n == 2) { border_posn = ImVec2(0, 1); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Bottom 4766bf215546Sopenharmony_ci if (border_n == 3) { border_posn = ImVec2(0, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Left 4767bf215546Sopenharmony_ci CalcResizePosSizeFromAnyCorner(window, border_target, border_posn, &pos_target, &size_target); 4768bf215546Sopenharmony_ci } 4769bf215546Sopenharmony_ci } 4770bf215546Sopenharmony_ci PopID(); 4771bf215546Sopenharmony_ci 4772bf215546Sopenharmony_ci // Navigation resize (keyboard/gamepad) 4773bf215546Sopenharmony_ci if (g.NavWindowingTarget && g.NavWindowingTarget->RootWindow == window) 4774bf215546Sopenharmony_ci { 4775bf215546Sopenharmony_ci ImVec2 nav_resize_delta; 4776bf215546Sopenharmony_ci if (g.NavInputSource == ImGuiInputSource_NavKeyboard && g.IO.KeyShift) 4777bf215546Sopenharmony_ci nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down); 4778bf215546Sopenharmony_ci if (g.NavInputSource == ImGuiInputSource_NavGamepad) 4779bf215546Sopenharmony_ci nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_Down); 4780bf215546Sopenharmony_ci if (nav_resize_delta.x != 0.0f || nav_resize_delta.y != 0.0f) 4781bf215546Sopenharmony_ci { 4782bf215546Sopenharmony_ci const float NAV_RESIZE_SPEED = 600.0f; 4783bf215546Sopenharmony_ci nav_resize_delta *= ImFloor(NAV_RESIZE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y)); 4784bf215546Sopenharmony_ci g.NavWindowingToggleLayer = false; 4785bf215546Sopenharmony_ci g.NavDisableMouseHover = true; 4786bf215546Sopenharmony_ci resize_grip_col[0] = GetColorU32(ImGuiCol_ResizeGripActive); 4787bf215546Sopenharmony_ci // FIXME-NAV: Should store and accumulate into a separate size buffer to handle sizing constraints properly, right now a constraint will make us stuck. 4788bf215546Sopenharmony_ci size_target = CalcSizeAfterConstraint(window, window->SizeFull + nav_resize_delta); 4789bf215546Sopenharmony_ci } 4790bf215546Sopenharmony_ci } 4791bf215546Sopenharmony_ci 4792bf215546Sopenharmony_ci // Apply back modified position/size to window 4793bf215546Sopenharmony_ci if (size_target.x != FLT_MAX) 4794bf215546Sopenharmony_ci { 4795bf215546Sopenharmony_ci window->SizeFull = size_target; 4796bf215546Sopenharmony_ci MarkIniSettingsDirty(window); 4797bf215546Sopenharmony_ci } 4798bf215546Sopenharmony_ci if (pos_target.x != FLT_MAX) 4799bf215546Sopenharmony_ci { 4800bf215546Sopenharmony_ci window->Pos = ImFloor(pos_target); 4801bf215546Sopenharmony_ci MarkIniSettingsDirty(window); 4802bf215546Sopenharmony_ci } 4803bf215546Sopenharmony_ci 4804bf215546Sopenharmony_ci window->Size = window->SizeFull; 4805bf215546Sopenharmony_ci} 4806bf215546Sopenharmony_ci 4807bf215546Sopenharmony_cistatic void ImGui::RenderOuterBorders(ImGuiWindow* window) 4808bf215546Sopenharmony_ci{ 4809bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4810bf215546Sopenharmony_ci float rounding = window->WindowRounding; 4811bf215546Sopenharmony_ci float border_size = window->WindowBorderSize; 4812bf215546Sopenharmony_ci if (border_size > 0.0f && !(window->Flags & ImGuiWindowFlags_NoBackground)) 4813bf215546Sopenharmony_ci window->DrawList->AddRect(window->Pos, window->Pos + window->Size, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size); 4814bf215546Sopenharmony_ci 4815bf215546Sopenharmony_ci int border_held = window->ResizeBorderHeld; 4816bf215546Sopenharmony_ci if (border_held != -1) 4817bf215546Sopenharmony_ci { 4818bf215546Sopenharmony_ci struct ImGuiResizeBorderDef 4819bf215546Sopenharmony_ci { 4820bf215546Sopenharmony_ci ImVec2 InnerDir; 4821bf215546Sopenharmony_ci ImVec2 CornerPosN1, CornerPosN2; 4822bf215546Sopenharmony_ci float OuterAngle; 4823bf215546Sopenharmony_ci }; 4824bf215546Sopenharmony_ci static const ImGuiResizeBorderDef resize_border_def[4] = 4825bf215546Sopenharmony_ci { 4826bf215546Sopenharmony_ci { ImVec2(0,+1), ImVec2(0,0), ImVec2(1,0), IM_PI*1.50f }, // Top 4827bf215546Sopenharmony_ci { ImVec2(-1,0), ImVec2(1,0), ImVec2(1,1), IM_PI*0.00f }, // Right 4828bf215546Sopenharmony_ci { ImVec2(0,-1), ImVec2(1,1), ImVec2(0,1), IM_PI*0.50f }, // Bottom 4829bf215546Sopenharmony_ci { ImVec2(+1,0), ImVec2(0,1), ImVec2(0,0), IM_PI*1.00f } // Left 4830bf215546Sopenharmony_ci }; 4831bf215546Sopenharmony_ci const ImGuiResizeBorderDef& def = resize_border_def[border_held]; 4832bf215546Sopenharmony_ci ImRect border_r = GetResizeBorderRect(window, border_held, rounding, 0.0f); 4833bf215546Sopenharmony_ci window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.CornerPosN1) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle - IM_PI*0.25f, def.OuterAngle); 4834bf215546Sopenharmony_ci window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.CornerPosN2) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle, def.OuterAngle + IM_PI*0.25f); 4835bf215546Sopenharmony_ci window->DrawList->PathStroke(GetColorU32(ImGuiCol_SeparatorActive), false, ImMax(2.0f, border_size)); // Thicker than usual 4836bf215546Sopenharmony_ci } 4837bf215546Sopenharmony_ci if (g.Style.FrameBorderSize > 0 && !(window->Flags & ImGuiWindowFlags_NoTitleBar)) 4838bf215546Sopenharmony_ci { 4839bf215546Sopenharmony_ci float y = window->Pos.y + window->TitleBarHeight() - 1; 4840bf215546Sopenharmony_ci window->DrawList->AddLine(ImVec2(window->Pos.x + border_size, y), ImVec2(window->Pos.x + window->Size.x - border_size, y), GetColorU32(ImGuiCol_Border), g.Style.FrameBorderSize); 4841bf215546Sopenharmony_ci } 4842bf215546Sopenharmony_ci} 4843bf215546Sopenharmony_ci 4844bf215546Sopenharmony_civoid ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window) 4845bf215546Sopenharmony_ci{ 4846bf215546Sopenharmony_ci window->ParentWindow = parent_window; 4847bf215546Sopenharmony_ci window->RootWindow = window->RootWindowForTitleBarHighlight = window->RootWindowForNav = window; 4848bf215546Sopenharmony_ci if (parent_window && (flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip)) 4849bf215546Sopenharmony_ci window->RootWindow = parent_window->RootWindow; 4850bf215546Sopenharmony_ci if (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup))) 4851bf215546Sopenharmony_ci window->RootWindowForTitleBarHighlight = parent_window->RootWindowForTitleBarHighlight; 4852bf215546Sopenharmony_ci while (window->RootWindowForNav->Flags & ImGuiWindowFlags_NavFlattened) 4853bf215546Sopenharmony_ci { 4854bf215546Sopenharmony_ci IM_ASSERT(window->RootWindowForNav->ParentWindow != NULL); 4855bf215546Sopenharmony_ci window->RootWindowForNav = window->RootWindowForNav->ParentWindow; 4856bf215546Sopenharmony_ci } 4857bf215546Sopenharmony_ci} 4858bf215546Sopenharmony_ci 4859bf215546Sopenharmony_ci// Push a new ImGui window to add widgets to. 4860bf215546Sopenharmony_ci// - A default window called "Debug" is automatically stacked at the beginning of every frame so you can use widgets without explicitly calling a Begin/End pair. 4861bf215546Sopenharmony_ci// - Begin/End can be called multiple times during the frame with the same window name to append content. 4862bf215546Sopenharmony_ci// - The window name is used as a unique identifier to preserve window information across frames (and save rudimentary information to the .ini file). 4863bf215546Sopenharmony_ci// You can use the "##" or "###" markers to use the same label with different id, or same id with different label. See documentation at the top of this file. 4864bf215546Sopenharmony_ci// - Return false when window is collapsed, so you can early out in your code. You always need to call ImGui::End() even if false is returned. 4865bf215546Sopenharmony_ci// - Passing 'bool* p_open' displays a Close button on the upper-right corner of the window, the pointed value will be set to false when the button is pressed. 4866bf215546Sopenharmony_cibool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) 4867bf215546Sopenharmony_ci{ 4868bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 4869bf215546Sopenharmony_ci const ImGuiStyle& style = g.Style; 4870bf215546Sopenharmony_ci IM_ASSERT(name != NULL && name[0] != '\0'); // Window name required 4871bf215546Sopenharmony_ci IM_ASSERT(g.FrameScopeActive); // Forgot to call ImGui::NewFrame() 4872bf215546Sopenharmony_ci IM_ASSERT(g.FrameCountEnded != g.FrameCount); // Called ImGui::Render() or ImGui::EndFrame() and haven't called ImGui::NewFrame() again yet 4873bf215546Sopenharmony_ci 4874bf215546Sopenharmony_ci // Find or create 4875bf215546Sopenharmony_ci ImGuiWindow* window = FindWindowByName(name); 4876bf215546Sopenharmony_ci const bool window_just_created = (window == NULL); 4877bf215546Sopenharmony_ci if (window_just_created) 4878bf215546Sopenharmony_ci { 4879bf215546Sopenharmony_ci ImVec2 size_on_first_use = (g.NextWindowData.SizeCond != 0) ? g.NextWindowData.SizeVal : ImVec2(0.0f, 0.0f); // Any condition flag will do since we are creating a new window here. 4880bf215546Sopenharmony_ci window = CreateNewWindow(name, size_on_first_use, flags); 4881bf215546Sopenharmony_ci } 4882bf215546Sopenharmony_ci 4883bf215546Sopenharmony_ci // Automatically disable manual moving/resizing when NoInputs is set 4884bf215546Sopenharmony_ci if ((flags & ImGuiWindowFlags_NoInputs) == ImGuiWindowFlags_NoInputs) 4885bf215546Sopenharmony_ci flags |= ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize; 4886bf215546Sopenharmony_ci 4887bf215546Sopenharmony_ci if (flags & ImGuiWindowFlags_NavFlattened) 4888bf215546Sopenharmony_ci IM_ASSERT(flags & ImGuiWindowFlags_ChildWindow); 4889bf215546Sopenharmony_ci 4890bf215546Sopenharmony_ci const int current_frame = g.FrameCount; 4891bf215546Sopenharmony_ci const bool first_begin_of_the_frame = (window->LastFrameActive != current_frame); 4892bf215546Sopenharmony_ci 4893bf215546Sopenharmony_ci // Update Flags, LastFrameActive, BeginOrderXXX fields 4894bf215546Sopenharmony_ci if (first_begin_of_the_frame) 4895bf215546Sopenharmony_ci window->Flags = (ImGuiWindowFlags)flags; 4896bf215546Sopenharmony_ci else 4897bf215546Sopenharmony_ci flags = window->Flags; 4898bf215546Sopenharmony_ci 4899bf215546Sopenharmony_ci // Parent window is latched only on the first call to Begin() of the frame, so further append-calls can be done from a different window stack 4900bf215546Sopenharmony_ci ImGuiWindow* parent_window_in_stack = g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back(); 4901bf215546Sopenharmony_ci ImGuiWindow* parent_window = first_begin_of_the_frame ? ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)) ? parent_window_in_stack : NULL) : window->ParentWindow; 4902bf215546Sopenharmony_ci IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow)); 4903bf215546Sopenharmony_ci window->HasCloseButton = (p_open != NULL); 4904bf215546Sopenharmony_ci 4905bf215546Sopenharmony_ci // Update the Appearing flag 4906bf215546Sopenharmony_ci bool window_just_activated_by_user = (window->LastFrameActive < current_frame - 1); // Not using !WasActive because the implicit "Debug" window would always toggle off->on 4907bf215546Sopenharmony_ci const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesForResize > 0); 4908bf215546Sopenharmony_ci if (flags & ImGuiWindowFlags_Popup) 4909bf215546Sopenharmony_ci { 4910bf215546Sopenharmony_ci ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size]; 4911bf215546Sopenharmony_ci window_just_activated_by_user |= (window->PopupId != popup_ref.PopupId); // We recycle popups so treat window as activated if popup id changed 4912bf215546Sopenharmony_ci window_just_activated_by_user |= (window != popup_ref.Window); 4913bf215546Sopenharmony_ci } 4914bf215546Sopenharmony_ci window->Appearing = (window_just_activated_by_user || window_just_appearing_after_hidden_for_resize); 4915bf215546Sopenharmony_ci if (window->Appearing) 4916bf215546Sopenharmony_ci SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, true); 4917bf215546Sopenharmony_ci 4918bf215546Sopenharmony_ci // Add to stack 4919bf215546Sopenharmony_ci g.CurrentWindowStack.push_back(window); 4920bf215546Sopenharmony_ci SetCurrentWindow(window); 4921bf215546Sopenharmony_ci CheckStacksSize(window, true); 4922bf215546Sopenharmony_ci if (flags & ImGuiWindowFlags_Popup) 4923bf215546Sopenharmony_ci { 4924bf215546Sopenharmony_ci ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size]; 4925bf215546Sopenharmony_ci popup_ref.Window = window; 4926bf215546Sopenharmony_ci g.BeginPopupStack.push_back(popup_ref); 4927bf215546Sopenharmony_ci window->PopupId = popup_ref.PopupId; 4928bf215546Sopenharmony_ci } 4929bf215546Sopenharmony_ci 4930bf215546Sopenharmony_ci if (window_just_appearing_after_hidden_for_resize && !(flags & ImGuiWindowFlags_ChildWindow)) 4931bf215546Sopenharmony_ci window->NavLastIds[0] = 0; 4932bf215546Sopenharmony_ci 4933bf215546Sopenharmony_ci // Process SetNextWindow***() calls 4934bf215546Sopenharmony_ci bool window_pos_set_by_api = false; 4935bf215546Sopenharmony_ci bool window_size_x_set_by_api = false, window_size_y_set_by_api = false; 4936bf215546Sopenharmony_ci if (g.NextWindowData.PosCond) 4937bf215546Sopenharmony_ci { 4938bf215546Sopenharmony_ci window_pos_set_by_api = (window->SetWindowPosAllowFlags & g.NextWindowData.PosCond) != 0; 4939bf215546Sopenharmony_ci if (window_pos_set_by_api && ImLengthSqr(g.NextWindowData.PosPivotVal) > 0.00001f) 4940bf215546Sopenharmony_ci { 4941bf215546Sopenharmony_ci // May be processed on the next frame if this is our first frame and we are measuring size 4942bf215546Sopenharmony_ci // FIXME: Look into removing the branch so everything can go through this same code path for consistency. 4943bf215546Sopenharmony_ci window->SetWindowPosVal = g.NextWindowData.PosVal; 4944bf215546Sopenharmony_ci window->SetWindowPosPivot = g.NextWindowData.PosPivotVal; 4945bf215546Sopenharmony_ci window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); 4946bf215546Sopenharmony_ci } 4947bf215546Sopenharmony_ci else 4948bf215546Sopenharmony_ci { 4949bf215546Sopenharmony_ci SetWindowPos(window, g.NextWindowData.PosVal, g.NextWindowData.PosCond); 4950bf215546Sopenharmony_ci } 4951bf215546Sopenharmony_ci } 4952bf215546Sopenharmony_ci if (g.NextWindowData.SizeCond) 4953bf215546Sopenharmony_ci { 4954bf215546Sopenharmony_ci window_size_x_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.x > 0.0f); 4955bf215546Sopenharmony_ci window_size_y_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.y > 0.0f); 4956bf215546Sopenharmony_ci SetWindowSize(window, g.NextWindowData.SizeVal, g.NextWindowData.SizeCond); 4957bf215546Sopenharmony_ci } 4958bf215546Sopenharmony_ci if (g.NextWindowData.ContentSizeCond) 4959bf215546Sopenharmony_ci { 4960bf215546Sopenharmony_ci // Adjust passed "client size" to become a "window size" 4961bf215546Sopenharmony_ci window->SizeContentsExplicit = g.NextWindowData.ContentSizeVal; 4962bf215546Sopenharmony_ci if (window->SizeContentsExplicit.y != 0.0f) 4963bf215546Sopenharmony_ci window->SizeContentsExplicit.y += window->TitleBarHeight() + window->MenuBarHeight(); 4964bf215546Sopenharmony_ci } 4965bf215546Sopenharmony_ci else if (first_begin_of_the_frame) 4966bf215546Sopenharmony_ci { 4967bf215546Sopenharmony_ci window->SizeContentsExplicit = ImVec2(0.0f, 0.0f); 4968bf215546Sopenharmony_ci } 4969bf215546Sopenharmony_ci if (g.NextWindowData.CollapsedCond) 4970bf215546Sopenharmony_ci SetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond); 4971bf215546Sopenharmony_ci if (g.NextWindowData.FocusCond) 4972bf215546Sopenharmony_ci FocusWindow(window); 4973bf215546Sopenharmony_ci if (window->Appearing) 4974bf215546Sopenharmony_ci SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, false); 4975bf215546Sopenharmony_ci 4976bf215546Sopenharmony_ci // When reusing window again multiple times a frame, just append content (don't need to setup again) 4977bf215546Sopenharmony_ci if (first_begin_of_the_frame) 4978bf215546Sopenharmony_ci { 4979bf215546Sopenharmony_ci // Initialize 4980bf215546Sopenharmony_ci const bool window_is_child_tooltip = (flags & ImGuiWindowFlags_ChildWindow) && (flags & ImGuiWindowFlags_Tooltip); // FIXME-WIP: Undocumented behavior of Child+Tooltip for pinned tooltip (#1345) 4981bf215546Sopenharmony_ci UpdateWindowParentAndRootLinks(window, flags, parent_window); 4982bf215546Sopenharmony_ci 4983bf215546Sopenharmony_ci window->Active = true; 4984bf215546Sopenharmony_ci window->BeginOrderWithinParent = 0; 4985bf215546Sopenharmony_ci window->BeginOrderWithinContext = (short)(g.WindowsActiveCount++); 4986bf215546Sopenharmony_ci window->BeginCount = 0; 4987bf215546Sopenharmony_ci window->ClipRect = ImVec4(-FLT_MAX,-FLT_MAX,+FLT_MAX,+FLT_MAX); 4988bf215546Sopenharmony_ci window->LastFrameActive = current_frame; 4989bf215546Sopenharmony_ci window->IDStack.resize(1); 4990bf215546Sopenharmony_ci 4991bf215546Sopenharmony_ci // Update stored window name when it changes (which can _only_ happen with the "###" operator, so the ID would stay unchanged). 4992bf215546Sopenharmony_ci // The title bar always display the 'name' parameter, so we only update the string storage if it needs to be visible to the end-user elsewhere. 4993bf215546Sopenharmony_ci bool window_title_visible_elsewhere = false; 4994bf215546Sopenharmony_ci if (g.NavWindowingList != NULL && (window->Flags & ImGuiWindowFlags_NoNavFocus) == 0) // Window titles visible when using CTRL+TAB 4995bf215546Sopenharmony_ci window_title_visible_elsewhere = true; 4996bf215546Sopenharmony_ci if (window_title_visible_elsewhere && !window_just_created && strcmp(name, window->Name) != 0) 4997bf215546Sopenharmony_ci { 4998bf215546Sopenharmony_ci size_t buf_len = (size_t)window->NameBufLen; 4999bf215546Sopenharmony_ci window->Name = ImStrdupcpy(window->Name, &buf_len, name); 5000bf215546Sopenharmony_ci window->NameBufLen = (int)buf_len; 5001bf215546Sopenharmony_ci } 5002bf215546Sopenharmony_ci 5003bf215546Sopenharmony_ci // UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS 5004bf215546Sopenharmony_ci 5005bf215546Sopenharmony_ci // Update contents size from last frame for auto-fitting (or use explicit size) 5006bf215546Sopenharmony_ci window->SizeContents = CalcSizeContents(window); 5007bf215546Sopenharmony_ci if (window->HiddenFramesRegular > 0) 5008bf215546Sopenharmony_ci window->HiddenFramesRegular--; 5009bf215546Sopenharmony_ci if (window->HiddenFramesForResize > 0) 5010bf215546Sopenharmony_ci window->HiddenFramesForResize--; 5011bf215546Sopenharmony_ci 5012bf215546Sopenharmony_ci // Hide new windows for one frame until they calculate their size 5013bf215546Sopenharmony_ci if (window_just_created && (!window_size_x_set_by_api || !window_size_y_set_by_api)) 5014bf215546Sopenharmony_ci window->HiddenFramesForResize = 1; 5015bf215546Sopenharmony_ci 5016bf215546Sopenharmony_ci // Hide popup/tooltip window when re-opening while we measure size (because we recycle the windows) 5017bf215546Sopenharmony_ci // We reset Size/SizeContents for reappearing popups/tooltips early in this function, so further code won't be tempted to use the old size. 5018bf215546Sopenharmony_ci if (window_just_activated_by_user && (flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0) 5019bf215546Sopenharmony_ci { 5020bf215546Sopenharmony_ci window->HiddenFramesForResize = 1; 5021bf215546Sopenharmony_ci if (flags & ImGuiWindowFlags_AlwaysAutoResize) 5022bf215546Sopenharmony_ci { 5023bf215546Sopenharmony_ci if (!window_size_x_set_by_api) 5024bf215546Sopenharmony_ci window->Size.x = window->SizeFull.x = 0.f; 5025bf215546Sopenharmony_ci if (!window_size_y_set_by_api) 5026bf215546Sopenharmony_ci window->Size.y = window->SizeFull.y = 0.f; 5027bf215546Sopenharmony_ci window->SizeContents = ImVec2(0.f, 0.f); 5028bf215546Sopenharmony_ci } 5029bf215546Sopenharmony_ci } 5030bf215546Sopenharmony_ci 5031bf215546Sopenharmony_ci SetCurrentWindow(window); 5032bf215546Sopenharmony_ci 5033bf215546Sopenharmony_ci // Lock border size and padding for the frame (so that altering them doesn't cause inconsistencies) 5034bf215546Sopenharmony_ci window->WindowBorderSize = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildBorderSize : ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupBorderSize : style.WindowBorderSize; 5035bf215546Sopenharmony_ci window->WindowPadding = style.WindowPadding; 5036bf215546Sopenharmony_ci if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_Popup)) && window->WindowBorderSize == 0.0f) 5037bf215546Sopenharmony_ci window->WindowPadding = ImVec2(0.0f, (flags & ImGuiWindowFlags_MenuBar) ? style.WindowPadding.y : 0.0f); 5038bf215546Sopenharmony_ci window->DC.MenuBarOffset.x = ImMax(ImMax(window->WindowPadding.x, style.ItemSpacing.x), g.NextWindowData.MenuBarOffsetMinVal.x); 5039bf215546Sopenharmony_ci window->DC.MenuBarOffset.y = g.NextWindowData.MenuBarOffsetMinVal.y; 5040bf215546Sopenharmony_ci 5041bf215546Sopenharmony_ci // Collapse window by double-clicking on title bar 5042bf215546Sopenharmony_ci // At this point we don't have a clipping rectangle setup yet, so we can use the title bar area for hit detection and drawing 5043bf215546Sopenharmony_ci if (!(flags & ImGuiWindowFlags_NoTitleBar) && !(flags & ImGuiWindowFlags_NoCollapse)) 5044bf215546Sopenharmony_ci { 5045bf215546Sopenharmony_ci // We don't use a regular button+id to test for double-click on title bar (mostly due to legacy reason, could be fixed), so verify that we don't have items over the title bar. 5046bf215546Sopenharmony_ci ImRect title_bar_rect = window->TitleBarRect(); 5047bf215546Sopenharmony_ci if (g.HoveredWindow == window && g.HoveredId == 0 && g.HoveredIdPreviousFrame == 0 && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max) && g.IO.MouseDoubleClicked[0]) 5048bf215546Sopenharmony_ci window->WantCollapseToggle = true; 5049bf215546Sopenharmony_ci if (window->WantCollapseToggle) 5050bf215546Sopenharmony_ci { 5051bf215546Sopenharmony_ci window->Collapsed = !window->Collapsed; 5052bf215546Sopenharmony_ci MarkIniSettingsDirty(window); 5053bf215546Sopenharmony_ci FocusWindow(window); 5054bf215546Sopenharmony_ci } 5055bf215546Sopenharmony_ci } 5056bf215546Sopenharmony_ci else 5057bf215546Sopenharmony_ci { 5058bf215546Sopenharmony_ci window->Collapsed = false; 5059bf215546Sopenharmony_ci } 5060bf215546Sopenharmony_ci window->WantCollapseToggle = false; 5061bf215546Sopenharmony_ci 5062bf215546Sopenharmony_ci // SIZE 5063bf215546Sopenharmony_ci 5064bf215546Sopenharmony_ci // Calculate auto-fit size, handle automatic resize 5065bf215546Sopenharmony_ci const ImVec2 size_auto_fit = CalcSizeAutoFit(window, window->SizeContents); 5066bf215546Sopenharmony_ci ImVec2 size_full_modified(FLT_MAX, FLT_MAX); 5067bf215546Sopenharmony_ci if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed) 5068bf215546Sopenharmony_ci { 5069bf215546Sopenharmony_ci // Using SetNextWindowSize() overrides ImGuiWindowFlags_AlwaysAutoResize, so it can be used on tooltips/popups, etc. 5070bf215546Sopenharmony_ci if (!window_size_x_set_by_api) 5071bf215546Sopenharmony_ci window->SizeFull.x = size_full_modified.x = size_auto_fit.x; 5072bf215546Sopenharmony_ci if (!window_size_y_set_by_api) 5073bf215546Sopenharmony_ci window->SizeFull.y = size_full_modified.y = size_auto_fit.y; 5074bf215546Sopenharmony_ci } 5075bf215546Sopenharmony_ci else if (window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0) 5076bf215546Sopenharmony_ci { 5077bf215546Sopenharmony_ci // Auto-fit may only grow window during the first few frames 5078bf215546Sopenharmony_ci // We still process initial auto-fit on collapsed windows to get a window width, but otherwise don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed. 5079bf215546Sopenharmony_ci if (!window_size_x_set_by_api && window->AutoFitFramesX > 0) 5080bf215546Sopenharmony_ci window->SizeFull.x = size_full_modified.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x; 5081bf215546Sopenharmony_ci if (!window_size_y_set_by_api && window->AutoFitFramesY > 0) 5082bf215546Sopenharmony_ci window->SizeFull.y = size_full_modified.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y; 5083bf215546Sopenharmony_ci if (!window->Collapsed) 5084bf215546Sopenharmony_ci MarkIniSettingsDirty(window); 5085bf215546Sopenharmony_ci } 5086bf215546Sopenharmony_ci 5087bf215546Sopenharmony_ci // Apply minimum/maximum window size constraints and final size 5088bf215546Sopenharmony_ci window->SizeFull = CalcSizeAfterConstraint(window, window->SizeFull); 5089bf215546Sopenharmony_ci window->Size = window->Collapsed && !(flags & ImGuiWindowFlags_ChildWindow) ? window->TitleBarRect().GetSize() : window->SizeFull; 5090bf215546Sopenharmony_ci 5091bf215546Sopenharmony_ci // SCROLLBAR STATUS 5092bf215546Sopenharmony_ci 5093bf215546Sopenharmony_ci // Update scrollbar status (based on the Size that was effective during last frame or the auto-resized Size). 5094bf215546Sopenharmony_ci if (!window->Collapsed) 5095bf215546Sopenharmony_ci { 5096bf215546Sopenharmony_ci // When reading the current size we need to read it after size constraints have been applied 5097bf215546Sopenharmony_ci float size_x_for_scrollbars = size_full_modified.x != FLT_MAX ? window->SizeFull.x : window->SizeFullAtLastBegin.x; 5098bf215546Sopenharmony_ci float size_y_for_scrollbars = size_full_modified.y != FLT_MAX ? window->SizeFull.y : window->SizeFullAtLastBegin.y; 5099bf215546Sopenharmony_ci window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((window->SizeContents.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar)); 5100bf215546Sopenharmony_ci window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((window->SizeContents.x > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar)); 5101bf215546Sopenharmony_ci if (window->ScrollbarX && !window->ScrollbarY) 5102bf215546Sopenharmony_ci window->ScrollbarY = (window->SizeContents.y > size_y_for_scrollbars - style.ScrollbarSize) && !(flags & ImGuiWindowFlags_NoScrollbar); 5103bf215546Sopenharmony_ci window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f); 5104bf215546Sopenharmony_ci } 5105bf215546Sopenharmony_ci 5106bf215546Sopenharmony_ci // POSITION 5107bf215546Sopenharmony_ci 5108bf215546Sopenharmony_ci // Popup latch its initial position, will position itself when it appears next frame 5109bf215546Sopenharmony_ci if (window_just_activated_by_user) 5110bf215546Sopenharmony_ci { 5111bf215546Sopenharmony_ci window->AutoPosLastDirection = ImGuiDir_None; 5112bf215546Sopenharmony_ci if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api) 5113bf215546Sopenharmony_ci window->Pos = g.BeginPopupStack.back().OpenPopupPos; 5114bf215546Sopenharmony_ci } 5115bf215546Sopenharmony_ci 5116bf215546Sopenharmony_ci // Position child window 5117bf215546Sopenharmony_ci if (flags & ImGuiWindowFlags_ChildWindow) 5118bf215546Sopenharmony_ci { 5119bf215546Sopenharmony_ci IM_ASSERT(parent_window && parent_window->Active); 5120bf215546Sopenharmony_ci window->BeginOrderWithinParent = (short)parent_window->DC.ChildWindows.Size; 5121bf215546Sopenharmony_ci parent_window->DC.ChildWindows.push_back(window); 5122bf215546Sopenharmony_ci if (!(flags & ImGuiWindowFlags_Popup) && !window_pos_set_by_api && !window_is_child_tooltip) 5123bf215546Sopenharmony_ci window->Pos = parent_window->DC.CursorPos; 5124bf215546Sopenharmony_ci } 5125bf215546Sopenharmony_ci 5126bf215546Sopenharmony_ci const bool window_pos_with_pivot = (window->SetWindowPosVal.x != FLT_MAX && window->HiddenFramesForResize == 0); 5127bf215546Sopenharmony_ci if (window_pos_with_pivot) 5128bf215546Sopenharmony_ci SetWindowPos(window, ImMax(style.DisplaySafeAreaPadding, window->SetWindowPosVal - window->SizeFull * window->SetWindowPosPivot), 0); // Position given a pivot (e.g. for centering) 5129bf215546Sopenharmony_ci else if ((flags & ImGuiWindowFlags_ChildMenu) != 0) 5130bf215546Sopenharmony_ci window->Pos = FindBestWindowPosForPopup(window); 5131bf215546Sopenharmony_ci else if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api && window_just_appearing_after_hidden_for_resize) 5132bf215546Sopenharmony_ci window->Pos = FindBestWindowPosForPopup(window); 5133bf215546Sopenharmony_ci else if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api && !window_is_child_tooltip) 5134bf215546Sopenharmony_ci window->Pos = FindBestWindowPosForPopup(window); 5135bf215546Sopenharmony_ci 5136bf215546Sopenharmony_ci // Clamp position so it stays visible 5137bf215546Sopenharmony_ci // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing. 5138bf215546Sopenharmony_ci if (!window_pos_set_by_api && !(flags & ImGuiWindowFlags_ChildWindow) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) 5139bf215546Sopenharmony_ci { 5140bf215546Sopenharmony_ci if (g.IO.DisplaySize.x > 0.0f && g.IO.DisplaySize.y > 0.0f) // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing. 5141bf215546Sopenharmony_ci { 5142bf215546Sopenharmony_ci ImVec2 padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding); 5143bf215546Sopenharmony_ci ImVec2 size_for_clamping = ((g.IO.ConfigWindowsMoveFromTitleBarOnly) && !(window->Flags & ImGuiWindowFlags_NoTitleBar)) ? ImVec2(window->Size.x, window->TitleBarHeight()) : window->Size; 5144bf215546Sopenharmony_ci window->Pos = ImMax(window->Pos + size_for_clamping, padding) - size_for_clamping; 5145bf215546Sopenharmony_ci window->Pos = ImMin(window->Pos, g.IO.DisplaySize - padding); 5146bf215546Sopenharmony_ci } 5147bf215546Sopenharmony_ci } 5148bf215546Sopenharmony_ci window->Pos = ImFloor(window->Pos); 5149bf215546Sopenharmony_ci 5150bf215546Sopenharmony_ci // Lock window rounding for the frame (so that altering them doesn't cause inconsistencies) 5151bf215546Sopenharmony_ci window->WindowRounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildRounding : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupRounding : style.WindowRounding; 5152bf215546Sopenharmony_ci 5153bf215546Sopenharmony_ci // Prepare for item focus requests 5154bf215546Sopenharmony_ci window->FocusIdxAllRequestCurrent = (window->FocusIdxAllRequestNext == INT_MAX || window->FocusIdxAllCounter == -1) ? INT_MAX : (window->FocusIdxAllRequestNext + (window->FocusIdxAllCounter+1)) % (window->FocusIdxAllCounter+1); 5155bf215546Sopenharmony_ci window->FocusIdxTabRequestCurrent = (window->FocusIdxTabRequestNext == INT_MAX || window->FocusIdxTabCounter == -1) ? INT_MAX : (window->FocusIdxTabRequestNext + (window->FocusIdxTabCounter+1)) % (window->FocusIdxTabCounter+1); 5156bf215546Sopenharmony_ci window->FocusIdxAllCounter = window->FocusIdxTabCounter = -1; 5157bf215546Sopenharmony_ci window->FocusIdxAllRequestNext = window->FocusIdxTabRequestNext = INT_MAX; 5158bf215546Sopenharmony_ci 5159bf215546Sopenharmony_ci // Apply scrolling 5160bf215546Sopenharmony_ci window->Scroll = CalcNextScrollFromScrollTargetAndClamp(window, true); 5161bf215546Sopenharmony_ci window->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX); 5162bf215546Sopenharmony_ci 5163bf215546Sopenharmony_ci // Apply window focus (new and reactivated windows are moved to front) 5164bf215546Sopenharmony_ci bool want_focus = false; 5165bf215546Sopenharmony_ci if (window_just_activated_by_user && !(flags & ImGuiWindowFlags_NoFocusOnAppearing)) 5166bf215546Sopenharmony_ci { 5167bf215546Sopenharmony_ci if (flags & ImGuiWindowFlags_Popup) 5168bf215546Sopenharmony_ci want_focus = true; 5169bf215546Sopenharmony_ci else if ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip)) == 0) 5170bf215546Sopenharmony_ci want_focus = true; 5171bf215546Sopenharmony_ci } 5172bf215546Sopenharmony_ci 5173bf215546Sopenharmony_ci // Handle manual resize: Resize Grips, Borders, Gamepad 5174bf215546Sopenharmony_ci int border_held = -1; 5175bf215546Sopenharmony_ci ImU32 resize_grip_col[4] = { 0 }; 5176bf215546Sopenharmony_ci const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // 4 5177bf215546Sopenharmony_ci const float grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f); 5178bf215546Sopenharmony_ci if (!window->Collapsed) 5179bf215546Sopenharmony_ci UpdateManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0]); 5180bf215546Sopenharmony_ci window->ResizeBorderHeld = (signed char)border_held; 5181bf215546Sopenharmony_ci 5182bf215546Sopenharmony_ci // Default item width. Make it proportional to window size if window manually resizes 5183bf215546Sopenharmony_ci if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize)) 5184bf215546Sopenharmony_ci window->ItemWidthDefault = (float)(int)(window->Size.x * 0.65f); 5185bf215546Sopenharmony_ci else 5186bf215546Sopenharmony_ci window->ItemWidthDefault = (float)(int)(g.FontSize * 16.0f); 5187bf215546Sopenharmony_ci 5188bf215546Sopenharmony_ci // DRAWING 5189bf215546Sopenharmony_ci 5190bf215546Sopenharmony_ci // Setup draw list and outer clipping rectangle 5191bf215546Sopenharmony_ci window->DrawList->Clear(); 5192bf215546Sopenharmony_ci window->DrawList->Flags = (g.Style.AntiAliasedLines ? ImDrawListFlags_AntiAliasedLines : 0) | (g.Style.AntiAliasedFill ? ImDrawListFlags_AntiAliasedFill : 0); 5193bf215546Sopenharmony_ci window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID); 5194bf215546Sopenharmony_ci ImRect viewport_rect(GetViewportRect()); 5195bf215546Sopenharmony_ci if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) 5196bf215546Sopenharmony_ci PushClipRect(parent_window->ClipRect.Min, parent_window->ClipRect.Max, true); 5197bf215546Sopenharmony_ci else 5198bf215546Sopenharmony_ci PushClipRect(viewport_rect.Min, viewport_rect.Max, true); 5199bf215546Sopenharmony_ci 5200bf215546Sopenharmony_ci // Draw modal window background (darkens what is behind them, all viewports) 5201bf215546Sopenharmony_ci const bool dim_bg_for_modal = (flags & ImGuiWindowFlags_Modal) && window == GetFrontMostPopupModal() && window->HiddenFramesForResize <= 0; 5202bf215546Sopenharmony_ci const bool dim_bg_for_window_list = g.NavWindowingTargetAnim && (window == g.NavWindowingTargetAnim->RootWindow); 5203bf215546Sopenharmony_ci if (dim_bg_for_modal || dim_bg_for_window_list) 5204bf215546Sopenharmony_ci { 5205bf215546Sopenharmony_ci const ImU32 dim_bg_col = GetColorU32(dim_bg_for_modal ? ImGuiCol_ModalWindowDimBg : ImGuiCol_NavWindowingDimBg, g.DimBgRatio); 5206bf215546Sopenharmony_ci window->DrawList->AddRectFilled(viewport_rect.Min, viewport_rect.Max, dim_bg_col); 5207bf215546Sopenharmony_ci } 5208bf215546Sopenharmony_ci 5209bf215546Sopenharmony_ci // Draw navigation selection/windowing rectangle background 5210bf215546Sopenharmony_ci if (dim_bg_for_window_list && window == g.NavWindowingTargetAnim) 5211bf215546Sopenharmony_ci { 5212bf215546Sopenharmony_ci ImRect bb = window->Rect(); 5213bf215546Sopenharmony_ci bb.Expand(g.FontSize); 5214bf215546Sopenharmony_ci if (!bb.Contains(viewport_rect)) // Avoid drawing if the window covers all the viewport anyway 5215bf215546Sopenharmony_ci window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha * 0.25f), g.Style.WindowRounding); 5216bf215546Sopenharmony_ci } 5217bf215546Sopenharmony_ci 5218bf215546Sopenharmony_ci // Draw window + handle manual resize 5219bf215546Sopenharmony_ci // As we highlight the title bar when want_focus is set, multiple reappearing windows will have have their title bar highlighted on their reappearing frame. 5220bf215546Sopenharmony_ci const float window_rounding = window->WindowRounding; 5221bf215546Sopenharmony_ci const float window_border_size = window->WindowBorderSize; 5222bf215546Sopenharmony_ci const ImGuiWindow* window_to_highlight = g.NavWindowingTarget ? g.NavWindowingTarget : g.NavWindow; 5223bf215546Sopenharmony_ci const bool title_bar_is_highlight = want_focus || (window_to_highlight && window->RootWindowForTitleBarHighlight == window_to_highlight->RootWindowForTitleBarHighlight); 5224bf215546Sopenharmony_ci const ImRect title_bar_rect = window->TitleBarRect(); 5225bf215546Sopenharmony_ci if (window->Collapsed) 5226bf215546Sopenharmony_ci { 5227bf215546Sopenharmony_ci // Title bar only 5228bf215546Sopenharmony_ci float backup_border_size = style.FrameBorderSize; 5229bf215546Sopenharmony_ci g.Style.FrameBorderSize = window->WindowBorderSize; 5230bf215546Sopenharmony_ci ImU32 title_bar_col = GetColorU32((title_bar_is_highlight && !g.NavDisableHighlight) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed); 5231bf215546Sopenharmony_ci RenderFrame(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, true, window_rounding); 5232bf215546Sopenharmony_ci g.Style.FrameBorderSize = backup_border_size; 5233bf215546Sopenharmony_ci } 5234bf215546Sopenharmony_ci else 5235bf215546Sopenharmony_ci { 5236bf215546Sopenharmony_ci // Window background 5237bf215546Sopenharmony_ci if (!(flags & ImGuiWindowFlags_NoBackground)) 5238bf215546Sopenharmony_ci { 5239bf215546Sopenharmony_ci ImU32 bg_col = GetColorU32(GetWindowBgColorIdxFromFlags(flags)); 5240bf215546Sopenharmony_ci float alpha = 1.0f; 5241bf215546Sopenharmony_ci if (g.NextWindowData.BgAlphaCond != 0) 5242bf215546Sopenharmony_ci alpha = g.NextWindowData.BgAlphaVal; 5243bf215546Sopenharmony_ci if (alpha != 1.0f) 5244bf215546Sopenharmony_ci bg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(alpha) << IM_COL32_A_SHIFT); 5245bf215546Sopenharmony_ci window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Bot); 5246bf215546Sopenharmony_ci } 5247bf215546Sopenharmony_ci g.NextWindowData.BgAlphaCond = 0; 5248bf215546Sopenharmony_ci 5249bf215546Sopenharmony_ci // Title bar 5250bf215546Sopenharmony_ci if (!(flags & ImGuiWindowFlags_NoTitleBar)) 5251bf215546Sopenharmony_ci { 5252bf215546Sopenharmony_ci ImU32 title_bar_col = GetColorU32(title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg); 5253bf215546Sopenharmony_ci window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawCornerFlags_Top); 5254bf215546Sopenharmony_ci } 5255bf215546Sopenharmony_ci 5256bf215546Sopenharmony_ci // Menu bar 5257bf215546Sopenharmony_ci if (flags & ImGuiWindowFlags_MenuBar) 5258bf215546Sopenharmony_ci { 5259bf215546Sopenharmony_ci ImRect menu_bar_rect = window->MenuBarRect(); 5260bf215546Sopenharmony_ci menu_bar_rect.ClipWith(window->Rect()); // Soft clipping, in particular child window don't have minimum size covering the menu bar so this is useful for them. 5261bf215546Sopenharmony_ci window->DrawList->AddRectFilled(menu_bar_rect.Min, menu_bar_rect.Max, GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawCornerFlags_Top); 5262bf215546Sopenharmony_ci if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y) 5263bf215546Sopenharmony_ci window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize); 5264bf215546Sopenharmony_ci } 5265bf215546Sopenharmony_ci 5266bf215546Sopenharmony_ci // Scrollbars 5267bf215546Sopenharmony_ci if (window->ScrollbarX) 5268bf215546Sopenharmony_ci Scrollbar(ImGuiLayoutType_Horizontal); 5269bf215546Sopenharmony_ci if (window->ScrollbarY) 5270bf215546Sopenharmony_ci Scrollbar(ImGuiLayoutType_Vertical); 5271bf215546Sopenharmony_ci 5272bf215546Sopenharmony_ci // Render resize grips (after their input handling so we don't have a frame of latency) 5273bf215546Sopenharmony_ci if (!(flags & ImGuiWindowFlags_NoResize)) 5274bf215546Sopenharmony_ci { 5275bf215546Sopenharmony_ci for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++) 5276bf215546Sopenharmony_ci { 5277bf215546Sopenharmony_ci const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n]; 5278bf215546Sopenharmony_ci const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN); 5279bf215546Sopenharmony_ci window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, grip_draw_size) : ImVec2(grip_draw_size, window_border_size))); 5280bf215546Sopenharmony_ci window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(grip_draw_size, window_border_size) : ImVec2(window_border_size, grip_draw_size))); 5281bf215546Sopenharmony_ci window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + window_border_size), corner.y + grip.InnerDir.y * (window_rounding + window_border_size)), window_rounding, grip.AngleMin12, grip.AngleMax12); 5282bf215546Sopenharmony_ci window->DrawList->PathFillConvex(resize_grip_col[resize_grip_n]); 5283bf215546Sopenharmony_ci } 5284bf215546Sopenharmony_ci } 5285bf215546Sopenharmony_ci 5286bf215546Sopenharmony_ci // Borders 5287bf215546Sopenharmony_ci RenderOuterBorders(window); 5288bf215546Sopenharmony_ci } 5289bf215546Sopenharmony_ci 5290bf215546Sopenharmony_ci // Draw navigation selection/windowing rectangle border 5291bf215546Sopenharmony_ci if (g.NavWindowingTargetAnim == window) 5292bf215546Sopenharmony_ci { 5293bf215546Sopenharmony_ci float rounding = ImMax(window->WindowRounding, g.Style.WindowRounding); 5294bf215546Sopenharmony_ci ImRect bb = window->Rect(); 5295bf215546Sopenharmony_ci bb.Expand(g.FontSize); 5296bf215546Sopenharmony_ci if (bb.Contains(viewport_rect)) // If a window fits the entire viewport, adjust its highlight inward 5297bf215546Sopenharmony_ci { 5298bf215546Sopenharmony_ci bb.Expand(-g.FontSize - 1.0f); 5299bf215546Sopenharmony_ci rounding = window->WindowRounding; 5300bf215546Sopenharmony_ci } 5301bf215546Sopenharmony_ci window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), rounding, ~0, 3.0f); 5302bf215546Sopenharmony_ci } 5303bf215546Sopenharmony_ci 5304bf215546Sopenharmony_ci // Store a backup of SizeFull which we will use next frame to decide if we need scrollbars. 5305bf215546Sopenharmony_ci window->SizeFullAtLastBegin = window->SizeFull; 5306bf215546Sopenharmony_ci 5307bf215546Sopenharmony_ci // Update various regions. Variables they depends on are set above in this function. 5308bf215546Sopenharmony_ci // FIXME: window->ContentsRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it. 5309bf215546Sopenharmony_ci window->ContentsRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x; 5310bf215546Sopenharmony_ci window->ContentsRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + window->TitleBarHeight() + window->MenuBarHeight(); 5311bf215546Sopenharmony_ci window->ContentsRegionRect.Max.x = window->Pos.x - window->Scroll.x - window->WindowPadding.x + (window->SizeContentsExplicit.x != 0.0f ? window->SizeContentsExplicit.x : (window->Size.x - window->ScrollbarSizes.x)); 5312bf215546Sopenharmony_ci window->ContentsRegionRect.Max.y = window->Pos.y - window->Scroll.y - window->WindowPadding.y + (window->SizeContentsExplicit.y != 0.0f ? window->SizeContentsExplicit.y : (window->Size.y - window->ScrollbarSizes.y)); 5313bf215546Sopenharmony_ci 5314bf215546Sopenharmony_ci // Setup drawing context 5315bf215546Sopenharmony_ci // (NB: That term "drawing context / DC" lost its meaning a long time ago. Initially was meant to hold transient data only. Nowadays difference between window-> and window->DC-> is dubious.) 5316bf215546Sopenharmony_ci window->DC.Indent.x = 0.0f + window->WindowPadding.x - window->Scroll.x; 5317bf215546Sopenharmony_ci window->DC.GroupOffset.x = 0.0f; 5318bf215546Sopenharmony_ci window->DC.ColumnsOffset.x = 0.0f; 5319bf215546Sopenharmony_ci window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.Indent.x + window->DC.ColumnsOffset.x, window->TitleBarHeight() + window->MenuBarHeight() + window->WindowPadding.y - window->Scroll.y); 5320bf215546Sopenharmony_ci window->DC.CursorPos = window->DC.CursorStartPos; 5321bf215546Sopenharmony_ci window->DC.CursorPosPrevLine = window->DC.CursorPos; 5322bf215546Sopenharmony_ci window->DC.CursorMaxPos = window->DC.CursorStartPos; 5323bf215546Sopenharmony_ci window->DC.CurrentLineSize = window->DC.PrevLineSize = ImVec2(0.0f, 0.0f); 5324bf215546Sopenharmony_ci window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f; 5325bf215546Sopenharmony_ci window->DC.NavHideHighlightOneFrame = false; 5326bf215546Sopenharmony_ci window->DC.NavHasScroll = (GetWindowScrollMaxY(window) > 0.0f); 5327bf215546Sopenharmony_ci window->DC.NavLayerActiveMask = window->DC.NavLayerActiveMaskNext; 5328bf215546Sopenharmony_ci window->DC.NavLayerActiveMaskNext = 0x00; 5329bf215546Sopenharmony_ci window->DC.MenuBarAppending = false; 5330bf215546Sopenharmony_ci window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; 5331bf215546Sopenharmony_ci window->DC.ChildWindows.resize(0); 5332bf215546Sopenharmony_ci window->DC.LayoutType = ImGuiLayoutType_Vertical; 5333bf215546Sopenharmony_ci window->DC.ParentLayoutType = parent_window ? parent_window->DC.LayoutType : ImGuiLayoutType_Vertical; 5334bf215546Sopenharmony_ci window->DC.ItemFlags = parent_window ? parent_window->DC.ItemFlags : ImGuiItemFlags_Default_; 5335bf215546Sopenharmony_ci window->DC.ItemWidth = window->ItemWidthDefault; 5336bf215546Sopenharmony_ci window->DC.TextWrapPos = -1.0f; // disabled 5337bf215546Sopenharmony_ci window->DC.ItemFlagsStack.resize(0); 5338bf215546Sopenharmony_ci window->DC.ItemWidthStack.resize(0); 5339bf215546Sopenharmony_ci window->DC.TextWrapPosStack.resize(0); 5340bf215546Sopenharmony_ci window->DC.ColumnsSet = NULL; 5341bf215546Sopenharmony_ci window->DC.TreeDepth = 0; 5342bf215546Sopenharmony_ci window->DC.TreeDepthMayJumpToParentOnPop = 0x00; 5343bf215546Sopenharmony_ci window->DC.StateStorage = &window->StateStorage; 5344bf215546Sopenharmony_ci window->DC.GroupStack.resize(0); 5345bf215546Sopenharmony_ci window->MenuColumns.Update(3, style.ItemSpacing.x, window_just_activated_by_user); 5346bf215546Sopenharmony_ci 5347bf215546Sopenharmony_ci if ((flags & ImGuiWindowFlags_ChildWindow) && (window->DC.ItemFlags != parent_window->DC.ItemFlags)) 5348bf215546Sopenharmony_ci { 5349bf215546Sopenharmony_ci window->DC.ItemFlags = parent_window->DC.ItemFlags; 5350bf215546Sopenharmony_ci window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags); 5351bf215546Sopenharmony_ci } 5352bf215546Sopenharmony_ci 5353bf215546Sopenharmony_ci if (window->AutoFitFramesX > 0) 5354bf215546Sopenharmony_ci window->AutoFitFramesX--; 5355bf215546Sopenharmony_ci if (window->AutoFitFramesY > 0) 5356bf215546Sopenharmony_ci window->AutoFitFramesY--; 5357bf215546Sopenharmony_ci 5358bf215546Sopenharmony_ci // Apply focus (we need to call FocusWindow() AFTER setting DC.CursorStartPos so our initial navigation reference rectangle can start around there) 5359bf215546Sopenharmony_ci if (want_focus) 5360bf215546Sopenharmony_ci { 5361bf215546Sopenharmony_ci FocusWindow(window); 5362bf215546Sopenharmony_ci NavInitWindow(window, false); 5363bf215546Sopenharmony_ci } 5364bf215546Sopenharmony_ci 5365bf215546Sopenharmony_ci // Title bar 5366bf215546Sopenharmony_ci if (!(flags & ImGuiWindowFlags_NoTitleBar)) 5367bf215546Sopenharmony_ci { 5368bf215546Sopenharmony_ci // Close & collapse button are on layer 1 (same as menus) and don't default focus 5369bf215546Sopenharmony_ci const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags; 5370bf215546Sopenharmony_ci window->DC.ItemFlags |= ImGuiItemFlags_NoNavDefaultFocus; 5371bf215546Sopenharmony_ci window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; 5372bf215546Sopenharmony_ci window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Menu); 5373bf215546Sopenharmony_ci 5374bf215546Sopenharmony_ci // Collapse button 5375bf215546Sopenharmony_ci if (!(flags & ImGuiWindowFlags_NoCollapse)) 5376bf215546Sopenharmony_ci if (CollapseButton(window->GetID("#COLLAPSE"), window->Pos)) 5377bf215546Sopenharmony_ci window->WantCollapseToggle = true; // Defer collapsing to next frame as we are too far in the Begin() function 5378bf215546Sopenharmony_ci 5379bf215546Sopenharmony_ci // Close button 5380bf215546Sopenharmony_ci if (p_open != NULL) 5381bf215546Sopenharmony_ci { 5382bf215546Sopenharmony_ci const float pad = style.FramePadding.y; 5383bf215546Sopenharmony_ci const float rad = g.FontSize * 0.5f; 5384bf215546Sopenharmony_ci if (CloseButton(window->GetID("#CLOSE"), window->Rect().GetTR() + ImVec2(-pad - rad, pad + rad), rad + 1)) 5385bf215546Sopenharmony_ci *p_open = false; 5386bf215546Sopenharmony_ci } 5387bf215546Sopenharmony_ci 5388bf215546Sopenharmony_ci window->DC.NavLayerCurrent = ImGuiNavLayer_Main; 5389bf215546Sopenharmony_ci window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main); 5390bf215546Sopenharmony_ci window->DC.ItemFlags = item_flags_backup; 5391bf215546Sopenharmony_ci 5392bf215546Sopenharmony_ci // Title bar text (with: horizontal alignment, avoiding collapse/close button, optional "unsaved document" marker) 5393bf215546Sopenharmony_ci // FIXME: Refactor text alignment facilities along with RenderText helpers, this is too much code.. 5394bf215546Sopenharmony_ci const char* UNSAVED_DOCUMENT_MARKER = "*"; 5395bf215546Sopenharmony_ci float marker_size_x = (flags & ImGuiWindowFlags_UnsavedDocument) ? CalcTextSize(UNSAVED_DOCUMENT_MARKER, NULL, false).x : 0.0f; 5396bf215546Sopenharmony_ci ImVec2 text_size = CalcTextSize(name, NULL, true) + ImVec2(marker_size_x, 0.0f); 5397bf215546Sopenharmony_ci ImRect text_r = title_bar_rect; 5398bf215546Sopenharmony_ci float pad_left = (flags & ImGuiWindowFlags_NoCollapse) ? style.FramePadding.x : (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x); 5399bf215546Sopenharmony_ci float pad_right = (p_open == NULL) ? style.FramePadding.x : (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x); 5400bf215546Sopenharmony_ci if (style.WindowTitleAlign.x > 0.0f) 5401bf215546Sopenharmony_ci pad_right = ImLerp(pad_right, pad_left, style.WindowTitleAlign.x); 5402bf215546Sopenharmony_ci text_r.Min.x += pad_left; 5403bf215546Sopenharmony_ci text_r.Max.x -= pad_right; 5404bf215546Sopenharmony_ci ImRect clip_rect = text_r; 5405bf215546Sopenharmony_ci clip_rect.Max.x = window->Pos.x + window->Size.x - (p_open ? title_bar_rect.GetHeight() - 3 : style.FramePadding.x); // Match the size of CloseButton() 5406bf215546Sopenharmony_ci RenderTextClipped(text_r.Min, text_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_rect); 5407bf215546Sopenharmony_ci if (flags & ImGuiWindowFlags_UnsavedDocument) 5408bf215546Sopenharmony_ci { 5409bf215546Sopenharmony_ci ImVec2 marker_pos = ImVec2(ImMax(text_r.Min.x, text_r.Min.x + (text_r.GetWidth() - text_size.x) * style.WindowTitleAlign.x) + text_size.x, text_r.Min.y) + ImVec2(2 - marker_size_x, 0.0f); 5410bf215546Sopenharmony_ci ImVec2 off = ImVec2(0.0f, (float)(int)(-g.FontSize * 0.25f)); 5411bf215546Sopenharmony_ci RenderTextClipped(marker_pos + off, text_r.Max + off, UNSAVED_DOCUMENT_MARKER, NULL, NULL, ImVec2(0, style.WindowTitleAlign.y), &clip_rect); 5412bf215546Sopenharmony_ci } 5413bf215546Sopenharmony_ci } 5414bf215546Sopenharmony_ci 5415bf215546Sopenharmony_ci // Save clipped aabb so we can access it in constant-time in FindHoveredWindow() 5416bf215546Sopenharmony_ci window->OuterRectClipped = window->Rect(); 5417bf215546Sopenharmony_ci window->OuterRectClipped.ClipWith(window->ClipRect); 5418bf215546Sopenharmony_ci 5419bf215546Sopenharmony_ci // Pressing CTRL+C while holding on a window copy its content to the clipboard 5420bf215546Sopenharmony_ci // This works but 1. doesn't handle multiple Begin/End pairs, 2. recursing into another Begin/End pair - so we need to work that out and add better logging scope. 5421bf215546Sopenharmony_ci // Maybe we can support CTRL+C on every element? 5422bf215546Sopenharmony_ci /* 5423bf215546Sopenharmony_ci if (g.ActiveId == move_id) 5424bf215546Sopenharmony_ci if (g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_C)) 5425bf215546Sopenharmony_ci LogToClipboard(); 5426bf215546Sopenharmony_ci */ 5427bf215546Sopenharmony_ci 5428bf215546Sopenharmony_ci // Inner rectangle 5429bf215546Sopenharmony_ci // We set this up after processing the resize grip so that our clip rectangle doesn't lag by a frame 5430bf215546Sopenharmony_ci // Note that if our window is collapsed we will end up with an inverted (~null) clipping rectangle which is the correct behavior. 5431bf215546Sopenharmony_ci window->InnerMainRect.Min.x = title_bar_rect.Min.x + window->WindowBorderSize; 5432bf215546Sopenharmony_ci window->InnerMainRect.Min.y = title_bar_rect.Max.y + window->MenuBarHeight() + (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize); 5433bf215546Sopenharmony_ci window->InnerMainRect.Max.x = window->Pos.x + window->Size.x - window->ScrollbarSizes.x - window->WindowBorderSize; 5434bf215546Sopenharmony_ci window->InnerMainRect.Max.y = window->Pos.y + window->Size.y - window->ScrollbarSizes.y - window->WindowBorderSize; 5435bf215546Sopenharmony_ci //window->DrawList->AddRect(window->InnerRect.Min, window->InnerRect.Max, IM_COL32_WHITE); 5436bf215546Sopenharmony_ci 5437bf215546Sopenharmony_ci // Inner clipping rectangle 5438bf215546Sopenharmony_ci // Force round operator last to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result. 5439bf215546Sopenharmony_ci window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerMainRect.Min.x + ImMax(0.0f, ImFloor(window->WindowPadding.x*0.5f - window->WindowBorderSize))); 5440bf215546Sopenharmony_ci window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerMainRect.Min.y); 5441bf215546Sopenharmony_ci window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerMainRect.Max.x - ImMax(0.0f, ImFloor(window->WindowPadding.x*0.5f - window->WindowBorderSize))); 5442bf215546Sopenharmony_ci window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerMainRect.Max.y); 5443bf215546Sopenharmony_ci 5444bf215546Sopenharmony_ci // We fill last item data based on Title Bar, in order for IsItemHovered() and IsItemActive() to be usable after Begin(). 5445bf215546Sopenharmony_ci // This is useful to allow creating context menus on title bar only, etc. 5446bf215546Sopenharmony_ci window->DC.LastItemId = window->MoveId; 5447bf215546Sopenharmony_ci window->DC.LastItemStatusFlags = IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0; 5448bf215546Sopenharmony_ci window->DC.LastItemRect = title_bar_rect; 5449bf215546Sopenharmony_ci } 5450bf215546Sopenharmony_ci 5451bf215546Sopenharmony_ci PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true); 5452bf215546Sopenharmony_ci 5453bf215546Sopenharmony_ci // Clear 'accessed' flag last thing (After PushClipRect which will set the flag. We want the flag to stay false when the default "Debug" window is unused) 5454bf215546Sopenharmony_ci if (first_begin_of_the_frame) 5455bf215546Sopenharmony_ci window->WriteAccessed = false; 5456bf215546Sopenharmony_ci 5457bf215546Sopenharmony_ci window->BeginCount++; 5458bf215546Sopenharmony_ci g.NextWindowData.Clear(); 5459bf215546Sopenharmony_ci 5460bf215546Sopenharmony_ci if (flags & ImGuiWindowFlags_ChildWindow) 5461bf215546Sopenharmony_ci { 5462bf215546Sopenharmony_ci // Child window can be out of sight and have "negative" clip windows. 5463bf215546Sopenharmony_ci // Mark them as collapsed so commands are skipped earlier (we can't manually collapse them because they have no title bar). 5464bf215546Sopenharmony_ci IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0); 5465bf215546Sopenharmony_ci if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) 5466bf215546Sopenharmony_ci if (window->OuterRectClipped.Min.x >= window->OuterRectClipped.Max.x || window->OuterRectClipped.Min.y >= window->OuterRectClipped.Max.y) 5467bf215546Sopenharmony_ci window->HiddenFramesRegular = 1; 5468bf215546Sopenharmony_ci 5469bf215546Sopenharmony_ci // Completely hide along with parent or if parent is collapsed 5470bf215546Sopenharmony_ci if (parent_window && (parent_window->Collapsed || parent_window->Hidden)) 5471bf215546Sopenharmony_ci window->HiddenFramesRegular = 1; 5472bf215546Sopenharmony_ci } 5473bf215546Sopenharmony_ci 5474bf215546Sopenharmony_ci // Don't render if style alpha is 0.0 at the time of Begin(). This is arbitrary and inconsistent but has been there for a long while (may remove at some point) 5475bf215546Sopenharmony_ci if (style.Alpha <= 0.0f) 5476bf215546Sopenharmony_ci window->HiddenFramesRegular = 1; 5477bf215546Sopenharmony_ci 5478bf215546Sopenharmony_ci // Update the Hidden flag 5479bf215546Sopenharmony_ci window->Hidden = (window->HiddenFramesRegular > 0) || (window->HiddenFramesForResize > 0); 5480bf215546Sopenharmony_ci 5481bf215546Sopenharmony_ci // Return false if we don't intend to display anything to allow user to perform an early out optimization 5482bf215546Sopenharmony_ci window->SkipItems = (window->Collapsed || !window->Active || window->Hidden) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && window->HiddenFramesForResize <= 0; 5483bf215546Sopenharmony_ci 5484bf215546Sopenharmony_ci return !window->SkipItems; 5485bf215546Sopenharmony_ci} 5486bf215546Sopenharmony_ci 5487bf215546Sopenharmony_ci// Old Begin() API with 5 parameters, avoid calling this version directly! Use SetNextWindowSize()/SetNextWindowBgAlpha() + Begin() instead. 5488bf215546Sopenharmony_ci#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS 5489bf215546Sopenharmony_cibool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_first_use, float bg_alpha_override, ImGuiWindowFlags flags) 5490bf215546Sopenharmony_ci{ 5491bf215546Sopenharmony_ci // Old API feature: we could pass the initial window size as a parameter. This was misleading because it only had an effect if the window didn't have data in the .ini file. 5492bf215546Sopenharmony_ci if (size_first_use.x != 0.0f || size_first_use.y != 0.0f) 5493bf215546Sopenharmony_ci SetNextWindowSize(size_first_use, ImGuiCond_FirstUseEver); 5494bf215546Sopenharmony_ci 5495bf215546Sopenharmony_ci // Old API feature: override the window background alpha with a parameter. 5496bf215546Sopenharmony_ci if (bg_alpha_override >= 0.0f) 5497bf215546Sopenharmony_ci SetNextWindowBgAlpha(bg_alpha_override); 5498bf215546Sopenharmony_ci 5499bf215546Sopenharmony_ci return Begin(name, p_open, flags); 5500bf215546Sopenharmony_ci} 5501bf215546Sopenharmony_ci#endif // IMGUI_DISABLE_OBSOLETE_FUNCTIONS 5502bf215546Sopenharmony_ci 5503bf215546Sopenharmony_civoid ImGui::End() 5504bf215546Sopenharmony_ci{ 5505bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 5506bf215546Sopenharmony_ci 5507bf215546Sopenharmony_ci if (g.CurrentWindowStack.Size <= 1 && g.FrameScopePushedImplicitWindow) 5508bf215546Sopenharmony_ci { 5509bf215546Sopenharmony_ci IM_ASSERT(g.CurrentWindowStack.Size > 1 && "Calling End() too many times!"); 5510bf215546Sopenharmony_ci return; // FIXME-ERRORHANDLING 5511bf215546Sopenharmony_ci } 5512bf215546Sopenharmony_ci IM_ASSERT(g.CurrentWindowStack.Size > 0); 5513bf215546Sopenharmony_ci 5514bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 5515bf215546Sopenharmony_ci 5516bf215546Sopenharmony_ci if (window->DC.ColumnsSet != NULL) 5517bf215546Sopenharmony_ci EndColumns(); 5518bf215546Sopenharmony_ci PopClipRect(); // Inner window clip rectangle 5519bf215546Sopenharmony_ci 5520bf215546Sopenharmony_ci // Stop logging 5521bf215546Sopenharmony_ci if (!(window->Flags & ImGuiWindowFlags_ChildWindow)) // FIXME: add more options for scope of logging 5522bf215546Sopenharmony_ci LogFinish(); 5523bf215546Sopenharmony_ci 5524bf215546Sopenharmony_ci // Pop from window stack 5525bf215546Sopenharmony_ci g.CurrentWindowStack.pop_back(); 5526bf215546Sopenharmony_ci if (window->Flags & ImGuiWindowFlags_Popup) 5527bf215546Sopenharmony_ci g.BeginPopupStack.pop_back(); 5528bf215546Sopenharmony_ci CheckStacksSize(window, false); 5529bf215546Sopenharmony_ci SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back()); 5530bf215546Sopenharmony_ci} 5531bf215546Sopenharmony_ci 5532bf215546Sopenharmony_civoid ImGui::BringWindowToFocusFront(ImGuiWindow* window) 5533bf215546Sopenharmony_ci{ 5534bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 5535bf215546Sopenharmony_ci if (g.WindowsFocusOrder.back() == window) 5536bf215546Sopenharmony_ci return; 5537bf215546Sopenharmony_ci for (int i = g.WindowsFocusOrder.Size - 2; i >= 0; i--) // We can ignore the front most window 5538bf215546Sopenharmony_ci if (g.WindowsFocusOrder[i] == window) 5539bf215546Sopenharmony_ci { 5540bf215546Sopenharmony_ci memmove(&g.WindowsFocusOrder[i], &g.WindowsFocusOrder[i + 1], (size_t)(g.WindowsFocusOrder.Size - i - 1) * sizeof(ImGuiWindow*)); 5541bf215546Sopenharmony_ci g.WindowsFocusOrder[g.WindowsFocusOrder.Size - 1] = window; 5542bf215546Sopenharmony_ci break; 5543bf215546Sopenharmony_ci } 5544bf215546Sopenharmony_ci} 5545bf215546Sopenharmony_ci 5546bf215546Sopenharmony_civoid ImGui::BringWindowToDisplayFront(ImGuiWindow* window) 5547bf215546Sopenharmony_ci{ 5548bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 5549bf215546Sopenharmony_ci ImGuiWindow* current_front_window = g.Windows.back(); 5550bf215546Sopenharmony_ci if (current_front_window == window || current_front_window->RootWindow == window) 5551bf215546Sopenharmony_ci return; 5552bf215546Sopenharmony_ci for (int i = g.Windows.Size - 2; i >= 0; i--) // We can ignore the front most window 5553bf215546Sopenharmony_ci if (g.Windows[i] == window) 5554bf215546Sopenharmony_ci { 5555bf215546Sopenharmony_ci memmove(&g.Windows[i], &g.Windows[i + 1], (size_t)(g.Windows.Size - i - 1) * sizeof(ImGuiWindow*)); 5556bf215546Sopenharmony_ci g.Windows[g.Windows.Size - 1] = window; 5557bf215546Sopenharmony_ci break; 5558bf215546Sopenharmony_ci } 5559bf215546Sopenharmony_ci} 5560bf215546Sopenharmony_ci 5561bf215546Sopenharmony_civoid ImGui::BringWindowToDisplayBack(ImGuiWindow* window) 5562bf215546Sopenharmony_ci{ 5563bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 5564bf215546Sopenharmony_ci if (g.Windows[0] == window) 5565bf215546Sopenharmony_ci return; 5566bf215546Sopenharmony_ci for (int i = 0; i < g.Windows.Size; i++) 5567bf215546Sopenharmony_ci if (g.Windows[i] == window) 5568bf215546Sopenharmony_ci { 5569bf215546Sopenharmony_ci memmove(&g.Windows[1], &g.Windows[0], (size_t)i * sizeof(ImGuiWindow*)); 5570bf215546Sopenharmony_ci g.Windows[0] = window; 5571bf215546Sopenharmony_ci break; 5572bf215546Sopenharmony_ci } 5573bf215546Sopenharmony_ci} 5574bf215546Sopenharmony_ci 5575bf215546Sopenharmony_ci// Moving window to front of display and set focus (which happens to be back of our sorted list) 5576bf215546Sopenharmony_civoid ImGui::FocusWindow(ImGuiWindow* window) 5577bf215546Sopenharmony_ci{ 5578bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 5579bf215546Sopenharmony_ci 5580bf215546Sopenharmony_ci if (g.NavWindow != window) 5581bf215546Sopenharmony_ci { 5582bf215546Sopenharmony_ci g.NavWindow = window; 5583bf215546Sopenharmony_ci if (window && g.NavDisableMouseHover) 5584bf215546Sopenharmony_ci g.NavMousePosDirty = true; 5585bf215546Sopenharmony_ci g.NavInitRequest = false; 5586bf215546Sopenharmony_ci g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId 5587bf215546Sopenharmony_ci g.NavIdIsAlive = false; 5588bf215546Sopenharmony_ci g.NavLayer = ImGuiNavLayer_Main; 5589bf215546Sopenharmony_ci //IMGUI_DEBUG_LOG("FocusWindow(\"%s\")\n", window ? window->Name : NULL); 5590bf215546Sopenharmony_ci } 5591bf215546Sopenharmony_ci 5592bf215546Sopenharmony_ci // Passing NULL allow to disable keyboard focus 5593bf215546Sopenharmony_ci if (!window) 5594bf215546Sopenharmony_ci return; 5595bf215546Sopenharmony_ci 5596bf215546Sopenharmony_ci // Move the root window to the top of the pile 5597bf215546Sopenharmony_ci if (window->RootWindow) 5598bf215546Sopenharmony_ci window = window->RootWindow; 5599bf215546Sopenharmony_ci 5600bf215546Sopenharmony_ci // Steal focus on active widgets 5601bf215546Sopenharmony_ci if (window->Flags & ImGuiWindowFlags_Popup) // FIXME: This statement should be unnecessary. Need further testing before removing it.. 5602bf215546Sopenharmony_ci if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != window) 5603bf215546Sopenharmony_ci ClearActiveID(); 5604bf215546Sopenharmony_ci 5605bf215546Sopenharmony_ci // Bring to front 5606bf215546Sopenharmony_ci BringWindowToFocusFront(window); 5607bf215546Sopenharmony_ci if (!(window->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) 5608bf215546Sopenharmony_ci BringWindowToDisplayFront(window); 5609bf215546Sopenharmony_ci} 5610bf215546Sopenharmony_ci 5611bf215546Sopenharmony_civoid ImGui::FocusPreviousWindowIgnoringOne(ImGuiWindow* ignore_window) 5612bf215546Sopenharmony_ci{ 5613bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 5614bf215546Sopenharmony_ci for (int i = g.WindowsFocusOrder.Size - 1; i >= 0; i--) 5615bf215546Sopenharmony_ci { 5616bf215546Sopenharmony_ci // We may later decide to test for different NoXXXInputs based on the active navigation input (mouse vs nav) but that may feel more confusing to the user. 5617bf215546Sopenharmony_ci ImGuiWindow* window = g.WindowsFocusOrder[i]; 5618bf215546Sopenharmony_ci if (window != ignore_window && window->WasActive && !(window->Flags & ImGuiWindowFlags_ChildWindow)) 5619bf215546Sopenharmony_ci if ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) 5620bf215546Sopenharmony_ci { 5621bf215546Sopenharmony_ci ImGuiWindow* focus_window = NavRestoreLastChildNavWindow(window); 5622bf215546Sopenharmony_ci FocusWindow(focus_window); 5623bf215546Sopenharmony_ci return; 5624bf215546Sopenharmony_ci } 5625bf215546Sopenharmony_ci } 5626bf215546Sopenharmony_ci} 5627bf215546Sopenharmony_ci 5628bf215546Sopenharmony_civoid ImGui::PushItemWidth(float item_width) 5629bf215546Sopenharmony_ci{ 5630bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindow(); 5631bf215546Sopenharmony_ci window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width); 5632bf215546Sopenharmony_ci window->DC.ItemWidthStack.push_back(window->DC.ItemWidth); 5633bf215546Sopenharmony_ci} 5634bf215546Sopenharmony_ci 5635bf215546Sopenharmony_civoid ImGui::PushMultiItemsWidths(int components, float w_full) 5636bf215546Sopenharmony_ci{ 5637bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindow(); 5638bf215546Sopenharmony_ci const ImGuiStyle& style = GImGui->Style; 5639bf215546Sopenharmony_ci if (w_full <= 0.0f) 5640bf215546Sopenharmony_ci w_full = CalcItemWidth(); 5641bf215546Sopenharmony_ci const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.ItemInnerSpacing.x) * (components-1)) / (float)components)); 5642bf215546Sopenharmony_ci const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components-1))); 5643bf215546Sopenharmony_ci window->DC.ItemWidthStack.push_back(w_item_last); 5644bf215546Sopenharmony_ci for (int i = 0; i < components-1; i++) 5645bf215546Sopenharmony_ci window->DC.ItemWidthStack.push_back(w_item_one); 5646bf215546Sopenharmony_ci window->DC.ItemWidth = window->DC.ItemWidthStack.back(); 5647bf215546Sopenharmony_ci} 5648bf215546Sopenharmony_ci 5649bf215546Sopenharmony_civoid ImGui::PopItemWidth() 5650bf215546Sopenharmony_ci{ 5651bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindow(); 5652bf215546Sopenharmony_ci window->DC.ItemWidthStack.pop_back(); 5653bf215546Sopenharmony_ci window->DC.ItemWidth = window->DC.ItemWidthStack.empty() ? window->ItemWidthDefault : window->DC.ItemWidthStack.back(); 5654bf215546Sopenharmony_ci} 5655bf215546Sopenharmony_ci 5656bf215546Sopenharmony_cifloat ImGui::CalcItemWidth() 5657bf215546Sopenharmony_ci{ 5658bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindowRead(); 5659bf215546Sopenharmony_ci float w = window->DC.ItemWidth; 5660bf215546Sopenharmony_ci if (w < 0.0f) 5661bf215546Sopenharmony_ci { 5662bf215546Sopenharmony_ci // Align to a right-side limit. We include 1 frame padding in the calculation because this is how the width is always used (we add 2 frame padding to it), but we could move that responsibility to the widget as well. 5663bf215546Sopenharmony_ci float width_to_right_edge = GetContentRegionAvail().x; 5664bf215546Sopenharmony_ci w = ImMax(1.0f, width_to_right_edge + w); 5665bf215546Sopenharmony_ci } 5666bf215546Sopenharmony_ci w = (float)(int)w; 5667bf215546Sopenharmony_ci return w; 5668bf215546Sopenharmony_ci} 5669bf215546Sopenharmony_ci 5670bf215546Sopenharmony_civoid ImGui::SetCurrentFont(ImFont* font) 5671bf215546Sopenharmony_ci{ 5672bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 5673bf215546Sopenharmony_ci IM_ASSERT(font && font->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ? 5674bf215546Sopenharmony_ci IM_ASSERT(font->Scale > 0.0f); 5675bf215546Sopenharmony_ci g.Font = font; 5676bf215546Sopenharmony_ci g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale); 5677bf215546Sopenharmony_ci g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f; 5678bf215546Sopenharmony_ci 5679bf215546Sopenharmony_ci ImFontAtlas* atlas = g.Font->ContainerAtlas; 5680bf215546Sopenharmony_ci g.DrawListSharedData.TexUvWhitePixel = atlas->TexUvWhitePixel; 5681bf215546Sopenharmony_ci g.DrawListSharedData.Font = g.Font; 5682bf215546Sopenharmony_ci g.DrawListSharedData.FontSize = g.FontSize; 5683bf215546Sopenharmony_ci} 5684bf215546Sopenharmony_ci 5685bf215546Sopenharmony_civoid ImGui::PushFont(ImFont* font) 5686bf215546Sopenharmony_ci{ 5687bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 5688bf215546Sopenharmony_ci if (!font) 5689bf215546Sopenharmony_ci font = GetDefaultFont(); 5690bf215546Sopenharmony_ci SetCurrentFont(font); 5691bf215546Sopenharmony_ci g.FontStack.push_back(font); 5692bf215546Sopenharmony_ci g.CurrentWindow->DrawList->PushTextureID(font->ContainerAtlas->TexID); 5693bf215546Sopenharmony_ci} 5694bf215546Sopenharmony_ci 5695bf215546Sopenharmony_civoid ImGui::PopFont() 5696bf215546Sopenharmony_ci{ 5697bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 5698bf215546Sopenharmony_ci g.CurrentWindow->DrawList->PopTextureID(); 5699bf215546Sopenharmony_ci g.FontStack.pop_back(); 5700bf215546Sopenharmony_ci SetCurrentFont(g.FontStack.empty() ? GetDefaultFont() : g.FontStack.back()); 5701bf215546Sopenharmony_ci} 5702bf215546Sopenharmony_ci 5703bf215546Sopenharmony_civoid ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled) 5704bf215546Sopenharmony_ci{ 5705bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindow(); 5706bf215546Sopenharmony_ci if (enabled) 5707bf215546Sopenharmony_ci window->DC.ItemFlags |= option; 5708bf215546Sopenharmony_ci else 5709bf215546Sopenharmony_ci window->DC.ItemFlags &= ~option; 5710bf215546Sopenharmony_ci window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags); 5711bf215546Sopenharmony_ci} 5712bf215546Sopenharmony_ci 5713bf215546Sopenharmony_civoid ImGui::PopItemFlag() 5714bf215546Sopenharmony_ci{ 5715bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindow(); 5716bf215546Sopenharmony_ci window->DC.ItemFlagsStack.pop_back(); 5717bf215546Sopenharmony_ci window->DC.ItemFlags = window->DC.ItemFlagsStack.empty() ? ImGuiItemFlags_Default_ : window->DC.ItemFlagsStack.back(); 5718bf215546Sopenharmony_ci} 5719bf215546Sopenharmony_ci 5720bf215546Sopenharmony_ci// FIXME: Look into renaming this once we have settled the new Focus/Activation/TabStop system. 5721bf215546Sopenharmony_civoid ImGui::PushAllowKeyboardFocus(bool allow_keyboard_focus) 5722bf215546Sopenharmony_ci{ 5723bf215546Sopenharmony_ci PushItemFlag(ImGuiItemFlags_NoTabStop, !allow_keyboard_focus); 5724bf215546Sopenharmony_ci} 5725bf215546Sopenharmony_ci 5726bf215546Sopenharmony_civoid ImGui::PopAllowKeyboardFocus() 5727bf215546Sopenharmony_ci{ 5728bf215546Sopenharmony_ci PopItemFlag(); 5729bf215546Sopenharmony_ci} 5730bf215546Sopenharmony_ci 5731bf215546Sopenharmony_civoid ImGui::PushButtonRepeat(bool repeat) 5732bf215546Sopenharmony_ci{ 5733bf215546Sopenharmony_ci PushItemFlag(ImGuiItemFlags_ButtonRepeat, repeat); 5734bf215546Sopenharmony_ci} 5735bf215546Sopenharmony_ci 5736bf215546Sopenharmony_civoid ImGui::PopButtonRepeat() 5737bf215546Sopenharmony_ci{ 5738bf215546Sopenharmony_ci PopItemFlag(); 5739bf215546Sopenharmony_ci} 5740bf215546Sopenharmony_ci 5741bf215546Sopenharmony_civoid ImGui::PushTextWrapPos(float wrap_pos_x) 5742bf215546Sopenharmony_ci{ 5743bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindow(); 5744bf215546Sopenharmony_ci window->DC.TextWrapPos = wrap_pos_x; 5745bf215546Sopenharmony_ci window->DC.TextWrapPosStack.push_back(wrap_pos_x); 5746bf215546Sopenharmony_ci} 5747bf215546Sopenharmony_ci 5748bf215546Sopenharmony_civoid ImGui::PopTextWrapPos() 5749bf215546Sopenharmony_ci{ 5750bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindow(); 5751bf215546Sopenharmony_ci window->DC.TextWrapPosStack.pop_back(); 5752bf215546Sopenharmony_ci window->DC.TextWrapPos = window->DC.TextWrapPosStack.empty() ? -1.0f : window->DC.TextWrapPosStack.back(); 5753bf215546Sopenharmony_ci} 5754bf215546Sopenharmony_ci 5755bf215546Sopenharmony_ci// 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 5756bf215546Sopenharmony_civoid ImGui::PushStyleColor(ImGuiCol idx, ImU32 col) 5757bf215546Sopenharmony_ci{ 5758bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 5759bf215546Sopenharmony_ci ImGuiColorMod backup; 5760bf215546Sopenharmony_ci backup.Col = idx; 5761bf215546Sopenharmony_ci backup.BackupValue = g.Style.Colors[idx]; 5762bf215546Sopenharmony_ci g.ColorModifiers.push_back(backup); 5763bf215546Sopenharmony_ci g.Style.Colors[idx] = ColorConvertU32ToFloat4(col); 5764bf215546Sopenharmony_ci} 5765bf215546Sopenharmony_ci 5766bf215546Sopenharmony_civoid ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col) 5767bf215546Sopenharmony_ci{ 5768bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 5769bf215546Sopenharmony_ci ImGuiColorMod backup; 5770bf215546Sopenharmony_ci backup.Col = idx; 5771bf215546Sopenharmony_ci backup.BackupValue = g.Style.Colors[idx]; 5772bf215546Sopenharmony_ci g.ColorModifiers.push_back(backup); 5773bf215546Sopenharmony_ci g.Style.Colors[idx] = col; 5774bf215546Sopenharmony_ci} 5775bf215546Sopenharmony_ci 5776bf215546Sopenharmony_civoid ImGui::PopStyleColor(int count) 5777bf215546Sopenharmony_ci{ 5778bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 5779bf215546Sopenharmony_ci while (count > 0) 5780bf215546Sopenharmony_ci { 5781bf215546Sopenharmony_ci ImGuiColorMod& backup = g.ColorModifiers.back(); 5782bf215546Sopenharmony_ci g.Style.Colors[backup.Col] = backup.BackupValue; 5783bf215546Sopenharmony_ci g.ColorModifiers.pop_back(); 5784bf215546Sopenharmony_ci count--; 5785bf215546Sopenharmony_ci } 5786bf215546Sopenharmony_ci} 5787bf215546Sopenharmony_ci 5788bf215546Sopenharmony_cistruct ImGuiStyleVarInfo 5789bf215546Sopenharmony_ci{ 5790bf215546Sopenharmony_ci ImGuiDataType Type; 5791bf215546Sopenharmony_ci ImU32 Count; 5792bf215546Sopenharmony_ci ImU32 Offset; 5793bf215546Sopenharmony_ci void* GetVarPtr(ImGuiStyle* style) const { return (void*)((unsigned char*)style + Offset); } 5794bf215546Sopenharmony_ci}; 5795bf215546Sopenharmony_ci 5796bf215546Sopenharmony_cistatic const ImGuiStyleVarInfo GStyleVarInfo[] = 5797bf215546Sopenharmony_ci{ 5798bf215546Sopenharmony_ci { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, Alpha) }, // ImGuiStyleVar_Alpha 5799bf215546Sopenharmony_ci { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowPadding) }, // ImGuiStyleVar_WindowPadding 5800bf215546Sopenharmony_ci { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowRounding) }, // ImGuiStyleVar_WindowRounding 5801bf215546Sopenharmony_ci { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowBorderSize) }, // ImGuiStyleVar_WindowBorderSize 5802bf215546Sopenharmony_ci { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowMinSize) }, // ImGuiStyleVar_WindowMinSize 5803bf215546Sopenharmony_ci { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowTitleAlign) }, // ImGuiStyleVar_WindowTitleAlign 5804bf215546Sopenharmony_ci { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildRounding) }, // ImGuiStyleVar_ChildRounding 5805bf215546Sopenharmony_ci { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildBorderSize) }, // ImGuiStyleVar_ChildBorderSize 5806bf215546Sopenharmony_ci { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupRounding) }, // ImGuiStyleVar_PopupRounding 5807bf215546Sopenharmony_ci { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupBorderSize) }, // ImGuiStyleVar_PopupBorderSize 5808bf215546Sopenharmony_ci { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, FramePadding) }, // ImGuiStyleVar_FramePadding 5809bf215546Sopenharmony_ci { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameRounding) }, // ImGuiStyleVar_FrameRounding 5810bf215546Sopenharmony_ci { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameBorderSize) }, // ImGuiStyleVar_FrameBorderSize 5811bf215546Sopenharmony_ci { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemSpacing) }, // ImGuiStyleVar_ItemSpacing 5812bf215546Sopenharmony_ci { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemInnerSpacing) }, // ImGuiStyleVar_ItemInnerSpacing 5813bf215546Sopenharmony_ci { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, IndentSpacing) }, // ImGuiStyleVar_IndentSpacing 5814bf215546Sopenharmony_ci { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarSize) }, // ImGuiStyleVar_ScrollbarSize 5815bf215546Sopenharmony_ci { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarRounding) }, // ImGuiStyleVar_ScrollbarRounding 5816bf215546Sopenharmony_ci { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) }, // ImGuiStyleVar_GrabMinSize 5817bf215546Sopenharmony_ci { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabRounding) }, // ImGuiStyleVar_GrabRounding 5818bf215546Sopenharmony_ci { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, TabRounding) }, // ImGuiStyleVar_TabRounding 5819bf215546Sopenharmony_ci { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign 5820bf215546Sopenharmony_ci { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign 5821bf215546Sopenharmony_ci}; 5822bf215546Sopenharmony_ci 5823bf215546Sopenharmony_cistatic const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx) 5824bf215546Sopenharmony_ci{ 5825bf215546Sopenharmony_ci IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_COUNT); 5826bf215546Sopenharmony_ci IM_ASSERT(IM_ARRAYSIZE(GStyleVarInfo) == ImGuiStyleVar_COUNT); 5827bf215546Sopenharmony_ci return &GStyleVarInfo[idx]; 5828bf215546Sopenharmony_ci} 5829bf215546Sopenharmony_ci 5830bf215546Sopenharmony_civoid ImGui::PushStyleVar(ImGuiStyleVar idx, float val) 5831bf215546Sopenharmony_ci{ 5832bf215546Sopenharmony_ci const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); 5833bf215546Sopenharmony_ci if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1) 5834bf215546Sopenharmony_ci { 5835bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 5836bf215546Sopenharmony_ci float* pvar = (float*)var_info->GetVarPtr(&g.Style); 5837bf215546Sopenharmony_ci g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); 5838bf215546Sopenharmony_ci *pvar = val; 5839bf215546Sopenharmony_ci return; 5840bf215546Sopenharmony_ci } 5841bf215546Sopenharmony_ci IM_ASSERT(0); // Called function with wrong-type? Variable is not a float. 5842bf215546Sopenharmony_ci} 5843bf215546Sopenharmony_ci 5844bf215546Sopenharmony_civoid ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val) 5845bf215546Sopenharmony_ci{ 5846bf215546Sopenharmony_ci const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); 5847bf215546Sopenharmony_ci if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2) 5848bf215546Sopenharmony_ci { 5849bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 5850bf215546Sopenharmony_ci ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style); 5851bf215546Sopenharmony_ci g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); 5852bf215546Sopenharmony_ci *pvar = val; 5853bf215546Sopenharmony_ci return; 5854bf215546Sopenharmony_ci } 5855bf215546Sopenharmony_ci IM_ASSERT(0); // Called function with wrong-type? Variable is not a ImVec2. 5856bf215546Sopenharmony_ci} 5857bf215546Sopenharmony_ci 5858bf215546Sopenharmony_civoid ImGui::PopStyleVar(int count) 5859bf215546Sopenharmony_ci{ 5860bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 5861bf215546Sopenharmony_ci while (count > 0) 5862bf215546Sopenharmony_ci { 5863bf215546Sopenharmony_ci // We avoid a generic memcpy(data, &backup.Backup.., GDataTypeSize[info->Type] * info->Count), the overhead in Debug is not worth it. 5864bf215546Sopenharmony_ci ImGuiStyleMod& backup = g.StyleModifiers.back(); 5865bf215546Sopenharmony_ci const ImGuiStyleVarInfo* info = GetStyleVarInfo(backup.VarIdx); 5866bf215546Sopenharmony_ci void* data = info->GetVarPtr(&g.Style); 5867bf215546Sopenharmony_ci if (info->Type == ImGuiDataType_Float && info->Count == 1) { ((float*)data)[0] = backup.BackupFloat[0]; } 5868bf215546Sopenharmony_ci else if (info->Type == ImGuiDataType_Float && info->Count == 2) { ((float*)data)[0] = backup.BackupFloat[0]; ((float*)data)[1] = backup.BackupFloat[1]; } 5869bf215546Sopenharmony_ci g.StyleModifiers.pop_back(); 5870bf215546Sopenharmony_ci count--; 5871bf215546Sopenharmony_ci } 5872bf215546Sopenharmony_ci} 5873bf215546Sopenharmony_ci 5874bf215546Sopenharmony_ciconst char* ImGui::GetStyleColorName(ImGuiCol idx) 5875bf215546Sopenharmony_ci{ 5876bf215546Sopenharmony_ci // Create switch-case from enum with regexp: ImGuiCol_{.*}, --> case ImGuiCol_\1: return "\1"; 5877bf215546Sopenharmony_ci switch (idx) 5878bf215546Sopenharmony_ci { 5879bf215546Sopenharmony_ci case ImGuiCol_Text: return "Text"; 5880bf215546Sopenharmony_ci case ImGuiCol_TextDisabled: return "TextDisabled"; 5881bf215546Sopenharmony_ci case ImGuiCol_WindowBg: return "WindowBg"; 5882bf215546Sopenharmony_ci case ImGuiCol_ChildBg: return "ChildBg"; 5883bf215546Sopenharmony_ci case ImGuiCol_PopupBg: return "PopupBg"; 5884bf215546Sopenharmony_ci case ImGuiCol_Border: return "Border"; 5885bf215546Sopenharmony_ci case ImGuiCol_BorderShadow: return "BorderShadow"; 5886bf215546Sopenharmony_ci case ImGuiCol_FrameBg: return "FrameBg"; 5887bf215546Sopenharmony_ci case ImGuiCol_FrameBgHovered: return "FrameBgHovered"; 5888bf215546Sopenharmony_ci case ImGuiCol_FrameBgActive: return "FrameBgActive"; 5889bf215546Sopenharmony_ci case ImGuiCol_TitleBg: return "TitleBg"; 5890bf215546Sopenharmony_ci case ImGuiCol_TitleBgActive: return "TitleBgActive"; 5891bf215546Sopenharmony_ci case ImGuiCol_TitleBgCollapsed: return "TitleBgCollapsed"; 5892bf215546Sopenharmony_ci case ImGuiCol_MenuBarBg: return "MenuBarBg"; 5893bf215546Sopenharmony_ci case ImGuiCol_ScrollbarBg: return "ScrollbarBg"; 5894bf215546Sopenharmony_ci case ImGuiCol_ScrollbarGrab: return "ScrollbarGrab"; 5895bf215546Sopenharmony_ci case ImGuiCol_ScrollbarGrabHovered: return "ScrollbarGrabHovered"; 5896bf215546Sopenharmony_ci case ImGuiCol_ScrollbarGrabActive: return "ScrollbarGrabActive"; 5897bf215546Sopenharmony_ci case ImGuiCol_CheckMark: return "CheckMark"; 5898bf215546Sopenharmony_ci case ImGuiCol_SliderGrab: return "SliderGrab"; 5899bf215546Sopenharmony_ci case ImGuiCol_SliderGrabActive: return "SliderGrabActive"; 5900bf215546Sopenharmony_ci case ImGuiCol_Button: return "Button"; 5901bf215546Sopenharmony_ci case ImGuiCol_ButtonHovered: return "ButtonHovered"; 5902bf215546Sopenharmony_ci case ImGuiCol_ButtonActive: return "ButtonActive"; 5903bf215546Sopenharmony_ci case ImGuiCol_Header: return "Header"; 5904bf215546Sopenharmony_ci case ImGuiCol_HeaderHovered: return "HeaderHovered"; 5905bf215546Sopenharmony_ci case ImGuiCol_HeaderActive: return "HeaderActive"; 5906bf215546Sopenharmony_ci case ImGuiCol_Separator: return "Separator"; 5907bf215546Sopenharmony_ci case ImGuiCol_SeparatorHovered: return "SeparatorHovered"; 5908bf215546Sopenharmony_ci case ImGuiCol_SeparatorActive: return "SeparatorActive"; 5909bf215546Sopenharmony_ci case ImGuiCol_ResizeGrip: return "ResizeGrip"; 5910bf215546Sopenharmony_ci case ImGuiCol_ResizeGripHovered: return "ResizeGripHovered"; 5911bf215546Sopenharmony_ci case ImGuiCol_ResizeGripActive: return "ResizeGripActive"; 5912bf215546Sopenharmony_ci case ImGuiCol_Tab: return "Tab"; 5913bf215546Sopenharmony_ci case ImGuiCol_TabHovered: return "TabHovered"; 5914bf215546Sopenharmony_ci case ImGuiCol_TabActive: return "TabActive"; 5915bf215546Sopenharmony_ci case ImGuiCol_TabUnfocused: return "TabUnfocused"; 5916bf215546Sopenharmony_ci case ImGuiCol_TabUnfocusedActive: return "TabUnfocusedActive"; 5917bf215546Sopenharmony_ci case ImGuiCol_PlotLines: return "PlotLines"; 5918bf215546Sopenharmony_ci case ImGuiCol_PlotLinesHovered: return "PlotLinesHovered"; 5919bf215546Sopenharmony_ci case ImGuiCol_PlotHistogram: return "PlotHistogram"; 5920bf215546Sopenharmony_ci case ImGuiCol_PlotHistogramHovered: return "PlotHistogramHovered"; 5921bf215546Sopenharmony_ci case ImGuiCol_TextSelectedBg: return "TextSelectedBg"; 5922bf215546Sopenharmony_ci case ImGuiCol_DragDropTarget: return "DragDropTarget"; 5923bf215546Sopenharmony_ci case ImGuiCol_NavHighlight: return "NavHighlight"; 5924bf215546Sopenharmony_ci case ImGuiCol_NavWindowingHighlight: return "NavWindowingHighlight"; 5925bf215546Sopenharmony_ci case ImGuiCol_NavWindowingDimBg: return "NavWindowingDimBg"; 5926bf215546Sopenharmony_ci case ImGuiCol_ModalWindowDimBg: return "ModalWindowDimBg"; 5927bf215546Sopenharmony_ci } 5928bf215546Sopenharmony_ci IM_ASSERT(0); 5929bf215546Sopenharmony_ci return "Unknown"; 5930bf215546Sopenharmony_ci} 5931bf215546Sopenharmony_ci 5932bf215546Sopenharmony_cibool ImGui::IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent) 5933bf215546Sopenharmony_ci{ 5934bf215546Sopenharmony_ci if (window->RootWindow == potential_parent) 5935bf215546Sopenharmony_ci return true; 5936bf215546Sopenharmony_ci while (window != NULL) 5937bf215546Sopenharmony_ci { 5938bf215546Sopenharmony_ci if (window == potential_parent) 5939bf215546Sopenharmony_ci return true; 5940bf215546Sopenharmony_ci window = window->ParentWindow; 5941bf215546Sopenharmony_ci } 5942bf215546Sopenharmony_ci return false; 5943bf215546Sopenharmony_ci} 5944bf215546Sopenharmony_ci 5945bf215546Sopenharmony_cibool ImGui::IsWindowHovered(ImGuiHoveredFlags flags) 5946bf215546Sopenharmony_ci{ 5947bf215546Sopenharmony_ci IM_ASSERT((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0); // Flags not supported by this function 5948bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 5949bf215546Sopenharmony_ci 5950bf215546Sopenharmony_ci if (flags & ImGuiHoveredFlags_AnyWindow) 5951bf215546Sopenharmony_ci { 5952bf215546Sopenharmony_ci if (g.HoveredWindow == NULL) 5953bf215546Sopenharmony_ci return false; 5954bf215546Sopenharmony_ci } 5955bf215546Sopenharmony_ci else 5956bf215546Sopenharmony_ci { 5957bf215546Sopenharmony_ci switch (flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) 5958bf215546Sopenharmony_ci { 5959bf215546Sopenharmony_ci case ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows: 5960bf215546Sopenharmony_ci if (g.HoveredRootWindow != g.CurrentWindow->RootWindow) 5961bf215546Sopenharmony_ci return false; 5962bf215546Sopenharmony_ci break; 5963bf215546Sopenharmony_ci case ImGuiHoveredFlags_RootWindow: 5964bf215546Sopenharmony_ci if (g.HoveredWindow != g.CurrentWindow->RootWindow) 5965bf215546Sopenharmony_ci return false; 5966bf215546Sopenharmony_ci break; 5967bf215546Sopenharmony_ci case ImGuiHoveredFlags_ChildWindows: 5968bf215546Sopenharmony_ci if (g.HoveredWindow == NULL || !IsWindowChildOf(g.HoveredWindow, g.CurrentWindow)) 5969bf215546Sopenharmony_ci return false; 5970bf215546Sopenharmony_ci break; 5971bf215546Sopenharmony_ci default: 5972bf215546Sopenharmony_ci if (g.HoveredWindow != g.CurrentWindow) 5973bf215546Sopenharmony_ci return false; 5974bf215546Sopenharmony_ci break; 5975bf215546Sopenharmony_ci } 5976bf215546Sopenharmony_ci } 5977bf215546Sopenharmony_ci 5978bf215546Sopenharmony_ci if (!IsWindowContentHoverable(g.HoveredRootWindow, flags)) 5979bf215546Sopenharmony_ci return false; 5980bf215546Sopenharmony_ci if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) 5981bf215546Sopenharmony_ci if (g.ActiveId != 0 && !g.ActiveIdAllowOverlap && g.ActiveId != g.HoveredWindow->MoveId) 5982bf215546Sopenharmony_ci return false; 5983bf215546Sopenharmony_ci return true; 5984bf215546Sopenharmony_ci} 5985bf215546Sopenharmony_ci 5986bf215546Sopenharmony_cibool ImGui::IsWindowFocused(ImGuiFocusedFlags flags) 5987bf215546Sopenharmony_ci{ 5988bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 5989bf215546Sopenharmony_ci 5990bf215546Sopenharmony_ci if (flags & ImGuiFocusedFlags_AnyWindow) 5991bf215546Sopenharmony_ci return g.NavWindow != NULL; 5992bf215546Sopenharmony_ci 5993bf215546Sopenharmony_ci IM_ASSERT(g.CurrentWindow); // Not inside a Begin()/End() 5994bf215546Sopenharmony_ci switch (flags & (ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows)) 5995bf215546Sopenharmony_ci { 5996bf215546Sopenharmony_ci case ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows: 5997bf215546Sopenharmony_ci return g.NavWindow && g.NavWindow->RootWindow == g.CurrentWindow->RootWindow; 5998bf215546Sopenharmony_ci case ImGuiFocusedFlags_RootWindow: 5999bf215546Sopenharmony_ci return g.NavWindow == g.CurrentWindow->RootWindow; 6000bf215546Sopenharmony_ci case ImGuiFocusedFlags_ChildWindows: 6001bf215546Sopenharmony_ci return g.NavWindow && IsWindowChildOf(g.NavWindow, g.CurrentWindow); 6002bf215546Sopenharmony_ci default: 6003bf215546Sopenharmony_ci return g.NavWindow == g.CurrentWindow; 6004bf215546Sopenharmony_ci } 6005bf215546Sopenharmony_ci} 6006bf215546Sopenharmony_ci 6007bf215546Sopenharmony_ci// Can we focus this window with CTRL+TAB (or PadMenu + PadFocusPrev/PadFocusNext) 6008bf215546Sopenharmony_ci// Note that NoNavFocus makes the window not reachable with CTRL+TAB but it can still be focused with mouse or programmaticaly. 6009bf215546Sopenharmony_ci// If you want a window to never be focused, you may use the e.g. NoInputs flag. 6010bf215546Sopenharmony_cibool ImGui::IsWindowNavFocusable(ImGuiWindow* window) 6011bf215546Sopenharmony_ci{ 6012bf215546Sopenharmony_ci return window->Active && window == window->RootWindow && !(window->Flags & ImGuiWindowFlags_NoNavFocus); 6013bf215546Sopenharmony_ci} 6014bf215546Sopenharmony_ci 6015bf215546Sopenharmony_cifloat ImGui::GetWindowWidth() 6016bf215546Sopenharmony_ci{ 6017bf215546Sopenharmony_ci ImGuiWindow* window = GImGui->CurrentWindow; 6018bf215546Sopenharmony_ci return window->Size.x; 6019bf215546Sopenharmony_ci} 6020bf215546Sopenharmony_ci 6021bf215546Sopenharmony_cifloat ImGui::GetWindowHeight() 6022bf215546Sopenharmony_ci{ 6023bf215546Sopenharmony_ci ImGuiWindow* window = GImGui->CurrentWindow; 6024bf215546Sopenharmony_ci return window->Size.y; 6025bf215546Sopenharmony_ci} 6026bf215546Sopenharmony_ci 6027bf215546Sopenharmony_ciImVec2 ImGui::GetWindowPos() 6028bf215546Sopenharmony_ci{ 6029bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6030bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 6031bf215546Sopenharmony_ci return window->Pos; 6032bf215546Sopenharmony_ci} 6033bf215546Sopenharmony_ci 6034bf215546Sopenharmony_civoid ImGui::SetWindowScrollX(ImGuiWindow* window, float new_scroll_x) 6035bf215546Sopenharmony_ci{ 6036bf215546Sopenharmony_ci window->DC.CursorMaxPos.x += window->Scroll.x; // SizeContents is generally computed based on CursorMaxPos which is affected by scroll position, so we need to apply our change to it. 6037bf215546Sopenharmony_ci window->Scroll.x = new_scroll_x; 6038bf215546Sopenharmony_ci window->DC.CursorMaxPos.x -= window->Scroll.x; 6039bf215546Sopenharmony_ci} 6040bf215546Sopenharmony_ci 6041bf215546Sopenharmony_civoid ImGui::SetWindowScrollY(ImGuiWindow* window, float new_scroll_y) 6042bf215546Sopenharmony_ci{ 6043bf215546Sopenharmony_ci window->DC.CursorMaxPos.y += window->Scroll.y; // SizeContents is generally computed based on CursorMaxPos which is affected by scroll position, so we need to apply our change to it. 6044bf215546Sopenharmony_ci window->Scroll.y = new_scroll_y; 6045bf215546Sopenharmony_ci window->DC.CursorMaxPos.y -= window->Scroll.y; 6046bf215546Sopenharmony_ci} 6047bf215546Sopenharmony_ci 6048bf215546Sopenharmony_civoid ImGui::SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond) 6049bf215546Sopenharmony_ci{ 6050bf215546Sopenharmony_ci // Test condition (NB: bit 0 is always true) and clear flags for next time 6051bf215546Sopenharmony_ci if (cond && (window->SetWindowPosAllowFlags & cond) == 0) 6052bf215546Sopenharmony_ci return; 6053bf215546Sopenharmony_ci 6054bf215546Sopenharmony_ci IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. 6055bf215546Sopenharmony_ci window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); 6056bf215546Sopenharmony_ci window->SetWindowPosVal = ImVec2(FLT_MAX, FLT_MAX); 6057bf215546Sopenharmony_ci 6058bf215546Sopenharmony_ci // Set 6059bf215546Sopenharmony_ci const ImVec2 old_pos = window->Pos; 6060bf215546Sopenharmony_ci window->Pos = ImFloor(pos); 6061bf215546Sopenharmony_ci window->DC.CursorPos += (window->Pos - old_pos); // As we happen to move the window while it is being appended to (which is a bad idea - will smear) let's at least offset the cursor 6062bf215546Sopenharmony_ci window->DC.CursorMaxPos += (window->Pos - old_pos); // And more importantly we need to adjust this so size calculation doesn't get affected. 6063bf215546Sopenharmony_ci} 6064bf215546Sopenharmony_ci 6065bf215546Sopenharmony_civoid ImGui::SetWindowPos(const ImVec2& pos, ImGuiCond cond) 6066bf215546Sopenharmony_ci{ 6067bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindowRead(); 6068bf215546Sopenharmony_ci SetWindowPos(window, pos, cond); 6069bf215546Sopenharmony_ci} 6070bf215546Sopenharmony_ci 6071bf215546Sopenharmony_civoid ImGui::SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond) 6072bf215546Sopenharmony_ci{ 6073bf215546Sopenharmony_ci if (ImGuiWindow* window = FindWindowByName(name)) 6074bf215546Sopenharmony_ci SetWindowPos(window, pos, cond); 6075bf215546Sopenharmony_ci} 6076bf215546Sopenharmony_ci 6077bf215546Sopenharmony_ciImVec2 ImGui::GetWindowSize() 6078bf215546Sopenharmony_ci{ 6079bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindowRead(); 6080bf215546Sopenharmony_ci return window->Size; 6081bf215546Sopenharmony_ci} 6082bf215546Sopenharmony_ci 6083bf215546Sopenharmony_civoid ImGui::SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond) 6084bf215546Sopenharmony_ci{ 6085bf215546Sopenharmony_ci // Test condition (NB: bit 0 is always true) and clear flags for next time 6086bf215546Sopenharmony_ci if (cond && (window->SetWindowSizeAllowFlags & cond) == 0) 6087bf215546Sopenharmony_ci return; 6088bf215546Sopenharmony_ci 6089bf215546Sopenharmony_ci IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. 6090bf215546Sopenharmony_ci window->SetWindowSizeAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); 6091bf215546Sopenharmony_ci 6092bf215546Sopenharmony_ci // Set 6093bf215546Sopenharmony_ci if (size.x > 0.0f) 6094bf215546Sopenharmony_ci { 6095bf215546Sopenharmony_ci window->AutoFitFramesX = 0; 6096bf215546Sopenharmony_ci window->SizeFull.x = ImFloor(size.x); 6097bf215546Sopenharmony_ci } 6098bf215546Sopenharmony_ci else 6099bf215546Sopenharmony_ci { 6100bf215546Sopenharmony_ci window->AutoFitFramesX = 2; 6101bf215546Sopenharmony_ci window->AutoFitOnlyGrows = false; 6102bf215546Sopenharmony_ci } 6103bf215546Sopenharmony_ci if (size.y > 0.0f) 6104bf215546Sopenharmony_ci { 6105bf215546Sopenharmony_ci window->AutoFitFramesY = 0; 6106bf215546Sopenharmony_ci window->SizeFull.y = ImFloor(size.y); 6107bf215546Sopenharmony_ci } 6108bf215546Sopenharmony_ci else 6109bf215546Sopenharmony_ci { 6110bf215546Sopenharmony_ci window->AutoFitFramesY = 2; 6111bf215546Sopenharmony_ci window->AutoFitOnlyGrows = false; 6112bf215546Sopenharmony_ci } 6113bf215546Sopenharmony_ci} 6114bf215546Sopenharmony_ci 6115bf215546Sopenharmony_civoid ImGui::SetWindowSize(const ImVec2& size, ImGuiCond cond) 6116bf215546Sopenharmony_ci{ 6117bf215546Sopenharmony_ci SetWindowSize(GImGui->CurrentWindow, size, cond); 6118bf215546Sopenharmony_ci} 6119bf215546Sopenharmony_ci 6120bf215546Sopenharmony_civoid ImGui::SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond) 6121bf215546Sopenharmony_ci{ 6122bf215546Sopenharmony_ci if (ImGuiWindow* window = FindWindowByName(name)) 6123bf215546Sopenharmony_ci SetWindowSize(window, size, cond); 6124bf215546Sopenharmony_ci} 6125bf215546Sopenharmony_ci 6126bf215546Sopenharmony_civoid ImGui::SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond) 6127bf215546Sopenharmony_ci{ 6128bf215546Sopenharmony_ci // Test condition (NB: bit 0 is always true) and clear flags for next time 6129bf215546Sopenharmony_ci if (cond && (window->SetWindowCollapsedAllowFlags & cond) == 0) 6130bf215546Sopenharmony_ci return; 6131bf215546Sopenharmony_ci window->SetWindowCollapsedAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); 6132bf215546Sopenharmony_ci 6133bf215546Sopenharmony_ci // Set 6134bf215546Sopenharmony_ci window->Collapsed = collapsed; 6135bf215546Sopenharmony_ci} 6136bf215546Sopenharmony_ci 6137bf215546Sopenharmony_civoid ImGui::SetWindowCollapsed(bool collapsed, ImGuiCond cond) 6138bf215546Sopenharmony_ci{ 6139bf215546Sopenharmony_ci SetWindowCollapsed(GImGui->CurrentWindow, collapsed, cond); 6140bf215546Sopenharmony_ci} 6141bf215546Sopenharmony_ci 6142bf215546Sopenharmony_cibool ImGui::IsWindowCollapsed() 6143bf215546Sopenharmony_ci{ 6144bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindowRead(); 6145bf215546Sopenharmony_ci return window->Collapsed; 6146bf215546Sopenharmony_ci} 6147bf215546Sopenharmony_ci 6148bf215546Sopenharmony_cibool ImGui::IsWindowAppearing() 6149bf215546Sopenharmony_ci{ 6150bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindowRead(); 6151bf215546Sopenharmony_ci return window->Appearing; 6152bf215546Sopenharmony_ci} 6153bf215546Sopenharmony_ci 6154bf215546Sopenharmony_civoid ImGui::SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond) 6155bf215546Sopenharmony_ci{ 6156bf215546Sopenharmony_ci if (ImGuiWindow* window = FindWindowByName(name)) 6157bf215546Sopenharmony_ci SetWindowCollapsed(window, collapsed, cond); 6158bf215546Sopenharmony_ci} 6159bf215546Sopenharmony_ci 6160bf215546Sopenharmony_civoid ImGui::SetWindowFocus() 6161bf215546Sopenharmony_ci{ 6162bf215546Sopenharmony_ci FocusWindow(GImGui->CurrentWindow); 6163bf215546Sopenharmony_ci} 6164bf215546Sopenharmony_ci 6165bf215546Sopenharmony_civoid ImGui::SetWindowFocus(const char* name) 6166bf215546Sopenharmony_ci{ 6167bf215546Sopenharmony_ci if (name) 6168bf215546Sopenharmony_ci { 6169bf215546Sopenharmony_ci if (ImGuiWindow* window = FindWindowByName(name)) 6170bf215546Sopenharmony_ci FocusWindow(window); 6171bf215546Sopenharmony_ci } 6172bf215546Sopenharmony_ci else 6173bf215546Sopenharmony_ci { 6174bf215546Sopenharmony_ci FocusWindow(NULL); 6175bf215546Sopenharmony_ci } 6176bf215546Sopenharmony_ci} 6177bf215546Sopenharmony_ci 6178bf215546Sopenharmony_civoid ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiCond cond, const ImVec2& pivot) 6179bf215546Sopenharmony_ci{ 6180bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6181bf215546Sopenharmony_ci IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. 6182bf215546Sopenharmony_ci g.NextWindowData.PosVal = pos; 6183bf215546Sopenharmony_ci g.NextWindowData.PosPivotVal = pivot; 6184bf215546Sopenharmony_ci g.NextWindowData.PosCond = cond ? cond : ImGuiCond_Always; 6185bf215546Sopenharmony_ci} 6186bf215546Sopenharmony_ci 6187bf215546Sopenharmony_civoid ImGui::SetNextWindowSize(const ImVec2& size, ImGuiCond cond) 6188bf215546Sopenharmony_ci{ 6189bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6190bf215546Sopenharmony_ci IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. 6191bf215546Sopenharmony_ci g.NextWindowData.SizeVal = size; 6192bf215546Sopenharmony_ci g.NextWindowData.SizeCond = cond ? cond : ImGuiCond_Always; 6193bf215546Sopenharmony_ci} 6194bf215546Sopenharmony_ci 6195bf215546Sopenharmony_civoid ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback, void* custom_callback_user_data) 6196bf215546Sopenharmony_ci{ 6197bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6198bf215546Sopenharmony_ci g.NextWindowData.SizeConstraintCond = ImGuiCond_Always; 6199bf215546Sopenharmony_ci g.NextWindowData.SizeConstraintRect = ImRect(size_min, size_max); 6200bf215546Sopenharmony_ci g.NextWindowData.SizeCallback = custom_callback; 6201bf215546Sopenharmony_ci g.NextWindowData.SizeCallbackUserData = custom_callback_user_data; 6202bf215546Sopenharmony_ci} 6203bf215546Sopenharmony_ci 6204bf215546Sopenharmony_civoid ImGui::SetNextWindowContentSize(const ImVec2& size) 6205bf215546Sopenharmony_ci{ 6206bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6207bf215546Sopenharmony_ci g.NextWindowData.ContentSizeVal = size; // In Begin() we will add the size of window decorations (title bar, menu etc.) to that to form a SizeContents value. 6208bf215546Sopenharmony_ci g.NextWindowData.ContentSizeCond = ImGuiCond_Always; 6209bf215546Sopenharmony_ci} 6210bf215546Sopenharmony_ci 6211bf215546Sopenharmony_civoid ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond) 6212bf215546Sopenharmony_ci{ 6213bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6214bf215546Sopenharmony_ci IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. 6215bf215546Sopenharmony_ci g.NextWindowData.CollapsedVal = collapsed; 6216bf215546Sopenharmony_ci g.NextWindowData.CollapsedCond = cond ? cond : ImGuiCond_Always; 6217bf215546Sopenharmony_ci} 6218bf215546Sopenharmony_ci 6219bf215546Sopenharmony_civoid ImGui::SetNextWindowFocus() 6220bf215546Sopenharmony_ci{ 6221bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6222bf215546Sopenharmony_ci g.NextWindowData.FocusCond = ImGuiCond_Always; // Using a Cond member for consistency (may transition all of them to single flag set for fast Clear() op) 6223bf215546Sopenharmony_ci} 6224bf215546Sopenharmony_ci 6225bf215546Sopenharmony_civoid ImGui::SetNextWindowBgAlpha(float alpha) 6226bf215546Sopenharmony_ci{ 6227bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6228bf215546Sopenharmony_ci g.NextWindowData.BgAlphaVal = alpha; 6229bf215546Sopenharmony_ci g.NextWindowData.BgAlphaCond = ImGuiCond_Always; // Using a Cond member for consistency (may transition all of them to single flag set for fast Clear() op) 6230bf215546Sopenharmony_ci} 6231bf215546Sopenharmony_ci 6232bf215546Sopenharmony_ci// FIXME: This is in window space (not screen space!) 6233bf215546Sopenharmony_ciImVec2 ImGui::GetContentRegionMax() 6234bf215546Sopenharmony_ci{ 6235bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindowRead(); 6236bf215546Sopenharmony_ci ImVec2 mx = window->ContentsRegionRect.Max - window->Pos; 6237bf215546Sopenharmony_ci if (window->DC.ColumnsSet) 6238bf215546Sopenharmony_ci mx.x = GetColumnOffset(window->DC.ColumnsSet->Current + 1) - window->WindowPadding.x; 6239bf215546Sopenharmony_ci return mx; 6240bf215546Sopenharmony_ci} 6241bf215546Sopenharmony_ci 6242bf215546Sopenharmony_ciImVec2 ImGui::GetContentRegionAvail() 6243bf215546Sopenharmony_ci{ 6244bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindowRead(); 6245bf215546Sopenharmony_ci return GetContentRegionMax() - (window->DC.CursorPos - window->Pos); 6246bf215546Sopenharmony_ci} 6247bf215546Sopenharmony_ci 6248bf215546Sopenharmony_cifloat ImGui::GetContentRegionAvailWidth() 6249bf215546Sopenharmony_ci{ 6250bf215546Sopenharmony_ci return GetContentRegionAvail().x; 6251bf215546Sopenharmony_ci} 6252bf215546Sopenharmony_ci 6253bf215546Sopenharmony_ci// In window space (not screen space!) 6254bf215546Sopenharmony_ciImVec2 ImGui::GetWindowContentRegionMin() 6255bf215546Sopenharmony_ci{ 6256bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindowRead(); 6257bf215546Sopenharmony_ci return window->ContentsRegionRect.Min - window->Pos; 6258bf215546Sopenharmony_ci} 6259bf215546Sopenharmony_ci 6260bf215546Sopenharmony_ciImVec2 ImGui::GetWindowContentRegionMax() 6261bf215546Sopenharmony_ci{ 6262bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindowRead(); 6263bf215546Sopenharmony_ci return window->ContentsRegionRect.Max - window->Pos; 6264bf215546Sopenharmony_ci} 6265bf215546Sopenharmony_ci 6266bf215546Sopenharmony_cifloat ImGui::GetWindowContentRegionWidth() 6267bf215546Sopenharmony_ci{ 6268bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindowRead(); 6269bf215546Sopenharmony_ci return window->ContentsRegionRect.GetWidth(); 6270bf215546Sopenharmony_ci} 6271bf215546Sopenharmony_ci 6272bf215546Sopenharmony_cifloat ImGui::GetTextLineHeight() 6273bf215546Sopenharmony_ci{ 6274bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6275bf215546Sopenharmony_ci return g.FontSize; 6276bf215546Sopenharmony_ci} 6277bf215546Sopenharmony_ci 6278bf215546Sopenharmony_cifloat ImGui::GetTextLineHeightWithSpacing() 6279bf215546Sopenharmony_ci{ 6280bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6281bf215546Sopenharmony_ci return g.FontSize + g.Style.ItemSpacing.y; 6282bf215546Sopenharmony_ci} 6283bf215546Sopenharmony_ci 6284bf215546Sopenharmony_cifloat ImGui::GetFrameHeight() 6285bf215546Sopenharmony_ci{ 6286bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6287bf215546Sopenharmony_ci return g.FontSize + g.Style.FramePadding.y * 2.0f; 6288bf215546Sopenharmony_ci} 6289bf215546Sopenharmony_ci 6290bf215546Sopenharmony_cifloat ImGui::GetFrameHeightWithSpacing() 6291bf215546Sopenharmony_ci{ 6292bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6293bf215546Sopenharmony_ci return g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y; 6294bf215546Sopenharmony_ci} 6295bf215546Sopenharmony_ci 6296bf215546Sopenharmony_ciImDrawList* ImGui::GetWindowDrawList() 6297bf215546Sopenharmony_ci{ 6298bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindow(); 6299bf215546Sopenharmony_ci return window->DrawList; 6300bf215546Sopenharmony_ci} 6301bf215546Sopenharmony_ci 6302bf215546Sopenharmony_ciImFont* ImGui::GetFont() 6303bf215546Sopenharmony_ci{ 6304bf215546Sopenharmony_ci return GImGui->Font; 6305bf215546Sopenharmony_ci} 6306bf215546Sopenharmony_ci 6307bf215546Sopenharmony_cifloat ImGui::GetFontSize() 6308bf215546Sopenharmony_ci{ 6309bf215546Sopenharmony_ci return GImGui->FontSize; 6310bf215546Sopenharmony_ci} 6311bf215546Sopenharmony_ci 6312bf215546Sopenharmony_ciImVec2 ImGui::GetFontTexUvWhitePixel() 6313bf215546Sopenharmony_ci{ 6314bf215546Sopenharmony_ci return GImGui->DrawListSharedData.TexUvWhitePixel; 6315bf215546Sopenharmony_ci} 6316bf215546Sopenharmony_ci 6317bf215546Sopenharmony_civoid ImGui::SetWindowFontScale(float scale) 6318bf215546Sopenharmony_ci{ 6319bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6320bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindow(); 6321bf215546Sopenharmony_ci window->FontWindowScale = scale; 6322bf215546Sopenharmony_ci g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize(); 6323bf215546Sopenharmony_ci} 6324bf215546Sopenharmony_ci 6325bf215546Sopenharmony_ci// User generally sees positions in window coordinates. Internally we store CursorPos in absolute screen coordinates because it is more convenient. 6326bf215546Sopenharmony_ci// Conversion happens as we pass the value to user, but it makes our naming convention confusing because GetCursorPos() == (DC.CursorPos - window.Pos). May want to rename 'DC.CursorPos'. 6327bf215546Sopenharmony_ciImVec2 ImGui::GetCursorPos() 6328bf215546Sopenharmony_ci{ 6329bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindowRead(); 6330bf215546Sopenharmony_ci return window->DC.CursorPos - window->Pos + window->Scroll; 6331bf215546Sopenharmony_ci} 6332bf215546Sopenharmony_ci 6333bf215546Sopenharmony_cifloat ImGui::GetCursorPosX() 6334bf215546Sopenharmony_ci{ 6335bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindowRead(); 6336bf215546Sopenharmony_ci return window->DC.CursorPos.x - window->Pos.x + window->Scroll.x; 6337bf215546Sopenharmony_ci} 6338bf215546Sopenharmony_ci 6339bf215546Sopenharmony_cifloat ImGui::GetCursorPosY() 6340bf215546Sopenharmony_ci{ 6341bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindowRead(); 6342bf215546Sopenharmony_ci return window->DC.CursorPos.y - window->Pos.y + window->Scroll.y; 6343bf215546Sopenharmony_ci} 6344bf215546Sopenharmony_ci 6345bf215546Sopenharmony_civoid ImGui::SetCursorPos(const ImVec2& local_pos) 6346bf215546Sopenharmony_ci{ 6347bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindow(); 6348bf215546Sopenharmony_ci window->DC.CursorPos = window->Pos - window->Scroll + local_pos; 6349bf215546Sopenharmony_ci window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos); 6350bf215546Sopenharmony_ci} 6351bf215546Sopenharmony_ci 6352bf215546Sopenharmony_civoid ImGui::SetCursorPosX(float x) 6353bf215546Sopenharmony_ci{ 6354bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindow(); 6355bf215546Sopenharmony_ci window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + x; 6356bf215546Sopenharmony_ci window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPos.x); 6357bf215546Sopenharmony_ci} 6358bf215546Sopenharmony_ci 6359bf215546Sopenharmony_civoid ImGui::SetCursorPosY(float y) 6360bf215546Sopenharmony_ci{ 6361bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindow(); 6362bf215546Sopenharmony_ci window->DC.CursorPos.y = window->Pos.y - window->Scroll.y + y; 6363bf215546Sopenharmony_ci window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y); 6364bf215546Sopenharmony_ci} 6365bf215546Sopenharmony_ci 6366bf215546Sopenharmony_ciImVec2 ImGui::GetCursorStartPos() 6367bf215546Sopenharmony_ci{ 6368bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindowRead(); 6369bf215546Sopenharmony_ci return window->DC.CursorStartPos - window->Pos; 6370bf215546Sopenharmony_ci} 6371bf215546Sopenharmony_ci 6372bf215546Sopenharmony_ciImVec2 ImGui::GetCursorScreenPos() 6373bf215546Sopenharmony_ci{ 6374bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindowRead(); 6375bf215546Sopenharmony_ci return window->DC.CursorPos; 6376bf215546Sopenharmony_ci} 6377bf215546Sopenharmony_ci 6378bf215546Sopenharmony_civoid ImGui::SetCursorScreenPos(const ImVec2& pos) 6379bf215546Sopenharmony_ci{ 6380bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindow(); 6381bf215546Sopenharmony_ci window->DC.CursorPos = pos; 6382bf215546Sopenharmony_ci window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos); 6383bf215546Sopenharmony_ci} 6384bf215546Sopenharmony_ci 6385bf215546Sopenharmony_cifloat ImGui::GetScrollX() 6386bf215546Sopenharmony_ci{ 6387bf215546Sopenharmony_ci return GImGui->CurrentWindow->Scroll.x; 6388bf215546Sopenharmony_ci} 6389bf215546Sopenharmony_ci 6390bf215546Sopenharmony_cifloat ImGui::GetScrollY() 6391bf215546Sopenharmony_ci{ 6392bf215546Sopenharmony_ci return GImGui->CurrentWindow->Scroll.y; 6393bf215546Sopenharmony_ci} 6394bf215546Sopenharmony_ci 6395bf215546Sopenharmony_cifloat ImGui::GetScrollMaxX() 6396bf215546Sopenharmony_ci{ 6397bf215546Sopenharmony_ci return GetWindowScrollMaxX(GImGui->CurrentWindow); 6398bf215546Sopenharmony_ci} 6399bf215546Sopenharmony_ci 6400bf215546Sopenharmony_cifloat ImGui::GetScrollMaxY() 6401bf215546Sopenharmony_ci{ 6402bf215546Sopenharmony_ci return GetWindowScrollMaxY(GImGui->CurrentWindow); 6403bf215546Sopenharmony_ci} 6404bf215546Sopenharmony_ci 6405bf215546Sopenharmony_civoid ImGui::SetScrollX(float scroll_x) 6406bf215546Sopenharmony_ci{ 6407bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindow(); 6408bf215546Sopenharmony_ci window->ScrollTarget.x = scroll_x; 6409bf215546Sopenharmony_ci window->ScrollTargetCenterRatio.x = 0.0f; 6410bf215546Sopenharmony_ci} 6411bf215546Sopenharmony_ci 6412bf215546Sopenharmony_civoid ImGui::SetScrollY(float scroll_y) 6413bf215546Sopenharmony_ci{ 6414bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindow(); 6415bf215546Sopenharmony_ci window->ScrollTarget.y = scroll_y + window->TitleBarHeight() + window->MenuBarHeight(); // title bar height canceled out when using ScrollTargetRelY 6416bf215546Sopenharmony_ci window->ScrollTargetCenterRatio.y = 0.0f; 6417bf215546Sopenharmony_ci} 6418bf215546Sopenharmony_ci 6419bf215546Sopenharmony_civoid ImGui::SetScrollFromPosY(float local_y, float center_y_ratio) 6420bf215546Sopenharmony_ci{ 6421bf215546Sopenharmony_ci // We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size 6422bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindow(); 6423bf215546Sopenharmony_ci IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f); 6424bf215546Sopenharmony_ci window->ScrollTarget.y = (float)(int)(local_y + window->Scroll.y); 6425bf215546Sopenharmony_ci window->ScrollTargetCenterRatio.y = center_y_ratio; 6426bf215546Sopenharmony_ci} 6427bf215546Sopenharmony_ci 6428bf215546Sopenharmony_ci// center_y_ratio: 0.0f top of last item, 0.5f vertical center of last item, 1.0f bottom of last item. 6429bf215546Sopenharmony_civoid ImGui::SetScrollHereY(float center_y_ratio) 6430bf215546Sopenharmony_ci{ 6431bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindow(); 6432bf215546Sopenharmony_ci float target_y = window->DC.CursorPosPrevLine.y - window->Pos.y; // Top of last item, in window space 6433bf215546Sopenharmony_ci target_y += (window->DC.PrevLineSize.y * center_y_ratio) + (GImGui->Style.ItemSpacing.y * (center_y_ratio - 0.5f) * 2.0f); // Precisely aim above, in the middle or below the last line. 6434bf215546Sopenharmony_ci SetScrollFromPosY(target_y, center_y_ratio); 6435bf215546Sopenharmony_ci} 6436bf215546Sopenharmony_ci 6437bf215546Sopenharmony_civoid ImGui::ActivateItem(ImGuiID id) 6438bf215546Sopenharmony_ci{ 6439bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6440bf215546Sopenharmony_ci g.NavNextActivateId = id; 6441bf215546Sopenharmony_ci} 6442bf215546Sopenharmony_ci 6443bf215546Sopenharmony_civoid ImGui::SetKeyboardFocusHere(int offset) 6444bf215546Sopenharmony_ci{ 6445bf215546Sopenharmony_ci IM_ASSERT(offset >= -1); // -1 is allowed but not below 6446bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindow(); 6447bf215546Sopenharmony_ci window->FocusIdxAllRequestNext = window->FocusIdxAllCounter + 1 + offset; 6448bf215546Sopenharmony_ci window->FocusIdxTabRequestNext = INT_MAX; 6449bf215546Sopenharmony_ci} 6450bf215546Sopenharmony_ci 6451bf215546Sopenharmony_civoid ImGui::SetItemDefaultFocus() 6452bf215546Sopenharmony_ci{ 6453bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6454bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 6455bf215546Sopenharmony_ci if (!window->Appearing) 6456bf215546Sopenharmony_ci return; 6457bf215546Sopenharmony_ci if (g.NavWindow == window->RootWindowForNav && (g.NavInitRequest || g.NavInitResultId != 0) && g.NavLayer == g.NavWindow->DC.NavLayerCurrent) 6458bf215546Sopenharmony_ci { 6459bf215546Sopenharmony_ci g.NavInitRequest = false; 6460bf215546Sopenharmony_ci g.NavInitResultId = g.NavWindow->DC.LastItemId; 6461bf215546Sopenharmony_ci g.NavInitResultRectRel = ImRect(g.NavWindow->DC.LastItemRect.Min - g.NavWindow->Pos, g.NavWindow->DC.LastItemRect.Max - g.NavWindow->Pos); 6462bf215546Sopenharmony_ci NavUpdateAnyRequestFlag(); 6463bf215546Sopenharmony_ci if (!IsItemVisible()) 6464bf215546Sopenharmony_ci SetScrollHereY(); 6465bf215546Sopenharmony_ci } 6466bf215546Sopenharmony_ci} 6467bf215546Sopenharmony_ci 6468bf215546Sopenharmony_civoid ImGui::SetStateStorage(ImGuiStorage* tree) 6469bf215546Sopenharmony_ci{ 6470bf215546Sopenharmony_ci ImGuiWindow* window = GImGui->CurrentWindow; 6471bf215546Sopenharmony_ci window->DC.StateStorage = tree ? tree : &window->StateStorage; 6472bf215546Sopenharmony_ci} 6473bf215546Sopenharmony_ci 6474bf215546Sopenharmony_ciImGuiStorage* ImGui::GetStateStorage() 6475bf215546Sopenharmony_ci{ 6476bf215546Sopenharmony_ci ImGuiWindow* window = GImGui->CurrentWindow; 6477bf215546Sopenharmony_ci return window->DC.StateStorage; 6478bf215546Sopenharmony_ci} 6479bf215546Sopenharmony_ci 6480bf215546Sopenharmony_civoid ImGui::PushID(const char* str_id) 6481bf215546Sopenharmony_ci{ 6482bf215546Sopenharmony_ci ImGuiWindow* window = GImGui->CurrentWindow; 6483bf215546Sopenharmony_ci window->IDStack.push_back(window->GetIDNoKeepAlive(str_id)); 6484bf215546Sopenharmony_ci} 6485bf215546Sopenharmony_ci 6486bf215546Sopenharmony_civoid ImGui::PushID(const char* str_id_begin, const char* str_id_end) 6487bf215546Sopenharmony_ci{ 6488bf215546Sopenharmony_ci ImGuiWindow* window = GImGui->CurrentWindow; 6489bf215546Sopenharmony_ci window->IDStack.push_back(window->GetIDNoKeepAlive(str_id_begin, str_id_end)); 6490bf215546Sopenharmony_ci} 6491bf215546Sopenharmony_ci 6492bf215546Sopenharmony_civoid ImGui::PushID(const void* ptr_id) 6493bf215546Sopenharmony_ci{ 6494bf215546Sopenharmony_ci ImGuiWindow* window = GImGui->CurrentWindow; 6495bf215546Sopenharmony_ci window->IDStack.push_back(window->GetIDNoKeepAlive(ptr_id)); 6496bf215546Sopenharmony_ci} 6497bf215546Sopenharmony_ci 6498bf215546Sopenharmony_civoid ImGui::PushID(int int_id) 6499bf215546Sopenharmony_ci{ 6500bf215546Sopenharmony_ci const void* ptr_id = (void*)(intptr_t)int_id; 6501bf215546Sopenharmony_ci ImGuiWindow* window = GImGui->CurrentWindow; 6502bf215546Sopenharmony_ci window->IDStack.push_back(window->GetIDNoKeepAlive(ptr_id)); 6503bf215546Sopenharmony_ci} 6504bf215546Sopenharmony_ci 6505bf215546Sopenharmony_civoid ImGui::PopID() 6506bf215546Sopenharmony_ci{ 6507bf215546Sopenharmony_ci ImGuiWindow* window = GImGui->CurrentWindow; 6508bf215546Sopenharmony_ci window->IDStack.pop_back(); 6509bf215546Sopenharmony_ci} 6510bf215546Sopenharmony_ci 6511bf215546Sopenharmony_ciImGuiID ImGui::GetID(const char* str_id) 6512bf215546Sopenharmony_ci{ 6513bf215546Sopenharmony_ci ImGuiWindow* window = GImGui->CurrentWindow; 6514bf215546Sopenharmony_ci return window->GetID(str_id); 6515bf215546Sopenharmony_ci} 6516bf215546Sopenharmony_ci 6517bf215546Sopenharmony_ciImGuiID ImGui::GetID(const char* str_id_begin, const char* str_id_end) 6518bf215546Sopenharmony_ci{ 6519bf215546Sopenharmony_ci ImGuiWindow* window = GImGui->CurrentWindow; 6520bf215546Sopenharmony_ci return window->GetID(str_id_begin, str_id_end); 6521bf215546Sopenharmony_ci} 6522bf215546Sopenharmony_ci 6523bf215546Sopenharmony_ciImGuiID ImGui::GetID(const void* ptr_id) 6524bf215546Sopenharmony_ci{ 6525bf215546Sopenharmony_ci ImGuiWindow* window = GImGui->CurrentWindow; 6526bf215546Sopenharmony_ci return window->GetID(ptr_id); 6527bf215546Sopenharmony_ci} 6528bf215546Sopenharmony_ci 6529bf215546Sopenharmony_cibool ImGui::IsRectVisible(const ImVec2& size) 6530bf215546Sopenharmony_ci{ 6531bf215546Sopenharmony_ci ImGuiWindow* window = GImGui->CurrentWindow;; 6532bf215546Sopenharmony_ci return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size)); 6533bf215546Sopenharmony_ci} 6534bf215546Sopenharmony_ci 6535bf215546Sopenharmony_cibool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max) 6536bf215546Sopenharmony_ci{ 6537bf215546Sopenharmony_ci ImGuiWindow* window = GImGui->CurrentWindow;; 6538bf215546Sopenharmony_ci return window->ClipRect.Overlaps(ImRect(rect_min, rect_max)); 6539bf215546Sopenharmony_ci} 6540bf215546Sopenharmony_ci 6541bf215546Sopenharmony_ci// Lock horizontal starting position + capture group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.) 6542bf215546Sopenharmony_civoid ImGui::BeginGroup() 6543bf215546Sopenharmony_ci{ 6544bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6545bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindow(); 6546bf215546Sopenharmony_ci 6547bf215546Sopenharmony_ci window->DC.GroupStack.resize(window->DC.GroupStack.Size + 1); 6548bf215546Sopenharmony_ci ImGuiGroupData& group_data = window->DC.GroupStack.back(); 6549bf215546Sopenharmony_ci group_data.BackupCursorPos = window->DC.CursorPos; 6550bf215546Sopenharmony_ci group_data.BackupCursorMaxPos = window->DC.CursorMaxPos; 6551bf215546Sopenharmony_ci group_data.BackupIndent = window->DC.Indent; 6552bf215546Sopenharmony_ci group_data.BackupGroupOffset = window->DC.GroupOffset; 6553bf215546Sopenharmony_ci group_data.BackupCurrentLineSize = window->DC.CurrentLineSize; 6554bf215546Sopenharmony_ci group_data.BackupCurrentLineTextBaseOffset = window->DC.CurrentLineTextBaseOffset; 6555bf215546Sopenharmony_ci group_data.BackupLogLinePosY = window->DC.LogLinePosY; 6556bf215546Sopenharmony_ci group_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive; 6557bf215546Sopenharmony_ci group_data.BackupActiveIdPreviousFrameIsAlive = g.ActiveIdPreviousFrameIsAlive; 6558bf215546Sopenharmony_ci group_data.AdvanceCursor = true; 6559bf215546Sopenharmony_ci 6560bf215546Sopenharmony_ci window->DC.GroupOffset.x = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffset.x; 6561bf215546Sopenharmony_ci window->DC.Indent = window->DC.GroupOffset; 6562bf215546Sopenharmony_ci window->DC.CursorMaxPos = window->DC.CursorPos; 6563bf215546Sopenharmony_ci window->DC.CurrentLineSize = ImVec2(0.0f, 0.0f); 6564bf215546Sopenharmony_ci window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; // To enforce Log carriage return 6565bf215546Sopenharmony_ci} 6566bf215546Sopenharmony_ci 6567bf215546Sopenharmony_civoid ImGui::EndGroup() 6568bf215546Sopenharmony_ci{ 6569bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6570bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindow(); 6571bf215546Sopenharmony_ci IM_ASSERT(!window->DC.GroupStack.empty()); // Mismatched BeginGroup()/EndGroup() calls 6572bf215546Sopenharmony_ci 6573bf215546Sopenharmony_ci ImGuiGroupData& group_data = window->DC.GroupStack.back(); 6574bf215546Sopenharmony_ci 6575bf215546Sopenharmony_ci ImRect group_bb(group_data.BackupCursorPos, window->DC.CursorMaxPos); 6576bf215546Sopenharmony_ci group_bb.Max = ImMax(group_bb.Min, group_bb.Max); 6577bf215546Sopenharmony_ci 6578bf215546Sopenharmony_ci window->DC.CursorPos = group_data.BackupCursorPos; 6579bf215546Sopenharmony_ci window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos); 6580bf215546Sopenharmony_ci window->DC.Indent = group_data.BackupIndent; 6581bf215546Sopenharmony_ci window->DC.GroupOffset = group_data.BackupGroupOffset; 6582bf215546Sopenharmony_ci window->DC.CurrentLineSize = group_data.BackupCurrentLineSize; 6583bf215546Sopenharmony_ci window->DC.CurrentLineTextBaseOffset = group_data.BackupCurrentLineTextBaseOffset; 6584bf215546Sopenharmony_ci window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; // To enforce Log carriage return 6585bf215546Sopenharmony_ci 6586bf215546Sopenharmony_ci if (group_data.AdvanceCursor) 6587bf215546Sopenharmony_ci { 6588bf215546Sopenharmony_ci window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrentLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now. 6589bf215546Sopenharmony_ci ItemSize(group_bb.GetSize(), 0.0f); 6590bf215546Sopenharmony_ci ItemAdd(group_bb, 0); 6591bf215546Sopenharmony_ci } 6592bf215546Sopenharmony_ci 6593bf215546Sopenharmony_ci // If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive(), IsItemDeactivated() etc. will be functional on the entire group. 6594bf215546Sopenharmony_ci // It would be be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but would put a little more burden on individual widgets. 6595bf215546Sopenharmony_ci // (and if you grep for LastItemId you'll notice it is only used in that context. 6596bf215546Sopenharmony_ci if ((group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId) // && g.ActiveIdWindow->RootWindow == window->RootWindow) 6597bf215546Sopenharmony_ci window->DC.LastItemId = g.ActiveId; 6598bf215546Sopenharmony_ci else if (!group_data.BackupActiveIdPreviousFrameIsAlive && g.ActiveIdPreviousFrameIsAlive) // && g.ActiveIdPreviousFrameWindow->RootWindow == window->RootWindow) 6599bf215546Sopenharmony_ci window->DC.LastItemId = g.ActiveIdPreviousFrame; 6600bf215546Sopenharmony_ci window->DC.LastItemRect = group_bb; 6601bf215546Sopenharmony_ci 6602bf215546Sopenharmony_ci window->DC.GroupStack.pop_back(); 6603bf215546Sopenharmony_ci 6604bf215546Sopenharmony_ci //window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // [Debug] 6605bf215546Sopenharmony_ci} 6606bf215546Sopenharmony_ci 6607bf215546Sopenharmony_ci// Gets back to previous line and continue with horizontal layout 6608bf215546Sopenharmony_ci// pos_x == 0 : follow right after previous item 6609bf215546Sopenharmony_ci// pos_x != 0 : align to specified x position (relative to window/group left) 6610bf215546Sopenharmony_ci// spacing_w < 0 : use default spacing if pos_x == 0, no spacing if pos_x != 0 6611bf215546Sopenharmony_ci// spacing_w >= 0 : enforce spacing amount 6612bf215546Sopenharmony_civoid ImGui::SameLine(float pos_x, float spacing_w) 6613bf215546Sopenharmony_ci{ 6614bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindow(); 6615bf215546Sopenharmony_ci if (window->SkipItems) 6616bf215546Sopenharmony_ci return; 6617bf215546Sopenharmony_ci 6618bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6619bf215546Sopenharmony_ci if (pos_x != 0.0f) 6620bf215546Sopenharmony_ci { 6621bf215546Sopenharmony_ci if (spacing_w < 0.0f) spacing_w = 0.0f; 6622bf215546Sopenharmony_ci window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + pos_x + spacing_w + window->DC.GroupOffset.x + window->DC.ColumnsOffset.x; 6623bf215546Sopenharmony_ci window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y; 6624bf215546Sopenharmony_ci } 6625bf215546Sopenharmony_ci else 6626bf215546Sopenharmony_ci { 6627bf215546Sopenharmony_ci if (spacing_w < 0.0f) spacing_w = g.Style.ItemSpacing.x; 6628bf215546Sopenharmony_ci window->DC.CursorPos.x = window->DC.CursorPosPrevLine.x + spacing_w; 6629bf215546Sopenharmony_ci window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y; 6630bf215546Sopenharmony_ci } 6631bf215546Sopenharmony_ci window->DC.CurrentLineSize = window->DC.PrevLineSize; 6632bf215546Sopenharmony_ci window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset; 6633bf215546Sopenharmony_ci} 6634bf215546Sopenharmony_ci 6635bf215546Sopenharmony_civoid ImGui::Indent(float indent_w) 6636bf215546Sopenharmony_ci{ 6637bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6638bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindow(); 6639bf215546Sopenharmony_ci window->DC.Indent.x += (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing; 6640bf215546Sopenharmony_ci window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x; 6641bf215546Sopenharmony_ci} 6642bf215546Sopenharmony_ci 6643bf215546Sopenharmony_civoid ImGui::Unindent(float indent_w) 6644bf215546Sopenharmony_ci{ 6645bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6646bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindow(); 6647bf215546Sopenharmony_ci window->DC.Indent.x -= (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing; 6648bf215546Sopenharmony_ci window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x; 6649bf215546Sopenharmony_ci} 6650bf215546Sopenharmony_ci 6651bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 6652bf215546Sopenharmony_ci// [SECTION] TOOLTIPS 6653bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 6654bf215546Sopenharmony_ci 6655bf215546Sopenharmony_civoid ImGui::BeginTooltip() 6656bf215546Sopenharmony_ci{ 6657bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6658bf215546Sopenharmony_ci if (g.DragDropWithinSourceOrTarget) 6659bf215546Sopenharmony_ci { 6660bf215546Sopenharmony_ci // The default tooltip position is a little offset to give space to see the context menu (it's also clamped within the current viewport/monitor) 6661bf215546Sopenharmony_ci // In the context of a dragging tooltip we try to reduce that offset and we enforce following the cursor. 6662bf215546Sopenharmony_ci // Whatever we do we want to call SetNextWindowPos() to enforce a tooltip position and disable clipping the tooltip without our display area, like regular tooltip do. 6663bf215546Sopenharmony_ci //ImVec2 tooltip_pos = g.IO.MousePos - g.ActiveIdClickOffset - g.Style.WindowPadding; 6664bf215546Sopenharmony_ci ImVec2 tooltip_pos = g.IO.MousePos + ImVec2(16 * g.Style.MouseCursorScale, 8 * g.Style.MouseCursorScale); 6665bf215546Sopenharmony_ci SetNextWindowPos(tooltip_pos); 6666bf215546Sopenharmony_ci SetNextWindowBgAlpha(g.Style.Colors[ImGuiCol_PopupBg].w * 0.60f); 6667bf215546Sopenharmony_ci //PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * 0.60f); // This would be nice but e.g ColorButton with checkboard has issue with transparent colors :( 6668bf215546Sopenharmony_ci BeginTooltipEx(0, true); 6669bf215546Sopenharmony_ci } 6670bf215546Sopenharmony_ci else 6671bf215546Sopenharmony_ci { 6672bf215546Sopenharmony_ci BeginTooltipEx(0, false); 6673bf215546Sopenharmony_ci } 6674bf215546Sopenharmony_ci} 6675bf215546Sopenharmony_ci 6676bf215546Sopenharmony_ci// Not exposed publicly as BeginTooltip() because bool parameters are evil. Let's see if other needs arise first. 6677bf215546Sopenharmony_civoid ImGui::BeginTooltipEx(ImGuiWindowFlags extra_flags, bool override_previous_tooltip) 6678bf215546Sopenharmony_ci{ 6679bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6680bf215546Sopenharmony_ci char window_name[16]; 6681bf215546Sopenharmony_ci ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", g.TooltipOverrideCount); 6682bf215546Sopenharmony_ci if (override_previous_tooltip) 6683bf215546Sopenharmony_ci if (ImGuiWindow* window = FindWindowByName(window_name)) 6684bf215546Sopenharmony_ci if (window->Active) 6685bf215546Sopenharmony_ci { 6686bf215546Sopenharmony_ci // Hide previous tooltip from being displayed. We can't easily "reset" the content of a window so we create a new one. 6687bf215546Sopenharmony_ci window->Hidden = true; 6688bf215546Sopenharmony_ci window->HiddenFramesRegular = 1; 6689bf215546Sopenharmony_ci ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", ++g.TooltipOverrideCount); 6690bf215546Sopenharmony_ci } 6691bf215546Sopenharmony_ci ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip|ImGuiWindowFlags_NoInputs|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize; 6692bf215546Sopenharmony_ci Begin(window_name, NULL, flags | extra_flags); 6693bf215546Sopenharmony_ci} 6694bf215546Sopenharmony_ci 6695bf215546Sopenharmony_civoid ImGui::EndTooltip() 6696bf215546Sopenharmony_ci{ 6697bf215546Sopenharmony_ci IM_ASSERT(GetCurrentWindowRead()->Flags & ImGuiWindowFlags_Tooltip); // Mismatched BeginTooltip()/EndTooltip() calls 6698bf215546Sopenharmony_ci End(); 6699bf215546Sopenharmony_ci} 6700bf215546Sopenharmony_ci 6701bf215546Sopenharmony_civoid ImGui::SetTooltipV(const char* fmt, va_list args) 6702bf215546Sopenharmony_ci{ 6703bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6704bf215546Sopenharmony_ci if (g.DragDropWithinSourceOrTarget) 6705bf215546Sopenharmony_ci BeginTooltip(); 6706bf215546Sopenharmony_ci else 6707bf215546Sopenharmony_ci BeginTooltipEx(0, true); 6708bf215546Sopenharmony_ci TextV(fmt, args); 6709bf215546Sopenharmony_ci EndTooltip(); 6710bf215546Sopenharmony_ci} 6711bf215546Sopenharmony_ci 6712bf215546Sopenharmony_civoid ImGui::SetTooltip(const char* fmt, ...) 6713bf215546Sopenharmony_ci{ 6714bf215546Sopenharmony_ci va_list args; 6715bf215546Sopenharmony_ci va_start(args, fmt); 6716bf215546Sopenharmony_ci SetTooltipV(fmt, args); 6717bf215546Sopenharmony_ci va_end(args); 6718bf215546Sopenharmony_ci} 6719bf215546Sopenharmony_ci 6720bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 6721bf215546Sopenharmony_ci// [SECTION] POPUPS 6722bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 6723bf215546Sopenharmony_ci 6724bf215546Sopenharmony_cibool ImGui::IsPopupOpen(ImGuiID id) 6725bf215546Sopenharmony_ci{ 6726bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6727bf215546Sopenharmony_ci return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == id; 6728bf215546Sopenharmony_ci} 6729bf215546Sopenharmony_ci 6730bf215546Sopenharmony_cibool ImGui::IsPopupOpen(const char* str_id) 6731bf215546Sopenharmony_ci{ 6732bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6733bf215546Sopenharmony_ci return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == g.CurrentWindow->GetID(str_id); 6734bf215546Sopenharmony_ci} 6735bf215546Sopenharmony_ci 6736bf215546Sopenharmony_ciImGuiWindow* ImGui::GetFrontMostPopupModal() 6737bf215546Sopenharmony_ci{ 6738bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6739bf215546Sopenharmony_ci for (int n = g.OpenPopupStack.Size-1; n >= 0; n--) 6740bf215546Sopenharmony_ci if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window) 6741bf215546Sopenharmony_ci if (popup->Flags & ImGuiWindowFlags_Modal) 6742bf215546Sopenharmony_ci return popup; 6743bf215546Sopenharmony_ci return NULL; 6744bf215546Sopenharmony_ci} 6745bf215546Sopenharmony_ci 6746bf215546Sopenharmony_civoid ImGui::OpenPopup(const char* str_id) 6747bf215546Sopenharmony_ci{ 6748bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6749bf215546Sopenharmony_ci OpenPopupEx(g.CurrentWindow->GetID(str_id)); 6750bf215546Sopenharmony_ci} 6751bf215546Sopenharmony_ci 6752bf215546Sopenharmony_ci// Mark popup as open (toggle toward open state). 6753bf215546Sopenharmony_ci// Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. 6754bf215546Sopenharmony_ci// Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). 6755bf215546Sopenharmony_ci// One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL) 6756bf215546Sopenharmony_civoid ImGui::OpenPopupEx(ImGuiID id) 6757bf215546Sopenharmony_ci{ 6758bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6759bf215546Sopenharmony_ci ImGuiWindow* parent_window = g.CurrentWindow; 6760bf215546Sopenharmony_ci int current_stack_size = g.BeginPopupStack.Size; 6761bf215546Sopenharmony_ci ImGuiPopupRef popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack. 6762bf215546Sopenharmony_ci popup_ref.PopupId = id; 6763bf215546Sopenharmony_ci popup_ref.Window = NULL; 6764bf215546Sopenharmony_ci popup_ref.ParentWindow = parent_window; 6765bf215546Sopenharmony_ci popup_ref.OpenFrameCount = g.FrameCount; 6766bf215546Sopenharmony_ci popup_ref.OpenParentId = parent_window->IDStack.back(); 6767bf215546Sopenharmony_ci popup_ref.OpenPopupPos = NavCalcPreferredRefPos(); 6768bf215546Sopenharmony_ci popup_ref.OpenMousePos = IsMousePosValid(&g.IO.MousePos) ? g.IO.MousePos : popup_ref.OpenPopupPos; 6769bf215546Sopenharmony_ci 6770bf215546Sopenharmony_ci //IMGUI_DEBUG_LOG("OpenPopupEx(0x%08X)\n", g.FrameCount, id); 6771bf215546Sopenharmony_ci if (g.OpenPopupStack.Size < current_stack_size + 1) 6772bf215546Sopenharmony_ci { 6773bf215546Sopenharmony_ci g.OpenPopupStack.push_back(popup_ref); 6774bf215546Sopenharmony_ci } 6775bf215546Sopenharmony_ci else 6776bf215546Sopenharmony_ci { 6777bf215546Sopenharmony_ci // Gently handle the user mistakenly calling OpenPopup() every frame. It is a programming mistake! However, if we were to run the regular code path, the ui 6778bf215546Sopenharmony_ci // would become completely unusable because the popup will always be in hidden-while-calculating-size state _while_ claiming focus. Which would be a very confusing 6779bf215546Sopenharmony_ci // situation for the programmer. Instead, we silently allow the popup to proceed, it will keep reappearing and the programming error will be more obvious to understand. 6780bf215546Sopenharmony_ci if (g.OpenPopupStack[current_stack_size].PopupId == id && g.OpenPopupStack[current_stack_size].OpenFrameCount == g.FrameCount - 1) 6781bf215546Sopenharmony_ci { 6782bf215546Sopenharmony_ci g.OpenPopupStack[current_stack_size].OpenFrameCount = popup_ref.OpenFrameCount; 6783bf215546Sopenharmony_ci } 6784bf215546Sopenharmony_ci else 6785bf215546Sopenharmony_ci { 6786bf215546Sopenharmony_ci // Close child popups if any, then flag popup for open/reopen 6787bf215546Sopenharmony_ci g.OpenPopupStack.resize(current_stack_size + 1); 6788bf215546Sopenharmony_ci g.OpenPopupStack[current_stack_size] = popup_ref; 6789bf215546Sopenharmony_ci } 6790bf215546Sopenharmony_ci 6791bf215546Sopenharmony_ci // When reopening a popup we first refocus its parent, otherwise if its parent is itself a popup it would get closed by ClosePopupsOverWindow(). 6792bf215546Sopenharmony_ci // This is equivalent to what ClosePopupToLevel() does. 6793bf215546Sopenharmony_ci //if (g.OpenPopupStack[current_stack_size].PopupId == id) 6794bf215546Sopenharmony_ci // FocusWindow(parent_window); 6795bf215546Sopenharmony_ci } 6796bf215546Sopenharmony_ci} 6797bf215546Sopenharmony_ci 6798bf215546Sopenharmony_cibool ImGui::OpenPopupOnItemClick(const char* str_id, int mouse_button) 6799bf215546Sopenharmony_ci{ 6800bf215546Sopenharmony_ci ImGuiWindow* window = GImGui->CurrentWindow; 6801bf215546Sopenharmony_ci if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) 6802bf215546Sopenharmony_ci { 6803bf215546Sopenharmony_ci ImGuiID id = str_id ? window->GetID(str_id) : window->DC.LastItemId; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict! 6804bf215546Sopenharmony_ci IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item) 6805bf215546Sopenharmony_ci OpenPopupEx(id); 6806bf215546Sopenharmony_ci return true; 6807bf215546Sopenharmony_ci } 6808bf215546Sopenharmony_ci return false; 6809bf215546Sopenharmony_ci} 6810bf215546Sopenharmony_ci 6811bf215546Sopenharmony_civoid ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window) 6812bf215546Sopenharmony_ci{ 6813bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6814bf215546Sopenharmony_ci if (g.OpenPopupStack.empty()) 6815bf215546Sopenharmony_ci return; 6816bf215546Sopenharmony_ci 6817bf215546Sopenharmony_ci // When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it. 6818bf215546Sopenharmony_ci // Don't close our own child popup windows. 6819bf215546Sopenharmony_ci int popup_count_to_keep = 0; 6820bf215546Sopenharmony_ci if (ref_window) 6821bf215546Sopenharmony_ci { 6822bf215546Sopenharmony_ci // Find the highest popup which is a descendant of the reference window (generally reference window = NavWindow) 6823bf215546Sopenharmony_ci for (; popup_count_to_keep < g.OpenPopupStack.Size; popup_count_to_keep++) 6824bf215546Sopenharmony_ci { 6825bf215546Sopenharmony_ci ImGuiPopupRef& popup = g.OpenPopupStack[popup_count_to_keep]; 6826bf215546Sopenharmony_ci if (!popup.Window) 6827bf215546Sopenharmony_ci continue; 6828bf215546Sopenharmony_ci IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0); 6829bf215546Sopenharmony_ci if (popup.Window->Flags & ImGuiWindowFlags_ChildWindow) 6830bf215546Sopenharmony_ci continue; 6831bf215546Sopenharmony_ci 6832bf215546Sopenharmony_ci // Trim the stack if popups are not direct descendant of the reference window (which is often the NavWindow) 6833bf215546Sopenharmony_ci bool popup_or_descendent_has_focus = false; 6834bf215546Sopenharmony_ci for (int m = popup_count_to_keep; m < g.OpenPopupStack.Size && !popup_or_descendent_has_focus; m++) 6835bf215546Sopenharmony_ci if (g.OpenPopupStack[m].Window && g.OpenPopupStack[m].Window->RootWindow == ref_window->RootWindow) 6836bf215546Sopenharmony_ci popup_or_descendent_has_focus = true; 6837bf215546Sopenharmony_ci if (!popup_or_descendent_has_focus) 6838bf215546Sopenharmony_ci break; 6839bf215546Sopenharmony_ci } 6840bf215546Sopenharmony_ci } 6841bf215546Sopenharmony_ci if (popup_count_to_keep < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the statement below 6842bf215546Sopenharmony_ci { 6843bf215546Sopenharmony_ci //IMGUI_DEBUG_LOG("ClosePopupsOverWindow(%s) -> ClosePopupToLevel(%d)\n", ref_window->Name, popup_count_to_keep); 6844bf215546Sopenharmony_ci ClosePopupToLevel(popup_count_to_keep, false); 6845bf215546Sopenharmony_ci } 6846bf215546Sopenharmony_ci} 6847bf215546Sopenharmony_ci 6848bf215546Sopenharmony_civoid ImGui::ClosePopupToLevel(int remaining, bool apply_focus_to_window_under) 6849bf215546Sopenharmony_ci{ 6850bf215546Sopenharmony_ci IM_ASSERT(remaining >= 0); 6851bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6852bf215546Sopenharmony_ci ImGuiWindow* focus_window = (remaining > 0) ? g.OpenPopupStack[remaining-1].Window : g.OpenPopupStack[0].ParentWindow; 6853bf215546Sopenharmony_ci g.OpenPopupStack.resize(remaining); 6854bf215546Sopenharmony_ci 6855bf215546Sopenharmony_ci // FIXME: This code is faulty and we may want to eventually to replace or remove the 'apply_focus_to_window_under=true' path completely. 6856bf215546Sopenharmony_ci // Instead of using g.OpenPopupStack[remaining-1].Window etc. we should find the highest root window that is behind the popups we are closing. 6857bf215546Sopenharmony_ci // The current code will set focus to the parent of the popup window which is incorrect. 6858bf215546Sopenharmony_ci // It rarely manifested until now because UpdateMouseMovingWindowNewFrame() would call FocusWindow() again on the clicked window, 6859bf215546Sopenharmony_ci // leading to a chain of focusing A (clicked window) then B (parent window of the popup) then A again. 6860bf215546Sopenharmony_ci // However if the clicked window has the _NoMove flag set we would be left with B focused. 6861bf215546Sopenharmony_ci // For now, we have disabled this path when called from ClosePopupsOverWindow() because the users of ClosePopupsOverWindow() don't need to alter focus anyway, 6862bf215546Sopenharmony_ci // but we should inspect and fix this properly. 6863bf215546Sopenharmony_ci if (apply_focus_to_window_under) 6864bf215546Sopenharmony_ci { 6865bf215546Sopenharmony_ci if (g.NavLayer == 0) 6866bf215546Sopenharmony_ci focus_window = NavRestoreLastChildNavWindow(focus_window); 6867bf215546Sopenharmony_ci FocusWindow(focus_window); 6868bf215546Sopenharmony_ci } 6869bf215546Sopenharmony_ci} 6870bf215546Sopenharmony_ci 6871bf215546Sopenharmony_ci// Close the popup we have begin-ed into. 6872bf215546Sopenharmony_civoid ImGui::CloseCurrentPopup() 6873bf215546Sopenharmony_ci{ 6874bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6875bf215546Sopenharmony_ci int popup_idx = g.BeginPopupStack.Size - 1; 6876bf215546Sopenharmony_ci if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.BeginPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId) 6877bf215546Sopenharmony_ci return; 6878bf215546Sopenharmony_ci 6879bf215546Sopenharmony_ci // Closing a menu closes its top-most parent popup (unless a modal) 6880bf215546Sopenharmony_ci while (popup_idx > 0) 6881bf215546Sopenharmony_ci { 6882bf215546Sopenharmony_ci ImGuiWindow* popup_window = g.OpenPopupStack[popup_idx].Window; 6883bf215546Sopenharmony_ci ImGuiWindow* parent_popup_window = g.OpenPopupStack[popup_idx - 1].Window; 6884bf215546Sopenharmony_ci bool close_parent = false; 6885bf215546Sopenharmony_ci if (popup_window && (popup_window->Flags & ImGuiWindowFlags_ChildMenu)) 6886bf215546Sopenharmony_ci if (parent_popup_window == NULL || !(parent_popup_window->Flags & ImGuiWindowFlags_Modal)) 6887bf215546Sopenharmony_ci close_parent = true; 6888bf215546Sopenharmony_ci if (!close_parent) 6889bf215546Sopenharmony_ci break; 6890bf215546Sopenharmony_ci popup_idx--; 6891bf215546Sopenharmony_ci } 6892bf215546Sopenharmony_ci //IMGUI_DEBUG_LOG("CloseCurrentPopup %d -> %d\n", g.BeginPopupStack.Size - 1, popup_idx); 6893bf215546Sopenharmony_ci ClosePopupToLevel(popup_idx, true); 6894bf215546Sopenharmony_ci 6895bf215546Sopenharmony_ci // A common pattern is to close a popup when selecting a menu item/selectable that will open another window. 6896bf215546Sopenharmony_ci // To improve this usage pattern, we avoid nav highlight for a single frame in the parent window. 6897bf215546Sopenharmony_ci // Similarly, we could avoid mouse hover highlight in this window but it is less visually problematic. 6898bf215546Sopenharmony_ci if (ImGuiWindow* window = g.NavWindow) 6899bf215546Sopenharmony_ci window->DC.NavHideHighlightOneFrame = true; 6900bf215546Sopenharmony_ci} 6901bf215546Sopenharmony_ci 6902bf215546Sopenharmony_cibool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags) 6903bf215546Sopenharmony_ci{ 6904bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6905bf215546Sopenharmony_ci if (!IsPopupOpen(id)) 6906bf215546Sopenharmony_ci { 6907bf215546Sopenharmony_ci g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values 6908bf215546Sopenharmony_ci return false; 6909bf215546Sopenharmony_ci } 6910bf215546Sopenharmony_ci 6911bf215546Sopenharmony_ci char name[20]; 6912bf215546Sopenharmony_ci if (extra_flags & ImGuiWindowFlags_ChildMenu) 6913bf215546Sopenharmony_ci ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.BeginPopupStack.Size); // Recycle windows based on depth 6914bf215546Sopenharmony_ci else 6915bf215546Sopenharmony_ci ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame 6916bf215546Sopenharmony_ci 6917bf215546Sopenharmony_ci bool is_open = Begin(name, NULL, extra_flags | ImGuiWindowFlags_Popup); 6918bf215546Sopenharmony_ci if (!is_open) // NB: Begin can return false when the popup is completely clipped (e.g. zero size display) 6919bf215546Sopenharmony_ci EndPopup(); 6920bf215546Sopenharmony_ci 6921bf215546Sopenharmony_ci return is_open; 6922bf215546Sopenharmony_ci} 6923bf215546Sopenharmony_ci 6924bf215546Sopenharmony_cibool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags) 6925bf215546Sopenharmony_ci{ 6926bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6927bf215546Sopenharmony_ci if (g.OpenPopupStack.Size <= g.BeginPopupStack.Size) // Early out for performance 6928bf215546Sopenharmony_ci { 6929bf215546Sopenharmony_ci g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values 6930bf215546Sopenharmony_ci return false; 6931bf215546Sopenharmony_ci } 6932bf215546Sopenharmony_ci flags |= ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings; 6933bf215546Sopenharmony_ci return BeginPopupEx(g.CurrentWindow->GetID(str_id), flags); 6934bf215546Sopenharmony_ci} 6935bf215546Sopenharmony_ci 6936bf215546Sopenharmony_ci// If 'p_open' is specified for a modal popup window, the popup will have a regular close button which will close the popup. 6937bf215546Sopenharmony_ci// Note that popup visibility status is owned by imgui (and manipulated with e.g. OpenPopup) so the actual value of *p_open is meaningless here. 6938bf215546Sopenharmony_cibool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags) 6939bf215546Sopenharmony_ci{ 6940bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6941bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 6942bf215546Sopenharmony_ci const ImGuiID id = window->GetID(name); 6943bf215546Sopenharmony_ci if (!IsPopupOpen(id)) 6944bf215546Sopenharmony_ci { 6945bf215546Sopenharmony_ci g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values 6946bf215546Sopenharmony_ci return false; 6947bf215546Sopenharmony_ci } 6948bf215546Sopenharmony_ci 6949bf215546Sopenharmony_ci // Center modal windows by default 6950bf215546Sopenharmony_ci // FIXME: Should test for (PosCond & window->SetWindowPosAllowFlags) with the upcoming window. 6951bf215546Sopenharmony_ci if (g.NextWindowData.PosCond == 0) 6952bf215546Sopenharmony_ci SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); 6953bf215546Sopenharmony_ci 6954bf215546Sopenharmony_ci flags |= ImGuiWindowFlags_Popup | ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings; 6955bf215546Sopenharmony_ci const bool is_open = Begin(name, p_open, flags); 6956bf215546Sopenharmony_ci if (!is_open || (p_open && !*p_open)) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display) 6957bf215546Sopenharmony_ci { 6958bf215546Sopenharmony_ci EndPopup(); 6959bf215546Sopenharmony_ci if (is_open) 6960bf215546Sopenharmony_ci ClosePopupToLevel(g.BeginPopupStack.Size, true); 6961bf215546Sopenharmony_ci return false; 6962bf215546Sopenharmony_ci } 6963bf215546Sopenharmony_ci return is_open; 6964bf215546Sopenharmony_ci} 6965bf215546Sopenharmony_ci 6966bf215546Sopenharmony_civoid ImGui::EndPopup() 6967bf215546Sopenharmony_ci{ 6968bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 6969bf215546Sopenharmony_ci IM_ASSERT(g.CurrentWindow->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls 6970bf215546Sopenharmony_ci IM_ASSERT(g.BeginPopupStack.Size > 0); 6971bf215546Sopenharmony_ci 6972bf215546Sopenharmony_ci // Make all menus and popups wrap around for now, may need to expose that policy. 6973bf215546Sopenharmony_ci NavMoveRequestTryWrapping(g.CurrentWindow, ImGuiNavMoveFlags_LoopY); 6974bf215546Sopenharmony_ci 6975bf215546Sopenharmony_ci End(); 6976bf215546Sopenharmony_ci} 6977bf215546Sopenharmony_ci 6978bf215546Sopenharmony_ci// This is a helper to handle the simplest case of associating one named popup to one given widget. 6979bf215546Sopenharmony_ci// You may want to handle this on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters). 6980bf215546Sopenharmony_ci// You can pass a NULL str_id to use the identifier of the last item. 6981bf215546Sopenharmony_cibool ImGui::BeginPopupContextItem(const char* str_id, int mouse_button) 6982bf215546Sopenharmony_ci{ 6983bf215546Sopenharmony_ci ImGuiWindow* window = GImGui->CurrentWindow; 6984bf215546Sopenharmony_ci ImGuiID id = str_id ? window->GetID(str_id) : window->DC.LastItemId; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict! 6985bf215546Sopenharmony_ci IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item) 6986bf215546Sopenharmony_ci if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) 6987bf215546Sopenharmony_ci OpenPopupEx(id); 6988bf215546Sopenharmony_ci return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings); 6989bf215546Sopenharmony_ci} 6990bf215546Sopenharmony_ci 6991bf215546Sopenharmony_cibool ImGui::BeginPopupContextWindow(const char* str_id, int mouse_button, bool also_over_items) 6992bf215546Sopenharmony_ci{ 6993bf215546Sopenharmony_ci if (!str_id) 6994bf215546Sopenharmony_ci str_id = "window_context"; 6995bf215546Sopenharmony_ci ImGuiID id = GImGui->CurrentWindow->GetID(str_id); 6996bf215546Sopenharmony_ci if (IsMouseReleased(mouse_button) && IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) 6997bf215546Sopenharmony_ci if (also_over_items || !IsAnyItemHovered()) 6998bf215546Sopenharmony_ci OpenPopupEx(id); 6999bf215546Sopenharmony_ci return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings); 7000bf215546Sopenharmony_ci} 7001bf215546Sopenharmony_ci 7002bf215546Sopenharmony_cibool ImGui::BeginPopupContextVoid(const char* str_id, int mouse_button) 7003bf215546Sopenharmony_ci{ 7004bf215546Sopenharmony_ci if (!str_id) 7005bf215546Sopenharmony_ci str_id = "void_context"; 7006bf215546Sopenharmony_ci ImGuiID id = GImGui->CurrentWindow->GetID(str_id); 7007bf215546Sopenharmony_ci if (IsMouseReleased(mouse_button) && !IsWindowHovered(ImGuiHoveredFlags_AnyWindow)) 7008bf215546Sopenharmony_ci OpenPopupEx(id); 7009bf215546Sopenharmony_ci return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings); 7010bf215546Sopenharmony_ci} 7011bf215546Sopenharmony_ci 7012bf215546Sopenharmony_ciImRect ImGui::GetWindowAllowedExtentRect(ImGuiWindow*) 7013bf215546Sopenharmony_ci{ 7014bf215546Sopenharmony_ci ImVec2 padding = GImGui->Style.DisplaySafeAreaPadding; 7015bf215546Sopenharmony_ci ImRect r_screen = GetViewportRect(); 7016bf215546Sopenharmony_ci r_screen.Expand(ImVec2((r_screen.GetWidth() > padding.x * 2) ? -padding.x : 0.0f, (r_screen.GetHeight() > padding.y * 2) ? -padding.y : 0.0f)); 7017bf215546Sopenharmony_ci return r_screen; 7018bf215546Sopenharmony_ci} 7019bf215546Sopenharmony_ci 7020bf215546Sopenharmony_ci// r_avoid = the rectangle to avoid (e.g. for tooltip it is a rectangle around the mouse cursor which we want to avoid. for popups it's a small point around the cursor.) 7021bf215546Sopenharmony_ci// r_outer = the visible area rectangle, minus safe area padding. If our popup size won't fit because of safe area padding we ignore it. 7022bf215546Sopenharmony_ciImVec2 ImGui::FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy) 7023bf215546Sopenharmony_ci{ 7024bf215546Sopenharmony_ci ImVec2 base_pos_clamped = ImClamp(ref_pos, r_outer.Min, r_outer.Max - size); 7025bf215546Sopenharmony_ci //GImGui->OverlayDrawList.AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255,0,0,255)); 7026bf215546Sopenharmony_ci //GImGui->OverlayDrawList.AddRect(r_outer.Min, r_outer.Max, IM_COL32(0,255,0,255)); 7027bf215546Sopenharmony_ci 7028bf215546Sopenharmony_ci // Combo Box policy (we want a connecting edge) 7029bf215546Sopenharmony_ci if (policy == ImGuiPopupPositionPolicy_ComboBox) 7030bf215546Sopenharmony_ci { 7031bf215546Sopenharmony_ci const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Down, ImGuiDir_Right, ImGuiDir_Left, ImGuiDir_Up }; 7032bf215546Sopenharmony_ci for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++) 7033bf215546Sopenharmony_ci { 7034bf215546Sopenharmony_ci const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n]; 7035bf215546Sopenharmony_ci if (n != -1 && dir == *last_dir) // Already tried this direction? 7036bf215546Sopenharmony_ci continue; 7037bf215546Sopenharmony_ci ImVec2 pos; 7038bf215546Sopenharmony_ci if (dir == ImGuiDir_Down) pos = ImVec2(r_avoid.Min.x, r_avoid.Max.y); // Below, Toward Right (default) 7039bf215546Sopenharmony_ci if (dir == ImGuiDir_Right) pos = ImVec2(r_avoid.Min.x, r_avoid.Min.y - size.y); // Above, Toward Right 7040bf215546Sopenharmony_ci if (dir == ImGuiDir_Left) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Max.y); // Below, Toward Left 7041bf215546Sopenharmony_ci if (dir == ImGuiDir_Up) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Min.y - size.y); // Above, Toward Left 7042bf215546Sopenharmony_ci if (!r_outer.Contains(ImRect(pos, pos + size))) 7043bf215546Sopenharmony_ci continue; 7044bf215546Sopenharmony_ci *last_dir = dir; 7045bf215546Sopenharmony_ci return pos; 7046bf215546Sopenharmony_ci } 7047bf215546Sopenharmony_ci } 7048bf215546Sopenharmony_ci 7049bf215546Sopenharmony_ci // Default popup policy 7050bf215546Sopenharmony_ci const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Right, ImGuiDir_Down, ImGuiDir_Up, ImGuiDir_Left }; 7051bf215546Sopenharmony_ci for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++) 7052bf215546Sopenharmony_ci { 7053bf215546Sopenharmony_ci const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n]; 7054bf215546Sopenharmony_ci if (n != -1 && dir == *last_dir) // Already tried this direction? 7055bf215546Sopenharmony_ci continue; 7056bf215546Sopenharmony_ci float avail_w = (dir == ImGuiDir_Left ? r_avoid.Min.x : r_outer.Max.x) - (dir == ImGuiDir_Right ? r_avoid.Max.x : r_outer.Min.x); 7057bf215546Sopenharmony_ci float avail_h = (dir == ImGuiDir_Up ? r_avoid.Min.y : r_outer.Max.y) - (dir == ImGuiDir_Down ? r_avoid.Max.y : r_outer.Min.y); 7058bf215546Sopenharmony_ci if (avail_w < size.x || avail_h < size.y) 7059bf215546Sopenharmony_ci continue; 7060bf215546Sopenharmony_ci ImVec2 pos; 7061bf215546Sopenharmony_ci pos.x = (dir == ImGuiDir_Left) ? r_avoid.Min.x - size.x : (dir == ImGuiDir_Right) ? r_avoid.Max.x : base_pos_clamped.x; 7062bf215546Sopenharmony_ci pos.y = (dir == ImGuiDir_Up) ? r_avoid.Min.y - size.y : (dir == ImGuiDir_Down) ? r_avoid.Max.y : base_pos_clamped.y; 7063bf215546Sopenharmony_ci *last_dir = dir; 7064bf215546Sopenharmony_ci return pos; 7065bf215546Sopenharmony_ci } 7066bf215546Sopenharmony_ci 7067bf215546Sopenharmony_ci // Fallback, try to keep within display 7068bf215546Sopenharmony_ci *last_dir = ImGuiDir_None; 7069bf215546Sopenharmony_ci ImVec2 pos = ref_pos; 7070bf215546Sopenharmony_ci pos.x = ImMax(ImMin(pos.x + size.x, r_outer.Max.x) - size.x, r_outer.Min.x); 7071bf215546Sopenharmony_ci pos.y = ImMax(ImMin(pos.y + size.y, r_outer.Max.y) - size.y, r_outer.Min.y); 7072bf215546Sopenharmony_ci return pos; 7073bf215546Sopenharmony_ci} 7074bf215546Sopenharmony_ci 7075bf215546Sopenharmony_ciImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window) 7076bf215546Sopenharmony_ci{ 7077bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 7078bf215546Sopenharmony_ci 7079bf215546Sopenharmony_ci ImRect r_outer = GetWindowAllowedExtentRect(window); 7080bf215546Sopenharmony_ci if (window->Flags & ImGuiWindowFlags_ChildMenu) 7081bf215546Sopenharmony_ci { 7082bf215546Sopenharmony_ci // Child menus typically request _any_ position within the parent menu item, and then we move the new menu outside the parent bounds. 7083bf215546Sopenharmony_ci // This is how we end up with child menus appearing (most-commonly) on the right of the parent menu. 7084bf215546Sopenharmony_ci IM_ASSERT(g.CurrentWindow == window); 7085bf215546Sopenharmony_ci ImGuiWindow* parent_window = g.CurrentWindowStack[g.CurrentWindowStack.Size - 2]; 7086bf215546Sopenharmony_ci float horizontal_overlap = g.Style.ItemInnerSpacing.x; // We want some overlap to convey the relative depth of each menu (currently the amount of overlap is hard-coded to style.ItemSpacing.x). 7087bf215546Sopenharmony_ci ImRect r_avoid; 7088bf215546Sopenharmony_ci if (parent_window->DC.MenuBarAppending) 7089bf215546Sopenharmony_ci r_avoid = ImRect(-FLT_MAX, parent_window->Pos.y + parent_window->TitleBarHeight(), FLT_MAX, parent_window->Pos.y + parent_window->TitleBarHeight() + parent_window->MenuBarHeight()); 7090bf215546Sopenharmony_ci else 7091bf215546Sopenharmony_ci r_avoid = ImRect(parent_window->Pos.x + horizontal_overlap, -FLT_MAX, parent_window->Pos.x + parent_window->Size.x - horizontal_overlap - parent_window->ScrollbarSizes.x, FLT_MAX); 7092bf215546Sopenharmony_ci return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid); 7093bf215546Sopenharmony_ci } 7094bf215546Sopenharmony_ci if (window->Flags & ImGuiWindowFlags_Popup) 7095bf215546Sopenharmony_ci { 7096bf215546Sopenharmony_ci ImRect r_avoid = ImRect(window->Pos.x - 1, window->Pos.y - 1, window->Pos.x + 1, window->Pos.y + 1); 7097bf215546Sopenharmony_ci return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid); 7098bf215546Sopenharmony_ci } 7099bf215546Sopenharmony_ci if (window->Flags & ImGuiWindowFlags_Tooltip) 7100bf215546Sopenharmony_ci { 7101bf215546Sopenharmony_ci // Position tooltip (always follows mouse) 7102bf215546Sopenharmony_ci float sc = g.Style.MouseCursorScale; 7103bf215546Sopenharmony_ci ImVec2 ref_pos = NavCalcPreferredRefPos(); 7104bf215546Sopenharmony_ci ImRect r_avoid; 7105bf215546Sopenharmony_ci if (!g.NavDisableHighlight && g.NavDisableMouseHover && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos)) 7106bf215546Sopenharmony_ci r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8); 7107bf215546Sopenharmony_ci else 7108bf215546Sopenharmony_ci r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 24 * sc, ref_pos.y + 24 * sc); // FIXME: Hard-coded based on mouse cursor shape expectation. Exact dimension not very important. 7109bf215546Sopenharmony_ci ImVec2 pos = FindBestWindowPosForPopupEx(ref_pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid); 7110bf215546Sopenharmony_ci if (window->AutoPosLastDirection == ImGuiDir_None) 7111bf215546Sopenharmony_ci pos = ref_pos + ImVec2(2, 2); // If there's not enough room, for tooltip we prefer avoiding the cursor at all cost even if it means that part of the tooltip won't be visible. 7112bf215546Sopenharmony_ci return pos; 7113bf215546Sopenharmony_ci } 7114bf215546Sopenharmony_ci IM_ASSERT(0); 7115bf215546Sopenharmony_ci return window->Pos; 7116bf215546Sopenharmony_ci} 7117bf215546Sopenharmony_ci 7118bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 7119bf215546Sopenharmony_ci// [SECTION] VIEWPORTS, PLATFORM WINDOWS 7120bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 7121bf215546Sopenharmony_ci 7122bf215546Sopenharmony_ci// (this section is filled in the 'viewport' and 'docking' branches) 7123bf215546Sopenharmony_ci 7124bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 7125bf215546Sopenharmony_ci// [SECTION] KEYBOARD/GAMEPAD NAVIGATION 7126bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 7127bf215546Sopenharmony_ci 7128bf215546Sopenharmony_ciImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy) 7129bf215546Sopenharmony_ci{ 7130bf215546Sopenharmony_ci if (ImFabs(dx) > ImFabs(dy)) 7131bf215546Sopenharmony_ci return (dx > 0.0f) ? ImGuiDir_Right : ImGuiDir_Left; 7132bf215546Sopenharmony_ci return (dy > 0.0f) ? ImGuiDir_Down : ImGuiDir_Up; 7133bf215546Sopenharmony_ci} 7134bf215546Sopenharmony_ci 7135bf215546Sopenharmony_cistatic float inline NavScoreItemDistInterval(float a0, float a1, float b0, float b1) 7136bf215546Sopenharmony_ci{ 7137bf215546Sopenharmony_ci if (a1 < b0) 7138bf215546Sopenharmony_ci return a1 - b0; 7139bf215546Sopenharmony_ci if (b1 < a0) 7140bf215546Sopenharmony_ci return a0 - b1; 7141bf215546Sopenharmony_ci return 0.0f; 7142bf215546Sopenharmony_ci} 7143bf215546Sopenharmony_ci 7144bf215546Sopenharmony_cistatic void inline NavClampRectToVisibleAreaForMoveDir(ImGuiDir move_dir, ImRect& r, const ImRect& clip_rect) 7145bf215546Sopenharmony_ci{ 7146bf215546Sopenharmony_ci if (move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right) 7147bf215546Sopenharmony_ci { 7148bf215546Sopenharmony_ci r.Min.y = ImClamp(r.Min.y, clip_rect.Min.y, clip_rect.Max.y); 7149bf215546Sopenharmony_ci r.Max.y = ImClamp(r.Max.y, clip_rect.Min.y, clip_rect.Max.y); 7150bf215546Sopenharmony_ci } 7151bf215546Sopenharmony_ci else 7152bf215546Sopenharmony_ci { 7153bf215546Sopenharmony_ci r.Min.x = ImClamp(r.Min.x, clip_rect.Min.x, clip_rect.Max.x); 7154bf215546Sopenharmony_ci r.Max.x = ImClamp(r.Max.x, clip_rect.Min.x, clip_rect.Max.x); 7155bf215546Sopenharmony_ci } 7156bf215546Sopenharmony_ci} 7157bf215546Sopenharmony_ci 7158bf215546Sopenharmony_ci// Scoring function for directional navigation. Based on https://gist.github.com/rygorous/6981057 7159bf215546Sopenharmony_cistatic bool NavScoreItem(ImGuiNavMoveResult* result, ImRect cand) 7160bf215546Sopenharmony_ci{ 7161bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 7162bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 7163bf215546Sopenharmony_ci if (g.NavLayer != window->DC.NavLayerCurrent) 7164bf215546Sopenharmony_ci return false; 7165bf215546Sopenharmony_ci 7166bf215546Sopenharmony_ci const ImRect& curr = g.NavScoringRectScreen; // Current modified source rect (NB: we've applied Max.x = Min.x in NavUpdate() to inhibit the effect of having varied item width) 7167bf215546Sopenharmony_ci g.NavScoringCount++; 7168bf215546Sopenharmony_ci 7169bf215546Sopenharmony_ci // When entering through a NavFlattened border, we consider child window items as fully clipped for scoring 7170bf215546Sopenharmony_ci if (window->ParentWindow == g.NavWindow) 7171bf215546Sopenharmony_ci { 7172bf215546Sopenharmony_ci IM_ASSERT((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened); 7173bf215546Sopenharmony_ci if (!window->ClipRect.Contains(cand)) 7174bf215546Sopenharmony_ci return false; 7175bf215546Sopenharmony_ci cand.ClipWithFull(window->ClipRect); // This allows the scored item to not overlap other candidates in the parent window 7176bf215546Sopenharmony_ci } 7177bf215546Sopenharmony_ci 7178bf215546Sopenharmony_ci // We perform scoring on items bounding box clipped by the current clipping rectangle on the other axis (clipping on our movement axis would give us equal scores for all clipped items) 7179bf215546Sopenharmony_ci // For example, this ensure that items in one column are not reached when moving vertically from items in another column. 7180bf215546Sopenharmony_ci NavClampRectToVisibleAreaForMoveDir(g.NavMoveClipDir, cand, window->ClipRect); 7181bf215546Sopenharmony_ci 7182bf215546Sopenharmony_ci // Compute distance between boxes 7183bf215546Sopenharmony_ci // FIXME-NAV: Introducing biases for vertical navigation, needs to be removed. 7184bf215546Sopenharmony_ci float dbx = NavScoreItemDistInterval(cand.Min.x, cand.Max.x, curr.Min.x, curr.Max.x); 7185bf215546Sopenharmony_ci float dby = NavScoreItemDistInterval(ImLerp(cand.Min.y, cand.Max.y, 0.2f), ImLerp(cand.Min.y, cand.Max.y, 0.8f), ImLerp(curr.Min.y, curr.Max.y, 0.2f), ImLerp(curr.Min.y, curr.Max.y, 0.8f)); // Scale down on Y to keep using box-distance for vertically touching items 7186bf215546Sopenharmony_ci if (dby != 0.0f && dbx != 0.0f) 7187bf215546Sopenharmony_ci dbx = (dbx/1000.0f) + ((dbx > 0.0f) ? +1.0f : -1.0f); 7188bf215546Sopenharmony_ci float dist_box = ImFabs(dbx) + ImFabs(dby); 7189bf215546Sopenharmony_ci 7190bf215546Sopenharmony_ci // Compute distance between centers (this is off by a factor of 2, but we only compare center distances with each other so it doesn't matter) 7191bf215546Sopenharmony_ci float dcx = (cand.Min.x + cand.Max.x) - (curr.Min.x + curr.Max.x); 7192bf215546Sopenharmony_ci float dcy = (cand.Min.y + cand.Max.y) - (curr.Min.y + curr.Max.y); 7193bf215546Sopenharmony_ci float dist_center = ImFabs(dcx) + ImFabs(dcy); // L1 metric (need this for our connectedness guarantee) 7194bf215546Sopenharmony_ci 7195bf215546Sopenharmony_ci // Determine which quadrant of 'curr' our candidate item 'cand' lies in based on distance 7196bf215546Sopenharmony_ci ImGuiDir quadrant; 7197bf215546Sopenharmony_ci float dax = 0.0f, day = 0.0f, dist_axial = 0.0f; 7198bf215546Sopenharmony_ci if (dbx != 0.0f || dby != 0.0f) 7199bf215546Sopenharmony_ci { 7200bf215546Sopenharmony_ci // For non-overlapping boxes, use distance between boxes 7201bf215546Sopenharmony_ci dax = dbx; 7202bf215546Sopenharmony_ci day = dby; 7203bf215546Sopenharmony_ci dist_axial = dist_box; 7204bf215546Sopenharmony_ci quadrant = ImGetDirQuadrantFromDelta(dbx, dby); 7205bf215546Sopenharmony_ci } 7206bf215546Sopenharmony_ci else if (dcx != 0.0f || dcy != 0.0f) 7207bf215546Sopenharmony_ci { 7208bf215546Sopenharmony_ci // For overlapping boxes with different centers, use distance between centers 7209bf215546Sopenharmony_ci dax = dcx; 7210bf215546Sopenharmony_ci day = dcy; 7211bf215546Sopenharmony_ci dist_axial = dist_center; 7212bf215546Sopenharmony_ci quadrant = ImGetDirQuadrantFromDelta(dcx, dcy); 7213bf215546Sopenharmony_ci } 7214bf215546Sopenharmony_ci else 7215bf215546Sopenharmony_ci { 7216bf215546Sopenharmony_ci // Degenerate case: two overlapping buttons with same center, break ties arbitrarily (note that LastItemId here is really the _previous_ item order, but it doesn't matter) 7217bf215546Sopenharmony_ci quadrant = (window->DC.LastItemId < g.NavId) ? ImGuiDir_Left : ImGuiDir_Right; 7218bf215546Sopenharmony_ci } 7219bf215546Sopenharmony_ci 7220bf215546Sopenharmony_ci#if IMGUI_DEBUG_NAV_SCORING 7221bf215546Sopenharmony_ci char buf[128]; 7222bf215546Sopenharmony_ci if (ImGui::IsMouseHoveringRect(cand.Min, cand.Max)) 7223bf215546Sopenharmony_ci { 7224bf215546Sopenharmony_ci ImFormatString(buf, IM_ARRAYSIZE(buf), "dbox (%.2f,%.2f->%.4f)\ndcen (%.2f,%.2f->%.4f)\nd (%.2f,%.2f->%.4f)\nnav %c, quadrant %c", dbx, dby, dist_box, dcx, dcy, dist_center, dax, day, dist_axial, "WENS"[g.NavMoveDir], "WENS"[quadrant]); 7225bf215546Sopenharmony_ci ImDrawList* draw_list = ImGui::GetOverlayDrawList(window); 7226bf215546Sopenharmony_ci draw_list->AddRect(curr.Min, curr.Max, IM_COL32(255,200,0,100)); 7227bf215546Sopenharmony_ci draw_list->AddRect(cand.Min, cand.Max, IM_COL32(255,255,0,200)); 7228bf215546Sopenharmony_ci draw_list->AddRectFilled(cand.Max-ImVec2(4,4), cand.Max+ImGui::CalcTextSize(buf)+ImVec2(4,4), IM_COL32(40,0,0,150)); 7229bf215546Sopenharmony_ci draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Max, ~0U, buf); 7230bf215546Sopenharmony_ci } 7231bf215546Sopenharmony_ci else if (g.IO.KeyCtrl) // Hold to preview score in matching quadrant. Press C to rotate. 7232bf215546Sopenharmony_ci { 7233bf215546Sopenharmony_ci if (ImGui::IsKeyPressedMap(ImGuiKey_C)) { g.NavMoveDirLast = (ImGuiDir)((g.NavMoveDirLast + 1) & 3); g.IO.KeysDownDuration[g.IO.KeyMap[ImGuiKey_C]] = 0.01f; } 7234bf215546Sopenharmony_ci if (quadrant == g.NavMoveDir) 7235bf215546Sopenharmony_ci { 7236bf215546Sopenharmony_ci ImFormatString(buf, IM_ARRAYSIZE(buf), "%.0f/%.0f", dist_box, dist_center); 7237bf215546Sopenharmony_ci ImDrawList* draw_list = ImGui::GetOverlayDrawList(window); 7238bf215546Sopenharmony_ci draw_list->AddRectFilled(cand.Min, cand.Max, IM_COL32(255, 0, 0, 200)); 7239bf215546Sopenharmony_ci draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Min, IM_COL32(255, 255, 255, 255), buf); 7240bf215546Sopenharmony_ci } 7241bf215546Sopenharmony_ci } 7242bf215546Sopenharmony_ci #endif 7243bf215546Sopenharmony_ci 7244bf215546Sopenharmony_ci // Is it in the quadrant we're interesting in moving to? 7245bf215546Sopenharmony_ci bool new_best = false; 7246bf215546Sopenharmony_ci if (quadrant == g.NavMoveDir) 7247bf215546Sopenharmony_ci { 7248bf215546Sopenharmony_ci // Does it beat the current best candidate? 7249bf215546Sopenharmony_ci if (dist_box < result->DistBox) 7250bf215546Sopenharmony_ci { 7251bf215546Sopenharmony_ci result->DistBox = dist_box; 7252bf215546Sopenharmony_ci result->DistCenter = dist_center; 7253bf215546Sopenharmony_ci return true; 7254bf215546Sopenharmony_ci } 7255bf215546Sopenharmony_ci if (dist_box == result->DistBox) 7256bf215546Sopenharmony_ci { 7257bf215546Sopenharmony_ci // Try using distance between center points to break ties 7258bf215546Sopenharmony_ci if (dist_center < result->DistCenter) 7259bf215546Sopenharmony_ci { 7260bf215546Sopenharmony_ci result->DistCenter = dist_center; 7261bf215546Sopenharmony_ci new_best = true; 7262bf215546Sopenharmony_ci } 7263bf215546Sopenharmony_ci else if (dist_center == result->DistCenter) 7264bf215546Sopenharmony_ci { 7265bf215546Sopenharmony_ci // Still tied! we need to be extra-careful to make sure everything gets linked properly. We consistently break ties by symbolically moving "later" items 7266bf215546Sopenharmony_ci // (with higher index) to the right/downwards by an infinitesimal amount since we the current "best" button already (so it must have a lower index), 7267bf215546Sopenharmony_ci // this is fairly easy. This rule ensures that all buttons with dx==dy==0 will end up being linked in order of appearance along the x axis. 7268bf215546Sopenharmony_ci if (((g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? dby : dbx) < 0.0f) // moving bj to the right/down decreases distance 7269bf215546Sopenharmony_ci new_best = true; 7270bf215546Sopenharmony_ci } 7271bf215546Sopenharmony_ci } 7272bf215546Sopenharmony_ci } 7273bf215546Sopenharmony_ci 7274bf215546Sopenharmony_ci // Axial check: if 'curr' has no link at all in some direction and 'cand' lies roughly in that direction, add a tentative link. This will only be kept if no "real" matches 7275bf215546Sopenharmony_ci // are found, so it only augments the graph produced by the above method using extra links. (important, since it doesn't guarantee strong connectedness) 7276bf215546Sopenharmony_ci // This is just to avoid buttons having no links in a particular direction when there's a suitable neighbor. you get good graphs without this too. 7277bf215546Sopenharmony_ci // 2017/09/29: FIXME: This now currently only enabled inside menu bars, ideally we'd disable it everywhere. Menus in particular need to catch failure. For general navigation it feels awkward. 7278bf215546Sopenharmony_ci // Disabling it may lead to disconnected graphs when nodes are very spaced out on different axis. Perhaps consider offering this as an option? 7279bf215546Sopenharmony_ci if (result->DistBox == FLT_MAX && dist_axial < result->DistAxial) // Check axial match 7280bf215546Sopenharmony_ci if (g.NavLayer == 1 && !(g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu)) 7281bf215546Sopenharmony_ci if ((g.NavMoveDir == ImGuiDir_Left && dax < 0.0f) || (g.NavMoveDir == ImGuiDir_Right && dax > 0.0f) || (g.NavMoveDir == ImGuiDir_Up && day < 0.0f) || (g.NavMoveDir == ImGuiDir_Down && day > 0.0f)) 7282bf215546Sopenharmony_ci { 7283bf215546Sopenharmony_ci result->DistAxial = dist_axial; 7284bf215546Sopenharmony_ci new_best = true; 7285bf215546Sopenharmony_ci } 7286bf215546Sopenharmony_ci 7287bf215546Sopenharmony_ci return new_best; 7288bf215546Sopenharmony_ci} 7289bf215546Sopenharmony_ci 7290bf215546Sopenharmony_ci// We get there when either NavId == id, or when g.NavAnyRequest is set (which is updated by NavUpdateAnyRequestFlag above) 7291bf215546Sopenharmony_cistatic void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, const ImGuiID id) 7292bf215546Sopenharmony_ci{ 7293bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 7294bf215546Sopenharmony_ci //if (!g.IO.NavActive) // [2017/10/06] Removed this possibly redundant test but I am not sure of all the side-effects yet. Some of the feature here will need to work regardless of using a _NoNavInputs flag. 7295bf215546Sopenharmony_ci // return; 7296bf215546Sopenharmony_ci 7297bf215546Sopenharmony_ci const ImGuiItemFlags item_flags = window->DC.ItemFlags; 7298bf215546Sopenharmony_ci const ImRect nav_bb_rel(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos); 7299bf215546Sopenharmony_ci 7300bf215546Sopenharmony_ci // Process Init Request 7301bf215546Sopenharmony_ci if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent) 7302bf215546Sopenharmony_ci { 7303bf215546Sopenharmony_ci // Even if 'ImGuiItemFlags_NoNavDefaultFocus' is on (typically collapse/close button) we record the first ResultId so they can be used as a fallback 7304bf215546Sopenharmony_ci if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus) || g.NavInitResultId == 0) 7305bf215546Sopenharmony_ci { 7306bf215546Sopenharmony_ci g.NavInitResultId = id; 7307bf215546Sopenharmony_ci g.NavInitResultRectRel = nav_bb_rel; 7308bf215546Sopenharmony_ci } 7309bf215546Sopenharmony_ci if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus)) 7310bf215546Sopenharmony_ci { 7311bf215546Sopenharmony_ci g.NavInitRequest = false; // Found a match, clear request 7312bf215546Sopenharmony_ci NavUpdateAnyRequestFlag(); 7313bf215546Sopenharmony_ci } 7314bf215546Sopenharmony_ci } 7315bf215546Sopenharmony_ci 7316bf215546Sopenharmony_ci // Process Move Request (scoring for navigation) 7317bf215546Sopenharmony_ci // FIXME-NAV: Consider policy for double scoring (scoring from NavScoringRectScreen + scoring from a rect wrapped according to current wrapping policy) 7318bf215546Sopenharmony_ci if ((g.NavId != id || (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AllowCurrentNavId)) && !(item_flags & ImGuiItemFlags_NoNav)) 7319bf215546Sopenharmony_ci { 7320bf215546Sopenharmony_ci ImGuiNavMoveResult* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther; 7321bf215546Sopenharmony_ci#if IMGUI_DEBUG_NAV_SCORING 7322bf215546Sopenharmony_ci // [DEBUG] Score all items in NavWindow at all times 7323bf215546Sopenharmony_ci if (!g.NavMoveRequest) 7324bf215546Sopenharmony_ci g.NavMoveDir = g.NavMoveDirLast; 7325bf215546Sopenharmony_ci bool new_best = NavScoreItem(result, nav_bb) && g.NavMoveRequest; 7326bf215546Sopenharmony_ci#else 7327bf215546Sopenharmony_ci bool new_best = g.NavMoveRequest && NavScoreItem(result, nav_bb); 7328bf215546Sopenharmony_ci#endif 7329bf215546Sopenharmony_ci if (new_best) 7330bf215546Sopenharmony_ci { 7331bf215546Sopenharmony_ci result->ID = id; 7332bf215546Sopenharmony_ci result->SelectScopeId = g.MultiSelectScopeId; 7333bf215546Sopenharmony_ci result->Window = window; 7334bf215546Sopenharmony_ci result->RectRel = nav_bb_rel; 7335bf215546Sopenharmony_ci } 7336bf215546Sopenharmony_ci 7337bf215546Sopenharmony_ci const float VISIBLE_RATIO = 0.70f; 7338bf215546Sopenharmony_ci if ((g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) && window->ClipRect.Overlaps(nav_bb)) 7339bf215546Sopenharmony_ci if (ImClamp(nav_bb.Max.y, window->ClipRect.Min.y, window->ClipRect.Max.y) - ImClamp(nav_bb.Min.y, window->ClipRect.Min.y, window->ClipRect.Max.y) >= (nav_bb.Max.y - nav_bb.Min.y) * VISIBLE_RATIO) 7340bf215546Sopenharmony_ci if (NavScoreItem(&g.NavMoveResultLocalVisibleSet, nav_bb)) 7341bf215546Sopenharmony_ci { 7342bf215546Sopenharmony_ci result = &g.NavMoveResultLocalVisibleSet; 7343bf215546Sopenharmony_ci result->ID = id; 7344bf215546Sopenharmony_ci result->SelectScopeId = g.MultiSelectScopeId; 7345bf215546Sopenharmony_ci result->Window = window; 7346bf215546Sopenharmony_ci result->RectRel = nav_bb_rel; 7347bf215546Sopenharmony_ci } 7348bf215546Sopenharmony_ci } 7349bf215546Sopenharmony_ci 7350bf215546Sopenharmony_ci // Update window-relative bounding box of navigated item 7351bf215546Sopenharmony_ci if (g.NavId == id) 7352bf215546Sopenharmony_ci { 7353bf215546Sopenharmony_ci g.NavWindow = window; // Always refresh g.NavWindow, because some operations such as FocusItem() don't have a window. 7354bf215546Sopenharmony_ci g.NavLayer = window->DC.NavLayerCurrent; 7355bf215546Sopenharmony_ci g.NavIdIsAlive = true; 7356bf215546Sopenharmony_ci g.NavIdTabCounter = window->FocusIdxTabCounter; 7357bf215546Sopenharmony_ci window->NavRectRel[window->DC.NavLayerCurrent] = nav_bb_rel; // Store item bounding box (relative to window position) 7358bf215546Sopenharmony_ci } 7359bf215546Sopenharmony_ci} 7360bf215546Sopenharmony_ci 7361bf215546Sopenharmony_cibool ImGui::NavMoveRequestButNoResultYet() 7362bf215546Sopenharmony_ci{ 7363bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 7364bf215546Sopenharmony_ci return g.NavMoveRequest && g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0; 7365bf215546Sopenharmony_ci} 7366bf215546Sopenharmony_ci 7367bf215546Sopenharmony_civoid ImGui::NavMoveRequestCancel() 7368bf215546Sopenharmony_ci{ 7369bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 7370bf215546Sopenharmony_ci g.NavMoveRequest = false; 7371bf215546Sopenharmony_ci NavUpdateAnyRequestFlag(); 7372bf215546Sopenharmony_ci} 7373bf215546Sopenharmony_ci 7374bf215546Sopenharmony_civoid ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, const ImRect& bb_rel, ImGuiNavMoveFlags move_flags) 7375bf215546Sopenharmony_ci{ 7376bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 7377bf215546Sopenharmony_ci IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_None); 7378bf215546Sopenharmony_ci ImGui::NavMoveRequestCancel(); 7379bf215546Sopenharmony_ci g.NavMoveDir = move_dir; 7380bf215546Sopenharmony_ci g.NavMoveClipDir = clip_dir; 7381bf215546Sopenharmony_ci g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued; 7382bf215546Sopenharmony_ci g.NavMoveRequestFlags = move_flags; 7383bf215546Sopenharmony_ci g.NavWindow->NavRectRel[g.NavLayer] = bb_rel; 7384bf215546Sopenharmony_ci} 7385bf215546Sopenharmony_ci 7386bf215546Sopenharmony_civoid ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags) 7387bf215546Sopenharmony_ci{ 7388bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 7389bf215546Sopenharmony_ci if (g.NavWindow != window || !NavMoveRequestButNoResultYet() || g.NavMoveRequestForward != ImGuiNavForward_None || g.NavLayer != 0) 7390bf215546Sopenharmony_ci return; 7391bf215546Sopenharmony_ci IM_ASSERT(move_flags != 0); // No points calling this with no wrapping 7392bf215546Sopenharmony_ci ImRect bb_rel = window->NavRectRel[0]; 7393bf215546Sopenharmony_ci 7394bf215546Sopenharmony_ci ImGuiDir clip_dir = g.NavMoveDir; 7395bf215546Sopenharmony_ci if (g.NavMoveDir == ImGuiDir_Left && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX))) 7396bf215546Sopenharmony_ci { 7397bf215546Sopenharmony_ci bb_rel.Min.x = bb_rel.Max.x = ImMax(window->SizeFull.x, window->SizeContents.x) - window->Scroll.x; 7398bf215546Sopenharmony_ci if (move_flags & ImGuiNavMoveFlags_WrapX) { bb_rel.TranslateY(-bb_rel.GetHeight()); clip_dir = ImGuiDir_Up; } 7399bf215546Sopenharmony_ci NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); 7400bf215546Sopenharmony_ci } 7401bf215546Sopenharmony_ci if (g.NavMoveDir == ImGuiDir_Right && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX))) 7402bf215546Sopenharmony_ci { 7403bf215546Sopenharmony_ci bb_rel.Min.x = bb_rel.Max.x = -window->Scroll.x; 7404bf215546Sopenharmony_ci if (move_flags & ImGuiNavMoveFlags_WrapX) { bb_rel.TranslateY(+bb_rel.GetHeight()); clip_dir = ImGuiDir_Down; } 7405bf215546Sopenharmony_ci NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); 7406bf215546Sopenharmony_ci } 7407bf215546Sopenharmony_ci if (g.NavMoveDir == ImGuiDir_Up && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY))) 7408bf215546Sopenharmony_ci { 7409bf215546Sopenharmony_ci bb_rel.Min.y = bb_rel.Max.y = ImMax(window->SizeFull.y, window->SizeContents.y) - window->Scroll.y; 7410bf215546Sopenharmony_ci if (move_flags & ImGuiNavMoveFlags_WrapY) { bb_rel.TranslateX(-bb_rel.GetWidth()); clip_dir = ImGuiDir_Left; } 7411bf215546Sopenharmony_ci NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); 7412bf215546Sopenharmony_ci } 7413bf215546Sopenharmony_ci if (g.NavMoveDir == ImGuiDir_Down && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY))) 7414bf215546Sopenharmony_ci { 7415bf215546Sopenharmony_ci bb_rel.Min.y = bb_rel.Max.y = -window->Scroll.y; 7416bf215546Sopenharmony_ci if (move_flags & ImGuiNavMoveFlags_WrapY) { bb_rel.TranslateX(+bb_rel.GetWidth()); clip_dir = ImGuiDir_Right; } 7417bf215546Sopenharmony_ci NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); 7418bf215546Sopenharmony_ci } 7419bf215546Sopenharmony_ci} 7420bf215546Sopenharmony_ci 7421bf215546Sopenharmony_cistatic void ImGui::NavSaveLastChildNavWindow(ImGuiWindow* nav_window) 7422bf215546Sopenharmony_ci{ 7423bf215546Sopenharmony_ci ImGuiWindow* parent_window = nav_window; 7424bf215546Sopenharmony_ci while (parent_window && (parent_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 && (parent_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0) 7425bf215546Sopenharmony_ci parent_window = parent_window->ParentWindow; 7426bf215546Sopenharmony_ci if (parent_window && parent_window != nav_window) 7427bf215546Sopenharmony_ci parent_window->NavLastChildNavWindow = nav_window; 7428bf215546Sopenharmony_ci} 7429bf215546Sopenharmony_ci 7430bf215546Sopenharmony_ci// Call when we are expected to land on Layer 0 after FocusWindow() 7431bf215546Sopenharmony_cistatic ImGuiWindow* ImGui::NavRestoreLastChildNavWindow(ImGuiWindow* window) 7432bf215546Sopenharmony_ci{ 7433bf215546Sopenharmony_ci return window->NavLastChildNavWindow ? window->NavLastChildNavWindow : window; 7434bf215546Sopenharmony_ci} 7435bf215546Sopenharmony_ci 7436bf215546Sopenharmony_cistatic void NavRestoreLayer(ImGuiNavLayer layer) 7437bf215546Sopenharmony_ci{ 7438bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 7439bf215546Sopenharmony_ci g.NavLayer = layer; 7440bf215546Sopenharmony_ci if (layer == 0) 7441bf215546Sopenharmony_ci g.NavWindow = ImGui::NavRestoreLastChildNavWindow(g.NavWindow); 7442bf215546Sopenharmony_ci if (layer == 0 && g.NavWindow->NavLastIds[0] != 0) 7443bf215546Sopenharmony_ci ImGui::SetNavIDWithRectRel(g.NavWindow->NavLastIds[0], layer, g.NavWindow->NavRectRel[0]); 7444bf215546Sopenharmony_ci else 7445bf215546Sopenharmony_ci ImGui::NavInitWindow(g.NavWindow, true); 7446bf215546Sopenharmony_ci} 7447bf215546Sopenharmony_ci 7448bf215546Sopenharmony_cistatic inline void ImGui::NavUpdateAnyRequestFlag() 7449bf215546Sopenharmony_ci{ 7450bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 7451bf215546Sopenharmony_ci g.NavAnyRequest = g.NavMoveRequest || g.NavInitRequest || (IMGUI_DEBUG_NAV_SCORING && g.NavWindow != NULL); 7452bf215546Sopenharmony_ci if (g.NavAnyRequest) 7453bf215546Sopenharmony_ci IM_ASSERT(g.NavWindow != NULL); 7454bf215546Sopenharmony_ci} 7455bf215546Sopenharmony_ci 7456bf215546Sopenharmony_ci// This needs to be called before we submit any widget (aka in or before Begin) 7457bf215546Sopenharmony_civoid ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit) 7458bf215546Sopenharmony_ci{ 7459bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 7460bf215546Sopenharmony_ci IM_ASSERT(window == g.NavWindow); 7461bf215546Sopenharmony_ci bool init_for_nav = false; 7462bf215546Sopenharmony_ci if (!(window->Flags & ImGuiWindowFlags_NoNavInputs)) 7463bf215546Sopenharmony_ci if (!(window->Flags & ImGuiWindowFlags_ChildWindow) || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit) 7464bf215546Sopenharmony_ci init_for_nav = true; 7465bf215546Sopenharmony_ci if (init_for_nav) 7466bf215546Sopenharmony_ci { 7467bf215546Sopenharmony_ci SetNavID(0, g.NavLayer); 7468bf215546Sopenharmony_ci g.NavInitRequest = true; 7469bf215546Sopenharmony_ci g.NavInitRequestFromMove = false; 7470bf215546Sopenharmony_ci g.NavInitResultId = 0; 7471bf215546Sopenharmony_ci g.NavInitResultRectRel = ImRect(); 7472bf215546Sopenharmony_ci NavUpdateAnyRequestFlag(); 7473bf215546Sopenharmony_ci } 7474bf215546Sopenharmony_ci else 7475bf215546Sopenharmony_ci { 7476bf215546Sopenharmony_ci g.NavId = window->NavLastIds[0]; 7477bf215546Sopenharmony_ci } 7478bf215546Sopenharmony_ci} 7479bf215546Sopenharmony_ci 7480bf215546Sopenharmony_cistatic ImVec2 ImGui::NavCalcPreferredRefPos() 7481bf215546Sopenharmony_ci{ 7482bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 7483bf215546Sopenharmony_ci if (g.NavDisableHighlight || !g.NavDisableMouseHover || !g.NavWindow) 7484bf215546Sopenharmony_ci { 7485bf215546Sopenharmony_ci // Mouse (we need a fallback in case the mouse becomes invalid after being used) 7486bf215546Sopenharmony_ci if (IsMousePosValid(&g.IO.MousePos)) 7487bf215546Sopenharmony_ci return g.IO.MousePos; 7488bf215546Sopenharmony_ci return g.LastValidMousePos; 7489bf215546Sopenharmony_ci } 7490bf215546Sopenharmony_ci else 7491bf215546Sopenharmony_ci { 7492bf215546Sopenharmony_ci // When navigation is active and mouse is disabled, decide on an arbitrary position around the bottom left of the currently navigated item. 7493bf215546Sopenharmony_ci const ImRect& rect_rel = g.NavWindow->NavRectRel[g.NavLayer]; 7494bf215546Sopenharmony_ci ImVec2 pos = g.NavWindow->Pos + ImVec2(rect_rel.Min.x + ImMin(g.Style.FramePadding.x * 4, rect_rel.GetWidth()), rect_rel.Max.y - ImMin(g.Style.FramePadding.y, rect_rel.GetHeight())); 7495bf215546Sopenharmony_ci ImRect visible_rect = GetViewportRect(); 7496bf215546Sopenharmony_ci return ImFloor(ImClamp(pos, visible_rect.Min, visible_rect.Max)); // ImFloor() is important because non-integer mouse position application in back-end might be lossy and result in undesirable non-zero delta. 7497bf215546Sopenharmony_ci } 7498bf215546Sopenharmony_ci} 7499bf215546Sopenharmony_ci 7500bf215546Sopenharmony_cifloat ImGui::GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode) 7501bf215546Sopenharmony_ci{ 7502bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 7503bf215546Sopenharmony_ci if (mode == ImGuiInputReadMode_Down) 7504bf215546Sopenharmony_ci return g.IO.NavInputs[n]; // Instant, read analog input (0.0f..1.0f, as provided by user) 7505bf215546Sopenharmony_ci 7506bf215546Sopenharmony_ci const float t = g.IO.NavInputsDownDuration[n]; 7507bf215546Sopenharmony_ci if (t < 0.0f && mode == ImGuiInputReadMode_Released) // Return 1.0f when just released, no repeat, ignore analog input. 7508bf215546Sopenharmony_ci return (g.IO.NavInputsDownDurationPrev[n] >= 0.0f ? 1.0f : 0.0f); 7509bf215546Sopenharmony_ci if (t < 0.0f) 7510bf215546Sopenharmony_ci return 0.0f; 7511bf215546Sopenharmony_ci if (mode == ImGuiInputReadMode_Pressed) // Return 1.0f when just pressed, no repeat, ignore analog input. 7512bf215546Sopenharmony_ci return (t == 0.0f) ? 1.0f : 0.0f; 7513bf215546Sopenharmony_ci if (mode == ImGuiInputReadMode_Repeat) 7514bf215546Sopenharmony_ci return (float)CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 0.80f, g.IO.KeyRepeatRate * 0.80f); 7515bf215546Sopenharmony_ci if (mode == ImGuiInputReadMode_RepeatSlow) 7516bf215546Sopenharmony_ci return (float)CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 1.00f, g.IO.KeyRepeatRate * 2.00f); 7517bf215546Sopenharmony_ci if (mode == ImGuiInputReadMode_RepeatFast) 7518bf215546Sopenharmony_ci return (float)CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 0.80f, g.IO.KeyRepeatRate * 0.30f); 7519bf215546Sopenharmony_ci return 0.0f; 7520bf215546Sopenharmony_ci} 7521bf215546Sopenharmony_ci 7522bf215546Sopenharmony_ciImVec2 ImGui::GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor, float fast_factor) 7523bf215546Sopenharmony_ci{ 7524bf215546Sopenharmony_ci ImVec2 delta(0.0f, 0.0f); 7525bf215546Sopenharmony_ci if (dir_sources & ImGuiNavDirSourceFlags_Keyboard) 7526bf215546Sopenharmony_ci delta += ImVec2(GetNavInputAmount(ImGuiNavInput_KeyRight_, mode) - GetNavInputAmount(ImGuiNavInput_KeyLeft_, mode), GetNavInputAmount(ImGuiNavInput_KeyDown_, mode) - GetNavInputAmount(ImGuiNavInput_KeyUp_, mode)); 7527bf215546Sopenharmony_ci if (dir_sources & ImGuiNavDirSourceFlags_PadDPad) 7528bf215546Sopenharmony_ci delta += ImVec2(GetNavInputAmount(ImGuiNavInput_DpadRight, mode) - GetNavInputAmount(ImGuiNavInput_DpadLeft, mode), GetNavInputAmount(ImGuiNavInput_DpadDown, mode) - GetNavInputAmount(ImGuiNavInput_DpadUp, mode)); 7529bf215546Sopenharmony_ci if (dir_sources & ImGuiNavDirSourceFlags_PadLStick) 7530bf215546Sopenharmony_ci delta += ImVec2(GetNavInputAmount(ImGuiNavInput_LStickRight, mode) - GetNavInputAmount(ImGuiNavInput_LStickLeft, mode), GetNavInputAmount(ImGuiNavInput_LStickDown, mode) - GetNavInputAmount(ImGuiNavInput_LStickUp, mode)); 7531bf215546Sopenharmony_ci if (slow_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakSlow)) 7532bf215546Sopenharmony_ci delta *= slow_factor; 7533bf215546Sopenharmony_ci if (fast_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakFast)) 7534bf215546Sopenharmony_ci delta *= fast_factor; 7535bf215546Sopenharmony_ci return delta; 7536bf215546Sopenharmony_ci} 7537bf215546Sopenharmony_ci 7538bf215546Sopenharmony_ci// Scroll to keep newly navigated item fully into view 7539bf215546Sopenharmony_ci// NB: We modify rect_rel by the amount we scrolled for, so it is immediately updated. 7540bf215546Sopenharmony_cistatic void NavScrollToBringItemIntoView(ImGuiWindow* window, const ImRect& item_rect) 7541bf215546Sopenharmony_ci{ 7542bf215546Sopenharmony_ci ImRect window_rect(window->InnerMainRect.Min - ImVec2(1, 1), window->InnerMainRect.Max + ImVec2(1, 1)); 7543bf215546Sopenharmony_ci //GetOverlayDrawList(window)->AddRect(window_rect.Min, window_rect.Max, IM_COL32_WHITE); // [DEBUG] 7544bf215546Sopenharmony_ci if (window_rect.Contains(item_rect)) 7545bf215546Sopenharmony_ci return; 7546bf215546Sopenharmony_ci 7547bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 7548bf215546Sopenharmony_ci if (window->ScrollbarX && item_rect.Min.x < window_rect.Min.x) 7549bf215546Sopenharmony_ci { 7550bf215546Sopenharmony_ci window->ScrollTarget.x = item_rect.Min.x - window->Pos.x + window->Scroll.x - g.Style.ItemSpacing.x; 7551bf215546Sopenharmony_ci window->ScrollTargetCenterRatio.x = 0.0f; 7552bf215546Sopenharmony_ci } 7553bf215546Sopenharmony_ci else if (window->ScrollbarX && item_rect.Max.x >= window_rect.Max.x) 7554bf215546Sopenharmony_ci { 7555bf215546Sopenharmony_ci window->ScrollTarget.x = item_rect.Max.x - window->Pos.x + window->Scroll.x + g.Style.ItemSpacing.x; 7556bf215546Sopenharmony_ci window->ScrollTargetCenterRatio.x = 1.0f; 7557bf215546Sopenharmony_ci } 7558bf215546Sopenharmony_ci if (item_rect.Min.y < window_rect.Min.y) 7559bf215546Sopenharmony_ci { 7560bf215546Sopenharmony_ci window->ScrollTarget.y = item_rect.Min.y - window->Pos.y + window->Scroll.y - g.Style.ItemSpacing.y; 7561bf215546Sopenharmony_ci window->ScrollTargetCenterRatio.y = 0.0f; 7562bf215546Sopenharmony_ci } 7563bf215546Sopenharmony_ci else if (item_rect.Max.y >= window_rect.Max.y) 7564bf215546Sopenharmony_ci { 7565bf215546Sopenharmony_ci window->ScrollTarget.y = item_rect.Max.y - window->Pos.y + window->Scroll.y + g.Style.ItemSpacing.y; 7566bf215546Sopenharmony_ci window->ScrollTargetCenterRatio.y = 1.0f; 7567bf215546Sopenharmony_ci } 7568bf215546Sopenharmony_ci} 7569bf215546Sopenharmony_ci 7570bf215546Sopenharmony_cistatic void ImGui::NavUpdate() 7571bf215546Sopenharmony_ci{ 7572bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 7573bf215546Sopenharmony_ci g.IO.WantSetMousePos = false; 7574bf215546Sopenharmony_ci#if 0 7575bf215546Sopenharmony_ci if (g.NavScoringCount > 0) IMGUI_DEBUG_LOG("NavScoringCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.FrameCount, g.NavScoringCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest); 7576bf215546Sopenharmony_ci#endif 7577bf215546Sopenharmony_ci 7578bf215546Sopenharmony_ci // Set input source as Gamepad when buttons are pressed before we map Keyboard (some features differs when used with Gamepad vs Keyboard) 7579bf215546Sopenharmony_ci bool nav_keyboard_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; 7580bf215546Sopenharmony_ci bool nav_gamepad_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (g.IO.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; 7581bf215546Sopenharmony_ci if (nav_gamepad_active) 7582bf215546Sopenharmony_ci if (g.IO.NavInputs[ImGuiNavInput_Activate] > 0.0f || g.IO.NavInputs[ImGuiNavInput_Input] > 0.0f || g.IO.NavInputs[ImGuiNavInput_Cancel] > 0.0f || g.IO.NavInputs[ImGuiNavInput_Menu] > 0.0f) 7583bf215546Sopenharmony_ci g.NavInputSource = ImGuiInputSource_NavGamepad; 7584bf215546Sopenharmony_ci 7585bf215546Sopenharmony_ci // Update Keyboard->Nav inputs mapping 7586bf215546Sopenharmony_ci if (nav_keyboard_active) 7587bf215546Sopenharmony_ci { 7588bf215546Sopenharmony_ci #define NAV_MAP_KEY(_KEY, _NAV_INPUT) if (IsKeyDown(g.IO.KeyMap[_KEY])) { g.IO.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_NavKeyboard; } 7589bf215546Sopenharmony_ci NAV_MAP_KEY(ImGuiKey_Space, ImGuiNavInput_Activate ); 7590bf215546Sopenharmony_ci NAV_MAP_KEY(ImGuiKey_Enter, ImGuiNavInput_Input ); 7591bf215546Sopenharmony_ci NAV_MAP_KEY(ImGuiKey_Escape, ImGuiNavInput_Cancel ); 7592bf215546Sopenharmony_ci NAV_MAP_KEY(ImGuiKey_LeftArrow, ImGuiNavInput_KeyLeft_ ); 7593bf215546Sopenharmony_ci NAV_MAP_KEY(ImGuiKey_RightArrow,ImGuiNavInput_KeyRight_); 7594bf215546Sopenharmony_ci NAV_MAP_KEY(ImGuiKey_UpArrow, ImGuiNavInput_KeyUp_ ); 7595bf215546Sopenharmony_ci NAV_MAP_KEY(ImGuiKey_DownArrow, ImGuiNavInput_KeyDown_ ); 7596bf215546Sopenharmony_ci if (g.IO.KeyCtrl) g.IO.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f; 7597bf215546Sopenharmony_ci if (g.IO.KeyShift) g.IO.NavInputs[ImGuiNavInput_TweakFast] = 1.0f; 7598bf215546Sopenharmony_ci if (g.IO.KeyAlt) g.IO.NavInputs[ImGuiNavInput_KeyMenu_] = 1.0f; 7599bf215546Sopenharmony_ci #undef NAV_MAP_KEY 7600bf215546Sopenharmony_ci } 7601bf215546Sopenharmony_ci memcpy(g.IO.NavInputsDownDurationPrev, g.IO.NavInputsDownDuration, sizeof(g.IO.NavInputsDownDuration)); 7602bf215546Sopenharmony_ci for (int i = 0; i < IM_ARRAYSIZE(g.IO.NavInputs); i++) 7603bf215546Sopenharmony_ci g.IO.NavInputsDownDuration[i] = (g.IO.NavInputs[i] > 0.0f) ? (g.IO.NavInputsDownDuration[i] < 0.0f ? 0.0f : g.IO.NavInputsDownDuration[i] + g.IO.DeltaTime) : -1.0f; 7604bf215546Sopenharmony_ci 7605bf215546Sopenharmony_ci // Process navigation init request (select first/default focus) 7606bf215546Sopenharmony_ci if (g.NavInitResultId != 0 && (!g.NavDisableHighlight || g.NavInitRequestFromMove)) 7607bf215546Sopenharmony_ci { 7608bf215546Sopenharmony_ci // Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called) 7609bf215546Sopenharmony_ci IM_ASSERT(g.NavWindow); 7610bf215546Sopenharmony_ci if (g.NavInitRequestFromMove) 7611bf215546Sopenharmony_ci SetNavIDWithRectRel(g.NavInitResultId, g.NavLayer, g.NavInitResultRectRel); 7612bf215546Sopenharmony_ci else 7613bf215546Sopenharmony_ci SetNavID(g.NavInitResultId, g.NavLayer); 7614bf215546Sopenharmony_ci g.NavWindow->NavRectRel[g.NavLayer] = g.NavInitResultRectRel; 7615bf215546Sopenharmony_ci } 7616bf215546Sopenharmony_ci g.NavInitRequest = false; 7617bf215546Sopenharmony_ci g.NavInitRequestFromMove = false; 7618bf215546Sopenharmony_ci g.NavInitResultId = 0; 7619bf215546Sopenharmony_ci g.NavJustMovedToId = 0; 7620bf215546Sopenharmony_ci 7621bf215546Sopenharmony_ci // Process navigation move request 7622bf215546Sopenharmony_ci if (g.NavMoveRequest) 7623bf215546Sopenharmony_ci NavUpdateMoveResult(); 7624bf215546Sopenharmony_ci 7625bf215546Sopenharmony_ci // When a forwarded move request failed, we restore the highlight that we disabled during the forward frame 7626bf215546Sopenharmony_ci if (g.NavMoveRequestForward == ImGuiNavForward_ForwardActive) 7627bf215546Sopenharmony_ci { 7628bf215546Sopenharmony_ci IM_ASSERT(g.NavMoveRequest); 7629bf215546Sopenharmony_ci if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0) 7630bf215546Sopenharmony_ci g.NavDisableHighlight = false; 7631bf215546Sopenharmony_ci g.NavMoveRequestForward = ImGuiNavForward_None; 7632bf215546Sopenharmony_ci } 7633bf215546Sopenharmony_ci 7634bf215546Sopenharmony_ci // Apply application mouse position movement, after we had a chance to process move request result. 7635bf215546Sopenharmony_ci if (g.NavMousePosDirty && g.NavIdIsAlive) 7636bf215546Sopenharmony_ci { 7637bf215546Sopenharmony_ci // Set mouse position given our knowledge of the navigated item position from last frame 7638bf215546Sopenharmony_ci if ((g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) && (g.IO.BackendFlags & ImGuiBackendFlags_HasSetMousePos)) 7639bf215546Sopenharmony_ci { 7640bf215546Sopenharmony_ci if (!g.NavDisableHighlight && g.NavDisableMouseHover && g.NavWindow) 7641bf215546Sopenharmony_ci { 7642bf215546Sopenharmony_ci g.IO.MousePos = g.IO.MousePosPrev = NavCalcPreferredRefPos(); 7643bf215546Sopenharmony_ci g.IO.WantSetMousePos = true; 7644bf215546Sopenharmony_ci } 7645bf215546Sopenharmony_ci } 7646bf215546Sopenharmony_ci g.NavMousePosDirty = false; 7647bf215546Sopenharmony_ci } 7648bf215546Sopenharmony_ci g.NavIdIsAlive = false; 7649bf215546Sopenharmony_ci g.NavJustTabbedId = 0; 7650bf215546Sopenharmony_ci IM_ASSERT(g.NavLayer == 0 || g.NavLayer == 1); 7651bf215546Sopenharmony_ci 7652bf215546Sopenharmony_ci // Store our return window (for returning from Layer 1 to Layer 0) and clear it as soon as we step back in our own Layer 0 7653bf215546Sopenharmony_ci if (g.NavWindow) 7654bf215546Sopenharmony_ci NavSaveLastChildNavWindow(g.NavWindow); 7655bf215546Sopenharmony_ci if (g.NavWindow && g.NavWindow->NavLastChildNavWindow != NULL && g.NavLayer == 0) 7656bf215546Sopenharmony_ci g.NavWindow->NavLastChildNavWindow = NULL; 7657bf215546Sopenharmony_ci 7658bf215546Sopenharmony_ci // Update CTRL+TAB and Windowing features (hold Square to move/resize/etc.) 7659bf215546Sopenharmony_ci NavUpdateWindowing(); 7660bf215546Sopenharmony_ci 7661bf215546Sopenharmony_ci // Set output flags for user application 7662bf215546Sopenharmony_ci g.IO.NavActive = (nav_keyboard_active || nav_gamepad_active) && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs); 7663bf215546Sopenharmony_ci g.IO.NavVisible = (g.IO.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL); 7664bf215546Sopenharmony_ci 7665bf215546Sopenharmony_ci // Process NavCancel input (to close a popup, get back to parent, clear focus) 7666bf215546Sopenharmony_ci if (IsNavInputPressed(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed)) 7667bf215546Sopenharmony_ci { 7668bf215546Sopenharmony_ci if (g.ActiveId != 0) 7669bf215546Sopenharmony_ci { 7670bf215546Sopenharmony_ci if (!(g.ActiveIdBlockNavInputFlags & (1 << ImGuiNavInput_Cancel))) 7671bf215546Sopenharmony_ci ClearActiveID(); 7672bf215546Sopenharmony_ci } 7673bf215546Sopenharmony_ci else if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow) && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow) 7674bf215546Sopenharmony_ci { 7675bf215546Sopenharmony_ci // Exit child window 7676bf215546Sopenharmony_ci ImGuiWindow* child_window = g.NavWindow; 7677bf215546Sopenharmony_ci ImGuiWindow* parent_window = g.NavWindow->ParentWindow; 7678bf215546Sopenharmony_ci IM_ASSERT(child_window->ChildId != 0); 7679bf215546Sopenharmony_ci FocusWindow(parent_window); 7680bf215546Sopenharmony_ci SetNavID(child_window->ChildId, 0); 7681bf215546Sopenharmony_ci g.NavIdIsAlive = false; 7682bf215546Sopenharmony_ci if (g.NavDisableMouseHover) 7683bf215546Sopenharmony_ci g.NavMousePosDirty = true; 7684bf215546Sopenharmony_ci } 7685bf215546Sopenharmony_ci else if (g.OpenPopupStack.Size > 0) 7686bf215546Sopenharmony_ci { 7687bf215546Sopenharmony_ci // Close open popup/menu 7688bf215546Sopenharmony_ci if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal)) 7689bf215546Sopenharmony_ci ClosePopupToLevel(g.OpenPopupStack.Size - 1, true); 7690bf215546Sopenharmony_ci } 7691bf215546Sopenharmony_ci else if (g.NavLayer != 0) 7692bf215546Sopenharmony_ci { 7693bf215546Sopenharmony_ci // Leave the "menu" layer 7694bf215546Sopenharmony_ci NavRestoreLayer(ImGuiNavLayer_Main); 7695bf215546Sopenharmony_ci } 7696bf215546Sopenharmony_ci else 7697bf215546Sopenharmony_ci { 7698bf215546Sopenharmony_ci // Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were 7699bf215546Sopenharmony_ci if (g.NavWindow && ((g.NavWindow->Flags & ImGuiWindowFlags_Popup) || !(g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow))) 7700bf215546Sopenharmony_ci g.NavWindow->NavLastIds[0] = 0; 7701bf215546Sopenharmony_ci g.NavId = 0; 7702bf215546Sopenharmony_ci } 7703bf215546Sopenharmony_ci } 7704bf215546Sopenharmony_ci 7705bf215546Sopenharmony_ci // Process manual activation request 7706bf215546Sopenharmony_ci g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = 0; 7707bf215546Sopenharmony_ci if (g.NavId != 0 && !g.NavDisableHighlight && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) 7708bf215546Sopenharmony_ci { 7709bf215546Sopenharmony_ci bool activate_down = IsNavInputDown(ImGuiNavInput_Activate); 7710bf215546Sopenharmony_ci bool activate_pressed = activate_down && IsNavInputPressed(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed); 7711bf215546Sopenharmony_ci if (g.ActiveId == 0 && activate_pressed) 7712bf215546Sopenharmony_ci g.NavActivateId = g.NavId; 7713bf215546Sopenharmony_ci if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_down) 7714bf215546Sopenharmony_ci g.NavActivateDownId = g.NavId; 7715bf215546Sopenharmony_ci if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_pressed) 7716bf215546Sopenharmony_ci g.NavActivatePressedId = g.NavId; 7717bf215546Sopenharmony_ci if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && IsNavInputPressed(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed)) 7718bf215546Sopenharmony_ci g.NavInputId = g.NavId; 7719bf215546Sopenharmony_ci } 7720bf215546Sopenharmony_ci if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) 7721bf215546Sopenharmony_ci g.NavDisableHighlight = true; 7722bf215546Sopenharmony_ci if (g.NavActivateId != 0) 7723bf215546Sopenharmony_ci IM_ASSERT(g.NavActivateDownId == g.NavActivateId); 7724bf215546Sopenharmony_ci g.NavMoveRequest = false; 7725bf215546Sopenharmony_ci 7726bf215546Sopenharmony_ci // Process programmatic activation request 7727bf215546Sopenharmony_ci if (g.NavNextActivateId != 0) 7728bf215546Sopenharmony_ci g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = g.NavNextActivateId; 7729bf215546Sopenharmony_ci g.NavNextActivateId = 0; 7730bf215546Sopenharmony_ci 7731bf215546Sopenharmony_ci // Initiate directional inputs request 7732bf215546Sopenharmony_ci const int allowed_dir_flags = (g.ActiveId == 0) ? ~0 : g.ActiveIdAllowNavDirFlags; 7733bf215546Sopenharmony_ci if (g.NavMoveRequestForward == ImGuiNavForward_None) 7734bf215546Sopenharmony_ci { 7735bf215546Sopenharmony_ci g.NavMoveDir = ImGuiDir_None; 7736bf215546Sopenharmony_ci g.NavMoveRequestFlags = ImGuiNavMoveFlags_None; 7737bf215546Sopenharmony_ci if (g.NavWindow && !g.NavWindowingTarget && allowed_dir_flags && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) 7738bf215546Sopenharmony_ci { 7739bf215546Sopenharmony_ci if ((allowed_dir_flags & (1<<ImGuiDir_Left)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadLeft, ImGuiNavInput_KeyLeft_, ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Left; 7740bf215546Sopenharmony_ci if ((allowed_dir_flags & (1<<ImGuiDir_Right)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadRight,ImGuiNavInput_KeyRight_,ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Right; 7741bf215546Sopenharmony_ci if ((allowed_dir_flags & (1<<ImGuiDir_Up)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadUp, ImGuiNavInput_KeyUp_, ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Up; 7742bf215546Sopenharmony_ci if ((allowed_dir_flags & (1<<ImGuiDir_Down)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadDown, ImGuiNavInput_KeyDown_, ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Down; 7743bf215546Sopenharmony_ci } 7744bf215546Sopenharmony_ci g.NavMoveClipDir = g.NavMoveDir; 7745bf215546Sopenharmony_ci } 7746bf215546Sopenharmony_ci else 7747bf215546Sopenharmony_ci { 7748bf215546Sopenharmony_ci // Forwarding previous request (which has been modified, e.g. wrap around menus rewrite the requests with a starting rectangle at the other side of the window) 7749bf215546Sopenharmony_ci // (Preserve g.NavMoveRequestFlags, g.NavMoveClipDir which were set by the NavMoveRequestForward() function) 7750bf215546Sopenharmony_ci IM_ASSERT(g.NavMoveDir != ImGuiDir_None && g.NavMoveClipDir != ImGuiDir_None); 7751bf215546Sopenharmony_ci IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_ForwardQueued); 7752bf215546Sopenharmony_ci g.NavMoveRequestForward = ImGuiNavForward_ForwardActive; 7753bf215546Sopenharmony_ci } 7754bf215546Sopenharmony_ci 7755bf215546Sopenharmony_ci // Update PageUp/PageDown scroll 7756bf215546Sopenharmony_ci float nav_scoring_rect_offset_y = 0.0f; 7757bf215546Sopenharmony_ci if (nav_keyboard_active) 7758bf215546Sopenharmony_ci nav_scoring_rect_offset_y = NavUpdatePageUpPageDown(allowed_dir_flags); 7759bf215546Sopenharmony_ci 7760bf215546Sopenharmony_ci // If we initiate a movement request and have no current NavId, we initiate a InitDefautRequest that will be used as a fallback if the direction fails to find a match 7761bf215546Sopenharmony_ci if (g.NavMoveDir != ImGuiDir_None) 7762bf215546Sopenharmony_ci { 7763bf215546Sopenharmony_ci g.NavMoveRequest = true; 7764bf215546Sopenharmony_ci g.NavMoveDirLast = g.NavMoveDir; 7765bf215546Sopenharmony_ci } 7766bf215546Sopenharmony_ci if (g.NavMoveRequest && g.NavId == 0) 7767bf215546Sopenharmony_ci { 7768bf215546Sopenharmony_ci g.NavInitRequest = g.NavInitRequestFromMove = true; 7769bf215546Sopenharmony_ci g.NavInitResultId = 0; 7770bf215546Sopenharmony_ci g.NavDisableHighlight = false; 7771bf215546Sopenharmony_ci } 7772bf215546Sopenharmony_ci NavUpdateAnyRequestFlag(); 7773bf215546Sopenharmony_ci 7774bf215546Sopenharmony_ci // Scrolling 7775bf215546Sopenharmony_ci if (g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget) 7776bf215546Sopenharmony_ci { 7777bf215546Sopenharmony_ci // *Fallback* manual-scroll with Nav directional keys when window has no navigable item 7778bf215546Sopenharmony_ci ImGuiWindow* window = g.NavWindow; 7779bf215546Sopenharmony_ci const float scroll_speed = ImFloor(window->CalcFontSize() * 100 * g.IO.DeltaTime + 0.5f); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported. 7780bf215546Sopenharmony_ci if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest) 7781bf215546Sopenharmony_ci { 7782bf215546Sopenharmony_ci if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) 7783bf215546Sopenharmony_ci SetWindowScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed)); 7784bf215546Sopenharmony_ci if (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) 7785bf215546Sopenharmony_ci SetWindowScrollY(window, ImFloor(window->Scroll.y + ((g.NavMoveDir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed)); 7786bf215546Sopenharmony_ci } 7787bf215546Sopenharmony_ci 7788bf215546Sopenharmony_ci // *Normal* Manual scroll with NavScrollXXX keys 7789bf215546Sopenharmony_ci // Next movement request will clamp the NavId reference rectangle to the visible area, so navigation will resume within those bounds. 7790bf215546Sopenharmony_ci ImVec2 scroll_dir = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down, 1.0f/10.0f, 10.0f); 7791bf215546Sopenharmony_ci if (scroll_dir.x != 0.0f && window->ScrollbarX) 7792bf215546Sopenharmony_ci { 7793bf215546Sopenharmony_ci SetWindowScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed)); 7794bf215546Sopenharmony_ci g.NavMoveFromClampedRefRect = true; 7795bf215546Sopenharmony_ci } 7796bf215546Sopenharmony_ci if (scroll_dir.y != 0.0f) 7797bf215546Sopenharmony_ci { 7798bf215546Sopenharmony_ci SetWindowScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed)); 7799bf215546Sopenharmony_ci g.NavMoveFromClampedRefRect = true; 7800bf215546Sopenharmony_ci } 7801bf215546Sopenharmony_ci } 7802bf215546Sopenharmony_ci 7803bf215546Sopenharmony_ci // Reset search results 7804bf215546Sopenharmony_ci g.NavMoveResultLocal.Clear(); 7805bf215546Sopenharmony_ci g.NavMoveResultLocalVisibleSet.Clear(); 7806bf215546Sopenharmony_ci g.NavMoveResultOther.Clear(); 7807bf215546Sopenharmony_ci 7808bf215546Sopenharmony_ci // When we have manually scrolled (without using navigation) and NavId becomes out of bounds, we project its bounding box to the visible area to restart navigation within visible items 7809bf215546Sopenharmony_ci if (g.NavMoveRequest && g.NavMoveFromClampedRefRect && g.NavLayer == 0) 7810bf215546Sopenharmony_ci { 7811bf215546Sopenharmony_ci ImGuiWindow* window = g.NavWindow; 7812bf215546Sopenharmony_ci ImRect window_rect_rel(window->InnerMainRect.Min - window->Pos - ImVec2(1,1), window->InnerMainRect.Max - window->Pos + ImVec2(1,1)); 7813bf215546Sopenharmony_ci if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer])) 7814bf215546Sopenharmony_ci { 7815bf215546Sopenharmony_ci float pad = window->CalcFontSize() * 0.5f; 7816bf215546Sopenharmony_ci window_rect_rel.Expand(ImVec2(-ImMin(window_rect_rel.GetWidth(), pad), -ImMin(window_rect_rel.GetHeight(), pad))); // Terrible approximation for the intent of starting navigation from first fully visible item 7817bf215546Sopenharmony_ci window->NavRectRel[g.NavLayer].ClipWith(window_rect_rel); 7818bf215546Sopenharmony_ci g.NavId = 0; 7819bf215546Sopenharmony_ci } 7820bf215546Sopenharmony_ci g.NavMoveFromClampedRefRect = false; 7821bf215546Sopenharmony_ci } 7822bf215546Sopenharmony_ci 7823bf215546Sopenharmony_ci // For scoring we use a single segment on the left side our current item bounding box (not touching the edge to avoid box overlap with zero-spaced items) 7824bf215546Sopenharmony_ci ImRect nav_rect_rel = (g.NavWindow && !g.NavWindow->NavRectRel[g.NavLayer].IsInverted()) ? g.NavWindow->NavRectRel[g.NavLayer] : ImRect(0,0,0,0); 7825bf215546Sopenharmony_ci g.NavScoringRectScreen = g.NavWindow ? ImRect(g.NavWindow->Pos + nav_rect_rel.Min, g.NavWindow->Pos + nav_rect_rel.Max) : GetViewportRect(); 7826bf215546Sopenharmony_ci g.NavScoringRectScreen.TranslateY(nav_scoring_rect_offset_y); 7827bf215546Sopenharmony_ci g.NavScoringRectScreen.Min.x = ImMin(g.NavScoringRectScreen.Min.x + 1.0f, g.NavScoringRectScreen.Max.x); 7828bf215546Sopenharmony_ci g.NavScoringRectScreen.Max.x = g.NavScoringRectScreen.Min.x; 7829bf215546Sopenharmony_ci IM_ASSERT(!g.NavScoringRectScreen.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allows us to remove extraneous ImFabs() calls in NavScoreItem(). 7830bf215546Sopenharmony_ci //g.OverlayDrawList.AddRect(g.NavScoringRectScreen.Min, g.NavScoringRectScreen.Max, IM_COL32(255,200,0,255)); // [DEBUG] 7831bf215546Sopenharmony_ci g.NavScoringCount = 0; 7832bf215546Sopenharmony_ci#if IMGUI_DEBUG_NAV_RECTS 7833bf215546Sopenharmony_ci if (g.NavWindow) { for (int layer = 0; layer < 2; layer++) GetOverlayDrawList(g.NavWindow)->AddRect(g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Min, g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Max, IM_COL32(255,200,0,255)); } // [DEBUG] 7834bf215546Sopenharmony_ci if (g.NavWindow) { ImU32 col = (!g.NavWindow->Hidden) ? IM_COL32(255,0,255,255) : IM_COL32(255,0,0,255); ImVec2 p = NavCalcPreferredRefPos(); char buf[32]; ImFormatString(buf, 32, "%d", g.NavLayer); GetOverlayDrawList(g.NavWindow)->AddCircleFilled(p, 3.0f, col); GetOverlayDrawList(g.NavWindow)->AddText(NULL, 13.0f, p + ImVec2(8,-4), col, buf); } 7835bf215546Sopenharmony_ci#endif 7836bf215546Sopenharmony_ci} 7837bf215546Sopenharmony_ci 7838bf215546Sopenharmony_ci// Apply result from previous frame navigation directional move request 7839bf215546Sopenharmony_cistatic void ImGui::NavUpdateMoveResult() 7840bf215546Sopenharmony_ci{ 7841bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 7842bf215546Sopenharmony_ci if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0) 7843bf215546Sopenharmony_ci { 7844bf215546Sopenharmony_ci // In a situation when there is no results but NavId != 0, re-enable the Navigation highlight (because g.NavId is not considered as a possible result) 7845bf215546Sopenharmony_ci if (g.NavId != 0) 7846bf215546Sopenharmony_ci { 7847bf215546Sopenharmony_ci g.NavDisableHighlight = false; 7848bf215546Sopenharmony_ci g.NavDisableMouseHover = true; 7849bf215546Sopenharmony_ci } 7850bf215546Sopenharmony_ci return; 7851bf215546Sopenharmony_ci } 7852bf215546Sopenharmony_ci 7853bf215546Sopenharmony_ci // Select which result to use 7854bf215546Sopenharmony_ci ImGuiNavMoveResult* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : &g.NavMoveResultOther; 7855bf215546Sopenharmony_ci 7856bf215546Sopenharmony_ci // PageUp/PageDown behavior first jumps to the bottom/top mostly visible item, _otherwise_ use the result from the previous/next page. 7857bf215546Sopenharmony_ci if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) 7858bf215546Sopenharmony_ci if (g.NavMoveResultLocalVisibleSet.ID != 0 && g.NavMoveResultLocalVisibleSet.ID != g.NavId) 7859bf215546Sopenharmony_ci result = &g.NavMoveResultLocalVisibleSet; 7860bf215546Sopenharmony_ci 7861bf215546Sopenharmony_ci // Maybe entering a flattened child from the outside? In this case solve the tie using the regular scoring rules. 7862bf215546Sopenharmony_ci if (result != &g.NavMoveResultOther && g.NavMoveResultOther.ID != 0 && g.NavMoveResultOther.Window->ParentWindow == g.NavWindow) 7863bf215546Sopenharmony_ci if ((g.NavMoveResultOther.DistBox < result->DistBox) || (g.NavMoveResultOther.DistBox == result->DistBox && g.NavMoveResultOther.DistCenter < result->DistCenter)) 7864bf215546Sopenharmony_ci result = &g.NavMoveResultOther; 7865bf215546Sopenharmony_ci IM_ASSERT(g.NavWindow && result->Window); 7866bf215546Sopenharmony_ci 7867bf215546Sopenharmony_ci // Scroll to keep newly navigated item fully into view. 7868bf215546Sopenharmony_ci if (g.NavLayer == 0) 7869bf215546Sopenharmony_ci { 7870bf215546Sopenharmony_ci ImRect rect_abs = ImRect(result->RectRel.Min + result->Window->Pos, result->RectRel.Max + result->Window->Pos); 7871bf215546Sopenharmony_ci NavScrollToBringItemIntoView(result->Window, rect_abs); 7872bf215546Sopenharmony_ci 7873bf215546Sopenharmony_ci // Estimate upcoming scroll so we can offset our result position so mouse position can be applied immediately after in NavUpdate() 7874bf215546Sopenharmony_ci ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(result->Window, false); 7875bf215546Sopenharmony_ci ImVec2 delta_scroll = result->Window->Scroll - next_scroll; 7876bf215546Sopenharmony_ci result->RectRel.Translate(delta_scroll); 7877bf215546Sopenharmony_ci 7878bf215546Sopenharmony_ci // Also scroll parent window to keep us into view if necessary (we could/should technically recurse back the whole the parent hierarchy). 7879bf215546Sopenharmony_ci if (result->Window->Flags & ImGuiWindowFlags_ChildWindow) 7880bf215546Sopenharmony_ci NavScrollToBringItemIntoView(result->Window->ParentWindow, ImRect(rect_abs.Min + delta_scroll, rect_abs.Max + delta_scroll)); 7881bf215546Sopenharmony_ci } 7882bf215546Sopenharmony_ci 7883bf215546Sopenharmony_ci ClearActiveID(); 7884bf215546Sopenharmony_ci g.NavWindow = result->Window; 7885bf215546Sopenharmony_ci if (g.NavId != result->ID) 7886bf215546Sopenharmony_ci { 7887bf215546Sopenharmony_ci // Don't set NavJustMovedToId if just landed on the same spot (which may happen with ImGuiNavMoveFlags_AllowCurrentNavId) 7888bf215546Sopenharmony_ci g.NavJustMovedToId = result->ID; 7889bf215546Sopenharmony_ci g.NavJustMovedToSelectScopeId = result->SelectScopeId; 7890bf215546Sopenharmony_ci } 7891bf215546Sopenharmony_ci SetNavIDWithRectRel(result->ID, g.NavLayer, result->RectRel); 7892bf215546Sopenharmony_ci g.NavMoveFromClampedRefRect = false; 7893bf215546Sopenharmony_ci} 7894bf215546Sopenharmony_ci 7895bf215546Sopenharmony_cistatic float ImGui::NavUpdatePageUpPageDown(int allowed_dir_flags) 7896bf215546Sopenharmony_ci{ 7897bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 7898bf215546Sopenharmony_ci if (g.NavMoveDir == ImGuiDir_None && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget && g.NavLayer == 0) 7899bf215546Sopenharmony_ci { 7900bf215546Sopenharmony_ci ImGuiWindow* window = g.NavWindow; 7901bf215546Sopenharmony_ci bool page_up_held = IsKeyDown(g.IO.KeyMap[ImGuiKey_PageUp]) && (allowed_dir_flags & (1 << ImGuiDir_Up)); 7902bf215546Sopenharmony_ci bool page_down_held = IsKeyDown(g.IO.KeyMap[ImGuiKey_PageDown]) && (allowed_dir_flags & (1 << ImGuiDir_Down)); 7903bf215546Sopenharmony_ci if (page_up_held != page_down_held) // If either (not both) are pressed 7904bf215546Sopenharmony_ci { 7905bf215546Sopenharmony_ci if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll) 7906bf215546Sopenharmony_ci { 7907bf215546Sopenharmony_ci // Fallback manual-scroll when window has no navigable item 7908bf215546Sopenharmony_ci if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageUp], true)) 7909bf215546Sopenharmony_ci SetWindowScrollY(window, window->Scroll.y - window->InnerClipRect.GetHeight()); 7910bf215546Sopenharmony_ci else if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageDown], true)) 7911bf215546Sopenharmony_ci SetWindowScrollY(window, window->Scroll.y + window->InnerClipRect.GetHeight()); 7912bf215546Sopenharmony_ci } 7913bf215546Sopenharmony_ci else 7914bf215546Sopenharmony_ci { 7915bf215546Sopenharmony_ci const ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer]; 7916bf215546Sopenharmony_ci const float page_offset_y = ImMax(0.0f, window->InnerClipRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight()); 7917bf215546Sopenharmony_ci float nav_scoring_rect_offset_y = 0.0f; 7918bf215546Sopenharmony_ci if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageUp], true)) 7919bf215546Sopenharmony_ci { 7920bf215546Sopenharmony_ci nav_scoring_rect_offset_y = -page_offset_y; 7921bf215546Sopenharmony_ci g.NavMoveDir = ImGuiDir_Down; // Because our scoring rect is offset, we intentionally request the opposite direction (so we can always land on the last item) 7922bf215546Sopenharmony_ci g.NavMoveClipDir = ImGuiDir_Up; 7923bf215546Sopenharmony_ci g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet; 7924bf215546Sopenharmony_ci } 7925bf215546Sopenharmony_ci else if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageDown], true)) 7926bf215546Sopenharmony_ci { 7927bf215546Sopenharmony_ci nav_scoring_rect_offset_y = +page_offset_y; 7928bf215546Sopenharmony_ci g.NavMoveDir = ImGuiDir_Up; // Because our scoring rect is offset, we intentionally request the opposite direction (so we can always land on the last item) 7929bf215546Sopenharmony_ci g.NavMoveClipDir = ImGuiDir_Down; 7930bf215546Sopenharmony_ci g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet; 7931bf215546Sopenharmony_ci } 7932bf215546Sopenharmony_ci return nav_scoring_rect_offset_y; 7933bf215546Sopenharmony_ci } 7934bf215546Sopenharmony_ci } 7935bf215546Sopenharmony_ci } 7936bf215546Sopenharmony_ci return 0.0f; 7937bf215546Sopenharmony_ci} 7938bf215546Sopenharmony_ci 7939bf215546Sopenharmony_cistatic int FindWindowFocusIndex(ImGuiWindow* window) // FIXME-OPT O(N) 7940bf215546Sopenharmony_ci{ 7941bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 7942bf215546Sopenharmony_ci for (int i = g.WindowsFocusOrder.Size-1; i >= 0; i--) 7943bf215546Sopenharmony_ci if (g.WindowsFocusOrder[i] == window) 7944bf215546Sopenharmony_ci return i; 7945bf215546Sopenharmony_ci return -1; 7946bf215546Sopenharmony_ci} 7947bf215546Sopenharmony_ci 7948bf215546Sopenharmony_cistatic ImGuiWindow* FindWindowNavFocusable(int i_start, int i_stop, int dir) // FIXME-OPT O(N) 7949bf215546Sopenharmony_ci{ 7950bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 7951bf215546Sopenharmony_ci for (int i = i_start; i >= 0 && i < g.WindowsFocusOrder.Size && i != i_stop; i += dir) 7952bf215546Sopenharmony_ci if (ImGui::IsWindowNavFocusable(g.WindowsFocusOrder[i])) 7953bf215546Sopenharmony_ci return g.WindowsFocusOrder[i]; 7954bf215546Sopenharmony_ci return NULL; 7955bf215546Sopenharmony_ci} 7956bf215546Sopenharmony_ci 7957bf215546Sopenharmony_cistatic void NavUpdateWindowingHighlightWindow(int focus_change_dir) 7958bf215546Sopenharmony_ci{ 7959bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 7960bf215546Sopenharmony_ci IM_ASSERT(g.NavWindowingTarget); 7961bf215546Sopenharmony_ci if (g.NavWindowingTarget->Flags & ImGuiWindowFlags_Modal) 7962bf215546Sopenharmony_ci return; 7963bf215546Sopenharmony_ci 7964bf215546Sopenharmony_ci const int i_current = FindWindowFocusIndex(g.NavWindowingTarget); 7965bf215546Sopenharmony_ci ImGuiWindow* window_target = FindWindowNavFocusable(i_current + focus_change_dir, -INT_MAX, focus_change_dir); 7966bf215546Sopenharmony_ci if (!window_target) 7967bf215546Sopenharmony_ci window_target = FindWindowNavFocusable((focus_change_dir < 0) ? (g.WindowsFocusOrder.Size - 1) : 0, i_current, focus_change_dir); 7968bf215546Sopenharmony_ci if (window_target) // Don't reset windowing target if there's a single window in the list 7969bf215546Sopenharmony_ci g.NavWindowingTarget = g.NavWindowingTargetAnim = window_target; 7970bf215546Sopenharmony_ci g.NavWindowingToggleLayer = false; 7971bf215546Sopenharmony_ci} 7972bf215546Sopenharmony_ci 7973bf215546Sopenharmony_ci// Window management mode (hold to: change focus/move/resize, tap to: toggle menu layer) 7974bf215546Sopenharmony_cistatic void ImGui::NavUpdateWindowing() 7975bf215546Sopenharmony_ci{ 7976bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 7977bf215546Sopenharmony_ci ImGuiWindow* apply_focus_window = NULL; 7978bf215546Sopenharmony_ci bool apply_toggle_layer = false; 7979bf215546Sopenharmony_ci 7980bf215546Sopenharmony_ci ImGuiWindow* modal_window = GetFrontMostPopupModal(); 7981bf215546Sopenharmony_ci if (modal_window != NULL) 7982bf215546Sopenharmony_ci { 7983bf215546Sopenharmony_ci g.NavWindowingTarget = NULL; 7984bf215546Sopenharmony_ci return; 7985bf215546Sopenharmony_ci } 7986bf215546Sopenharmony_ci 7987bf215546Sopenharmony_ci // Fade out 7988bf215546Sopenharmony_ci if (g.NavWindowingTargetAnim && g.NavWindowingTarget == NULL) 7989bf215546Sopenharmony_ci { 7990bf215546Sopenharmony_ci g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha - g.IO.DeltaTime * 10.0f, 0.0f); 7991bf215546Sopenharmony_ci if (g.DimBgRatio <= 0.0f && g.NavWindowingHighlightAlpha <= 0.0f) 7992bf215546Sopenharmony_ci g.NavWindowingTargetAnim = NULL; 7993bf215546Sopenharmony_ci } 7994bf215546Sopenharmony_ci 7995bf215546Sopenharmony_ci // Start CTRL-TAB or Square+L/R window selection 7996bf215546Sopenharmony_ci bool start_windowing_with_gamepad = !g.NavWindowingTarget && IsNavInputPressed(ImGuiNavInput_Menu, ImGuiInputReadMode_Pressed); 7997bf215546Sopenharmony_ci bool start_windowing_with_keyboard = !g.NavWindowingTarget && g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab) && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard); 7998bf215546Sopenharmony_ci if (start_windowing_with_gamepad || start_windowing_with_keyboard) 7999bf215546Sopenharmony_ci if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavFocusable(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1)) 8000bf215546Sopenharmony_ci { 8001bf215546Sopenharmony_ci g.NavWindowingTarget = g.NavWindowingTargetAnim = window; 8002bf215546Sopenharmony_ci g.NavWindowingTimer = g.NavWindowingHighlightAlpha = 0.0f; 8003bf215546Sopenharmony_ci g.NavWindowingToggleLayer = start_windowing_with_keyboard ? false : true; 8004bf215546Sopenharmony_ci g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_NavKeyboard : ImGuiInputSource_NavGamepad; 8005bf215546Sopenharmony_ci } 8006bf215546Sopenharmony_ci 8007bf215546Sopenharmony_ci // Gamepad update 8008bf215546Sopenharmony_ci g.NavWindowingTimer += g.IO.DeltaTime; 8009bf215546Sopenharmony_ci if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavGamepad) 8010bf215546Sopenharmony_ci { 8011bf215546Sopenharmony_ci // Highlight only appears after a brief time holding the button, so that a fast tap on PadMenu (to toggle NavLayer) doesn't add visual noise 8012bf215546Sopenharmony_ci g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); 8013bf215546Sopenharmony_ci 8014bf215546Sopenharmony_ci // Select window to focus 8015bf215546Sopenharmony_ci const int focus_change_dir = (int)IsNavInputPressed(ImGuiNavInput_FocusPrev, ImGuiInputReadMode_RepeatSlow) - (int)IsNavInputPressed(ImGuiNavInput_FocusNext, ImGuiInputReadMode_RepeatSlow); 8016bf215546Sopenharmony_ci if (focus_change_dir != 0) 8017bf215546Sopenharmony_ci { 8018bf215546Sopenharmony_ci NavUpdateWindowingHighlightWindow(focus_change_dir); 8019bf215546Sopenharmony_ci g.NavWindowingHighlightAlpha = 1.0f; 8020bf215546Sopenharmony_ci } 8021bf215546Sopenharmony_ci 8022bf215546Sopenharmony_ci // Single press toggles NavLayer, long press with L/R apply actual focus on release (until then the window was merely rendered front-most) 8023bf215546Sopenharmony_ci if (!IsNavInputDown(ImGuiNavInput_Menu)) 8024bf215546Sopenharmony_ci { 8025bf215546Sopenharmony_ci g.NavWindowingToggleLayer &= (g.NavWindowingHighlightAlpha < 1.0f); // Once button was held long enough we don't consider it a tap-to-toggle-layer press anymore. 8026bf215546Sopenharmony_ci if (g.NavWindowingToggleLayer && g.NavWindow) 8027bf215546Sopenharmony_ci apply_toggle_layer = true; 8028bf215546Sopenharmony_ci else if (!g.NavWindowingToggleLayer) 8029bf215546Sopenharmony_ci apply_focus_window = g.NavWindowingTarget; 8030bf215546Sopenharmony_ci g.NavWindowingTarget = NULL; 8031bf215546Sopenharmony_ci } 8032bf215546Sopenharmony_ci } 8033bf215546Sopenharmony_ci 8034bf215546Sopenharmony_ci // Keyboard: Focus 8035bf215546Sopenharmony_ci if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavKeyboard) 8036bf215546Sopenharmony_ci { 8037bf215546Sopenharmony_ci // Visuals only appears after a brief time after pressing TAB the first time, so that a fast CTRL+TAB doesn't add visual noise 8038bf215546Sopenharmony_ci g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); // 1.0f 8039bf215546Sopenharmony_ci if (IsKeyPressedMap(ImGuiKey_Tab, true)) 8040bf215546Sopenharmony_ci NavUpdateWindowingHighlightWindow(g.IO.KeyShift ? +1 : -1); 8041bf215546Sopenharmony_ci if (!g.IO.KeyCtrl) 8042bf215546Sopenharmony_ci apply_focus_window = g.NavWindowingTarget; 8043bf215546Sopenharmony_ci } 8044bf215546Sopenharmony_ci 8045bf215546Sopenharmony_ci // Keyboard: Press and Release ALT to toggle menu layer 8046bf215546Sopenharmony_ci // FIXME: We lack an explicit IO variable for "is the imgui window focused", so compare mouse validity to detect the common case of back-end clearing releases all keys on ALT-TAB 8047bf215546Sopenharmony_ci if ((g.ActiveId == 0 || g.ActiveIdAllowOverlap) && IsNavInputPressed(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Released)) 8048bf215546Sopenharmony_ci if (IsMousePosValid(&g.IO.MousePos) == IsMousePosValid(&g.IO.MousePosPrev)) 8049bf215546Sopenharmony_ci apply_toggle_layer = true; 8050bf215546Sopenharmony_ci 8051bf215546Sopenharmony_ci // Move window 8052bf215546Sopenharmony_ci if (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoMove)) 8053bf215546Sopenharmony_ci { 8054bf215546Sopenharmony_ci ImVec2 move_delta; 8055bf215546Sopenharmony_ci if (g.NavInputSource == ImGuiInputSource_NavKeyboard && !g.IO.KeyShift) 8056bf215546Sopenharmony_ci move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down); 8057bf215546Sopenharmony_ci if (g.NavInputSource == ImGuiInputSource_NavGamepad) 8058bf215546Sopenharmony_ci move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down); 8059bf215546Sopenharmony_ci if (move_delta.x != 0.0f || move_delta.y != 0.0f) 8060bf215546Sopenharmony_ci { 8061bf215546Sopenharmony_ci const float NAV_MOVE_SPEED = 800.0f; 8062bf215546Sopenharmony_ci const float move_speed = ImFloor(NAV_MOVE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y)); // FIXME: Doesn't code variable framerate very well 8063bf215546Sopenharmony_ci g.NavWindowingTarget->RootWindow->Pos += move_delta * move_speed; 8064bf215546Sopenharmony_ci g.NavDisableMouseHover = true; 8065bf215546Sopenharmony_ci MarkIniSettingsDirty(g.NavWindowingTarget); 8066bf215546Sopenharmony_ci } 8067bf215546Sopenharmony_ci } 8068bf215546Sopenharmony_ci 8069bf215546Sopenharmony_ci // Apply final focus 8070bf215546Sopenharmony_ci if (apply_focus_window && (g.NavWindow == NULL || apply_focus_window != g.NavWindow->RootWindow)) 8071bf215546Sopenharmony_ci { 8072bf215546Sopenharmony_ci g.NavDisableHighlight = false; 8073bf215546Sopenharmony_ci g.NavDisableMouseHover = true; 8074bf215546Sopenharmony_ci apply_focus_window = NavRestoreLastChildNavWindow(apply_focus_window); 8075bf215546Sopenharmony_ci ClosePopupsOverWindow(apply_focus_window); 8076bf215546Sopenharmony_ci FocusWindow(apply_focus_window); 8077bf215546Sopenharmony_ci if (apply_focus_window->NavLastIds[0] == 0) 8078bf215546Sopenharmony_ci NavInitWindow(apply_focus_window, false); 8079bf215546Sopenharmony_ci 8080bf215546Sopenharmony_ci // If the window only has a menu layer, select it directly 8081bf215546Sopenharmony_ci if (apply_focus_window->DC.NavLayerActiveMask == (1 << ImGuiNavLayer_Menu)) 8082bf215546Sopenharmony_ci g.NavLayer = ImGuiNavLayer_Menu; 8083bf215546Sopenharmony_ci } 8084bf215546Sopenharmony_ci if (apply_focus_window) 8085bf215546Sopenharmony_ci g.NavWindowingTarget = NULL; 8086bf215546Sopenharmony_ci 8087bf215546Sopenharmony_ci // Apply menu/layer toggle 8088bf215546Sopenharmony_ci if (apply_toggle_layer && g.NavWindow) 8089bf215546Sopenharmony_ci { 8090bf215546Sopenharmony_ci // Move to parent menu if necessary 8091bf215546Sopenharmony_ci ImGuiWindow* new_nav_window = g.NavWindow; 8092bf215546Sopenharmony_ci while ((new_nav_window->DC.NavLayerActiveMask & (1 << 1)) == 0 8093bf215546Sopenharmony_ci && (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 8094bf215546Sopenharmony_ci && (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0) 8095bf215546Sopenharmony_ci new_nav_window = new_nav_window->ParentWindow; 8096bf215546Sopenharmony_ci if (new_nav_window != g.NavWindow) 8097bf215546Sopenharmony_ci { 8098bf215546Sopenharmony_ci ImGuiWindow* old_nav_window = g.NavWindow; 8099bf215546Sopenharmony_ci FocusWindow(new_nav_window); 8100bf215546Sopenharmony_ci new_nav_window->NavLastChildNavWindow = old_nav_window; 8101bf215546Sopenharmony_ci } 8102bf215546Sopenharmony_ci g.NavDisableHighlight = false; 8103bf215546Sopenharmony_ci g.NavDisableMouseHover = true; 8104bf215546Sopenharmony_ci NavRestoreLayer((g.NavWindow->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) ? (ImGuiNavLayer)((int)g.NavLayer ^ 1) : ImGuiNavLayer_Main); 8105bf215546Sopenharmony_ci } 8106bf215546Sopenharmony_ci} 8107bf215546Sopenharmony_ci 8108bf215546Sopenharmony_ci// Window has already passed the IsWindowNavFocusable() 8109bf215546Sopenharmony_cistatic const char* GetFallbackWindowNameForWindowingList(ImGuiWindow* window) 8110bf215546Sopenharmony_ci{ 8111bf215546Sopenharmony_ci if (window->Flags & ImGuiWindowFlags_Popup) 8112bf215546Sopenharmony_ci return "(Popup)"; 8113bf215546Sopenharmony_ci if ((window->Flags & ImGuiWindowFlags_MenuBar) && strcmp(window->Name, "##MainMenuBar") == 0) 8114bf215546Sopenharmony_ci return "(Main menu bar)"; 8115bf215546Sopenharmony_ci return "(Untitled)"; 8116bf215546Sopenharmony_ci} 8117bf215546Sopenharmony_ci 8118bf215546Sopenharmony_ci// Overlay displayed when using CTRL+TAB. Called by EndFrame(). 8119bf215546Sopenharmony_civoid ImGui::NavUpdateWindowingList() 8120bf215546Sopenharmony_ci{ 8121bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 8122bf215546Sopenharmony_ci IM_ASSERT(g.NavWindowingTarget != NULL); 8123bf215546Sopenharmony_ci 8124bf215546Sopenharmony_ci if (g.NavWindowingTimer < NAV_WINDOWING_LIST_APPEAR_DELAY) 8125bf215546Sopenharmony_ci return; 8126bf215546Sopenharmony_ci 8127bf215546Sopenharmony_ci if (g.NavWindowingList == NULL) 8128bf215546Sopenharmony_ci g.NavWindowingList = FindWindowByName("###NavWindowingList"); 8129bf215546Sopenharmony_ci SetNextWindowSizeConstraints(ImVec2(g.IO.DisplaySize.x * 0.20f, g.IO.DisplaySize.y * 0.20f), ImVec2(FLT_MAX, FLT_MAX)); 8130bf215546Sopenharmony_ci SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f)); 8131bf215546Sopenharmony_ci PushStyleVar(ImGuiStyleVar_WindowPadding, g.Style.WindowPadding * 2.0f); 8132bf215546Sopenharmony_ci Begin("###NavWindowingList", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings); 8133bf215546Sopenharmony_ci for (int n = g.WindowsFocusOrder.Size - 1; n >= 0; n--) 8134bf215546Sopenharmony_ci { 8135bf215546Sopenharmony_ci ImGuiWindow* window = g.WindowsFocusOrder[n]; 8136bf215546Sopenharmony_ci if (!IsWindowNavFocusable(window)) 8137bf215546Sopenharmony_ci continue; 8138bf215546Sopenharmony_ci const char* label = window->Name; 8139bf215546Sopenharmony_ci if (label == FindRenderedTextEnd(label)) 8140bf215546Sopenharmony_ci label = GetFallbackWindowNameForWindowingList(window); 8141bf215546Sopenharmony_ci Selectable(label, g.NavWindowingTarget == window); 8142bf215546Sopenharmony_ci } 8143bf215546Sopenharmony_ci End(); 8144bf215546Sopenharmony_ci PopStyleVar(); 8145bf215546Sopenharmony_ci} 8146bf215546Sopenharmony_ci 8147bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 8148bf215546Sopenharmony_ci// [SECTION] COLUMNS 8149bf215546Sopenharmony_ci// In the current version, Columns are very weak. Needs to be replaced with a more full-featured system. 8150bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 8151bf215546Sopenharmony_ci 8152bf215546Sopenharmony_civoid ImGui::NextColumn() 8153bf215546Sopenharmony_ci{ 8154bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindow(); 8155bf215546Sopenharmony_ci if (window->SkipItems || window->DC.ColumnsSet == NULL) 8156bf215546Sopenharmony_ci return; 8157bf215546Sopenharmony_ci 8158bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 8159bf215546Sopenharmony_ci PopItemWidth(); 8160bf215546Sopenharmony_ci PopClipRect(); 8161bf215546Sopenharmony_ci 8162bf215546Sopenharmony_ci ImGuiColumnsSet* columns = window->DC.ColumnsSet; 8163bf215546Sopenharmony_ci columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); 8164bf215546Sopenharmony_ci if (++columns->Current < columns->Count) 8165bf215546Sopenharmony_ci { 8166bf215546Sopenharmony_ci // Columns 1+ cancel out IndentX 8167bf215546Sopenharmony_ci window->DC.ColumnsOffset.x = GetColumnOffset(columns->Current) - window->DC.Indent.x + g.Style.ItemSpacing.x; 8168bf215546Sopenharmony_ci window->DrawList->ChannelsSetCurrent(columns->Current); 8169bf215546Sopenharmony_ci } 8170bf215546Sopenharmony_ci else 8171bf215546Sopenharmony_ci { 8172bf215546Sopenharmony_ci window->DC.ColumnsOffset.x = 0.0f; 8173bf215546Sopenharmony_ci window->DrawList->ChannelsSetCurrent(0); 8174bf215546Sopenharmony_ci columns->Current = 0; 8175bf215546Sopenharmony_ci columns->LineMinY = columns->LineMaxY; 8176bf215546Sopenharmony_ci } 8177bf215546Sopenharmony_ci window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); 8178bf215546Sopenharmony_ci window->DC.CursorPos.y = columns->LineMinY; 8179bf215546Sopenharmony_ci window->DC.CurrentLineSize = ImVec2(0.0f, 0.0f); 8180bf215546Sopenharmony_ci window->DC.CurrentLineTextBaseOffset = 0.0f; 8181bf215546Sopenharmony_ci 8182bf215546Sopenharmony_ci PushColumnClipRect(); 8183bf215546Sopenharmony_ci PushItemWidth(GetColumnWidth() * 0.65f); // FIXME: Move on columns setup 8184bf215546Sopenharmony_ci} 8185bf215546Sopenharmony_ci 8186bf215546Sopenharmony_ciint ImGui::GetColumnIndex() 8187bf215546Sopenharmony_ci{ 8188bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindowRead(); 8189bf215546Sopenharmony_ci return window->DC.ColumnsSet ? window->DC.ColumnsSet->Current : 0; 8190bf215546Sopenharmony_ci} 8191bf215546Sopenharmony_ci 8192bf215546Sopenharmony_ciint ImGui::GetColumnsCount() 8193bf215546Sopenharmony_ci{ 8194bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindowRead(); 8195bf215546Sopenharmony_ci return window->DC.ColumnsSet ? window->DC.ColumnsSet->Count : 1; 8196bf215546Sopenharmony_ci} 8197bf215546Sopenharmony_ci 8198bf215546Sopenharmony_cistatic float OffsetNormToPixels(const ImGuiColumnsSet* columns, float offset_norm) 8199bf215546Sopenharmony_ci{ 8200bf215546Sopenharmony_ci return offset_norm * (columns->MaxX - columns->MinX); 8201bf215546Sopenharmony_ci} 8202bf215546Sopenharmony_ci 8203bf215546Sopenharmony_cistatic float PixelsToOffsetNorm(const ImGuiColumnsSet* columns, float offset) 8204bf215546Sopenharmony_ci{ 8205bf215546Sopenharmony_ci return offset / (columns->MaxX - columns->MinX); 8206bf215546Sopenharmony_ci} 8207bf215546Sopenharmony_ci 8208bf215546Sopenharmony_cistatic inline float GetColumnsRectHalfWidth() { return 4.0f; } 8209bf215546Sopenharmony_ci 8210bf215546Sopenharmony_cistatic float GetDraggedColumnOffset(ImGuiColumnsSet* columns, int column_index) 8211bf215546Sopenharmony_ci{ 8212bf215546Sopenharmony_ci // Active (dragged) column always follow mouse. The reason we need this is that dragging a column to the right edge of an auto-resizing 8213bf215546Sopenharmony_ci // window creates a feedback loop because we store normalized positions. So while dragging we enforce absolute positioning. 8214bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 8215bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 8216bf215546Sopenharmony_ci IM_ASSERT(column_index > 0); // We are not supposed to drag column 0. 8217bf215546Sopenharmony_ci IM_ASSERT(g.ActiveId == columns->ID + ImGuiID(column_index)); 8218bf215546Sopenharmony_ci 8219bf215546Sopenharmony_ci float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x + GetColumnsRectHalfWidth() - window->Pos.x; 8220bf215546Sopenharmony_ci x = ImMax(x, ImGui::GetColumnOffset(column_index - 1) + g.Style.ColumnsMinSpacing); 8221bf215546Sopenharmony_ci if ((columns->Flags & ImGuiColumnsFlags_NoPreserveWidths)) 8222bf215546Sopenharmony_ci x = ImMin(x, ImGui::GetColumnOffset(column_index + 1) - g.Style.ColumnsMinSpacing); 8223bf215546Sopenharmony_ci 8224bf215546Sopenharmony_ci return x; 8225bf215546Sopenharmony_ci} 8226bf215546Sopenharmony_ci 8227bf215546Sopenharmony_cifloat ImGui::GetColumnOffset(int column_index) 8228bf215546Sopenharmony_ci{ 8229bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindowRead(); 8230bf215546Sopenharmony_ci ImGuiColumnsSet* columns = window->DC.ColumnsSet; 8231bf215546Sopenharmony_ci IM_ASSERT(columns != NULL); 8232bf215546Sopenharmony_ci 8233bf215546Sopenharmony_ci if (column_index < 0) 8234bf215546Sopenharmony_ci column_index = columns->Current; 8235bf215546Sopenharmony_ci IM_ASSERT(column_index < columns->Columns.Size); 8236bf215546Sopenharmony_ci 8237bf215546Sopenharmony_ci const float t = columns->Columns[column_index].OffsetNorm; 8238bf215546Sopenharmony_ci const float x_offset = ImLerp(columns->MinX, columns->MaxX, t); 8239bf215546Sopenharmony_ci return x_offset; 8240bf215546Sopenharmony_ci} 8241bf215546Sopenharmony_ci 8242bf215546Sopenharmony_cistatic float GetColumnWidthEx(ImGuiColumnsSet* columns, int column_index, bool before_resize = false) 8243bf215546Sopenharmony_ci{ 8244bf215546Sopenharmony_ci if (column_index < 0) 8245bf215546Sopenharmony_ci column_index = columns->Current; 8246bf215546Sopenharmony_ci 8247bf215546Sopenharmony_ci float offset_norm; 8248bf215546Sopenharmony_ci if (before_resize) 8249bf215546Sopenharmony_ci offset_norm = columns->Columns[column_index + 1].OffsetNormBeforeResize - columns->Columns[column_index].OffsetNormBeforeResize; 8250bf215546Sopenharmony_ci else 8251bf215546Sopenharmony_ci offset_norm = columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm; 8252bf215546Sopenharmony_ci return OffsetNormToPixels(columns, offset_norm); 8253bf215546Sopenharmony_ci} 8254bf215546Sopenharmony_ci 8255bf215546Sopenharmony_cifloat ImGui::GetColumnWidth(int column_index) 8256bf215546Sopenharmony_ci{ 8257bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindowRead(); 8258bf215546Sopenharmony_ci ImGuiColumnsSet* columns = window->DC.ColumnsSet; 8259bf215546Sopenharmony_ci IM_ASSERT(columns != NULL); 8260bf215546Sopenharmony_ci 8261bf215546Sopenharmony_ci if (column_index < 0) 8262bf215546Sopenharmony_ci column_index = columns->Current; 8263bf215546Sopenharmony_ci return OffsetNormToPixels(columns, columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm); 8264bf215546Sopenharmony_ci} 8265bf215546Sopenharmony_ci 8266bf215546Sopenharmony_civoid ImGui::SetColumnOffset(int column_index, float offset) 8267bf215546Sopenharmony_ci{ 8268bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 8269bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 8270bf215546Sopenharmony_ci ImGuiColumnsSet* columns = window->DC.ColumnsSet; 8271bf215546Sopenharmony_ci IM_ASSERT(columns != NULL); 8272bf215546Sopenharmony_ci 8273bf215546Sopenharmony_ci if (column_index < 0) 8274bf215546Sopenharmony_ci column_index = columns->Current; 8275bf215546Sopenharmony_ci IM_ASSERT(column_index < columns->Columns.Size); 8276bf215546Sopenharmony_ci 8277bf215546Sopenharmony_ci const bool preserve_width = !(columns->Flags & ImGuiColumnsFlags_NoPreserveWidths) && (column_index < columns->Count-1); 8278bf215546Sopenharmony_ci const float width = preserve_width ? GetColumnWidthEx(columns, column_index, columns->IsBeingResized) : 0.0f; 8279bf215546Sopenharmony_ci 8280bf215546Sopenharmony_ci if (!(columns->Flags & ImGuiColumnsFlags_NoForceWithinWindow)) 8281bf215546Sopenharmony_ci offset = ImMin(offset, columns->MaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index)); 8282bf215546Sopenharmony_ci columns->Columns[column_index].OffsetNorm = PixelsToOffsetNorm(columns, offset - columns->MinX); 8283bf215546Sopenharmony_ci 8284bf215546Sopenharmony_ci if (preserve_width) 8285bf215546Sopenharmony_ci SetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width)); 8286bf215546Sopenharmony_ci} 8287bf215546Sopenharmony_ci 8288bf215546Sopenharmony_civoid ImGui::SetColumnWidth(int column_index, float width) 8289bf215546Sopenharmony_ci{ 8290bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindowRead(); 8291bf215546Sopenharmony_ci ImGuiColumnsSet* columns = window->DC.ColumnsSet; 8292bf215546Sopenharmony_ci IM_ASSERT(columns != NULL); 8293bf215546Sopenharmony_ci 8294bf215546Sopenharmony_ci if (column_index < 0) 8295bf215546Sopenharmony_ci column_index = columns->Current; 8296bf215546Sopenharmony_ci SetColumnOffset(column_index + 1, GetColumnOffset(column_index) + width); 8297bf215546Sopenharmony_ci} 8298bf215546Sopenharmony_ci 8299bf215546Sopenharmony_civoid ImGui::PushColumnClipRect(int column_index) 8300bf215546Sopenharmony_ci{ 8301bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindowRead(); 8302bf215546Sopenharmony_ci ImGuiColumnsSet* columns = window->DC.ColumnsSet; 8303bf215546Sopenharmony_ci if (column_index < 0) 8304bf215546Sopenharmony_ci column_index = columns->Current; 8305bf215546Sopenharmony_ci 8306bf215546Sopenharmony_ci PushClipRect(columns->Columns[column_index].ClipRect.Min, columns->Columns[column_index].ClipRect.Max, false); 8307bf215546Sopenharmony_ci} 8308bf215546Sopenharmony_ci 8309bf215546Sopenharmony_cistatic ImGuiColumnsSet* FindOrAddColumnsSet(ImGuiWindow* window, ImGuiID id) 8310bf215546Sopenharmony_ci{ 8311bf215546Sopenharmony_ci for (int n = 0; n < window->ColumnsStorage.Size; n++) 8312bf215546Sopenharmony_ci if (window->ColumnsStorage[n].ID == id) 8313bf215546Sopenharmony_ci return &window->ColumnsStorage[n]; 8314bf215546Sopenharmony_ci 8315bf215546Sopenharmony_ci window->ColumnsStorage.push_back(ImGuiColumnsSet()); 8316bf215546Sopenharmony_ci ImGuiColumnsSet* columns = &window->ColumnsStorage.back(); 8317bf215546Sopenharmony_ci columns->ID = id; 8318bf215546Sopenharmony_ci return columns; 8319bf215546Sopenharmony_ci} 8320bf215546Sopenharmony_ci 8321bf215546Sopenharmony_civoid ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlags flags) 8322bf215546Sopenharmony_ci{ 8323bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 8324bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindow(); 8325bf215546Sopenharmony_ci 8326bf215546Sopenharmony_ci IM_ASSERT(columns_count > 1); 8327bf215546Sopenharmony_ci IM_ASSERT(window->DC.ColumnsSet == NULL); // Nested columns are currently not supported 8328bf215546Sopenharmony_ci 8329bf215546Sopenharmony_ci // Differentiate column ID with an arbitrary prefix for cases where users name their columns set the same as another widget. 8330bf215546Sopenharmony_ci // In addition, when an identifier isn't explicitly provided we include the number of columns in the hash to make it uniquer. 8331bf215546Sopenharmony_ci PushID(0x11223347 + (str_id ? 0 : columns_count)); 8332bf215546Sopenharmony_ci ImGuiID id = window->GetID(str_id ? str_id : "columns"); 8333bf215546Sopenharmony_ci PopID(); 8334bf215546Sopenharmony_ci 8335bf215546Sopenharmony_ci // Acquire storage for the columns set 8336bf215546Sopenharmony_ci ImGuiColumnsSet* columns = FindOrAddColumnsSet(window, id); 8337bf215546Sopenharmony_ci IM_ASSERT(columns->ID == id); 8338bf215546Sopenharmony_ci columns->Current = 0; 8339bf215546Sopenharmony_ci columns->Count = columns_count; 8340bf215546Sopenharmony_ci columns->Flags = flags; 8341bf215546Sopenharmony_ci window->DC.ColumnsSet = columns; 8342bf215546Sopenharmony_ci 8343bf215546Sopenharmony_ci // Set state for first column 8344bf215546Sopenharmony_ci const float content_region_width = (window->SizeContentsExplicit.x != 0.0f) ? (window->SizeContentsExplicit.x) : (window->InnerClipRect.Max.x - window->Pos.x); 8345bf215546Sopenharmony_ci columns->MinX = window->DC.Indent.x - g.Style.ItemSpacing.x; // Lock our horizontal range 8346bf215546Sopenharmony_ci columns->MaxX = ImMax(content_region_width - window->Scroll.x, columns->MinX + 1.0f); 8347bf215546Sopenharmony_ci columns->StartPosY = window->DC.CursorPos.y; 8348bf215546Sopenharmony_ci columns->StartMaxPosX = window->DC.CursorMaxPos.x; 8349bf215546Sopenharmony_ci columns->LineMinY = columns->LineMaxY = window->DC.CursorPos.y; 8350bf215546Sopenharmony_ci window->DC.ColumnsOffset.x = 0.0f; 8351bf215546Sopenharmony_ci window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); 8352bf215546Sopenharmony_ci 8353bf215546Sopenharmony_ci // Clear data if columns count changed 8354bf215546Sopenharmony_ci if (columns->Columns.Size != 0 && columns->Columns.Size != columns_count + 1) 8355bf215546Sopenharmony_ci columns->Columns.resize(0); 8356bf215546Sopenharmony_ci 8357bf215546Sopenharmony_ci // Initialize defaults 8358bf215546Sopenharmony_ci columns->IsFirstFrame = (columns->Columns.Size == 0); 8359bf215546Sopenharmony_ci if (columns->Columns.Size == 0) 8360bf215546Sopenharmony_ci { 8361bf215546Sopenharmony_ci columns->Columns.reserve(columns_count + 1); 8362bf215546Sopenharmony_ci for (int n = 0; n < columns_count + 1; n++) 8363bf215546Sopenharmony_ci { 8364bf215546Sopenharmony_ci ImGuiColumnData column; 8365bf215546Sopenharmony_ci column.OffsetNorm = n / (float)columns_count; 8366bf215546Sopenharmony_ci columns->Columns.push_back(column); 8367bf215546Sopenharmony_ci } 8368bf215546Sopenharmony_ci } 8369bf215546Sopenharmony_ci 8370bf215546Sopenharmony_ci for (int n = 0; n < columns_count; n++) 8371bf215546Sopenharmony_ci { 8372bf215546Sopenharmony_ci // Compute clipping rectangle 8373bf215546Sopenharmony_ci ImGuiColumnData* column = &columns->Columns[n]; 8374bf215546Sopenharmony_ci float clip_x1 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n) - 1.0f); 8375bf215546Sopenharmony_ci float clip_x2 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n + 1) - 1.0f); 8376bf215546Sopenharmony_ci column->ClipRect = ImRect(clip_x1, -FLT_MAX, clip_x2, +FLT_MAX); 8377bf215546Sopenharmony_ci column->ClipRect.ClipWith(window->ClipRect); 8378bf215546Sopenharmony_ci } 8379bf215546Sopenharmony_ci 8380bf215546Sopenharmony_ci window->DrawList->ChannelsSplit(columns->Count); 8381bf215546Sopenharmony_ci PushColumnClipRect(); 8382bf215546Sopenharmony_ci PushItemWidth(GetColumnWidth() * 0.65f); 8383bf215546Sopenharmony_ci} 8384bf215546Sopenharmony_ci 8385bf215546Sopenharmony_civoid ImGui::EndColumns() 8386bf215546Sopenharmony_ci{ 8387bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 8388bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindow(); 8389bf215546Sopenharmony_ci ImGuiColumnsSet* columns = window->DC.ColumnsSet; 8390bf215546Sopenharmony_ci IM_ASSERT(columns != NULL); 8391bf215546Sopenharmony_ci 8392bf215546Sopenharmony_ci PopItemWidth(); 8393bf215546Sopenharmony_ci PopClipRect(); 8394bf215546Sopenharmony_ci window->DrawList->ChannelsMerge(); 8395bf215546Sopenharmony_ci 8396bf215546Sopenharmony_ci columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); 8397bf215546Sopenharmony_ci window->DC.CursorPos.y = columns->LineMaxY; 8398bf215546Sopenharmony_ci if (!(columns->Flags & ImGuiColumnsFlags_GrowParentContentsSize)) 8399bf215546Sopenharmony_ci window->DC.CursorMaxPos.x = columns->StartMaxPosX; // Restore cursor max pos, as columns don't grow parent 8400bf215546Sopenharmony_ci 8401bf215546Sopenharmony_ci // Draw columns borders and handle resize 8402bf215546Sopenharmony_ci bool is_being_resized = false; 8403bf215546Sopenharmony_ci if (!(columns->Flags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems) 8404bf215546Sopenharmony_ci { 8405bf215546Sopenharmony_ci const float y1 = columns->StartPosY; 8406bf215546Sopenharmony_ci const float y2 = window->DC.CursorPos.y; 8407bf215546Sopenharmony_ci int dragging_column = -1; 8408bf215546Sopenharmony_ci for (int n = 1; n < columns->Count; n++) 8409bf215546Sopenharmony_ci { 8410bf215546Sopenharmony_ci float x = window->Pos.x + GetColumnOffset(n); 8411bf215546Sopenharmony_ci const ImGuiID column_id = columns->ID + ImGuiID(n); 8412bf215546Sopenharmony_ci const float column_hw = GetColumnsRectHalfWidth(); // Half-width for interaction 8413bf215546Sopenharmony_ci const ImRect column_rect(ImVec2(x - column_hw, y1), ImVec2(x + column_hw, y2)); 8414bf215546Sopenharmony_ci KeepAliveID(column_id); 8415bf215546Sopenharmony_ci if (IsClippedEx(column_rect, column_id, false)) 8416bf215546Sopenharmony_ci continue; 8417bf215546Sopenharmony_ci 8418bf215546Sopenharmony_ci bool hovered = false, held = false; 8419bf215546Sopenharmony_ci if (!(columns->Flags & ImGuiColumnsFlags_NoResize)) 8420bf215546Sopenharmony_ci { 8421bf215546Sopenharmony_ci ButtonBehavior(column_rect, column_id, &hovered, &held); 8422bf215546Sopenharmony_ci if (hovered || held) 8423bf215546Sopenharmony_ci g.MouseCursor = ImGuiMouseCursor_ResizeEW; 8424bf215546Sopenharmony_ci if (held && !(columns->Columns[n].Flags & ImGuiColumnsFlags_NoResize)) 8425bf215546Sopenharmony_ci dragging_column = n; 8426bf215546Sopenharmony_ci } 8427bf215546Sopenharmony_ci 8428bf215546Sopenharmony_ci // Draw column (we clip the Y boundaries CPU side because very long triangles are mishandled by some GPU drivers.) 8429bf215546Sopenharmony_ci const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : hovered ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator); 8430bf215546Sopenharmony_ci const float xi = (float)(int)x; 8431bf215546Sopenharmony_ci window->DrawList->AddLine(ImVec2(xi, ImMax(y1 + 1.0f, window->ClipRect.Min.y)), ImVec2(xi, ImMin(y2, window->ClipRect.Max.y)), col); 8432bf215546Sopenharmony_ci } 8433bf215546Sopenharmony_ci 8434bf215546Sopenharmony_ci // Apply dragging after drawing the column lines, so our rendered lines are in sync with how items were displayed during the frame. 8435bf215546Sopenharmony_ci if (dragging_column != -1) 8436bf215546Sopenharmony_ci { 8437bf215546Sopenharmony_ci if (!columns->IsBeingResized) 8438bf215546Sopenharmony_ci for (int n = 0; n < columns->Count + 1; n++) 8439bf215546Sopenharmony_ci columns->Columns[n].OffsetNormBeforeResize = columns->Columns[n].OffsetNorm; 8440bf215546Sopenharmony_ci columns->IsBeingResized = is_being_resized = true; 8441bf215546Sopenharmony_ci float x = GetDraggedColumnOffset(columns, dragging_column); 8442bf215546Sopenharmony_ci SetColumnOffset(dragging_column, x); 8443bf215546Sopenharmony_ci } 8444bf215546Sopenharmony_ci } 8445bf215546Sopenharmony_ci columns->IsBeingResized = is_being_resized; 8446bf215546Sopenharmony_ci 8447bf215546Sopenharmony_ci window->DC.ColumnsSet = NULL; 8448bf215546Sopenharmony_ci window->DC.ColumnsOffset.x = 0.0f; 8449bf215546Sopenharmony_ci window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); 8450bf215546Sopenharmony_ci} 8451bf215546Sopenharmony_ci 8452bf215546Sopenharmony_ci// [2018-03: This is currently the only public API, while we are working on making BeginColumns/EndColumns user-facing] 8453bf215546Sopenharmony_civoid ImGui::Columns(int columns_count, const char* id, bool border) 8454bf215546Sopenharmony_ci{ 8455bf215546Sopenharmony_ci ImGuiWindow* window = GetCurrentWindow(); 8456bf215546Sopenharmony_ci IM_ASSERT(columns_count >= 1); 8457bf215546Sopenharmony_ci 8458bf215546Sopenharmony_ci ImGuiColumnsFlags flags = (border ? 0 : ImGuiColumnsFlags_NoBorder); 8459bf215546Sopenharmony_ci //flags |= ImGuiColumnsFlags_NoPreserveWidths; // NB: Legacy behavior 8460bf215546Sopenharmony_ci if (window->DC.ColumnsSet != NULL && window->DC.ColumnsSet->Count == columns_count && window->DC.ColumnsSet->Flags == flags) 8461bf215546Sopenharmony_ci return; 8462bf215546Sopenharmony_ci 8463bf215546Sopenharmony_ci if (window->DC.ColumnsSet != NULL) 8464bf215546Sopenharmony_ci EndColumns(); 8465bf215546Sopenharmony_ci 8466bf215546Sopenharmony_ci if (columns_count != 1) 8467bf215546Sopenharmony_ci BeginColumns(id, columns_count, flags); 8468bf215546Sopenharmony_ci} 8469bf215546Sopenharmony_ci 8470bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 8471bf215546Sopenharmony_ci// [SECTION] DRAG AND DROP 8472bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 8473bf215546Sopenharmony_ci 8474bf215546Sopenharmony_civoid ImGui::ClearDragDrop() 8475bf215546Sopenharmony_ci{ 8476bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 8477bf215546Sopenharmony_ci g.DragDropActive = false; 8478bf215546Sopenharmony_ci g.DragDropPayload.Clear(); 8479bf215546Sopenharmony_ci g.DragDropAcceptFlags = ImGuiDragDropFlags_None; 8480bf215546Sopenharmony_ci g.DragDropAcceptIdCurr = g.DragDropAcceptIdPrev = 0; 8481bf215546Sopenharmony_ci g.DragDropAcceptIdCurrRectSurface = FLT_MAX; 8482bf215546Sopenharmony_ci g.DragDropAcceptFrameCount = -1; 8483bf215546Sopenharmony_ci 8484bf215546Sopenharmony_ci g.DragDropPayloadBufHeap.clear(); 8485bf215546Sopenharmony_ci memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal)); 8486bf215546Sopenharmony_ci} 8487bf215546Sopenharmony_ci 8488bf215546Sopenharmony_ci// Call when current ID is active. 8489bf215546Sopenharmony_ci// When this returns true you need to: a) call SetDragDropPayload() exactly once, b) you may render the payload visual/description, c) call EndDragDropSource() 8490bf215546Sopenharmony_cibool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags) 8491bf215546Sopenharmony_ci{ 8492bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 8493bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 8494bf215546Sopenharmony_ci 8495bf215546Sopenharmony_ci bool source_drag_active = false; 8496bf215546Sopenharmony_ci ImGuiID source_id = 0; 8497bf215546Sopenharmony_ci ImGuiID source_parent_id = 0; 8498bf215546Sopenharmony_ci int mouse_button = 0; 8499bf215546Sopenharmony_ci if (!(flags & ImGuiDragDropFlags_SourceExtern)) 8500bf215546Sopenharmony_ci { 8501bf215546Sopenharmony_ci source_id = window->DC.LastItemId; 8502bf215546Sopenharmony_ci if (source_id != 0 && g.ActiveId != source_id) // Early out for most common case 8503bf215546Sopenharmony_ci return false; 8504bf215546Sopenharmony_ci if (g.IO.MouseDown[mouse_button] == false) 8505bf215546Sopenharmony_ci return false; 8506bf215546Sopenharmony_ci 8507bf215546Sopenharmony_ci if (source_id == 0) 8508bf215546Sopenharmony_ci { 8509bf215546Sopenharmony_ci // If you want to use BeginDragDropSource() on an item with no unique identifier for interaction, such as Text() or Image(), you need to: 8510bf215546Sopenharmony_ci // A) Read the explanation below, B) Use the ImGuiDragDropFlags_SourceAllowNullID flag, C) Swallow your programmer pride. 8511bf215546Sopenharmony_ci if (!(flags & ImGuiDragDropFlags_SourceAllowNullID)) 8512bf215546Sopenharmony_ci { 8513bf215546Sopenharmony_ci IM_ASSERT(0); 8514bf215546Sopenharmony_ci return false; 8515bf215546Sopenharmony_ci } 8516bf215546Sopenharmony_ci 8517bf215546Sopenharmony_ci // Magic fallback (=somehow reprehensible) to handle items with no assigned ID, e.g. Text(), Image() 8518bf215546Sopenharmony_ci // We build a throwaway ID based on current ID stack + relative AABB of items in window. 8519bf215546Sopenharmony_ci // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING OF THE WIDGET, so if your widget moves your dragging operation will be canceled. 8520bf215546Sopenharmony_ci // We don't need to maintain/call ClearActiveID() as releasing the button will early out this function and trigger !ActiveIdIsAlive. 8521bf215546Sopenharmony_ci bool is_hovered = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect) != 0; 8522bf215546Sopenharmony_ci if (!is_hovered && (g.ActiveId == 0 || g.ActiveIdWindow != window)) 8523bf215546Sopenharmony_ci return false; 8524bf215546Sopenharmony_ci source_id = window->DC.LastItemId = window->GetIDFromRectangle(window->DC.LastItemRect); 8525bf215546Sopenharmony_ci if (is_hovered) 8526bf215546Sopenharmony_ci SetHoveredID(source_id); 8527bf215546Sopenharmony_ci if (is_hovered && g.IO.MouseClicked[mouse_button]) 8528bf215546Sopenharmony_ci { 8529bf215546Sopenharmony_ci SetActiveID(source_id, window); 8530bf215546Sopenharmony_ci FocusWindow(window); 8531bf215546Sopenharmony_ci } 8532bf215546Sopenharmony_ci if (g.ActiveId == source_id) // Allow the underlying widget to display/return hovered during the mouse release frame, else we would get a flicker. 8533bf215546Sopenharmony_ci g.ActiveIdAllowOverlap = is_hovered; 8534bf215546Sopenharmony_ci } 8535bf215546Sopenharmony_ci else 8536bf215546Sopenharmony_ci { 8537bf215546Sopenharmony_ci g.ActiveIdAllowOverlap = false; 8538bf215546Sopenharmony_ci } 8539bf215546Sopenharmony_ci if (g.ActiveId != source_id) 8540bf215546Sopenharmony_ci return false; 8541bf215546Sopenharmony_ci source_parent_id = window->IDStack.back(); 8542bf215546Sopenharmony_ci source_drag_active = IsMouseDragging(mouse_button); 8543bf215546Sopenharmony_ci } 8544bf215546Sopenharmony_ci else 8545bf215546Sopenharmony_ci { 8546bf215546Sopenharmony_ci window = NULL; 8547bf215546Sopenharmony_ci source_id = ImHashStr("#SourceExtern", 0); 8548bf215546Sopenharmony_ci source_drag_active = true; 8549bf215546Sopenharmony_ci } 8550bf215546Sopenharmony_ci 8551bf215546Sopenharmony_ci if (source_drag_active) 8552bf215546Sopenharmony_ci { 8553bf215546Sopenharmony_ci if (!g.DragDropActive) 8554bf215546Sopenharmony_ci { 8555bf215546Sopenharmony_ci IM_ASSERT(source_id != 0); 8556bf215546Sopenharmony_ci ClearDragDrop(); 8557bf215546Sopenharmony_ci ImGuiPayload& payload = g.DragDropPayload; 8558bf215546Sopenharmony_ci payload.SourceId = source_id; 8559bf215546Sopenharmony_ci payload.SourceParentId = source_parent_id; 8560bf215546Sopenharmony_ci g.DragDropActive = true; 8561bf215546Sopenharmony_ci g.DragDropSourceFlags = flags; 8562bf215546Sopenharmony_ci g.DragDropMouseButton = mouse_button; 8563bf215546Sopenharmony_ci } 8564bf215546Sopenharmony_ci g.DragDropSourceFrameCount = g.FrameCount; 8565bf215546Sopenharmony_ci g.DragDropWithinSourceOrTarget = true; 8566bf215546Sopenharmony_ci 8567bf215546Sopenharmony_ci if (!(flags & ImGuiDragDropFlags_SourceNoPreviewTooltip)) 8568bf215546Sopenharmony_ci { 8569bf215546Sopenharmony_ci // Target can request the Source to not display its tooltip (we use a dedicated flag to make this request explicit) 8570bf215546Sopenharmony_ci // We unfortunately can't just modify the source flags and skip the call to BeginTooltip, as caller may be emitting contents. 8571bf215546Sopenharmony_ci BeginTooltip(); 8572bf215546Sopenharmony_ci if (g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip)) 8573bf215546Sopenharmony_ci { 8574bf215546Sopenharmony_ci ImGuiWindow* tooltip_window = g.CurrentWindow; 8575bf215546Sopenharmony_ci tooltip_window->SkipItems = true; 8576bf215546Sopenharmony_ci tooltip_window->HiddenFramesRegular = 1; 8577bf215546Sopenharmony_ci } 8578bf215546Sopenharmony_ci } 8579bf215546Sopenharmony_ci 8580bf215546Sopenharmony_ci if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover) && !(flags & ImGuiDragDropFlags_SourceExtern)) 8581bf215546Sopenharmony_ci window->DC.LastItemStatusFlags &= ~ImGuiItemStatusFlags_HoveredRect; 8582bf215546Sopenharmony_ci 8583bf215546Sopenharmony_ci return true; 8584bf215546Sopenharmony_ci } 8585bf215546Sopenharmony_ci return false; 8586bf215546Sopenharmony_ci} 8587bf215546Sopenharmony_ci 8588bf215546Sopenharmony_civoid ImGui::EndDragDropSource() 8589bf215546Sopenharmony_ci{ 8590bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 8591bf215546Sopenharmony_ci IM_ASSERT(g.DragDropActive); 8592bf215546Sopenharmony_ci IM_ASSERT(g.DragDropWithinSourceOrTarget && "Not after a BeginDragDropSource()?"); 8593bf215546Sopenharmony_ci 8594bf215546Sopenharmony_ci if (!(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip)) 8595bf215546Sopenharmony_ci EndTooltip(); 8596bf215546Sopenharmony_ci 8597bf215546Sopenharmony_ci // Discard the drag if have not called SetDragDropPayload() 8598bf215546Sopenharmony_ci if (g.DragDropPayload.DataFrameCount == -1) 8599bf215546Sopenharmony_ci ClearDragDrop(); 8600bf215546Sopenharmony_ci g.DragDropWithinSourceOrTarget = false; 8601bf215546Sopenharmony_ci} 8602bf215546Sopenharmony_ci 8603bf215546Sopenharmony_ci// Use 'cond' to choose to submit payload on drag start or every frame 8604bf215546Sopenharmony_cibool ImGui::SetDragDropPayload(const char* type, const void* data, size_t data_size, ImGuiCond cond) 8605bf215546Sopenharmony_ci{ 8606bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 8607bf215546Sopenharmony_ci ImGuiPayload& payload = g.DragDropPayload; 8608bf215546Sopenharmony_ci if (cond == 0) 8609bf215546Sopenharmony_ci cond = ImGuiCond_Always; 8610bf215546Sopenharmony_ci 8611bf215546Sopenharmony_ci IM_ASSERT(type != NULL); 8612bf215546Sopenharmony_ci IM_ASSERT(strlen(type) < IM_ARRAYSIZE(payload.DataType) && "Payload type can be at most 32 characters long"); 8613bf215546Sopenharmony_ci IM_ASSERT((data != NULL && data_size > 0) || (data == NULL && data_size == 0)); 8614bf215546Sopenharmony_ci IM_ASSERT(cond == ImGuiCond_Always || cond == ImGuiCond_Once); 8615bf215546Sopenharmony_ci IM_ASSERT(payload.SourceId != 0); // Not called between BeginDragDropSource() and EndDragDropSource() 8616bf215546Sopenharmony_ci 8617bf215546Sopenharmony_ci if (cond == ImGuiCond_Always || payload.DataFrameCount == -1) 8618bf215546Sopenharmony_ci { 8619bf215546Sopenharmony_ci // Copy payload 8620bf215546Sopenharmony_ci ImStrncpy(payload.DataType, type, IM_ARRAYSIZE(payload.DataType)); 8621bf215546Sopenharmony_ci g.DragDropPayloadBufHeap.resize(0); 8622bf215546Sopenharmony_ci if (data_size > sizeof(g.DragDropPayloadBufLocal)) 8623bf215546Sopenharmony_ci { 8624bf215546Sopenharmony_ci // Store in heap 8625bf215546Sopenharmony_ci g.DragDropPayloadBufHeap.resize((int)data_size); 8626bf215546Sopenharmony_ci payload.Data = g.DragDropPayloadBufHeap.Data; 8627bf215546Sopenharmony_ci memcpy(payload.Data, data, data_size); 8628bf215546Sopenharmony_ci } 8629bf215546Sopenharmony_ci else if (data_size > 0) 8630bf215546Sopenharmony_ci { 8631bf215546Sopenharmony_ci // Store locally 8632bf215546Sopenharmony_ci memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal)); 8633bf215546Sopenharmony_ci payload.Data = g.DragDropPayloadBufLocal; 8634bf215546Sopenharmony_ci memcpy(payload.Data, data, data_size); 8635bf215546Sopenharmony_ci } 8636bf215546Sopenharmony_ci else 8637bf215546Sopenharmony_ci { 8638bf215546Sopenharmony_ci payload.Data = NULL; 8639bf215546Sopenharmony_ci } 8640bf215546Sopenharmony_ci payload.DataSize = (int)data_size; 8641bf215546Sopenharmony_ci } 8642bf215546Sopenharmony_ci payload.DataFrameCount = g.FrameCount; 8643bf215546Sopenharmony_ci 8644bf215546Sopenharmony_ci return (g.DragDropAcceptFrameCount == g.FrameCount) || (g.DragDropAcceptFrameCount == g.FrameCount - 1); 8645bf215546Sopenharmony_ci} 8646bf215546Sopenharmony_ci 8647bf215546Sopenharmony_cibool ImGui::BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id) 8648bf215546Sopenharmony_ci{ 8649bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 8650bf215546Sopenharmony_ci if (!g.DragDropActive) 8651bf215546Sopenharmony_ci return false; 8652bf215546Sopenharmony_ci 8653bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 8654bf215546Sopenharmony_ci if (g.HoveredWindow == NULL || window->RootWindow != g.HoveredWindow->RootWindow) 8655bf215546Sopenharmony_ci return false; 8656bf215546Sopenharmony_ci IM_ASSERT(id != 0); 8657bf215546Sopenharmony_ci if (!IsMouseHoveringRect(bb.Min, bb.Max) || (id == g.DragDropPayload.SourceId)) 8658bf215546Sopenharmony_ci return false; 8659bf215546Sopenharmony_ci if (window->SkipItems) 8660bf215546Sopenharmony_ci return false; 8661bf215546Sopenharmony_ci 8662bf215546Sopenharmony_ci IM_ASSERT(g.DragDropWithinSourceOrTarget == false); 8663bf215546Sopenharmony_ci g.DragDropTargetRect = bb; 8664bf215546Sopenharmony_ci g.DragDropTargetId = id; 8665bf215546Sopenharmony_ci g.DragDropWithinSourceOrTarget = true; 8666bf215546Sopenharmony_ci return true; 8667bf215546Sopenharmony_ci} 8668bf215546Sopenharmony_ci 8669bf215546Sopenharmony_ci// We don't use BeginDragDropTargetCustom() and duplicate its code because: 8670bf215546Sopenharmony_ci// 1) we use LastItemRectHoveredRect which handles items that pushes a temporarily clip rectangle in their code. Calling BeginDragDropTargetCustom(LastItemRect) would not handle them. 8671bf215546Sopenharmony_ci// 2) and it's faster. as this code may be very frequently called, we want to early out as fast as we can. 8672bf215546Sopenharmony_ci// Also note how the HoveredWindow test is positioned differently in both functions (in both functions we optimize for the cheapest early out case) 8673bf215546Sopenharmony_cibool ImGui::BeginDragDropTarget() 8674bf215546Sopenharmony_ci{ 8675bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 8676bf215546Sopenharmony_ci if (!g.DragDropActive) 8677bf215546Sopenharmony_ci return false; 8678bf215546Sopenharmony_ci 8679bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 8680bf215546Sopenharmony_ci if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect)) 8681bf215546Sopenharmony_ci return false; 8682bf215546Sopenharmony_ci if (g.HoveredWindow == NULL || window->RootWindow != g.HoveredWindow->RootWindow) 8683bf215546Sopenharmony_ci return false; 8684bf215546Sopenharmony_ci 8685bf215546Sopenharmony_ci const ImRect& display_rect = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? window->DC.LastItemDisplayRect : window->DC.LastItemRect; 8686bf215546Sopenharmony_ci ImGuiID id = window->DC.LastItemId; 8687bf215546Sopenharmony_ci if (id == 0) 8688bf215546Sopenharmony_ci id = window->GetIDFromRectangle(display_rect); 8689bf215546Sopenharmony_ci if (g.DragDropPayload.SourceId == id) 8690bf215546Sopenharmony_ci return false; 8691bf215546Sopenharmony_ci 8692bf215546Sopenharmony_ci IM_ASSERT(g.DragDropWithinSourceOrTarget == false); 8693bf215546Sopenharmony_ci g.DragDropTargetRect = display_rect; 8694bf215546Sopenharmony_ci g.DragDropTargetId = id; 8695bf215546Sopenharmony_ci g.DragDropWithinSourceOrTarget = true; 8696bf215546Sopenharmony_ci return true; 8697bf215546Sopenharmony_ci} 8698bf215546Sopenharmony_ci 8699bf215546Sopenharmony_cibool ImGui::IsDragDropPayloadBeingAccepted() 8700bf215546Sopenharmony_ci{ 8701bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 8702bf215546Sopenharmony_ci return g.DragDropActive && g.DragDropAcceptIdPrev != 0; 8703bf215546Sopenharmony_ci} 8704bf215546Sopenharmony_ci 8705bf215546Sopenharmony_ciconst ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags) 8706bf215546Sopenharmony_ci{ 8707bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 8708bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 8709bf215546Sopenharmony_ci ImGuiPayload& payload = g.DragDropPayload; 8710bf215546Sopenharmony_ci IM_ASSERT(g.DragDropActive); // Not called between BeginDragDropTarget() and EndDragDropTarget() ? 8711bf215546Sopenharmony_ci IM_ASSERT(payload.DataFrameCount != -1); // Forgot to call EndDragDropTarget() ? 8712bf215546Sopenharmony_ci if (type != NULL && !payload.IsDataType(type)) 8713bf215546Sopenharmony_ci return NULL; 8714bf215546Sopenharmony_ci 8715bf215546Sopenharmony_ci // Accept smallest drag target bounding box, this allows us to nest drag targets conveniently without ordering constraints. 8716bf215546Sopenharmony_ci // NB: We currently accept NULL id as target. However, overlapping targets requires a unique ID to function! 8717bf215546Sopenharmony_ci const bool was_accepted_previously = (g.DragDropAcceptIdPrev == g.DragDropTargetId); 8718bf215546Sopenharmony_ci ImRect r = g.DragDropTargetRect; 8719bf215546Sopenharmony_ci float r_surface = r.GetWidth() * r.GetHeight(); 8720bf215546Sopenharmony_ci if (r_surface < g.DragDropAcceptIdCurrRectSurface) 8721bf215546Sopenharmony_ci { 8722bf215546Sopenharmony_ci g.DragDropAcceptFlags = flags; 8723bf215546Sopenharmony_ci g.DragDropAcceptIdCurr = g.DragDropTargetId; 8724bf215546Sopenharmony_ci g.DragDropAcceptIdCurrRectSurface = r_surface; 8725bf215546Sopenharmony_ci } 8726bf215546Sopenharmony_ci 8727bf215546Sopenharmony_ci // Render default drop visuals 8728bf215546Sopenharmony_ci payload.Preview = was_accepted_previously; 8729bf215546Sopenharmony_ci flags |= (g.DragDropSourceFlags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect); // Source can also inhibit the preview (useful for external sources that lives for 1 frame) 8730bf215546Sopenharmony_ci if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && payload.Preview) 8731bf215546Sopenharmony_ci { 8732bf215546Sopenharmony_ci // FIXME-DRAG: Settle on a proper default visuals for drop target. 8733bf215546Sopenharmony_ci r.Expand(3.5f); 8734bf215546Sopenharmony_ci bool push_clip_rect = !window->ClipRect.Contains(r); 8735bf215546Sopenharmony_ci if (push_clip_rect) window->DrawList->PushClipRect(r.Min-ImVec2(1,1), r.Max+ImVec2(1,1)); 8736bf215546Sopenharmony_ci window->DrawList->AddRect(r.Min, r.Max, GetColorU32(ImGuiCol_DragDropTarget), 0.0f, ~0, 2.0f); 8737bf215546Sopenharmony_ci if (push_clip_rect) window->DrawList->PopClipRect(); 8738bf215546Sopenharmony_ci } 8739bf215546Sopenharmony_ci 8740bf215546Sopenharmony_ci g.DragDropAcceptFrameCount = g.FrameCount; 8741bf215546Sopenharmony_ci payload.Delivery = was_accepted_previously && !IsMouseDown(g.DragDropMouseButton); // For extern drag sources affecting os window focus, it's easier to just test !IsMouseDown() instead of IsMouseReleased() 8742bf215546Sopenharmony_ci if (!payload.Delivery && !(flags & ImGuiDragDropFlags_AcceptBeforeDelivery)) 8743bf215546Sopenharmony_ci return NULL; 8744bf215546Sopenharmony_ci 8745bf215546Sopenharmony_ci return &payload; 8746bf215546Sopenharmony_ci} 8747bf215546Sopenharmony_ci 8748bf215546Sopenharmony_ciconst ImGuiPayload* ImGui::GetDragDropPayload() 8749bf215546Sopenharmony_ci{ 8750bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 8751bf215546Sopenharmony_ci return g.DragDropActive ? &g.DragDropPayload : NULL; 8752bf215546Sopenharmony_ci} 8753bf215546Sopenharmony_ci 8754bf215546Sopenharmony_ci// We don't really use/need this now, but added it for the sake of consistency and because we might need it later. 8755bf215546Sopenharmony_civoid ImGui::EndDragDropTarget() 8756bf215546Sopenharmony_ci{ 8757bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 8758bf215546Sopenharmony_ci IM_ASSERT(g.DragDropActive); 8759bf215546Sopenharmony_ci IM_ASSERT(g.DragDropWithinSourceOrTarget); 8760bf215546Sopenharmony_ci g.DragDropWithinSourceOrTarget = false; 8761bf215546Sopenharmony_ci} 8762bf215546Sopenharmony_ci 8763bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 8764bf215546Sopenharmony_ci// [SECTION] DOCKING 8765bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 8766bf215546Sopenharmony_ci 8767bf215546Sopenharmony_ci// (this section is filled in the 'docking' branch) 8768bf215546Sopenharmony_ci 8769bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 8770bf215546Sopenharmony_ci// [SECTION] LOGGING/CAPTURING 8771bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 8772bf215546Sopenharmony_ci// All text output from the interface can be captured into tty/file/clipboard. 8773bf215546Sopenharmony_ci// By default, tree nodes are automatically opened during logging. 8774bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 8775bf215546Sopenharmony_ci 8776bf215546Sopenharmony_ci// Pass text data straight to log (without being displayed) 8777bf215546Sopenharmony_civoid ImGui::LogText(const char* fmt, ...) 8778bf215546Sopenharmony_ci{ 8779bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 8780bf215546Sopenharmony_ci if (!g.LogEnabled) 8781bf215546Sopenharmony_ci return; 8782bf215546Sopenharmony_ci 8783bf215546Sopenharmony_ci va_list args; 8784bf215546Sopenharmony_ci va_start(args, fmt); 8785bf215546Sopenharmony_ci if (g.LogFile) 8786bf215546Sopenharmony_ci vfprintf(g.LogFile, fmt, args); 8787bf215546Sopenharmony_ci else 8788bf215546Sopenharmony_ci g.LogClipboard.appendfv(fmt, args); 8789bf215546Sopenharmony_ci va_end(args); 8790bf215546Sopenharmony_ci} 8791bf215546Sopenharmony_ci 8792bf215546Sopenharmony_ci// Internal version that takes a position to decide on newline placement and pad items according to their depth. 8793bf215546Sopenharmony_ci// We split text into individual lines to add current tree level padding 8794bf215546Sopenharmony_civoid ImGui::LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end) 8795bf215546Sopenharmony_ci{ 8796bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 8797bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 8798bf215546Sopenharmony_ci 8799bf215546Sopenharmony_ci if (!text_end) 8800bf215546Sopenharmony_ci text_end = FindRenderedTextEnd(text, text_end); 8801bf215546Sopenharmony_ci 8802bf215546Sopenharmony_ci const bool log_new_line = ref_pos && (ref_pos->y > window->DC.LogLinePosY + 1); 8803bf215546Sopenharmony_ci if (ref_pos) 8804bf215546Sopenharmony_ci window->DC.LogLinePosY = ref_pos->y; 8805bf215546Sopenharmony_ci 8806bf215546Sopenharmony_ci const char* text_remaining = text; 8807bf215546Sopenharmony_ci if (g.LogStartDepth > window->DC.TreeDepth) // Re-adjust padding if we have popped out of our starting depth 8808bf215546Sopenharmony_ci g.LogStartDepth = window->DC.TreeDepth; 8809bf215546Sopenharmony_ci const int tree_depth = (window->DC.TreeDepth - g.LogStartDepth); 8810bf215546Sopenharmony_ci for (;;) 8811bf215546Sopenharmony_ci { 8812bf215546Sopenharmony_ci // Split the string. Each new line (after a '\n') is followed by spacing corresponding to the current depth of our log entry. 8813bf215546Sopenharmony_ci const char* line_start = text_remaining; 8814bf215546Sopenharmony_ci const char* line_end = ImStreolRange(line_start, text_end); 8815bf215546Sopenharmony_ci const bool is_first_line = (line_start == text); 8816bf215546Sopenharmony_ci const bool is_last_line = (line_end == text_end); 8817bf215546Sopenharmony_ci if (!is_last_line || (line_start != line_end)) 8818bf215546Sopenharmony_ci { 8819bf215546Sopenharmony_ci const int char_count = (int)(line_end - line_start); 8820bf215546Sopenharmony_ci if (log_new_line || !is_first_line) 8821bf215546Sopenharmony_ci LogText(IM_NEWLINE "%*s%.*s", tree_depth*4, "", char_count, line_start); 8822bf215546Sopenharmony_ci else 8823bf215546Sopenharmony_ci LogText(" %.*s", char_count, line_start); 8824bf215546Sopenharmony_ci } 8825bf215546Sopenharmony_ci 8826bf215546Sopenharmony_ci if (is_last_line) 8827bf215546Sopenharmony_ci break; 8828bf215546Sopenharmony_ci text_remaining = line_end + 1; 8829bf215546Sopenharmony_ci } 8830bf215546Sopenharmony_ci} 8831bf215546Sopenharmony_ci 8832bf215546Sopenharmony_ci// Start logging ImGui output to TTY 8833bf215546Sopenharmony_civoid ImGui::LogToTTY(int max_depth) 8834bf215546Sopenharmony_ci{ 8835bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 8836bf215546Sopenharmony_ci if (g.LogEnabled) 8837bf215546Sopenharmony_ci return; 8838bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 8839bf215546Sopenharmony_ci 8840bf215546Sopenharmony_ci IM_ASSERT(g.LogFile == NULL); 8841bf215546Sopenharmony_ci g.LogFile = stdout; 8842bf215546Sopenharmony_ci g.LogEnabled = true; 8843bf215546Sopenharmony_ci g.LogStartDepth = window->DC.TreeDepth; 8844bf215546Sopenharmony_ci if (max_depth >= 0) 8845bf215546Sopenharmony_ci g.LogAutoExpandMaxDepth = max_depth; 8846bf215546Sopenharmony_ci} 8847bf215546Sopenharmony_ci 8848bf215546Sopenharmony_ci// Start logging ImGui output to given file 8849bf215546Sopenharmony_civoid ImGui::LogToFile(int max_depth, const char* filename) 8850bf215546Sopenharmony_ci{ 8851bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 8852bf215546Sopenharmony_ci if (g.LogEnabled) 8853bf215546Sopenharmony_ci return; 8854bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 8855bf215546Sopenharmony_ci 8856bf215546Sopenharmony_ci if (!filename) 8857bf215546Sopenharmony_ci { 8858bf215546Sopenharmony_ci filename = g.IO.LogFilename; 8859bf215546Sopenharmony_ci if (!filename) 8860bf215546Sopenharmony_ci return; 8861bf215546Sopenharmony_ci } 8862bf215546Sopenharmony_ci 8863bf215546Sopenharmony_ci IM_ASSERT(g.LogFile == NULL); 8864bf215546Sopenharmony_ci g.LogFile = ImFileOpen(filename, "ab"); 8865bf215546Sopenharmony_ci if (!g.LogFile) 8866bf215546Sopenharmony_ci { 8867bf215546Sopenharmony_ci IM_ASSERT(0); 8868bf215546Sopenharmony_ci return; 8869bf215546Sopenharmony_ci } 8870bf215546Sopenharmony_ci g.LogEnabled = true; 8871bf215546Sopenharmony_ci g.LogStartDepth = window->DC.TreeDepth; 8872bf215546Sopenharmony_ci if (max_depth >= 0) 8873bf215546Sopenharmony_ci g.LogAutoExpandMaxDepth = max_depth; 8874bf215546Sopenharmony_ci} 8875bf215546Sopenharmony_ci 8876bf215546Sopenharmony_ci// Start logging ImGui output to clipboard 8877bf215546Sopenharmony_civoid ImGui::LogToClipboard(int max_depth) 8878bf215546Sopenharmony_ci{ 8879bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 8880bf215546Sopenharmony_ci if (g.LogEnabled) 8881bf215546Sopenharmony_ci return; 8882bf215546Sopenharmony_ci ImGuiWindow* window = g.CurrentWindow; 8883bf215546Sopenharmony_ci 8884bf215546Sopenharmony_ci IM_ASSERT(g.LogFile == NULL); 8885bf215546Sopenharmony_ci g.LogFile = NULL; 8886bf215546Sopenharmony_ci g.LogEnabled = true; 8887bf215546Sopenharmony_ci g.LogStartDepth = window->DC.TreeDepth; 8888bf215546Sopenharmony_ci if (max_depth >= 0) 8889bf215546Sopenharmony_ci g.LogAutoExpandMaxDepth = max_depth; 8890bf215546Sopenharmony_ci} 8891bf215546Sopenharmony_ci 8892bf215546Sopenharmony_civoid ImGui::LogFinish() 8893bf215546Sopenharmony_ci{ 8894bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 8895bf215546Sopenharmony_ci if (!g.LogEnabled) 8896bf215546Sopenharmony_ci return; 8897bf215546Sopenharmony_ci 8898bf215546Sopenharmony_ci LogText(IM_NEWLINE); 8899bf215546Sopenharmony_ci if (g.LogFile != NULL) 8900bf215546Sopenharmony_ci { 8901bf215546Sopenharmony_ci if (g.LogFile == stdout) 8902bf215546Sopenharmony_ci fflush(g.LogFile); 8903bf215546Sopenharmony_ci else 8904bf215546Sopenharmony_ci fclose(g.LogFile); 8905bf215546Sopenharmony_ci g.LogFile = NULL; 8906bf215546Sopenharmony_ci } 8907bf215546Sopenharmony_ci if (g.LogClipboard.size() > 1) 8908bf215546Sopenharmony_ci { 8909bf215546Sopenharmony_ci SetClipboardText(g.LogClipboard.begin()); 8910bf215546Sopenharmony_ci g.LogClipboard.clear(); 8911bf215546Sopenharmony_ci } 8912bf215546Sopenharmony_ci g.LogEnabled = false; 8913bf215546Sopenharmony_ci} 8914bf215546Sopenharmony_ci 8915bf215546Sopenharmony_ci// Helper to display logging buttons 8916bf215546Sopenharmony_civoid ImGui::LogButtons() 8917bf215546Sopenharmony_ci{ 8918bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 8919bf215546Sopenharmony_ci 8920bf215546Sopenharmony_ci PushID("LogButtons"); 8921bf215546Sopenharmony_ci const bool log_to_tty = Button("Log To TTY"); SameLine(); 8922bf215546Sopenharmony_ci const bool log_to_file = Button("Log To File"); SameLine(); 8923bf215546Sopenharmony_ci const bool log_to_clipboard = Button("Log To Clipboard"); SameLine(); 8924bf215546Sopenharmony_ci PushItemWidth(80.0f); 8925bf215546Sopenharmony_ci PushAllowKeyboardFocus(false); 8926bf215546Sopenharmony_ci SliderInt("Depth", &g.LogAutoExpandMaxDepth, 0, 9, NULL); 8927bf215546Sopenharmony_ci PopAllowKeyboardFocus(); 8928bf215546Sopenharmony_ci PopItemWidth(); 8929bf215546Sopenharmony_ci PopID(); 8930bf215546Sopenharmony_ci 8931bf215546Sopenharmony_ci // Start logging at the end of the function so that the buttons don't appear in the log 8932bf215546Sopenharmony_ci if (log_to_tty) 8933bf215546Sopenharmony_ci LogToTTY(g.LogAutoExpandMaxDepth); 8934bf215546Sopenharmony_ci if (log_to_file) 8935bf215546Sopenharmony_ci LogToFile(g.LogAutoExpandMaxDepth, g.IO.LogFilename); 8936bf215546Sopenharmony_ci if (log_to_clipboard) 8937bf215546Sopenharmony_ci LogToClipboard(g.LogAutoExpandMaxDepth); 8938bf215546Sopenharmony_ci} 8939bf215546Sopenharmony_ci 8940bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 8941bf215546Sopenharmony_ci// [SECTION] SETTINGS 8942bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 8943bf215546Sopenharmony_ci 8944bf215546Sopenharmony_civoid ImGui::MarkIniSettingsDirty() 8945bf215546Sopenharmony_ci{ 8946bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 8947bf215546Sopenharmony_ci if (g.SettingsDirtyTimer <= 0.0f) 8948bf215546Sopenharmony_ci g.SettingsDirtyTimer = g.IO.IniSavingRate; 8949bf215546Sopenharmony_ci} 8950bf215546Sopenharmony_ci 8951bf215546Sopenharmony_civoid ImGui::MarkIniSettingsDirty(ImGuiWindow* window) 8952bf215546Sopenharmony_ci{ 8953bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 8954bf215546Sopenharmony_ci if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings)) 8955bf215546Sopenharmony_ci if (g.SettingsDirtyTimer <= 0.0f) 8956bf215546Sopenharmony_ci g.SettingsDirtyTimer = g.IO.IniSavingRate; 8957bf215546Sopenharmony_ci} 8958bf215546Sopenharmony_ci 8959bf215546Sopenharmony_ciImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name) 8960bf215546Sopenharmony_ci{ 8961bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 8962bf215546Sopenharmony_ci g.SettingsWindows.push_back(ImGuiWindowSettings()); 8963bf215546Sopenharmony_ci ImGuiWindowSettings* settings = &g.SettingsWindows.back(); 8964bf215546Sopenharmony_ci settings->Name = ImStrdup(name); 8965bf215546Sopenharmony_ci settings->ID = ImHashStr(name, 0); 8966bf215546Sopenharmony_ci return settings; 8967bf215546Sopenharmony_ci} 8968bf215546Sopenharmony_ci 8969bf215546Sopenharmony_ciImGuiWindowSettings* ImGui::FindWindowSettings(ImGuiID id) 8970bf215546Sopenharmony_ci{ 8971bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 8972bf215546Sopenharmony_ci for (int i = 0; i != g.SettingsWindows.Size; i++) 8973bf215546Sopenharmony_ci if (g.SettingsWindows[i].ID == id) 8974bf215546Sopenharmony_ci return &g.SettingsWindows[i]; 8975bf215546Sopenharmony_ci return NULL; 8976bf215546Sopenharmony_ci} 8977bf215546Sopenharmony_ci 8978bf215546Sopenharmony_ciImGuiWindowSettings* ImGui::FindOrCreateWindowSettings(const char* name) 8979bf215546Sopenharmony_ci{ 8980bf215546Sopenharmony_ci if (ImGuiWindowSettings* settings = FindWindowSettings(ImHashStr(name, 0))) 8981bf215546Sopenharmony_ci return settings; 8982bf215546Sopenharmony_ci return CreateNewWindowSettings(name); 8983bf215546Sopenharmony_ci} 8984bf215546Sopenharmony_ci 8985bf215546Sopenharmony_civoid ImGui::LoadIniSettingsFromDisk(const char* ini_filename) 8986bf215546Sopenharmony_ci{ 8987bf215546Sopenharmony_ci size_t file_data_size = 0; 8988bf215546Sopenharmony_ci char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", &file_data_size); 8989bf215546Sopenharmony_ci if (!file_data) 8990bf215546Sopenharmony_ci return; 8991bf215546Sopenharmony_ci LoadIniSettingsFromMemory(file_data, (size_t)file_data_size); 8992bf215546Sopenharmony_ci ImGui::MemFree(file_data); 8993bf215546Sopenharmony_ci} 8994bf215546Sopenharmony_ci 8995bf215546Sopenharmony_ciImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name) 8996bf215546Sopenharmony_ci{ 8997bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 8998bf215546Sopenharmony_ci const ImGuiID type_hash = ImHashStr(type_name, 0); 8999bf215546Sopenharmony_ci for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) 9000bf215546Sopenharmony_ci if (g.SettingsHandlers[handler_n].TypeHash == type_hash) 9001bf215546Sopenharmony_ci return &g.SettingsHandlers[handler_n]; 9002bf215546Sopenharmony_ci return NULL; 9003bf215546Sopenharmony_ci} 9004bf215546Sopenharmony_ci 9005bf215546Sopenharmony_ci// Zero-tolerance, no error reporting, cheap .ini parsing 9006bf215546Sopenharmony_civoid ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size) 9007bf215546Sopenharmony_ci{ 9008bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 9009bf215546Sopenharmony_ci IM_ASSERT(g.Initialized); 9010bf215546Sopenharmony_ci IM_ASSERT(g.SettingsLoaded == false && g.FrameCount == 0); 9011bf215546Sopenharmony_ci 9012bf215546Sopenharmony_ci // For user convenience, we allow passing a non zero-terminated string (hence the ini_size parameter). 9013bf215546Sopenharmony_ci // For our convenience and to make the code simpler, we'll also write zero-terminators within the buffer. So let's create a writable copy.. 9014bf215546Sopenharmony_ci if (ini_size == 0) 9015bf215546Sopenharmony_ci ini_size = strlen(ini_data); 9016bf215546Sopenharmony_ci char* buf = (char*)ImGui::MemAlloc(ini_size + 1); 9017bf215546Sopenharmony_ci char* buf_end = buf + ini_size; 9018bf215546Sopenharmony_ci memcpy(buf, ini_data, ini_size); 9019bf215546Sopenharmony_ci buf[ini_size] = 0; 9020bf215546Sopenharmony_ci 9021bf215546Sopenharmony_ci void* entry_data = NULL; 9022bf215546Sopenharmony_ci ImGuiSettingsHandler* entry_handler = NULL; 9023bf215546Sopenharmony_ci 9024bf215546Sopenharmony_ci char* line_end = NULL; 9025bf215546Sopenharmony_ci for (char* line = buf; line < buf_end; line = line_end + 1) 9026bf215546Sopenharmony_ci { 9027bf215546Sopenharmony_ci // Skip new lines markers, then find end of the line 9028bf215546Sopenharmony_ci while (*line == '\n' || *line == '\r') 9029bf215546Sopenharmony_ci line++; 9030bf215546Sopenharmony_ci line_end = line; 9031bf215546Sopenharmony_ci while (line_end < buf_end && *line_end != '\n' && *line_end != '\r') 9032bf215546Sopenharmony_ci line_end++; 9033bf215546Sopenharmony_ci line_end[0] = 0; 9034bf215546Sopenharmony_ci if (line[0] == ';') 9035bf215546Sopenharmony_ci continue; 9036bf215546Sopenharmony_ci if (line[0] == '[' && line_end > line && line_end[-1] == ']') 9037bf215546Sopenharmony_ci { 9038bf215546Sopenharmony_ci // Parse "[Type][Name]". Note that 'Name' can itself contains [] characters, which is acceptable with the current format and parsing code. 9039bf215546Sopenharmony_ci line_end[-1] = 0; 9040bf215546Sopenharmony_ci const char* name_end = line_end - 1; 9041bf215546Sopenharmony_ci const char* type_start = line + 1; 9042bf215546Sopenharmony_ci char* type_end = (char*)(intptr_t)ImStrchrRange(type_start, name_end, ']'); 9043bf215546Sopenharmony_ci const char* name_start = type_end ? ImStrchrRange(type_end + 1, name_end, '[') : NULL; 9044bf215546Sopenharmony_ci if (!type_end || !name_start) 9045bf215546Sopenharmony_ci { 9046bf215546Sopenharmony_ci name_start = type_start; // Import legacy entries that have no type 9047bf215546Sopenharmony_ci type_start = "Window"; 9048bf215546Sopenharmony_ci } 9049bf215546Sopenharmony_ci else 9050bf215546Sopenharmony_ci { 9051bf215546Sopenharmony_ci *type_end = 0; // Overwrite first ']' 9052bf215546Sopenharmony_ci name_start++; // Skip second '[' 9053bf215546Sopenharmony_ci } 9054bf215546Sopenharmony_ci entry_handler = FindSettingsHandler(type_start); 9055bf215546Sopenharmony_ci entry_data = entry_handler ? entry_handler->ReadOpenFn(&g, entry_handler, name_start) : NULL; 9056bf215546Sopenharmony_ci } 9057bf215546Sopenharmony_ci else if (entry_handler != NULL && entry_data != NULL) 9058bf215546Sopenharmony_ci { 9059bf215546Sopenharmony_ci // Let type handler parse the line 9060bf215546Sopenharmony_ci entry_handler->ReadLineFn(&g, entry_handler, entry_data, line); 9061bf215546Sopenharmony_ci } 9062bf215546Sopenharmony_ci } 9063bf215546Sopenharmony_ci ImGui::MemFree(buf); 9064bf215546Sopenharmony_ci g.SettingsLoaded = true; 9065bf215546Sopenharmony_ci} 9066bf215546Sopenharmony_ci 9067bf215546Sopenharmony_civoid ImGui::SaveIniSettingsToDisk(const char* ini_filename) 9068bf215546Sopenharmony_ci{ 9069bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 9070bf215546Sopenharmony_ci g.SettingsDirtyTimer = 0.0f; 9071bf215546Sopenharmony_ci if (!ini_filename) 9072bf215546Sopenharmony_ci return; 9073bf215546Sopenharmony_ci 9074bf215546Sopenharmony_ci size_t ini_data_size = 0; 9075bf215546Sopenharmony_ci const char* ini_data = SaveIniSettingsToMemory(&ini_data_size); 9076bf215546Sopenharmony_ci FILE* f = ImFileOpen(ini_filename, "wt"); 9077bf215546Sopenharmony_ci if (!f) 9078bf215546Sopenharmony_ci return; 9079bf215546Sopenharmony_ci fwrite(ini_data, sizeof(char), ini_data_size, f); 9080bf215546Sopenharmony_ci fclose(f); 9081bf215546Sopenharmony_ci} 9082bf215546Sopenharmony_ci 9083bf215546Sopenharmony_ci// Call registered handlers (e.g. SettingsHandlerWindow_WriteAll() + custom handlers) to write their stuff into a text buffer 9084bf215546Sopenharmony_ciconst char* ImGui::SaveIniSettingsToMemory(size_t* out_size) 9085bf215546Sopenharmony_ci{ 9086bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 9087bf215546Sopenharmony_ci g.SettingsDirtyTimer = 0.0f; 9088bf215546Sopenharmony_ci g.SettingsIniData.Buf.resize(0); 9089bf215546Sopenharmony_ci g.SettingsIniData.Buf.push_back(0); 9090bf215546Sopenharmony_ci for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) 9091bf215546Sopenharmony_ci { 9092bf215546Sopenharmony_ci ImGuiSettingsHandler* handler = &g.SettingsHandlers[handler_n]; 9093bf215546Sopenharmony_ci handler->WriteAllFn(&g, handler, &g.SettingsIniData); 9094bf215546Sopenharmony_ci } 9095bf215546Sopenharmony_ci if (out_size) 9096bf215546Sopenharmony_ci *out_size = (size_t)g.SettingsIniData.size(); 9097bf215546Sopenharmony_ci return g.SettingsIniData.c_str(); 9098bf215546Sopenharmony_ci} 9099bf215546Sopenharmony_ci 9100bf215546Sopenharmony_cistatic void* SettingsHandlerWindow_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name) 9101bf215546Sopenharmony_ci{ 9102bf215546Sopenharmony_ci ImGuiWindowSettings* settings = ImGui::FindWindowSettings(ImHashStr(name, 0)); 9103bf215546Sopenharmony_ci if (!settings) 9104bf215546Sopenharmony_ci settings = ImGui::CreateNewWindowSettings(name); 9105bf215546Sopenharmony_ci return (void*)settings; 9106bf215546Sopenharmony_ci} 9107bf215546Sopenharmony_ci 9108bf215546Sopenharmony_cistatic void SettingsHandlerWindow_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line) 9109bf215546Sopenharmony_ci{ 9110bf215546Sopenharmony_ci ImGuiWindowSettings* settings = (ImGuiWindowSettings*)entry; 9111bf215546Sopenharmony_ci float x, y; 9112bf215546Sopenharmony_ci int i; 9113bf215546Sopenharmony_ci if (sscanf(line, "Pos=%f,%f", &x, &y) == 2) settings->Pos = ImVec2(x, y); 9114bf215546Sopenharmony_ci else if (sscanf(line, "Size=%f,%f", &x, &y) == 2) settings->Size = ImMax(ImVec2(x, y), GImGui->Style.WindowMinSize); 9115bf215546Sopenharmony_ci else if (sscanf(line, "Collapsed=%d", &i) == 1) settings->Collapsed = (i != 0); 9116bf215546Sopenharmony_ci} 9117bf215546Sopenharmony_ci 9118bf215546Sopenharmony_cistatic void SettingsHandlerWindow_WriteAll(ImGuiContext* imgui_ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf) 9119bf215546Sopenharmony_ci{ 9120bf215546Sopenharmony_ci // Gather data from windows that were active during this session 9121bf215546Sopenharmony_ci // (if a window wasn't opened in this session we preserve its settings) 9122bf215546Sopenharmony_ci ImGuiContext& g = *imgui_ctx; 9123bf215546Sopenharmony_ci for (int i = 0; i != g.Windows.Size; i++) 9124bf215546Sopenharmony_ci { 9125bf215546Sopenharmony_ci ImGuiWindow* window = g.Windows[i]; 9126bf215546Sopenharmony_ci if (window->Flags & ImGuiWindowFlags_NoSavedSettings) 9127bf215546Sopenharmony_ci continue; 9128bf215546Sopenharmony_ci 9129bf215546Sopenharmony_ci ImGuiWindowSettings* settings = (window->SettingsIdx != -1) ? &g.SettingsWindows[window->SettingsIdx] : ImGui::FindWindowSettings(window->ID); 9130bf215546Sopenharmony_ci if (!settings) 9131bf215546Sopenharmony_ci { 9132bf215546Sopenharmony_ci settings = ImGui::CreateNewWindowSettings(window->Name); 9133bf215546Sopenharmony_ci window->SettingsIdx = g.SettingsWindows.index_from_ptr(settings); 9134bf215546Sopenharmony_ci } 9135bf215546Sopenharmony_ci IM_ASSERT(settings->ID == window->ID); 9136bf215546Sopenharmony_ci settings->Pos = window->Pos; 9137bf215546Sopenharmony_ci settings->Size = window->SizeFull; 9138bf215546Sopenharmony_ci settings->Collapsed = window->Collapsed; 9139bf215546Sopenharmony_ci } 9140bf215546Sopenharmony_ci 9141bf215546Sopenharmony_ci // Write to text buffer 9142bf215546Sopenharmony_ci buf->reserve(buf->size() + g.SettingsWindows.Size * 96); // ballpark reserve 9143bf215546Sopenharmony_ci for (int i = 0; i != g.SettingsWindows.Size; i++) 9144bf215546Sopenharmony_ci { 9145bf215546Sopenharmony_ci const ImGuiWindowSettings* settings = &g.SettingsWindows[i]; 9146bf215546Sopenharmony_ci if (settings->Pos.x == FLT_MAX) 9147bf215546Sopenharmony_ci continue; 9148bf215546Sopenharmony_ci const char* name = settings->Name; 9149bf215546Sopenharmony_ci if (const char* p = strstr(name, "###")) // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID() 9150bf215546Sopenharmony_ci name = p; 9151bf215546Sopenharmony_ci buf->appendf("[%s][%s]\n", handler->TypeName, name); 9152bf215546Sopenharmony_ci buf->appendf("Pos=%d,%d\n", (int)settings->Pos.x, (int)settings->Pos.y); 9153bf215546Sopenharmony_ci buf->appendf("Size=%d,%d\n", (int)settings->Size.x, (int)settings->Size.y); 9154bf215546Sopenharmony_ci buf->appendf("Collapsed=%d\n", settings->Collapsed); 9155bf215546Sopenharmony_ci buf->appendf("\n"); 9156bf215546Sopenharmony_ci } 9157bf215546Sopenharmony_ci} 9158bf215546Sopenharmony_ci 9159bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 9160bf215546Sopenharmony_ci// [SECTION] PLATFORM DEPENDENT HELPERS 9161bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 9162bf215546Sopenharmony_ci 9163bf215546Sopenharmony_ci#if defined(_WIN32) && !defined(_WINDOWS_) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && (!defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) || !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)) 9164bf215546Sopenharmony_ci#ifndef WIN32_LEAN_AND_MEAN 9165bf215546Sopenharmony_ci#define WIN32_LEAN_AND_MEAN 9166bf215546Sopenharmony_ci#endif 9167bf215546Sopenharmony_ci#ifndef __MINGW32__ 9168bf215546Sopenharmony_ci#include <Windows.h> 9169bf215546Sopenharmony_ci#else 9170bf215546Sopenharmony_ci#include <windows.h> 9171bf215546Sopenharmony_ci#endif 9172bf215546Sopenharmony_ci#endif 9173bf215546Sopenharmony_ci 9174bf215546Sopenharmony_ci// Win32 API clipboard implementation 9175bf215546Sopenharmony_ci#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) 9176bf215546Sopenharmony_ci 9177bf215546Sopenharmony_ci#ifdef _MSC_VER 9178bf215546Sopenharmony_ci#pragma comment(lib, "user32") 9179bf215546Sopenharmony_ci#endif 9180bf215546Sopenharmony_ci 9181bf215546Sopenharmony_cistatic const char* GetClipboardTextFn_DefaultImpl(void*) 9182bf215546Sopenharmony_ci{ 9183bf215546Sopenharmony_ci static ImVector<char> buf_local; 9184bf215546Sopenharmony_ci buf_local.clear(); 9185bf215546Sopenharmony_ci if (!::OpenClipboard(NULL)) 9186bf215546Sopenharmony_ci return NULL; 9187bf215546Sopenharmony_ci HANDLE wbuf_handle = ::GetClipboardData(CF_UNICODETEXT); 9188bf215546Sopenharmony_ci if (wbuf_handle == NULL) 9189bf215546Sopenharmony_ci { 9190bf215546Sopenharmony_ci ::CloseClipboard(); 9191bf215546Sopenharmony_ci return NULL; 9192bf215546Sopenharmony_ci } 9193bf215546Sopenharmony_ci if (ImWchar* wbuf_global = (ImWchar*)::GlobalLock(wbuf_handle)) 9194bf215546Sopenharmony_ci { 9195bf215546Sopenharmony_ci int buf_len = ImTextCountUtf8BytesFromStr(wbuf_global, NULL) + 1; 9196bf215546Sopenharmony_ci buf_local.resize(buf_len); 9197bf215546Sopenharmony_ci ImTextStrToUtf8(buf_local.Data, buf_len, wbuf_global, NULL); 9198bf215546Sopenharmony_ci } 9199bf215546Sopenharmony_ci ::GlobalUnlock(wbuf_handle); 9200bf215546Sopenharmony_ci ::CloseClipboard(); 9201bf215546Sopenharmony_ci return buf_local.Data; 9202bf215546Sopenharmony_ci} 9203bf215546Sopenharmony_ci 9204bf215546Sopenharmony_cistatic void SetClipboardTextFn_DefaultImpl(void*, const char* text) 9205bf215546Sopenharmony_ci{ 9206bf215546Sopenharmony_ci if (!::OpenClipboard(NULL)) 9207bf215546Sopenharmony_ci return; 9208bf215546Sopenharmony_ci const int wbuf_length = ImTextCountCharsFromUtf8(text, NULL) + 1; 9209bf215546Sopenharmony_ci HGLOBAL wbuf_handle = ::GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(ImWchar)); 9210bf215546Sopenharmony_ci if (wbuf_handle == NULL) 9211bf215546Sopenharmony_ci { 9212bf215546Sopenharmony_ci ::CloseClipboard(); 9213bf215546Sopenharmony_ci return; 9214bf215546Sopenharmony_ci } 9215bf215546Sopenharmony_ci ImWchar* wbuf_global = (ImWchar*)::GlobalLock(wbuf_handle); 9216bf215546Sopenharmony_ci ImTextStrFromUtf8(wbuf_global, wbuf_length, text, NULL); 9217bf215546Sopenharmony_ci ::GlobalUnlock(wbuf_handle); 9218bf215546Sopenharmony_ci ::EmptyClipboard(); 9219bf215546Sopenharmony_ci if (::SetClipboardData(CF_UNICODETEXT, wbuf_handle) == NULL) 9220bf215546Sopenharmony_ci ::GlobalFree(wbuf_handle); 9221bf215546Sopenharmony_ci ::CloseClipboard(); 9222bf215546Sopenharmony_ci} 9223bf215546Sopenharmony_ci 9224bf215546Sopenharmony_ci#else 9225bf215546Sopenharmony_ci 9226bf215546Sopenharmony_ci// Local ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers 9227bf215546Sopenharmony_cistatic const char* GetClipboardTextFn_DefaultImpl(void*) 9228bf215546Sopenharmony_ci{ 9229bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 9230bf215546Sopenharmony_ci return g.PrivateClipboard.empty() ? NULL : g.PrivateClipboard.begin(); 9231bf215546Sopenharmony_ci} 9232bf215546Sopenharmony_ci 9233bf215546Sopenharmony_ci// Local ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers 9234bf215546Sopenharmony_cistatic void SetClipboardTextFn_DefaultImpl(void*, const char* text) 9235bf215546Sopenharmony_ci{ 9236bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 9237bf215546Sopenharmony_ci g.PrivateClipboard.clear(); 9238bf215546Sopenharmony_ci const char* text_end = text + strlen(text); 9239bf215546Sopenharmony_ci g.PrivateClipboard.resize((int)(text_end - text) + 1); 9240bf215546Sopenharmony_ci memcpy(&g.PrivateClipboard[0], text, (size_t)(text_end - text)); 9241bf215546Sopenharmony_ci g.PrivateClipboard[(int)(text_end - text)] = 0; 9242bf215546Sopenharmony_ci} 9243bf215546Sopenharmony_ci 9244bf215546Sopenharmony_ci#endif 9245bf215546Sopenharmony_ci 9246bf215546Sopenharmony_ci// Win32 API IME support (for Asian languages, etc.) 9247bf215546Sopenharmony_ci#if defined(_WIN32) && !defined(__GNUC__) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) 9248bf215546Sopenharmony_ci 9249bf215546Sopenharmony_ci#include <imm.h> 9250bf215546Sopenharmony_ci#ifdef _MSC_VER 9251bf215546Sopenharmony_ci#pragma comment(lib, "imm32") 9252bf215546Sopenharmony_ci#endif 9253bf215546Sopenharmony_ci 9254bf215546Sopenharmony_cistatic void ImeSetInputScreenPosFn_DefaultImpl(int x, int y) 9255bf215546Sopenharmony_ci{ 9256bf215546Sopenharmony_ci // Notify OS Input Method Editor of text input position 9257bf215546Sopenharmony_ci if (HWND hwnd = (HWND)GImGui->IO.ImeWindowHandle) 9258bf215546Sopenharmony_ci if (HIMC himc = ::ImmGetContext(hwnd)) 9259bf215546Sopenharmony_ci { 9260bf215546Sopenharmony_ci COMPOSITIONFORM cf; 9261bf215546Sopenharmony_ci cf.ptCurrentPos.x = x; 9262bf215546Sopenharmony_ci cf.ptCurrentPos.y = y; 9263bf215546Sopenharmony_ci cf.dwStyle = CFS_FORCE_POSITION; 9264bf215546Sopenharmony_ci ::ImmSetCompositionWindow(himc, &cf); 9265bf215546Sopenharmony_ci ::ImmReleaseContext(hwnd, himc); 9266bf215546Sopenharmony_ci } 9267bf215546Sopenharmony_ci} 9268bf215546Sopenharmony_ci 9269bf215546Sopenharmony_ci#else 9270bf215546Sopenharmony_ci 9271bf215546Sopenharmony_cistatic void ImeSetInputScreenPosFn_DefaultImpl(int, int) {} 9272bf215546Sopenharmony_ci 9273bf215546Sopenharmony_ci#endif 9274bf215546Sopenharmony_ci 9275bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 9276bf215546Sopenharmony_ci// [SECTION] METRICS/DEBUG WINDOW 9277bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 9278bf215546Sopenharmony_ci 9279bf215546Sopenharmony_civoid ImGui::ShowMetricsWindow(bool* p_open) 9280bf215546Sopenharmony_ci{ 9281bf215546Sopenharmony_ci if (!ImGui::Begin("ImGui Metrics", p_open)) 9282bf215546Sopenharmony_ci { 9283bf215546Sopenharmony_ci ImGui::End(); 9284bf215546Sopenharmony_ci return; 9285bf215546Sopenharmony_ci } 9286bf215546Sopenharmony_ci 9287bf215546Sopenharmony_ci static bool show_draw_cmd_clip_rects = true; 9288bf215546Sopenharmony_ci static bool show_window_begin_order = false; 9289bf215546Sopenharmony_ci ImGuiIO& io = ImGui::GetIO(); 9290bf215546Sopenharmony_ci ImGui::Text("Dear ImGui %s", ImGui::GetVersion()); 9291bf215546Sopenharmony_ci ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); 9292bf215546Sopenharmony_ci ImGui::Text("%d vertices, %d indices (%d triangles)", io.MetricsRenderVertices, io.MetricsRenderIndices, io.MetricsRenderIndices / 3); 9293bf215546Sopenharmony_ci ImGui::Text("%d active windows (%d visible)", io.MetricsActiveWindows, io.MetricsRenderWindows); 9294bf215546Sopenharmony_ci ImGui::Text("%d allocations", io.MetricsActiveAllocations); 9295bf215546Sopenharmony_ci ImGui::Checkbox("Show clipping rectangles when hovering draw commands", &show_draw_cmd_clip_rects); 9296bf215546Sopenharmony_ci ImGui::Checkbox("Ctrl shows window begin order", &show_window_begin_order); 9297bf215546Sopenharmony_ci ImGui::Separator(); 9298bf215546Sopenharmony_ci 9299bf215546Sopenharmony_ci struct Funcs 9300bf215546Sopenharmony_ci { 9301bf215546Sopenharmony_ci static void NodeDrawList(ImGuiWindow* window, ImDrawList* draw_list, const char* label) 9302bf215546Sopenharmony_ci { 9303bf215546Sopenharmony_ci bool node_open = ImGui::TreeNode(draw_list, "%s: '%s' %d vtx, %d indices, %d cmds", label, draw_list->_OwnerName ? draw_list->_OwnerName : "", draw_list->VtxBuffer.Size, draw_list->IdxBuffer.Size, draw_list->CmdBuffer.Size); 9304bf215546Sopenharmony_ci if (draw_list == ImGui::GetWindowDrawList()) 9305bf215546Sopenharmony_ci { 9306bf215546Sopenharmony_ci ImGui::SameLine(); 9307bf215546Sopenharmony_ci ImGui::TextColored(ImVec4(1.0f,0.4f,0.4f,1.0f), "CURRENTLY APPENDING"); // Can't display stats for active draw list! (we don't have the data double-buffered) 9308bf215546Sopenharmony_ci if (node_open) ImGui::TreePop(); 9309bf215546Sopenharmony_ci return; 9310bf215546Sopenharmony_ci } 9311bf215546Sopenharmony_ci 9312bf215546Sopenharmony_ci ImDrawList* overlay_draw_list = GetOverlayDrawList(window); // Render additional visuals into the top-most draw list 9313bf215546Sopenharmony_ci if (window && IsItemHovered()) 9314bf215546Sopenharmony_ci overlay_draw_list->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255)); 9315bf215546Sopenharmony_ci if (!node_open) 9316bf215546Sopenharmony_ci return; 9317bf215546Sopenharmony_ci 9318bf215546Sopenharmony_ci int elem_offset = 0; 9319bf215546Sopenharmony_ci for (const ImDrawCmd* pcmd = draw_list->CmdBuffer.begin(); pcmd < draw_list->CmdBuffer.end(); elem_offset += pcmd->ElemCount, pcmd++) 9320bf215546Sopenharmony_ci { 9321bf215546Sopenharmony_ci if (pcmd->UserCallback == NULL && pcmd->ElemCount == 0) 9322bf215546Sopenharmony_ci continue; 9323bf215546Sopenharmony_ci if (pcmd->UserCallback) 9324bf215546Sopenharmony_ci { 9325bf215546Sopenharmony_ci ImGui::BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData); 9326bf215546Sopenharmony_ci continue; 9327bf215546Sopenharmony_ci } 9328bf215546Sopenharmony_ci ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; 9329bf215546Sopenharmony_ci bool pcmd_node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "Draw %4d %s vtx, tex 0x%p, clip_rect (%4.0f,%4.0f)-(%4.0f,%4.0f)", pcmd->ElemCount, draw_list->IdxBuffer.Size > 0 ? "indexed" : "non-indexed", pcmd->TextureId, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w); 9330bf215546Sopenharmony_ci if (show_draw_cmd_clip_rects && ImGui::IsItemHovered()) 9331bf215546Sopenharmony_ci { 9332bf215546Sopenharmony_ci ImRect clip_rect = pcmd->ClipRect; 9333bf215546Sopenharmony_ci ImRect vtxs_rect; 9334bf215546Sopenharmony_ci for (int i = elem_offset; i < elem_offset + (int)pcmd->ElemCount; i++) 9335bf215546Sopenharmony_ci vtxs_rect.Add(draw_list->VtxBuffer[idx_buffer ? idx_buffer[i] : i].pos); 9336bf215546Sopenharmony_ci clip_rect.Floor(); overlay_draw_list->AddRect(clip_rect.Min, clip_rect.Max, IM_COL32(255,255,0,255)); 9337bf215546Sopenharmony_ci vtxs_rect.Floor(); overlay_draw_list->AddRect(vtxs_rect.Min, vtxs_rect.Max, IM_COL32(255,0,255,255)); 9338bf215546Sopenharmony_ci } 9339bf215546Sopenharmony_ci if (!pcmd_node_open) 9340bf215546Sopenharmony_ci continue; 9341bf215546Sopenharmony_ci 9342bf215546Sopenharmony_ci // Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted. 9343bf215546Sopenharmony_ci ImGuiListClipper clipper(pcmd->ElemCount/3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible. 9344bf215546Sopenharmony_ci while (clipper.Step()) 9345bf215546Sopenharmony_ci for (int prim = clipper.DisplayStart, idx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++) 9346bf215546Sopenharmony_ci { 9347bf215546Sopenharmony_ci char buf[300]; 9348bf215546Sopenharmony_ci char *buf_p = buf, *buf_end = buf + IM_ARRAYSIZE(buf); 9349bf215546Sopenharmony_ci ImVec2 triangles_pos[3]; 9350bf215546Sopenharmony_ci for (int n = 0; n < 3; n++, idx_i++) 9351bf215546Sopenharmony_ci { 9352bf215546Sopenharmony_ci int vtx_i = idx_buffer ? idx_buffer[idx_i] : idx_i; 9353bf215546Sopenharmony_ci ImDrawVert& v = draw_list->VtxBuffer[vtx_i]; 9354bf215546Sopenharmony_ci triangles_pos[n] = v.pos; 9355bf215546Sopenharmony_ci buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n", 9356bf215546Sopenharmony_ci (n == 0) ? "idx" : " ", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); 9357bf215546Sopenharmony_ci } 9358bf215546Sopenharmony_ci ImGui::Selectable(buf, false); 9359bf215546Sopenharmony_ci if (ImGui::IsItemHovered()) 9360bf215546Sopenharmony_ci { 9361bf215546Sopenharmony_ci ImDrawListFlags backup_flags = overlay_draw_list->Flags; 9362bf215546Sopenharmony_ci overlay_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines at is more readable for very large and thin triangles. 9363bf215546Sopenharmony_ci overlay_draw_list->AddPolyline(triangles_pos, 3, IM_COL32(255,255,0,255), true, 1.0f); 9364bf215546Sopenharmony_ci overlay_draw_list->Flags = backup_flags; 9365bf215546Sopenharmony_ci } 9366bf215546Sopenharmony_ci } 9367bf215546Sopenharmony_ci ImGui::TreePop(); 9368bf215546Sopenharmony_ci } 9369bf215546Sopenharmony_ci ImGui::TreePop(); 9370bf215546Sopenharmony_ci } 9371bf215546Sopenharmony_ci 9372bf215546Sopenharmony_ci static void NodeWindows(ImVector<ImGuiWindow*>& windows, const char* label) 9373bf215546Sopenharmony_ci { 9374bf215546Sopenharmony_ci if (!ImGui::TreeNode(label, "%s (%d)", label, windows.Size)) 9375bf215546Sopenharmony_ci return; 9376bf215546Sopenharmony_ci for (int i = 0; i < windows.Size; i++) 9377bf215546Sopenharmony_ci Funcs::NodeWindow(windows[i], "Window"); 9378bf215546Sopenharmony_ci ImGui::TreePop(); 9379bf215546Sopenharmony_ci } 9380bf215546Sopenharmony_ci 9381bf215546Sopenharmony_ci static void NodeWindow(ImGuiWindow* window, const char* label) 9382bf215546Sopenharmony_ci { 9383bf215546Sopenharmony_ci if (!ImGui::TreeNode(window, "%s '%s', %d @ 0x%p", label, window->Name, window->Active || window->WasActive, window)) 9384bf215546Sopenharmony_ci return; 9385bf215546Sopenharmony_ci ImGuiWindowFlags flags = window->Flags; 9386bf215546Sopenharmony_ci NodeDrawList(window, window->DrawList, "DrawList"); 9387bf215546Sopenharmony_ci ImGui::BulletText("Pos: (%.1f,%.1f), Size: (%.1f,%.1f), SizeContents (%.1f,%.1f)", window->Pos.x, window->Pos.y, window->Size.x, window->Size.y, window->SizeContents.x, window->SizeContents.y); 9388bf215546Sopenharmony_ci ImGui::BulletText("Flags: 0x%08X (%s%s%s%s%s%s%s%s%s..)", flags, 9389bf215546Sopenharmony_ci (flags & ImGuiWindowFlags_ChildWindow) ? "Child " : "", (flags & ImGuiWindowFlags_Tooltip) ? "Tooltip " : "", (flags & ImGuiWindowFlags_Popup) ? "Popup " : "", 9390bf215546Sopenharmony_ci (flags & ImGuiWindowFlags_Modal) ? "Modal " : "", (flags & ImGuiWindowFlags_ChildMenu) ? "ChildMenu " : "", (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : "", 9391bf215546Sopenharmony_ci (flags & ImGuiWindowFlags_NoMouseInputs)? "NoMouseInputs":"", (flags & ImGuiWindowFlags_NoNavInputs) ? "NoNavInputs" : "", (flags & ImGuiWindowFlags_AlwaysAutoResize) ? "AlwaysAutoResize" : ""); 9392bf215546Sopenharmony_ci ImGui::BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f)", window->Scroll.x, GetWindowScrollMaxX(window), window->Scroll.y, GetWindowScrollMaxY(window)); 9393bf215546Sopenharmony_ci ImGui::BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1); 9394bf215546Sopenharmony_ci ImGui::BulletText("Appearing: %d, Hidden: %d (Reg %d Resize %d), SkipItems: %d", window->Appearing, window->Hidden, window->HiddenFramesRegular, window->HiddenFramesForResize, window->SkipItems); 9395bf215546Sopenharmony_ci ImGui::BulletText("NavLastIds: 0x%08X,0x%08X, NavLayerActiveMask: %X", window->NavLastIds[0], window->NavLastIds[1], window->DC.NavLayerActiveMask); 9396bf215546Sopenharmony_ci ImGui::BulletText("NavLastChildNavWindow: %s", window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL"); 9397bf215546Sopenharmony_ci if (!window->NavRectRel[0].IsInverted()) 9398bf215546Sopenharmony_ci ImGui::BulletText("NavRectRel[0]: (%.1f,%.1f)(%.1f,%.1f)", window->NavRectRel[0].Min.x, window->NavRectRel[0].Min.y, window->NavRectRel[0].Max.x, window->NavRectRel[0].Max.y); 9399bf215546Sopenharmony_ci else 9400bf215546Sopenharmony_ci ImGui::BulletText("NavRectRel[0]: <None>"); 9401bf215546Sopenharmony_ci if (window->RootWindow != window) NodeWindow(window->RootWindow, "RootWindow"); 9402bf215546Sopenharmony_ci if (window->ParentWindow != NULL) NodeWindow(window->ParentWindow, "ParentWindow"); 9403bf215546Sopenharmony_ci if (window->DC.ChildWindows.Size > 0) NodeWindows(window->DC.ChildWindows, "ChildWindows"); 9404bf215546Sopenharmony_ci if (window->ColumnsStorage.Size > 0 && ImGui::TreeNode("Columns", "Columns sets (%d)", window->ColumnsStorage.Size)) 9405bf215546Sopenharmony_ci { 9406bf215546Sopenharmony_ci for (int n = 0; n < window->ColumnsStorage.Size; n++) 9407bf215546Sopenharmony_ci { 9408bf215546Sopenharmony_ci const ImGuiColumnsSet* columns = &window->ColumnsStorage[n]; 9409bf215546Sopenharmony_ci if (ImGui::TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags)) 9410bf215546Sopenharmony_ci { 9411bf215546Sopenharmony_ci ImGui::BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->MaxX - columns->MinX, columns->MinX, columns->MaxX); 9412bf215546Sopenharmony_ci for (int column_n = 0; column_n < columns->Columns.Size; column_n++) 9413bf215546Sopenharmony_ci ImGui::BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, OffsetNormToPixels(columns, columns->Columns[column_n].OffsetNorm)); 9414bf215546Sopenharmony_ci ImGui::TreePop(); 9415bf215546Sopenharmony_ci } 9416bf215546Sopenharmony_ci } 9417bf215546Sopenharmony_ci ImGui::TreePop(); 9418bf215546Sopenharmony_ci } 9419bf215546Sopenharmony_ci ImGui::BulletText("Storage: %d bytes", window->StateStorage.Data.Size * (int)sizeof(ImGuiStorage::Pair)); 9420bf215546Sopenharmony_ci ImGui::TreePop(); 9421bf215546Sopenharmony_ci } 9422bf215546Sopenharmony_ci 9423bf215546Sopenharmony_ci static void NodeTabBar(ImGuiTabBar* tab_bar) 9424bf215546Sopenharmony_ci { 9425bf215546Sopenharmony_ci // Standalone tab bars (not associated to docking/windows functionality) currently hold no discernible strings. 9426bf215546Sopenharmony_ci char buf[256]; 9427bf215546Sopenharmony_ci char* p = buf; 9428bf215546Sopenharmony_ci const char* buf_end = buf + IM_ARRAYSIZE(buf); 9429bf215546Sopenharmony_ci ImFormatString(p, buf_end - p, "TabBar (%d tabs)%s", tab_bar->Tabs.Size, (tab_bar->PrevFrameVisible < ImGui::GetFrameCount() - 2) ? " *Inactive*" : ""); 9430bf215546Sopenharmony_ci if (ImGui::TreeNode(tab_bar, "%s", buf)) 9431bf215546Sopenharmony_ci { 9432bf215546Sopenharmony_ci for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) 9433bf215546Sopenharmony_ci { 9434bf215546Sopenharmony_ci const ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; 9435bf215546Sopenharmony_ci ImGui::PushID(tab); 9436bf215546Sopenharmony_ci if (ImGui::SmallButton("<")) { TabBarQueueChangeTabOrder(tab_bar, tab, -1); } ImGui::SameLine(0, 2); 9437bf215546Sopenharmony_ci if (ImGui::SmallButton(">")) { TabBarQueueChangeTabOrder(tab_bar, tab, +1); } ImGui::SameLine(); 9438bf215546Sopenharmony_ci ImGui::Text("%02d%c Tab 0x%08X", tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID); 9439bf215546Sopenharmony_ci ImGui::PopID(); 9440bf215546Sopenharmony_ci } 9441bf215546Sopenharmony_ci ImGui::TreePop(); 9442bf215546Sopenharmony_ci } 9443bf215546Sopenharmony_ci } 9444bf215546Sopenharmony_ci }; 9445bf215546Sopenharmony_ci 9446bf215546Sopenharmony_ci // Access private state, we are going to display the draw lists from last frame 9447bf215546Sopenharmony_ci ImGuiContext& g = *GImGui; 9448bf215546Sopenharmony_ci Funcs::NodeWindows(g.Windows, "Windows"); 9449bf215546Sopenharmony_ci if (ImGui::TreeNode("DrawList", "Active DrawLists (%d)", g.DrawDataBuilder.Layers[0].Size)) 9450bf215546Sopenharmony_ci { 9451bf215546Sopenharmony_ci for (int i = 0; i < g.DrawDataBuilder.Layers[0].Size; i++) 9452bf215546Sopenharmony_ci Funcs::NodeDrawList(NULL, g.DrawDataBuilder.Layers[0][i], "DrawList"); 9453bf215546Sopenharmony_ci ImGui::TreePop(); 9454bf215546Sopenharmony_ci } 9455bf215546Sopenharmony_ci if (ImGui::TreeNode("Popups", "Popups (%d)", g.OpenPopupStack.Size)) 9456bf215546Sopenharmony_ci { 9457bf215546Sopenharmony_ci for (int i = 0; i < g.OpenPopupStack.Size; i++) 9458bf215546Sopenharmony_ci { 9459bf215546Sopenharmony_ci ImGuiWindow* window = g.OpenPopupStack[i].Window; 9460bf215546Sopenharmony_ci ImGui::BulletText("PopupID: %08x, Window: '%s'%s%s", g.OpenPopupStack[i].PopupId, window ? window->Name : "NULL", window && (window->Flags & ImGuiWindowFlags_ChildWindow) ? " ChildWindow" : "", window && (window->Flags & ImGuiWindowFlags_ChildMenu) ? " ChildMenu" : ""); 9461bf215546Sopenharmony_ci } 9462bf215546Sopenharmony_ci ImGui::TreePop(); 9463bf215546Sopenharmony_ci } 9464bf215546Sopenharmony_ci if (ImGui::TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.Data.Size)) 9465bf215546Sopenharmony_ci { 9466bf215546Sopenharmony_ci for (int n = 0; n < g.TabBars.Data.Size; n++) 9467bf215546Sopenharmony_ci Funcs::NodeTabBar(g.TabBars.GetByIndex(n)); 9468bf215546Sopenharmony_ci ImGui::TreePop(); 9469bf215546Sopenharmony_ci } 9470bf215546Sopenharmony_ci if (ImGui::TreeNode("Internal state")) 9471bf215546Sopenharmony_ci { 9472bf215546Sopenharmony_ci const char* input_source_names[] = { "None", "Mouse", "Nav", "NavKeyboard", "NavGamepad" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT); 9473bf215546Sopenharmony_ci ImGui::Text("HoveredWindow: '%s'", g.HoveredWindow ? g.HoveredWindow->Name : "NULL"); 9474bf215546Sopenharmony_ci ImGui::Text("HoveredRootWindow: '%s'", g.HoveredRootWindow ? g.HoveredRootWindow->Name : "NULL"); 9475bf215546Sopenharmony_ci ImGui::Text("HoveredId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d", g.HoveredId, g.HoveredIdPreviousFrame, g.HoveredIdTimer, g.HoveredIdAllowOverlap); // Data is "in-flight" so depending on when the Metrics window is called we may see current frame information or not 9476bf215546Sopenharmony_ci ImGui::Text("ActiveId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d, Source: %s", g.ActiveId, g.ActiveIdPreviousFrame, g.ActiveIdTimer, g.ActiveIdAllowOverlap, input_source_names[g.ActiveIdSource]); 9477bf215546Sopenharmony_ci ImGui::Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL"); 9478bf215546Sopenharmony_ci ImGui::Text("MovingWindow: '%s'", g.MovingWindow ? g.MovingWindow->Name : "NULL"); 9479bf215546Sopenharmony_ci ImGui::Text("NavWindow: '%s'", g.NavWindow ? g.NavWindow->Name : "NULL"); 9480bf215546Sopenharmony_ci ImGui::Text("NavId: 0x%08X, NavLayer: %d", g.NavId, g.NavLayer); 9481bf215546Sopenharmony_ci ImGui::Text("NavInputSource: %s", input_source_names[g.NavInputSource]); 9482bf215546Sopenharmony_ci ImGui::Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible); 9483bf215546Sopenharmony_ci ImGui::Text("NavActivateId: 0x%08X, NavInputId: 0x%08X", g.NavActivateId, g.NavInputId); 9484bf215546Sopenharmony_ci ImGui::Text("NavDisableHighlight: %d, NavDisableMouseHover: %d", g.NavDisableHighlight, g.NavDisableMouseHover); 9485bf215546Sopenharmony_ci ImGui::Text("NavWindowingTarget: '%s'", g.NavWindowingTarget ? g.NavWindowingTarget->Name : "NULL"); 9486bf215546Sopenharmony_ci ImGui::Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\" (%d bytes)", g.DragDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropPayload.DataSize); 9487bf215546Sopenharmony_ci ImGui::TreePop(); 9488bf215546Sopenharmony_ci } 9489bf215546Sopenharmony_ci 9490bf215546Sopenharmony_ci 9491bf215546Sopenharmony_ci if (g.IO.KeyCtrl && show_window_begin_order) 9492bf215546Sopenharmony_ci { 9493bf215546Sopenharmony_ci for (int n = 0; n < g.Windows.Size; n++) 9494bf215546Sopenharmony_ci { 9495bf215546Sopenharmony_ci ImGuiWindow* window = g.Windows[n]; 9496bf215546Sopenharmony_ci if ((window->Flags & ImGuiWindowFlags_ChildWindow) || !window->WasActive) 9497bf215546Sopenharmony_ci continue; 9498bf215546Sopenharmony_ci char buf[32]; 9499bf215546Sopenharmony_ci ImFormatString(buf, IM_ARRAYSIZE(buf), "%d", window->BeginOrderWithinContext); 9500bf215546Sopenharmony_ci float font_size = ImGui::GetFontSize() * 2; 9501bf215546Sopenharmony_ci ImDrawList* overlay_draw_list = GetOverlayDrawList(window); 9502bf215546Sopenharmony_ci overlay_draw_list->AddRectFilled(window->Pos, window->Pos + ImVec2(font_size, font_size), IM_COL32(200, 100, 100, 255)); 9503bf215546Sopenharmony_ci overlay_draw_list->AddText(NULL, font_size, window->Pos, IM_COL32(255, 255, 255, 255), buf); 9504bf215546Sopenharmony_ci } 9505bf215546Sopenharmony_ci } 9506bf215546Sopenharmony_ci ImGui::End(); 9507bf215546Sopenharmony_ci} 9508bf215546Sopenharmony_ci 9509bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 9510bf215546Sopenharmony_ci 9511bf215546Sopenharmony_ci// Include imgui_user.inl at the end of imgui.cpp to access private data/functions that aren't exposed. 9512bf215546Sopenharmony_ci// Prefer just including imgui_internal.h from your code rather than using this define. If a declaration is missing from imgui_internal.h add it or request it on the github. 9513bf215546Sopenharmony_ci#ifdef IMGUI_INCLUDE_IMGUI_USER_INL 9514bf215546Sopenharmony_ci#include "imgui_user.inl" 9515bf215546Sopenharmony_ci#endif 9516bf215546Sopenharmony_ci 9517bf215546Sopenharmony_ci//----------------------------------------------------------------------------- 9518