Changeset e66fd66 in opengl-game
- Timestamp:
- Dec 5, 2020, 7:14:31 PM (4 years ago)
- Branches:
- feature/imgui-sdl, master
- Children:
- 95c657f
- Parents:
- 78c3045
- Files:
-
- 8 added
- 4 deleted
- 8 edited
- 3 moved
Legend:
- Unmodified
- Added
- Removed
-
.gitignore
r78c3045 re66fd66 16 16 *.opendb 17 17 .vs/ 18 *.filters19 18 *.dll 20 19 Debug/ -
IMGUI/imgui.cpp
r78c3045 re66fd66 1 // dear imgui, v1. 61 WIP1 // dear imgui, v1.79 2 2 // (main code and documentation) 3 3 4 // Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp for demo code. 5 // Newcomers, read 'Programmer guide' below for notes on how to setup Dear ImGui in your codebase. 6 // Get latest version at https://github.com/ocornut/imgui 7 // Releases change-log at https://github.com/ocornut/imgui/releases 8 // Gallery (please post your screenshots/video there!): https://github.com/ocornut/imgui/issues/1269 4 // Help: 5 // - Read FAQ at http://dearimgui.org/faq 6 // - Newcomers, read 'Programmer guide' below for notes on how to setup Dear ImGui in your codebase. 7 // - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that. 8 // Read imgui.cpp for details, links and comments. 9 10 // Resources: 11 // - FAQ http://dearimgui.org/faq 12 // - Homepage & latest https://github.com/ocornut/imgui 13 // - Releases & changelog https://github.com/ocornut/imgui/releases 14 // - Gallery https://github.com/ocornut/imgui/issues/3488 (please post your screenshots/video there!) 15 // - Glossary https://github.com/ocornut/imgui/wiki/Glossary 16 // - Wiki https://github.com/ocornut/imgui/wiki 17 // - Issues & support https://github.com/ocornut/imgui/issues 18 9 19 // Developed by Omar Cornut and every direct or indirect contributors to the GitHub. 10 // This library is free but I need your support to sustain development and maintenance. 11 // If you work for a company, please consider financial support, see README. For individuals: https://www.patreon.com/imgui 20 // See LICENSE.txt for copyright and licensing details (standard MIT License). 21 // This library is free but needs your support to sustain development and maintenance. 22 // Businesses: you can support continued development via invoiced technical support, maintenance and sponsoring contracts. Please reach out to "contact AT dearimgui.org". 23 // Individuals: you can support continued development via donations. See docs/README or web page. 12 24 13 25 // It is recommended that you don't modify imgui.cpp! It will become difficult for you to update the library. 14 // Note that 'ImGui::' being a namespace, you can add functions into the namespace from your own source files, without 15 // modifying imgui.h or imgui.cpp. You may include imgui_internal.h to access internal data structures, but it doesn't 16 // come with any guarantee of forward compatibility. Discussing your changes on the GitHub Issue Tracker may lead you 26 // Note that 'ImGui::' being a namespace, you can add functions into the namespace from your own source files, without 27 // modifying imgui.h or imgui.cpp. You may include imgui_internal.h to access internal data structures, but it doesn't 28 // come with any guarantee of forward compatibility. Discussing your changes on the GitHub Issue Tracker may lead you 17 29 // to a better solution or official support for them. 18 30 19 31 /* 20 32 21 Index 33 Index of this file: 34 35 DOCUMENTATION 36 22 37 - MISSION STATEMENT 23 38 - END-USER GUIDE 24 - PROGRAMMER GUIDE (read me!) 25 - Read first 26 - How to update to a newer version of Dear ImGui 27 - Getting started with integrating Dear ImGui in your code/engine 28 - Using gamepad/keyboard navigation controls [BETA] 39 - PROGRAMMER GUIDE 40 - READ FIRST 41 - HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI 42 - GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE 43 - HOW A SIMPLE APPLICATION MAY LOOK LIKE 44 - HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE 45 - USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS 29 46 - API BREAKING CHANGES (read me when you update!) 30 - ISSUES & TODO LIST 31 - FREQUENTLY ASKED QUESTIONS (FAQ), TIPS 32 - How can I tell whether to dispatch mouse/keyboard to imgui or to my application? 33 - How can I display an image? What is ImTextureID, how does it works? 34 - How can I have multiple widgets with the same label or without a label? A primer on labels and the ID Stack. 35 - How can I load a different font than the default? 36 - How can I easily use icons in my application? 37 - How can I load multiple fonts? 38 - How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic? 39 - How can I use the drawing facilities without an ImGui window? (using ImDrawList API) 40 - I integrated Dear ImGui in my engine and the text or lines are blurry.. 41 - I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around.. 42 - How can I help? 43 - ISSUES & TODO-LIST 44 - CODE 45 46 47 MISSION STATEMENT 48 ================= 49 50 - Easy to use to create code-driven and data-driven tools 51 - Easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools 52 - Easy to hack and improve 53 - Minimize screen real-estate usage 54 - Minimize setup and maintenance 55 - Minimize state storage on user side 56 - Portable, minimize dependencies, run on target (consoles, phones, etc.) 57 - Efficient runtime and memory consumption (NB- we do allocate when "growing" content e.g. creating a window, 58 opening a tree node for the first time, etc. but a typical frame should not allocate anything) 59 60 Designed for developers and content-creators, not the typical end-user! Some of the weaknesses includes: 61 - Doesn't look fancy, doesn't animate 62 - Limited layout features, intricate layouts are typically crafted in code 63 64 65 END-USER GUIDE 66 ============== 67 68 - Double-click on title bar to collapse window. 69 - Click upper right corner to close a window, available when 'bool* p_open' is passed to ImGui::Begin(). 70 - Click and drag on lower right corner to resize window (double-click to auto fit window to its contents). 71 - Click and drag on any empty space to move window. 72 - TAB/SHIFT+TAB to cycle through keyboard editable fields. 73 - CTRL+Click on a slider or drag box to input value as text. 74 - Use mouse wheel to scroll. 75 - Text editor: 76 - Hold SHIFT or use mouse to select text. 77 - CTRL+Left/Right to word jump. 78 - CTRL+Shift+Left/Right to select words. 79 - CTRL+A our Double-Click to select all. 80 - CTRL+X,CTRL+C,CTRL+V to use OS clipboard/ 81 - CTRL+Z,CTRL+Y to undo/redo. 82 - ESCAPE to revert text to its original value. 83 - You can apply arithmetic operators +,*,/ on numerical values. Use +- to subtract (because - would set a negative value!) 84 - Controls are automatically adjusted for OSX to match standard OSX text editing operations. 85 - General Keyboard controls: enable with ImGuiConfigFlags_NavEnableKeyboard. 86 - General Gamepad controls: enable with ImGuiConfigFlags_NavEnableGamepad. See suggested mappings in imgui.h ImGuiNavInput_ + download PNG/PSD at http://goo.gl/9LgVZW 87 88 89 PROGRAMMER GUIDE 90 ================ 91 92 READ FIRST 93 94 - Read the FAQ below this section! 95 - 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 96 or destruction steps, less data retention on your side, less state duplication, less state synchronization, less bugs. 97 - Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features. 98 - You can learn about immediate-mode gui principles at http://www.johno.se/book/imgui.html or watch http://mollyrocket.com/861 99 100 HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI 101 102 - Overwrite all the sources files except for imconfig.h (if you have made modification to your copy of imconfig.h) 103 - Read the "API BREAKING CHANGES" section (below). This is where we list occasional API breaking changes. 104 If a function/type has been renamed / or marked obsolete, try to fix the name in your code before it is permanently removed 105 from the public API. If you have a problem with a missing function/symbols, search for its name in the code, there will 106 likely be a comment about it. Please report any issue to the GitHub page! 107 - Try to keep your copy of dear imgui reasonably up to date. 108 109 GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE 110 111 - Run and study the examples and demo to get acquainted with the library. 112 - Add the Dear ImGui source files to your projects, using your preferred build system. 113 It is recommended you build the .cpp files as part of your project and not as a library. 114 - You can later customize the imconfig.h file to tweak some compilation time behavior, such as integrating imgui types with your own maths types. 115 - You may be able to grab and copy a ready made imgui_impl_*** file from the examples/ folder. 116 - When using Dear ImGui, your programming IDE is your friend: follow the declaration of variables, functions and types to find comments about them. 117 118 - Init: retrieve the ImGuiIO structure with ImGui::GetIO() and fill the fields marked 'Settings': at minimum you need to set io.DisplaySize 119 (application resolution). Later on you will fill your keyboard mapping, clipboard handlers, and other advanced features but for a basic 120 integration you don't need to worry about it all. 121 - Init: call io.Fonts->GetTexDataAsRGBA32(...), it will build the font atlas texture, then load the texture pixels into graphics memory. 122 - Every frame: 123 - In your main loop as early a possible, fill the IO fields marked 'Input' (e.g. mouse position, buttons, keyboard info, etc.) 124 - Call ImGui::NewFrame() to begin the frame 125 - You can use any ImGui function you want between NewFrame() and Render() 126 - Call ImGui::Render() as late as you can to end the frame and finalize render data. it will call your io.RenderDrawListFn handler. 127 (Even if you don't render, call Render() and ignore the callback, or call EndFrame() instead. Otherwise some features will break) 128 - All rendering information are stored into command-lists until ImGui::Render() is called. 129 - Dear ImGui never touches or knows about your GPU state. the only function that knows about GPU is the RenderDrawListFn handler that you provide. 130 - Effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render" phases 131 of your own application. 132 - Refer to the examples applications in the examples/ folder for instruction on how to setup your code. 133 - A minimal application skeleton may be: 134 135 // Application init 136 ImGui::CreateContext(); 137 ImGuiIO& io = ImGui::GetIO(); 138 io.DisplaySize.x = 1920.0f; 139 io.DisplaySize.y = 1280.0f; 140 // TODO: Fill others settings of the io structure later. 141 142 // Load texture atlas (there is a default font so you don't need to care about choosing a font yet) 143 unsigned char* pixels; 144 int width, height; 145 io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); 146 // TODO: At this points you've got the texture data and you need to upload that your your graphic system: 147 MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA) 148 // TODO: Store your texture pointer/identifier (whatever your engine uses) in 'io.Fonts->TexID'. This will be passed back to your via the renderer. 149 io.Fonts->TexID = (void*)texture; 150 151 // Application main loop 152 while (true) 153 { 154 // Setup low-level inputs (e.g. on Win32, GetKeyboardState(), or write to those fields from your Windows message loop handlers, etc.) 155 ImGuiIO& io = ImGui::GetIO(); 156 io.DeltaTime = 1.0f/60.0f; 157 io.MousePos = mouse_pos; 158 io.MouseDown[0] = mouse_button_0; 159 io.MouseDown[1] = mouse_button_1; 160 161 // Call NewFrame(), after this point you can use ImGui::* functions anytime 162 ImGui::NewFrame(); 163 164 // Most of your application code here 165 MyGameUpdate(); // may use any ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End(); 166 MyGameRender(); // may use any ImGui functions as well! 167 168 // Render & swap video buffers 169 ImGui::Render(); 170 MyImGuiRenderFunction(ImGui::GetDrawData()); 171 SwapBuffers(); 172 } 173 174 // Shutdown 175 ImGui::DestroyContext(); 176 177 178 - A minimal render function skeleton may be: 179 180 void void MyRenderFunction(ImDrawData* draw_data) 181 { 182 // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled 183 // TODO: Setup viewport, orthographic projection matrix 184 // TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color. 185 for (int n = 0; n < draw_data->CmdListsCount; n++) 186 { 187 const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; // vertex buffer generated by ImGui 188 const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; // index buffer generated by ImGui 189 for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) 190 { 191 const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; 192 if (pcmd->UserCallback) 193 { 194 pcmd->UserCallback(cmd_list, pcmd); 195 } 196 else 197 { 198 // The texture for the draw call is specified by pcmd->TextureId. 199 // The vast majority of draw calls with use the imgui texture atlas, which value you have set yourself during initialization. 200 MyEngineBindTexture(pcmd->TextureId); 201 202 // We are using scissoring to clip some objects. All low-level graphics API supports it. 203 // If your engine doesn't support scissoring yet, you may ignore this at first. You will get some small glitches 204 // (some elements visible outside their bounds) but you can fix that once everywhere else works! 205 MyEngineScissor((int)pcmd->ClipRect.x, (int)pcmd->ClipRect.y, (int)(pcmd->ClipRect.z - pcmd->ClipRect.x), (int)(pcmd->ClipRect.w - pcmd->ClipRect.y)); 206 207 // Render 'pcmd->ElemCount/3' indexed triangles. 208 // By default the indices ImDrawIdx are 16-bits, you can change them to 32-bits if your engine doesn't support 16-bits indices. 209 MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer, vtx_buffer); 210 } 211 idx_buffer += pcmd->ElemCount; 212 } 213 } 214 } 215 216 - The examples/ folders contains many functional implementation of the pseudo-code above. 217 - When calling NewFrame(), the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags are updated. 218 They tell you if ImGui intends to use your inputs. When a flag is set you want to hide the corresponding inputs from the rest of your application. 219 However, in both cases you need to pass on the inputs to imgui. Read the FAQ below for more information about those flags. 220 - Please read the FAQ above. Amusingly, it is called a FAQ because people frequently have the same issues! 221 222 USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS [BETA] 223 224 - The gamepad/keyboard navigation is in Beta. Ask questions and report issues at https://github.com/ocornut/imgui/issues/787 225 - The initial focus was to support game controllers, but keyboard is becoming increasingly and decently usable. 226 - Gamepad: 227 - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable. 228 - Backend: Set io.BackendFlags |= ImGuiBackendFlags_HasGamepad + fill the io.NavInputs[] fields before calling NewFrame(). 229 Note that io.NavInputs[] is cleared by EndFrame(). 230 - See 'enum ImGuiNavInput_' in imgui.h for a description of inputs. For each entry of io.NavInputs[], set the following values: 231 0.0f= not held. 1.0f= fully held. Pass intermediate 0.0f..1.0f values for analog triggers/sticks. 232 - We uses a simple >0.0f test for activation testing, and won't attempt to test for a dead-zone. 233 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.). 234 - You can download PNG/PSD files depicting the gamepad controls for common controllers at: goo.gl/9LgVZW. 235 - 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 236 to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved. 237 - Keyboard: 238 - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. 239 NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays. 240 - When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard), the io.WantCaptureKeyboard flag 241 will be set. For more advanced uses, you may want to read from: 242 - io.NavActive: true when a window is focused and it doesn't have the ImGuiWindowFlags_NoNavInputs flag set. 243 - io.NavVisible: true when the navigation cursor is visible (and usually goes false when mouse is used). 244 - or query focus information with e.g. IsWindowFocused(ImGuiFocusedFlags_AnyWindow), IsItemFocused() etc. functions. 245 Please reach out if you think the game vs navigation input sharing could be improved. 246 - Mouse: 247 - PS4 users: Consider emulating a mouse cursor with DualShock4 touch pad or a spare analog stick as a mouse-emulation fallback. 248 - 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. 249 - 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. 250 Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs dear imgui to move your mouse cursor along with navigation movements. 251 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. 252 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. 253 (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!) 254 (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 255 to set a boolean to ignore your other external mouse positions until the external source is moved again.) 256 257 258 API BREAKING CHANGES 259 ==================== 260 261 Occasionally introducing changes that are breaking the API. The breakage are generally minor and easy to fix. 262 Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code. 263 Also read releases logs https://github.com/ocornut/imgui/releases for more details. 264 265 - 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", consistent with other functions. Kept redirection functions (will obsolete). 266 - 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. 267 - 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). 268 - 2018/03/12 (1.60) - Removed ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered as the closing cross uses regular button colors now. 269 - 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. 270 - 2018/03/03 (1.60) - Renamed ImGuiStyleVar_Count_ to ImGuiStyleVar_COUNT and ImGuiMouseCursor_Count_ to ImGuiMouseCursor_COUNT for consistency with other public enums. 271 - 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. 272 - 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. 273 - 2018/02/07 (1.60) - reorganized context handling to be more explicit, 274 - YOU NOW NEED TO CALL ImGui::CreateContext() AT THE BEGINNING OF YOUR APP, AND CALL ImGui::DestroyContext() AT THE END. 275 - removed Shutdown() function, as DestroyContext() serve this purpose. 276 - you may pass a ImFontAtlas* pointer to CreateContext() to share a font atlas between contexts. Otherwise CreateContext() will create its own font atlas instance. 277 - removed allocator parameters from CreateContext(), they are now setup with SetAllocatorFunctions(), and shared by all contexts. 278 - removed the default global context and font atlas instance, which were confusing for users of DLL reloading and users of multiple contexts. 279 - 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. 280 - 2018/01/11 (1.60) - obsoleted IsAnyWindowHovered() in favor of IsWindowHovered(ImGuiHoveredFlags_AnyWindow). Kept redirection function (will obsolete). 281 - 2018/01/11 (1.60) - obsoleted IsAnyWindowFocused() in favor of IsWindowFocused(ImGuiFocusedFlags_AnyWindow). Kept redirection function (will obsolete). 282 - 2018/01/03 (1.60) - renamed ImGuiSizeConstraintCallback to ImGuiSizeCallback, ImGuiSizeConstraintCallbackData to ImGuiSizeCallbackData. 283 - 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. 284 - 2017/12/24 (1.53) - renamed the emblematic ShowTestWindow() function to ShowDemoWindow(). Kept redirection function (will obsolete). 285 - 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 286 - 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. 287 - 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. 288 - 2017/12/13 (1.53) - renamed GetItemsLineHeightWithSpacing() to GetFrameHeightWithSpacing(). Kept redirection function (will obsolete). 289 - 2017/12/13 (1.53) - obsoleted IsRootWindowFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootWindow). Kept redirection function (will obsolete). 290 - obsoleted IsRootWindowOrAnyChildFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows). Kept redirection function (will obsolete). 291 - 2017/12/12 (1.53) - renamed ImGuiTreeNodeFlags_AllowOverlapMode to ImGuiTreeNodeFlags_AllowItemOverlap. Kept redirection enum (will obsolete). 292 - 2017/12/10 (1.53) - removed SetNextWindowContentWidth(), prefer using SetNextWindowContentSize(). Kept redirection function (will obsolete). 293 - 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. 294 - 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. 295 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. 296 - 2017/11/18 (1.53) - Style: removed ImGuiCol_ComboBg in favor of combo boxes using ImGuiCol_PopupBg for consistency. 297 - 2017/11/18 (1.53) - Style: renamed ImGuiCol_ChildWindowBg to ImGuiCol_ChildBg. 298 - 2017/11/18 (1.53) - Style: renamed style.ChildWindowRounding to style.ChildRounding, ImGuiStyleVar_ChildWindowRounding to ImGuiStyleVar_ChildRounding. 299 - 2017/11/02 (1.53) - obsoleted IsRootWindowOrAnyChildHovered() in favor of using IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows); 300 - 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. 301 - 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. 302 - 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. 303 removed the IsItemRectHovered()/IsWindowRectHovered() names introduced in 1.51 since they were merely more consistent names for the two functions we are now obsoleting. 304 - 2017/10/17 (1.52) - marked the old 5-parameters version of Begin() as obsolete (still available). Use SetNextWindowSize()+Begin() instead! 305 - 2017/10/11 (1.52) - renamed AlignFirstTextHeightToWidgets() to AlignTextToFramePadding(). Kept inline redirection function (will obsolete). 306 - 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). 307 - 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)". 308 - 2017/08/22 (1.51) - renamed IsItemHoveredRect() to IsItemRectHovered(). Kept inline redirection function (will obsolete). -> (1.52) use IsItemHovered(ImGuiHoveredFlags_RectOnly)! 309 - renamed IsMouseHoveringAnyWindow() to IsAnyWindowHovered() for consistency. Kept inline redirection function (will obsolete). 310 - renamed IsMouseHoveringWindow() to IsWindowRectHovered() for consistency. Kept inline redirection function (will obsolete). 311 - 2017/08/20 (1.51) - renamed GetStyleColName() to GetStyleColorName() for consistency. 312 - 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. 313 - 2017/08/15 (1.51) - marked the weird IMGUI_ONCE_UPON_A_FRAME helper macro as obsolete. prefer using the more explicit ImGuiOnceUponAFrame. 314 - 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. 315 - 2017/08/13 (1.51) - renamed ImGuiCol_Columns*** to ImGuiCol_Separator***. Kept redirection enums (will obsolete). 316 - 2017/08/11 (1.51) - renamed ImGuiSetCond_*** types and flags to ImGuiCond_***. Kept redirection enums (will obsolete). 317 - 2017/08/09 (1.51) - removed ValueColor() helpers, they are equivalent to calling Text(label) + SameLine() + ColorButton(). 318 - 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. 319 - 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. 320 - 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))' 321 - 2017/07/20 (1.51) - removed IsPosHoveringAnyWindow(ImVec2), which was partly broken and misleading. ASSERT + redirect user to io.WantCaptureMouse 322 - 2017/05/26 (1.50) - removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset. 323 - 2017/05/01 (1.50) - renamed ImDrawList::PathFill() (rarely used directly) to ImDrawList::PathFillConvex() for clarity. 324 - 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(). 325 - 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it. 326 - 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. 327 - 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. 328 - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore. 329 If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you. 330 However if your TitleBg/TitleBgActive alpha was <1.0f you need to tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar. 331 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. 332 ImVec4 ConvertTitleBgCol(const ImVec4& win_bg_col, const ImVec4& title_bg_col) 333 { 334 float new_a = 1.0f - ((1.0f - win_bg_col.w) * (1.0f - title_bg_col.w)), k = title_bg_col.w / new_a; 335 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); 336 } 337 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. 338 - 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext(). 339 - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection. 340 - 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). 341 - 2016/04/26 (1.49) - changed ImDrawList::PushClipRect(ImVec4 rect) to ImDraw::PushClipRect(Imvec2 min,ImVec2 max,bool intersect_with_current_clip_rect=false). Note that higher-level ImGui::PushClipRect() is preferable because it will clip at logic/widget level, whereas ImDrawList::PushClipRect() only affect your renderer. 342 - 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). 343 - 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) 344 - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete). 345 - 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. 346 - 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. 347 - 2015/12/27 (1.48) - fixed ImDrawList::AddRect() which used to render a rectangle 1 px too large on each axis. 348 - 2015/12/04 (1.47) - renamed Color() helpers to ValueColor() - dangerously named, rarely used and probably to be made obsolete. 349 - 2015/08/29 (1.45) - with the addition of horizontal scrollbar we made various fixes to inconsistencies with dealing with cursor position. 350 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. 351 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! 352 - 2015/08/29 (1.45) - renamed style.ScrollbarWidth to style.ScrollbarSize 353 - 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. 354 - 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 355 - 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. 356 you need to render your textured triangles with bilinear filtering to benefit from sub-pixel positioning of text. 357 - 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. 358 this necessary change will break your rendering function! the fix should be very easy. sorry for that :( 359 - 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. 360 - the signature of the io.RenderDrawListsFn handler has changed! 361 old: ImGui_XXXX_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count) 362 new: ImGui_XXXX_RenderDrawLists(ImDrawData* draw_data). 363 argument: 'cmd_lists' becomes 'draw_data->CmdLists', 'cmd_lists_count' becomes 'draw_data->CmdListsCount' 364 ImDrawList: 'commands' becomes 'CmdBuffer', 'vtx_buffer' becomes 'VtxBuffer', 'IdxBuffer' is new. 365 ImDrawCmd: 'vtx_count' becomes 'ElemCount', 'clip_rect' becomes 'ClipRect', 'user_callback' becomes 'UserCallback', 'texture_id' becomes 'TextureId'. 366 - 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. 367 - 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! 368 - refer to code in the examples/ folder or ask on the GitHub if you are unsure of how to upgrade. please upgrade! 369 - 2015/07/10 (1.43) - changed SameLine() parameters from int to float. 370 - 2015/07/02 (1.42) - renamed SetScrollPosHere() to SetScrollFromCursorPos(). Kept inline redirection function (will obsolete). 371 - 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. 372 - 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 373 - 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! 374 - 2015/05/31 (1.40) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete). 375 - 2015/05/31 (1.40) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete). 376 - 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. 377 - 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. 378 - 2015/05/03 (1.40) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same). 379 - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function until 1.50. 380 - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API 381 - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive. 382 - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead. 383 - 2015/03/17 (1.36) - renamed GetItemBoxMin()/GetItemBoxMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function until 1.50. 384 - 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing 385 - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function until 1.50. 386 - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth (casing) 387 - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function until 1.50. 388 - 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once. 389 - 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now. 390 - 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior 391 - 2015/02/08 (1.31) - renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing() 392 - 2015/02/01 (1.31) - removed IO.MemReallocFn (unused) 393 - 2015/01/19 (1.30) - renamed ImGuiStorage::GetIntPtr()/GetFloatPtr() to GetIntRef()/GetIntRef() because Ptr was conflicting with actual pointer storage functions. 394 - 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader. 395 (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels. 396 font init: const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); <..Upload texture to GPU..> 397 became: unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); <..Upload texture to GPU>; io.Fonts->TexId = YourTextureIdentifier; 398 you now more flexibility to load multiple TTF fonts and manage the texture buffer for internal needs. 399 it is now recommended that you sample the font texture with bilinear interpolation. 400 (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to set io.Fonts->TexID. 401 (1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix) 402 (1.30) - removed ImGui::IsItemFocused() in favor of ImGui::IsItemActive() which handles all widgets 403 - 2014/12/10 (1.18) - removed SetNewWindowDefaultPos() in favor of new generic API SetNextWindowPos(pos, ImGuiSetCondition_FirstUseEver) 404 - 2014/11/28 (1.17) - moved IO.Font*** options to inside the IO.Font-> structure (FontYOffset, FontTexUvForWhite, FontBaseScale, FontFallbackGlyph) 405 - 2014/11/26 (1.17) - reworked syntax of IMGUI_ONCE_UPON_A_FRAME helper macro to increase compiler compatibility 406 - 2014/11/07 (1.15) - renamed IsHovered() to IsItemHovered() 407 - 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) 408 - 2014/09/25 (1.13) - removed 'text_end' parameter from IO.SetClipboardTextFn (the string is now always zero-terminated for simplicity) 409 - 2014/09/24 (1.12) - renamed SetFontScale() to SetWindowFontScale() 410 - 2014/09/24 (1.12) - moved IM_MALLOC/IM_REALLOC/IM_FREE preprocessor defines to IO.MemAllocFn/IO.MemReallocFn/IO.MemFreeFn 411 - 2014/08/30 (1.09) - removed IO.FontHeight (now computed automatically) 412 - 2014/08/30 (1.09) - moved IMGUI_FONT_TEX_UV_FOR_WHITE preprocessor define to IO.FontTexUvForWhite 413 - 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes 414 415 416 ISSUES & TODO-LIST 417 ================== 418 See TODO.txt 419 420 421 FREQUENTLY ASKED QUESTIONS (FAQ), TIPS 422 ====================================== 423 424 Q: How can I tell whether to dispatch mouse/keyboard to imgui or to my application? 425 A: You can read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags from the ImGuiIO structure. 426 - 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. 427 - 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. 428 - 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). 429 Note: you should always pass your mouse/keyboard inputs to imgui, even when the io.WantCaptureXXX flag are set false. 430 This is because imgui needs to detect that you clicked in the void to unfocus its windows. 431 Note: The 'io.WantCaptureMouse' is more accurate that any attempt to "check if the mouse is hovering a window" (don't do that!). 432 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. 433 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 434 perfectly fine, as the bool toggle fairly rarely. If you have on a touch device, you might find use for an early call to NewFrameUpdateHoveredWindowAndCaptureFlags(). 435 Note: Text input widget releases focus on "Return KeyDown", so the subsequent "Return KeyUp" event that your application receive will typically 436 have 'io.WantCaptureKeyboard=false'. Depending on your application logic it may or not be inconvenient. You might want to track which key-downs 437 were targeted for Dear ImGui, e.g. with an array of bool, and filter out the corresponding key-ups.) 438 439 Q: How can I display an image? What is ImTextureID, how does it works? 440 A: ImTextureID is a void* used to pass renderer-agnostic texture references around until it hits your render function. 441 Dear ImGui knows nothing about what those bits represent, it just passes them around. It is up to you to decide what you want the void* to carry! 442 It could be an identifier to your OpenGL texture (cast GLuint to void*), a pointer to your custom engine material (cast MyMaterial* to void*), etc. 443 At the end of the chain, your renderer takes this void* to cast it back into whatever it needs to select a current texture to render. 444 Refer to examples applications, where each renderer (in a imgui_impl_xxxx.cpp file) is treating ImTextureID as a different thing. 445 (C++ tip: OpenGL uses integers to identify textures. You can safely store an integer into a void*, just cast it to void*, don't take it's address!) 446 To display a custom image/texture within an ImGui window, you may use ImGui::Image(), ImGui::ImageButton(), ImDrawList::AddImage() functions. 447 Dear ImGui will generate the geometry and draw calls using the ImTextureID that you passed and which your renderer can use. 448 You may call ImGui::ShowMetricsWindow() to explore active draw lists and visualize/understand how the draw data is generated. 449 It is your responsibility to get textures uploaded to your GPU. 450 451 Q: How can I have multiple widgets with the same label or without a label? 452 A: A primer on labels and the ID Stack... 453 454 - Elements that are typically not clickable, such as Text() items don't need an ID. 455 456 - Interactive widgets require state to be carried over multiple frames (most typically Dear ImGui 457 often needs to remember what is the "active" widget). To do so they need a unique ID. Unique ID 458 are typically derived from a string label, an integer index or a pointer. 459 460 Button("OK"); // Label = "OK", ID = top of id stack + hash of "OK" 461 Button("Cancel"); // Label = "Cancel", ID = top of id stack + hash of "Cancel" 462 463 - ID are uniquely scoped within windows, tree nodes, etc. which all pushes to the ID stack. Having 464 two buttons labeled "OK" in different windows or different tree locations is fine. 465 466 - If you have a same ID twice in the same location, you'll have a conflict: 467 468 Button("OK"); 469 Button("OK"); // ID collision! Interacting with either button will trigger the first one. 470 471 Fear not! this is easy to solve and there are many ways to solve it! 472 473 - Solving ID conflict in a simple/local context: 474 When passing a label you can optionally specify extra ID information within string itself. 475 Use "##" to pass a complement to the ID that won't be visible to the end-user. 476 This helps solving the simple collision cases when you know e.g. at compilation time which items 477 are going to be created: 478 479 Button("Play"); // Label = "Play", ID = top of id stack + hash of "Play" 480 Button("Play##foo1"); // Label = "Play", ID = top of id stack + hash of "Play##foo1" (different from above) 481 Button("Play##foo2"); // Label = "Play", ID = top of id stack + hash of "Play##foo2" (different from above) 482 483 - If you want to completely hide the label, but still need an ID: 484 485 Checkbox("##On", &b); // Label = "", ID = top of id stack + hash of "##On" (no label!) 486 487 - Occasionally/rarely you might want change a label while preserving a constant ID. This allows 488 you to animate labels. For example you may want to include varying information in a window title bar, 489 but windows are uniquely identified by their ID. Use "###" to pass a label that isn't part of ID: 490 491 Button("Hello###ID"; // Label = "Hello", ID = top of id stack + hash of "ID" 492 Button("World###ID"; // Label = "World", ID = top of id stack + hash of "ID" (same as above) 493 494 sprintf(buf, "My game (%f FPS)###MyGame", fps); 495 Begin(buf); // Variable label, ID = hash of "MyGame" 496 497 - Solving ID conflict in a more general manner: 498 Use PushID() / PopID() to create scopes and manipulate the ID stack, as to avoid ID conflicts 499 within the same window. This is the most convenient way of distinguishing ID when iterating and 500 creating many UI elements programmatically. 501 You can push a pointer, a string or an integer value into the ID stack. 502 Remember that ID are formed from the concatenation of _everything_ in the ID stack! 503 504 for (int i = 0; i < 100; i++) 505 { 506 PushID(i); 507 Button("Click"); // Label = "Click", ID = top of id stack + hash of integer + hash of "Click" 508 PopID(); 509 } 510 511 for (int i = 0; i < 100; i++) 512 { 513 MyObject* obj = Objects[i]; 514 PushID(obj); 515 Button("Click"); // Label = "Click", ID = top of id stack + hash of pointer + hash of "Click" 516 PopID(); 517 } 518 519 for (int i = 0; i < 100; i++) 520 { 521 MyObject* obj = Objects[i]; 522 PushID(obj->Name); 523 Button("Click"); // Label = "Click", ID = top of id stack + hash of string + hash of "Click" 524 PopID(); 525 } 526 527 - More example showing that you can stack multiple prefixes into the ID stack: 528 529 Button("Click"); // Label = "Click", ID = top of id stack + hash of "Click" 530 PushID("node"); 531 Button("Click"); // Label = "Click", ID = top of id stack + hash of "node" + hash of "Click" 532 PushID(my_ptr); 533 Button("Click"); // Label = "Click", ID = top of id stack + hash of "node" + hash of ptr + hash of "Click" 534 PopID(); 535 PopID(); 536 537 - Tree nodes implicitly creates a scope for you by calling PushID(). 538 539 Button("Click"); // Label = "Click", ID = top of id stack + hash of "Click" 540 if (TreeNode("node")) 541 { 542 Button("Click"); // Label = "Click", ID = top of id stack + hash of "node" + hash of "Click" 543 TreePop(); 544 } 545 546 - When working with trees, ID are used to preserve the open/close state of each tree node. 547 Depending on your use cases you may want to use strings, indices or pointers as ID. 548 e.g. when following a single pointer that may change over time, using a static string as ID 549 will preserve your node open/closed state when the targeted object change. 550 e.g. when displaying a list of objects, using indices or pointers as ID will preserve the 551 node open/closed state differently. See what makes more sense in your situation! 552 553 Q: How can I load a different font than the default? 554 A: Use the font atlas to load the TTF/OTF file you want: 555 ImGuiIO& io = ImGui::GetIO(); 556 io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels); 557 io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8() 558 (default is ProggyClean.ttf, rendered at size 13, embedded in dear imgui's source code) 559 560 New programmers: remember that in C/C++ and most programming languages if you want to use a 561 backslash \ within a string literal, you need to write it double backslash "\\": 562 io.Fonts->AddFontFromFileTTF("MyDataFolder\MyFontFile.ttf", size_in_pixels); // WRONG (you are escape the M here!) 563 io.Fonts->AddFontFromFileTTF("MyDataFolder\\MyFontFile.ttf", size_in_pixels); // CORRECT 564 io.Fonts->AddFontFromFileTTF("MyDataFolder/MyFontFile.ttf", size_in_pixels); // ALSO CORRECT 565 566 Q: How can I easily use icons in my application? 567 A: The most convenient and practical way is to merge an icon font such as FontAwesome inside you 568 main font. Then you can refer to icons within your strings. Read 'How can I load multiple fonts?' 569 and the file 'misc/fonts/README.txt' for instructions and useful header files. 570 571 Q: How can I load multiple fonts? 572 A: Use the font atlas to pack them into a single texture: 573 (Read misc/fonts/README.txt and the code in ImFontAtlas for more details.) 574 575 ImGuiIO& io = ImGui::GetIO(); 576 ImFont* font0 = io.Fonts->AddFontDefault(); 577 ImFont* font1 = io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels); 578 ImFont* font2 = io.Fonts->AddFontFromFileTTF("myfontfile2.ttf", size_in_pixels); 579 io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8() 580 // the first loaded font gets used by default 581 // use ImGui::PushFont()/ImGui::PopFont() to change the font at runtime 582 583 // Options 584 ImFontConfig config; 585 config.OversampleH = 3; 586 config.OversampleV = 1; 587 config.GlyphOffset.y -= 2.0f; // Move everything by 2 pixels up 588 config.GlyphExtraSpacing.x = 1.0f; // Increase spacing between characters 589 io.Fonts->LoadFromFileTTF("myfontfile.ttf", size_pixels, &config); 590 591 // Combine multiple fonts into one (e.g. for icon fonts) 592 ImWchar ranges[] = { 0xf000, 0xf3ff, 0 }; 593 ImFontConfig config; 594 config.MergeMode = true; 595 io.Fonts->AddFontDefault(); 596 io.Fonts->LoadFromFileTTF("fontawesome-webfont.ttf", 16.0f, &config, ranges); // Merge icon font 597 io.Fonts->LoadFromFileTTF("myfontfile.ttf", size_pixels, NULL, &config, io.Fonts->GetGlyphRangesJapanese()); // Merge japanese glyphs 598 599 Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic? 600 A: When loading a font, pass custom Unicode ranges to specify the glyphs to load. 601 602 // Add default Japanese ranges 603 io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, io.Fonts->GetGlyphRangesJapanese()); 604 605 // 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) 606 ImVector<ImWchar> ranges; 607 ImFontAtlas::GlyphRangesBuilder builder; 608 builder.AddText("Hello world"); // Add a string (here "Hello world" contains 7 unique characters) 609 builder.AddChar(0x7262); // Add a specific character 610 builder.AddRanges(io.Fonts->GetGlyphRangesJapanese()); // Add one of the default ranges 611 builder.BuildRanges(&ranges); // Build the final result (ordered ranges with all the unique characters submitted) 612 io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, ranges.Data); 613 614 All your strings needs to use UTF-8 encoding. In C++11 you can encode a string literal in UTF-8 615 by using the u8"hello" syntax. Specifying literal in your source code using a local code page 616 (such as CP-923 for Japanese or CP-1251 for Cyrillic) will NOT work! 617 Otherwise you can convert yourself to UTF-8 or load text data from file already saved as UTF-8. 618 619 Text input: it is up to your application to pass the right character code by calling 620 io.AddInputCharacter(). The applications in examples/ are doing that. For languages relying 621 on an Input Method Editor (IME), on Windows you can copy the Hwnd of your application in the 622 io.ImeWindowHandle field. The default implementation of io.ImeSetInputScreenPosFn() will set 623 your Microsoft IME position correctly. 624 625 Q: How can I use the drawing facilities without an ImGui window? (using ImDrawList API) 626 A: - You can create a dummy window. Call SetNextWindowBgAlpha(0.0f), call Begin() with NoTitleBar|NoResize|NoMove|NoScrollbar|NoSavedSettings|NoInputs flags. 627 Then you can retrieve the ImDrawList* via GetWindowDrawList() and draw to it in any way you like. 628 - You can call ImGui::GetOverlayDrawList() and use this draw list to display contents over every other imgui windows. 629 - You can create your own ImDrawList instance. You'll need to initialize them ImGui::GetDrawListSharedData(), or create your own ImDrawListSharedData. 630 631 Q: I integrated Dear ImGui in my engine and the text or lines are blurry.. 632 A: In your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f). 633 Also make sure your orthographic projection matrix and io.DisplaySize matches your actual framebuffer dimension. 634 635 Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around.. 636 A: You are probably mishandling the clipping rectangles in your render function. 637 Rectangles provided by ImGui are defined as (x1=left,y1=top,x2=right,y2=bottom) and NOT as (x1,y1,width,height). 638 639 Q: How can I help? 640 A: - If you are experienced with Dear ImGui and C++, look at the github issues, or TODO.txt and see how you want/can help! 641 - Convince your company to fund development time! Individual users: you can also become a Patron (patreon.com/imgui) or donate on PayPal! See README. 642 - Disclose your usage of dear imgui via a dev blog post, a tweet, a screenshot, a mention somewhere etc. 643 You may post screenshot or links in the gallery threads (github.com/ocornut/imgui/issues/1269). Visuals are ideal as they inspire other programmers. 644 But even without visuals, disclosing your use of dear imgui help the library grow credibility, and help other teams and programmers with taking decisions. 645 - 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). 646 647 - tip: you can call Begin() multiple times with the same name during the same frame, it will keep appending to the same window. 648 this is also useful to set yourself in the context of another window (to get/set other settings) 649 - tip: you can create widgets without a Begin()/End() block, they will go in an implicit window called "Debug". 650 - 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 651 of a deep nested inner loop in your code. 652 - tip: you can call Render() multiple times (e.g for VR renders). 653 - tip: call and read the ShowDemoWindow() code in imgui_demo.cpp for more example of how to use ImGui! 47 - FREQUENTLY ASKED QUESTIONS (FAQ) 48 - Read all answers online: https://www.dearimgui.org/faq, or in docs/FAQ.md (with a Markdown viewer) 49 50 CODE 51 (search for "[SECTION]" in the code to find them) 52 53 // [SECTION] INCLUDES 54 // [SECTION] FORWARD DECLARATIONS 55 // [SECTION] CONTEXT AND MEMORY ALLOCATORS 56 // [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO) 57 // [SECTION] MISC HELPERS/UTILITIES (Geometry functions) 58 // [SECTION] MISC HELPERS/UTILITIES (String, Format, Hash functions) 59 // [SECTION] MISC HELPERS/UTILITIES (File functions) 60 // [SECTION] MISC HELPERS/UTILITIES (ImText* functions) 61 // [SECTION] MISC HELPERS/UTILITIES (Color functions) 62 // [SECTION] ImGuiStorage 63 // [SECTION] ImGuiTextFilter 64 // [SECTION] ImGuiTextBuffer 65 // [SECTION] ImGuiListClipper 66 // [SECTION] STYLING 67 // [SECTION] RENDER HELPERS 68 // [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!) 69 // [SECTION] ERROR CHECKING 70 // [SECTION] LAYOUT 71 // [SECTION] SCROLLING 72 // [SECTION] TOOLTIPS 73 // [SECTION] POPUPS 74 // [SECTION] KEYBOARD/GAMEPAD NAVIGATION 75 // [SECTION] DRAG AND DROP 76 // [SECTION] LOGGING/CAPTURING 77 // [SECTION] SETTINGS 78 // [SECTION] PLATFORM DEPENDENT HELPERS 79 // [SECTION] METRICS/DEBUG WINDOW 654 80 655 81 */ 82 83 //----------------------------------------------------------------------------- 84 // DOCUMENTATION 85 //----------------------------------------------------------------------------- 86 87 /* 88 89 MISSION STATEMENT 90 ================= 91 92 - Easy to use to create code-driven and data-driven tools. 93 - Easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools. 94 - Easy to hack and improve. 95 - Minimize setup and maintenance. 96 - Minimize state storage on user side. 97 - Portable, minimize dependencies, run on target (consoles, phones, etc.). 98 - Efficient runtime and memory consumption. 99 100 Designed for developers and content-creators, not the typical end-user! Some of the current weaknesses includes: 101 102 - Doesn't look fancy, doesn't animate. 103 - Limited layout features, intricate layouts are typically crafted in code. 104 105 106 END-USER GUIDE 107 ============== 108 109 - Double-click on title bar to collapse window. 110 - Click upper right corner to close a window, available when 'bool* p_open' is passed to ImGui::Begin(). 111 - Click and drag on lower right corner to resize window (double-click to auto fit window to its contents). 112 - Click and drag on any empty space to move window. 113 - TAB/SHIFT+TAB to cycle through keyboard editable fields. 114 - CTRL+Click on a slider or drag box to input value as text. 115 - Use mouse wheel to scroll. 116 - Text editor: 117 - Hold SHIFT or use mouse to select text. 118 - CTRL+Left/Right to word jump. 119 - CTRL+Shift+Left/Right to select words. 120 - CTRL+A our Double-Click to select all. 121 - CTRL+X,CTRL+C,CTRL+V to use OS clipboard/ 122 - CTRL+Z,CTRL+Y to undo/redo. 123 - ESCAPE to revert text to its original value. 124 - You can apply arithmetic operators +,*,/ on numerical values. Use +- to subtract (because - would set a negative value!) 125 - Controls are automatically adjusted for OSX to match standard OSX text editing operations. 126 - General Keyboard controls: enable with ImGuiConfigFlags_NavEnableKeyboard. 127 - General Gamepad controls: enable with ImGuiConfigFlags_NavEnableGamepad. See suggested mappings in imgui.h ImGuiNavInput_ + download PNG/PSD at http://goo.gl/9LgVZW 128 129 130 PROGRAMMER GUIDE 131 ================ 132 133 READ FIRST 134 ---------- 135 - Remember to read the FAQ (https://www.dearimgui.org/faq) 136 - 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 137 or destruction steps, less superfluous data retention on your side, less state duplication, less state synchronization, less bugs. 138 - Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features. 139 - The library is designed to be built from sources. Avoid pre-compiled binaries and packaged versions. See imconfig.h to configure your build. 140 - Dear ImGui is an implementation of the IMGUI paradigm (immediate-mode graphical user interface, a term coined by Casey Muratori). 141 You can learn about IMGUI principles at http://www.johno.se/book/imgui.html, http://mollyrocket.com/861 & more links in the FAQ. 142 - Dear ImGui is a "single pass" rasterizing implementation of the IMGUI paradigm, aimed at ease of use and high-performances. 143 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, 144 where the UI code is called multiple times ("multiple passes") from a single entry point. There are pros and cons to both approaches. 145 - Our origin are on the top-left. In axis aligned bounding boxes, Min = top-left, Max = bottom-right. 146 - This codebase is also optimized to yield decent performances with typical "Debug" builds settings. 147 - Please make sure you have asserts enabled (IM_ASSERT redirects to assert() by default, but can be redirected). 148 If you get an assert, read the messages and comments around the assert. 149 - 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. 150 - C++: ImVec2/ImVec4 do not expose math operators by default, because it is expected that you use your own math types. 151 See FAQ "How can I use my own math types instead of ImVec2/ImVec4?" for details about setting up imconfig.h for that. 152 However, imgui_internal.h can optionally export math operators for ImVec2/ImVec4, which we use in this codebase. 153 - C++: pay attention that ImVector<> manipulates plain-old-data and does not honor construction/destruction (avoid using it in your code!). 154 155 156 HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI 157 ---------------------------------------------- 158 - Overwrite all the sources files except for imconfig.h (if you have made modification to your copy of imconfig.h) 159 - Or maintain your own branch where you have imconfig.h modified. 160 - Read the "API BREAKING CHANGES" section (below). This is where we list occasional API breaking changes. 161 If a function/type has been renamed / or marked obsolete, try to fix the name in your code before it is permanently removed 162 from the public API. If you have a problem with a missing function/symbols, search for its name in the code, there will 163 likely be a comment about it. Please report any issue to the GitHub page! 164 - Try to keep your copy of dear imgui reasonably up to date. 165 166 167 GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE 168 --------------------------------------------------------------- 169 - Run and study the examples and demo in imgui_demo.cpp to get acquainted with the library. 170 - In the majority of cases you should be able to use unmodified back-ends files available in the examples/ folder. 171 - Add the Dear ImGui source files + selected back-end source files to your projects or using your preferred build system. 172 It is recommended you build and statically link the .cpp files as part of your project and NOT as shared library (DLL). 173 - You can later customize the imconfig.h file to tweak some compile-time behavior, such as integrating Dear ImGui types with your own maths types. 174 - When using Dear ImGui, your programming IDE is your friend: follow the declaration of variables, functions and types to find comments about them. 175 - Dear ImGui never touches or knows about your GPU state. The only function that knows about GPU is the draw function that you provide. 176 Effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render" 177 phases of your own application. All rendering information are stored into command-lists that you will retrieve after calling ImGui::Render(). 178 - Refer to the bindings and demo applications in the examples/ folder for instruction on how to setup your code. 179 - 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. 180 181 182 HOW A SIMPLE APPLICATION MAY LOOK LIKE 183 -------------------------------------- 184 EXHIBIT 1: USING THE EXAMPLE BINDINGS (= imgui_impl_XXX.cpp files from the examples/ folder). 185 The sub-folders in examples/ contains examples applications following this structure. 186 187 // Application init: create a dear imgui context, setup some options, load fonts 188 ImGui::CreateContext(); 189 ImGuiIO& io = ImGui::GetIO(); 190 // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls. 191 // TODO: Fill optional fields of the io structure later. 192 // TODO: Load TTF/OTF fonts if you don't want to use the default font. 193 194 // Initialize helper Platform and Renderer bindings (here we are using imgui_impl_win32.cpp and imgui_impl_dx11.cpp) 195 ImGui_ImplWin32_Init(hwnd); 196 ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext); 197 198 // Application main loop 199 while (true) 200 { 201 // Feed inputs to dear imgui, start new frame 202 ImGui_ImplDX11_NewFrame(); 203 ImGui_ImplWin32_NewFrame(); 204 ImGui::NewFrame(); 205 206 // Any application code here 207 ImGui::Text("Hello, world!"); 208 209 // Render dear imgui into screen 210 ImGui::Render(); 211 ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); 212 g_pSwapChain->Present(1, 0); 213 } 214 215 // Shutdown 216 ImGui_ImplDX11_Shutdown(); 217 ImGui_ImplWin32_Shutdown(); 218 ImGui::DestroyContext(); 219 220 EXHIBIT 2: IMPLEMENTING CUSTOM BINDING / CUSTOM ENGINE 221 222 // Application init: create a dear imgui context, setup some options, load fonts 223 ImGui::CreateContext(); 224 ImGuiIO& io = ImGui::GetIO(); 225 // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls. 226 // TODO: Fill optional fields of the io structure later. 227 // TODO: Load TTF/OTF fonts if you don't want to use the default font. 228 229 // Build and load the texture atlas into a texture 230 // (In the examples/ app this is usually done within the ImGui_ImplXXX_Init() function from one of the demo Renderer) 231 int width, height; 232 unsigned char* pixels = NULL; 233 io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); 234 235 // At this point you've got the texture data and you need to upload that your your graphic system: 236 // After we have created the texture, store its pointer/identifier (_in whichever format your engine uses_) in 'io.Fonts->TexID'. 237 // This will be passed back to your via the renderer. Basically ImTextureID == void*. Read FAQ for details about ImTextureID. 238 MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA32) 239 io.Fonts->TexID = (void*)texture; 240 241 // Application main loop 242 while (true) 243 { 244 // Setup low-level inputs, e.g. on Win32: calling GetKeyboardState(), or write to those fields from your Windows message handlers, etc. 245 // (In the examples/ app this is usually done within the ImGui_ImplXXX_NewFrame() function from one of the demo Platform bindings) 246 io.DeltaTime = 1.0f/60.0f; // set the time elapsed since the previous frame (in seconds) 247 io.DisplaySize.x = 1920.0f; // set the current display width 248 io.DisplaySize.y = 1280.0f; // set the current display height here 249 io.MousePos = my_mouse_pos; // set the mouse position 250 io.MouseDown[0] = my_mouse_buttons[0]; // set the mouse button states 251 io.MouseDown[1] = my_mouse_buttons[1]; 252 253 // Call NewFrame(), after this point you can use ImGui::* functions anytime 254 // (So you want to try calling NewFrame() as early as you can in your mainloop to be able to use Dear ImGui everywhere) 255 ImGui::NewFrame(); 256 257 // Most of your application code here 258 ImGui::Text("Hello, world!"); 259 MyGameUpdate(); // may use any Dear ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End(); 260 MyGameRender(); // may use any Dear ImGui functions as well! 261 262 // Render dear imgui, swap buffers 263 // (You want to try calling EndFrame/Render as late as you can, to be able to use Dear ImGui in your own game rendering code) 264 ImGui::EndFrame(); 265 ImGui::Render(); 266 ImDrawData* draw_data = ImGui::GetDrawData(); 267 MyImGuiRenderFunction(draw_data); 268 SwapBuffers(); 269 } 270 271 // Shutdown 272 ImGui::DestroyContext(); 273 274 To decide whether to dispatch mouse/keyboard inputs to Dear ImGui to the rest your application, 275 you should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags! 276 Please read the FAQ and example applications for details about this! 277 278 279 HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE 280 --------------------------------------------- 281 The bindings in impl_impl_XXX.cpp files contains many working implementations of a rendering function. 282 283 void void MyImGuiRenderFunction(ImDrawData* draw_data) 284 { 285 // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled 286 // TODO: Setup viewport covering draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize 287 // TODO: Setup orthographic projection matrix cover draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize 288 // TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color. 289 for (int n = 0; n < draw_data->CmdListsCount; n++) 290 { 291 const ImDrawList* cmd_list = draw_data->CmdLists[n]; 292 const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; // vertex buffer generated by Dear ImGui 293 const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; // index buffer generated by Dear ImGui 294 for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) 295 { 296 const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; 297 if (pcmd->UserCallback) 298 { 299 pcmd->UserCallback(cmd_list, pcmd); 300 } 301 else 302 { 303 // The texture for the draw call is specified by pcmd->TextureId. 304 // The vast majority of draw calls will use the Dear ImGui texture atlas, which value you have set yourself during initialization. 305 MyEngineBindTexture((MyTexture*)pcmd->TextureId); 306 307 // We are using scissoring to clip some objects. All low-level graphics API should supports it. 308 // - If your engine doesn't support scissoring yet, you may ignore this at first. You will get some small glitches 309 // (some elements visible outside their bounds) but you can fix that once everything else works! 310 // - Clipping coordinates are provided in imgui coordinates space (from draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize) 311 // In a single viewport application, draw_data->DisplayPos will always be (0,0) and draw_data->DisplaySize will always be == io.DisplaySize. 312 // However, in the interest of supporting multi-viewport applications in the future (see 'viewport' branch on github), 313 // always subtract draw_data->DisplayPos from clipping bounds to convert them to your viewport space. 314 // - Note that pcmd->ClipRect contains Min+Max bounds. Some graphics API may use Min+Max, other may use Min+Size (size being Max-Min) 315 ImVec2 pos = draw_data->DisplayPos; 316 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)); 317 318 // Render 'pcmd->ElemCount/3' indexed triangles. 319 // By default the indices ImDrawIdx are 16-bit, you can change them to 32-bit in imconfig.h if your engine doesn't support 16-bit indices. 320 MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer, vtx_buffer); 321 } 322 idx_buffer += pcmd->ElemCount; 323 } 324 } 325 } 326 327 328 USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS 329 ------------------------------------------ 330 - The gamepad/keyboard navigation is fairly functional and keeps being improved. 331 - Gamepad support is particularly useful to use Dear ImGui on a console system (e.g. PS4, Switch, XB1) without a mouse! 332 - You can ask questions and report issues at https://github.com/ocornut/imgui/issues/787 333 - The initial focus was to support game controllers, but keyboard is becoming increasingly and decently usable. 334 - Keyboard: 335 - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. 336 NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays. 337 - When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard), the io.WantCaptureKeyboard flag 338 will be set. For more advanced uses, you may want to read from: 339 - io.NavActive: true when a window is focused and it doesn't have the ImGuiWindowFlags_NoNavInputs flag set. 340 - io.NavVisible: true when the navigation cursor is visible (and usually goes false when mouse is used). 341 - or query focus information with e.g. IsWindowFocused(ImGuiFocusedFlags_AnyWindow), IsItemFocused() etc. functions. 342 Please reach out if you think the game vs navigation input sharing could be improved. 343 - Gamepad: 344 - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable. 345 - Backend: Set io.BackendFlags |= ImGuiBackendFlags_HasGamepad + fill the io.NavInputs[] fields before calling NewFrame(). 346 Note that io.NavInputs[] is cleared by EndFrame(). 347 - See 'enum ImGuiNavInput_' in imgui.h for a description of inputs. For each entry of io.NavInputs[], set the following values: 348 0.0f= not held. 1.0f= fully held. Pass intermediate 0.0f..1.0f values for analog triggers/sticks. 349 - We uses a simple >0.0f test for activation testing, and won't attempt to test for a dead-zone. 350 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.). 351 - You can download PNG/PSD files depicting the gamepad controls for common controllers at: http://goo.gl/9LgVZW. 352 - 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 353 to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved. 354 - Mouse: 355 - PS4 users: Consider emulating a mouse cursor with DualShock4 touch pad or a spare analog stick as a mouse-emulation fallback. 356 - 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. 357 - 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. 358 Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs dear imgui to move your mouse cursor along with navigation movements. 359 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. 360 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. 361 (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!) 362 (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 363 to set a boolean to ignore your other external mouse positions until the external source is moved again.) 364 365 366 API BREAKING CHANGES 367 ==================== 368 369 Occasionally introducing changes that are breaking the API. We try to make the breakage minor and easy to fix. 370 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. 371 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. 372 You can read releases logs https://github.com/ocornut/imgui/releases for more details. 373 374 - 2020/10/05 (1.79) - removed ImGuiListClipper: Renamed constructor parameters which created an ambiguous alternative to using the ImGuiListClipper::Begin() function, with misleading edge cases (note: imgui_memory_editor <0.40 from imgui_club/ used this old clipper API. Update your copy if needed). 375 - 2020/09/25 (1.79) - renamed ImGuiSliderFlags_ClampOnInput to ImGuiSliderFlags_AlwaysClamp. Kept redirection enum (will obsolete sooner because previous name was added recently). 376 - 2020/09/25 (1.79) - renamed style.TabMinWidthForUnselectedCloseButton to style.TabMinWidthForCloseButton. 377 - 2020/09/21 (1.79) - renamed OpenPopupContextItem() back to OpenPopupOnItemClick(), reverting the change from 1.77. For varieties of reason this is more self-explanatory. 378 - 2020/09/21 (1.79) - removed return value from OpenPopupOnItemClick() - returned true on mouse release on item - because it is inconsistent with other popup APIs and makes others misleading. It's also and unnecessary: you can use IsWindowAppearing() after BeginPopup() for a similar result. 379 - 2020/09/17 (1.79) - removed ImFont::DisplayOffset in favor of ImFontConfig::GlyphOffset. DisplayOffset was applied after scaling and not very meaningful/useful outside of being needed by the default ProggyClean font. If you scaled this value after calling AddFontDefault(), this is now done automatically. It was also getting in the way of better font scaling, so let's get rid of it now! 380 - 2020/08/17 (1.78) - obsoleted use of the trailing 'float power=1.0f' parameter for DragFloat(), DragFloat2(), DragFloat3(), DragFloat4(), DragFloatRange2(), DragScalar(), DragScalarN(), SliderFloat(), SliderFloat2(), SliderFloat3(), SliderFloat4(), SliderScalar(), SliderScalarN(), VSliderFloat() and VSliderScalar(). 381 replaced the 'float power=1.0f' argument with integer-based flags defaulting to 0 (as with all our flags). 382 worked out a backward-compatibility scheme so hopefully most C++ codebase should not be affected. in short, when calling those functions: 383 - if you omitted the 'power' parameter (likely!), you are not affected. 384 - if you set the 'power' parameter to 1.0f (same as previous default value): 1/ your compiler may warn on float>int conversion, 2/ everything else will work. 3/ you can replace the 1.0f value with 0 to fix the warning, and be technically correct. 385 - if you set the 'power' parameter to >1.0f (to enable non-linear editing): 1/ your compiler may warn on float>int conversion, 2/ code will assert at runtime, 3/ in case asserts are disabled, the code will not crash and enable the _Logarithmic flag. 4/ you can replace the >1.0f value with ImGuiSliderFlags_Logarithmic to fix the warning/assert and get a _similar_ effect as previous uses of power >1.0f. 386 see https://github.com/ocornut/imgui/issues/3361 for all details. 387 kept inline redirection functions (will obsolete) apart for: DragFloatRange2(), VSliderFloat(), VSliderScalar(). For those three the 'float power=1.0f' version were removed directly as they were most unlikely ever used. 388 for shared code, you can version check at compile-time with `#if IMGUI_VERSION_NUM >= 17704`. 389 - obsoleted use of v_min > v_max in DragInt, DragFloat, DragScalar to lock edits (introduced in 1.73, was not demoed nor documented very), will be replaced by a more generic ReadOnly feature. You may use the ImGuiSliderFlags_ReadOnly internal flag in the meantime. 390 - 2020/06/23 (1.77) - removed BeginPopupContextWindow(const char*, int mouse_button, bool also_over_items) in favor of BeginPopupContextWindow(const char*, ImGuiPopupFlags flags) with ImGuiPopupFlags_NoOverItems. 391 - 2020/06/15 (1.77) - renamed OpenPopupOnItemClick() to OpenPopupContextItem(). Kept inline redirection function (will obsolete). [NOTE: THIS WAS REVERTED IN 1.79] 392 - 2020/06/15 (1.77) - removed CalcItemRectClosestPoint() entry point which was made obsolete and asserting in December 2017. 393 - 2020/04/23 (1.77) - removed unnecessary ID (first arg) of ImFontAtlas::AddCustomRectRegular(). 394 - 2020/01/22 (1.75) - ImDrawList::AddCircle()/AddCircleFilled() functions don't accept negative radius any more. 395 - 2019/12/17 (1.75) - [undid this change in 1.76] made Columns() limited to 64 columns by asserting above that limit. While the current code technically supports it, future code may not so we're putting the restriction ahead. 396 - 2019/12/13 (1.75) - [imgui_internal.h] changed ImRect() default constructor initializes all fields to 0.0f instead of (FLT_MAX,FLT_MAX,-FLT_MAX,-FLT_MAX). If you used ImRect::Add() to create bounding boxes by adding multiple points into it, you may need to fix your initial value. 397 - 2019/12/08 (1.75) - removed redirecting functions/enums that were marked obsolete in 1.53 (December 2017): 398 - ShowTestWindow() -> use ShowDemoWindow() 399 - IsRootWindowFocused() -> use IsWindowFocused(ImGuiFocusedFlags_RootWindow) 400 - IsRootWindowOrAnyChildFocused() -> use IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) 401 - SetNextWindowContentWidth(w) -> use SetNextWindowContentSize(ImVec2(w, 0.0f) 402 - GetItemsLineHeightWithSpacing() -> use GetFrameHeightWithSpacing() 403 - ImGuiCol_ChildWindowBg -> use ImGuiCol_ChildBg 404 - ImGuiStyleVar_ChildWindowRounding -> use ImGuiStyleVar_ChildRounding 405 - ImGuiTreeNodeFlags_AllowOverlapMode -> use ImGuiTreeNodeFlags_AllowItemOverlap 406 - IMGUI_DISABLE_TEST_WINDOWS -> use IMGUI_DISABLE_DEMO_WINDOWS 407 - 2019/12/08 (1.75) - obsoleted calling ImDrawList::PrimReserve() with a negative count (which was the vaguely documented and rarely if ever used). Instead we added an explicit PrimUnreserve() API. 408 - 2019/12/06 (1.75) - removed implicit default parameter to IsMouseDragging(int button = 0) to be consistent with other mouse functions (none of the other functions have it). 409 - 2019/11/21 (1.74) - ImFontAtlas::AddCustomRectRegular() now requires an ID larger than 0x110000 (instead of 0x10000) to conform with supporting Unicode planes 1-16 in a future update. ID below 0x110000 will now assert. 410 - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS to IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS for consistency. 411 - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_MATH_FUNCTIONS to IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS for consistency. 412 - 2019/10/22 (1.74) - removed redirecting functions/enums that were marked obsolete in 1.52 (October 2017): 413 - Begin() [old 5 args version] -> use Begin() [3 args], use SetNextWindowSize() SetNextWindowBgAlpha() if needed 414 - IsRootWindowOrAnyChildHovered() -> use IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows) 415 - AlignFirstTextHeightToWidgets() -> use AlignTextToFramePadding() 416 - SetNextWindowPosCenter() -> use SetNextWindowPos() with a pivot of (0.5f, 0.5f) 417 - ImFont::Glyph -> use ImFontGlyph 418 - 2019/10/14 (1.74) - inputs: Fixed a miscalculation in the keyboard/mouse "typematic" repeat delay/rate calculation, used by keys and e.g. repeating mouse buttons as well as the GetKeyPressedAmount() function. 419 if you were using a non-default value for io.KeyRepeatRate (previous default was 0.250), you can add +io.KeyRepeatDelay to it to compensate for the fix. 420 The function was triggering on: 0.0 and (delay+rate*N) where (N>=1). Fixed formula responds to (N>=0). Effectively it made io.KeyRepeatRate behave like it was set to (io.KeyRepeatRate + io.KeyRepeatDelay). 421 If you never altered io.KeyRepeatRate nor used GetKeyPressedAmount() this won't affect you. 422 - 2019/07/15 (1.72) - removed TreeAdvanceToLabelPos() which is rarely used and only does SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()). Kept redirection function (will obsolete). 423 - 2019/07/12 (1.72) - renamed ImFontAtlas::CustomRect to ImFontAtlasCustomRect. Kept redirection typedef (will obsolete). 424 - 2019/06/14 (1.72) - removed redirecting functions/enums names that were marked obsolete in 1.51 (June 2017): ImGuiCol_Column*, ImGuiSetCond_*, IsItemHoveredRect(), IsPosHoveringAnyWindow(), IsMouseHoveringAnyWindow(), IsMouseHoveringWindow(), IMGUI_ONCE_UPON_A_FRAME. Grep this log for details and new names, or see how they were implemented until 1.71. 425 - 2019/06/07 (1.71) - rendering of child window outer decorations (bg color, border, scrollbars) is now performed as part of the parent window. If you have 426 overlapping child windows in a same parent, and relied on their relative z-order to be mapped to their submission order, this will affect your rendering. 427 This optimization is disabled if the parent window has no visual output, because it appears to be the most common situation leading to the creation of overlapping child windows. 428 Please reach out if you are affected. 429 - 2019/05/13 (1.71) - renamed SetNextTreeNodeOpen() to SetNextItemOpen(). Kept inline redirection function (will obsolete). 430 - 2019/05/11 (1.71) - changed io.AddInputCharacter(unsigned short c) signature to io.AddInputCharacter(unsigned int c). 431 - 2019/04/29 (1.70) - improved ImDrawList thick strokes (>1.0f) preserving correct thickness up to 90 degrees angles (e.g. rectangles). If you have custom rendering using thick lines, they will appear thicker now. 432 - 2019/04/29 (1.70) - removed GetContentRegionAvailWidth(), use GetContentRegionAvail().x instead. Kept inline redirection function (will obsolete). 433 - 2019/03/04 (1.69) - renamed GetOverlayDrawList() to GetForegroundDrawList(). Kept redirection function (will obsolete). 434 - 2019/02/26 (1.69) - renamed ImGuiColorEditFlags_RGB/ImGuiColorEditFlags_HSV/ImGuiColorEditFlags_HEX to ImGuiColorEditFlags_DisplayRGB/ImGuiColorEditFlags_DisplayHSV/ImGuiColorEditFlags_DisplayHex. Kept redirection enums (will obsolete). 435 - 2019/02/14 (1.68) - made it illegal/assert when io.DisplayTime == 0.0f (with an exception for the first frame). If for some reason your time step calculation gives you a zero value, replace it with an arbitrary small value! 436 - 2019/02/01 (1.68) - removed io.DisplayVisibleMin/DisplayVisibleMax (which were marked obsolete and removed from viewport/docking branch already). 437 - 2019/01/06 (1.67) - renamed io.InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead! 438 - 2019/01/06 (1.67) - renamed ImFontAtlas::GlyphRangesBuilder to ImFontGlyphRangesBuilder. Kept redirection typedef (will obsolete). 439 - 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. 440 - 2018/12/10 (1.67) - renamed io.ConfigResizeWindowsFromEdges to io.ConfigWindowsResizeFromEdges as we are doing a large pass on configuration flags. 441 - 2018/10/12 (1.66) - renamed misc/stl/imgui_stl.* to misc/cpp/imgui_stdlib.* in prevision for other C++ helper files. 442 - 2018/09/28 (1.66) - renamed SetScrollHere() to SetScrollHereY(). Kept redirection function (will obsolete). 443 - 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. 444 If you were conveniently using the imgui copy of those STB headers in your project you will have to update your include paths. 445 - 2018/09/05 (1.65) - renamed io.OptCursorBlink/io.ConfigCursorBlink to io.ConfigInputTextCursorBlink. (#1427) 446 - 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. 447 NONE OF THE FUNCTIONS HAVE CHANGED. THE CODE IS SEMANTICALLY 100% IDENTICAL, BUT _EVERY_ FUNCTION HAS BEEN MOVED. 448 Because of this, any local modifications to imgui.cpp will likely conflict when you update. Read docs/CHANGELOG.txt for suggestions. 449 - 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). 450 - 2018/08/21 (1.63) - renamed ImGuiTextEditCallback to ImGuiInputTextCallback, ImGuiTextEditCallbackData to ImGuiInputTextCallbackData for consistency. Kept redirection types (will obsolete). 451 - 2018/08/21 (1.63) - removed ImGuiInputTextCallbackData::ReadOnly since it is a duplication of (ImGuiInputTextCallbackData::Flags & ImGuiInputTextFlags_ReadOnly). 452 - 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. 453 - 2018/08/01 (1.63) - renamed io.OptCursorBlink to io.ConfigCursorBlink [-> io.ConfigInputTextCursorBlink in 1.65], io.OptMacOSXBehaviors to ConfigMacOSXBehaviors for consistency. 454 - 2018/07/22 (1.63) - changed ImGui::GetTime() return value from float to double to avoid accumulating floating point imprecisions over time. 455 - 2018/07/08 (1.63) - style: renamed ImGuiCol_ModalWindowDarkening to ImGuiCol_ModalWindowDimBg for consistency with other features. Kept redirection enum (will obsolete). 456 - 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.). 457 old bindings will still work as is, however prefer using the separated bindings as they will be updated to support multi-viewports. 458 when adopting new bindings follow the main.cpp code of your preferred examples/ folder to know which functions to call. 459 in particular, note that old bindings called ImGui::NewFrame() at the end of their ImGui_ImplXXXX_NewFrame() function. 460 - 2018/06/06 (1.62) - renamed GetGlyphRangesChinese() to GetGlyphRangesChineseFull() to distinguish other variants and discourage using the full set. 461 - 2018/06/06 (1.62) - TreeNodeEx()/TreeNodeBehavior(): the ImGuiTreeNodeFlags_CollapsingHeader helper now include the ImGuiTreeNodeFlags_NoTreePushOnOpen flag. See Changelog for details. 462 - 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. 463 If you used DragInt() with custom format strings, make sure you change them to use %d or an integer-compatible format. 464 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. 465 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. 466 - 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", 467 consistent with other functions. Kept redirection functions (will obsolete). 468 - 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. 469 - 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). 470 - 2018/03/12 (1.60) - removed ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered as the closing cross uses regular button colors now. 471 - 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. 472 - 2018/03/03 (1.60) - renamed ImGuiStyleVar_Count_ to ImGuiStyleVar_COUNT and ImGuiMouseCursor_Count_ to ImGuiMouseCursor_COUNT for consistency with other public enums. 473 - 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. 474 - 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. 475 - 2018/02/07 (1.60) - reorganized context handling to be more explicit, 476 - YOU NOW NEED TO CALL ImGui::CreateContext() AT THE BEGINNING OF YOUR APP, AND CALL ImGui::DestroyContext() AT THE END. 477 - removed Shutdown() function, as DestroyContext() serve this purpose. 478 - you may pass a ImFontAtlas* pointer to CreateContext() to share a font atlas between contexts. Otherwise CreateContext() will create its own font atlas instance. 479 - removed allocator parameters from CreateContext(), they are now setup with SetAllocatorFunctions(), and shared by all contexts. 480 - removed the default global context and font atlas instance, which were confusing for users of DLL reloading and users of multiple contexts. 481 - 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. 482 - 2018/01/11 (1.60) - obsoleted IsAnyWindowHovered() in favor of IsWindowHovered(ImGuiHoveredFlags_AnyWindow). Kept redirection function (will obsolete). 483 - 2018/01/11 (1.60) - obsoleted IsAnyWindowFocused() in favor of IsWindowFocused(ImGuiFocusedFlags_AnyWindow). Kept redirection function (will obsolete). 484 - 2018/01/03 (1.60) - renamed ImGuiSizeConstraintCallback to ImGuiSizeCallback, ImGuiSizeConstraintCallbackData to ImGuiSizeCallbackData. 485 - 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. 486 - 2017/12/24 (1.53) - renamed the emblematic ShowTestWindow() function to ShowDemoWindow(). Kept redirection function (will obsolete). 487 - 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 488 - 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. 489 - 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. 490 - 2017/12/13 (1.53) - renamed GetItemsLineHeightWithSpacing() to GetFrameHeightWithSpacing(). Kept redirection function (will obsolete). 491 - 2017/12/13 (1.53) - obsoleted IsRootWindowFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootWindow). Kept redirection function (will obsolete). 492 - obsoleted IsRootWindowOrAnyChildFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows). Kept redirection function (will obsolete). 493 - 2017/12/12 (1.53) - renamed ImGuiTreeNodeFlags_AllowOverlapMode to ImGuiTreeNodeFlags_AllowItemOverlap. Kept redirection enum (will obsolete). 494 - 2017/12/10 (1.53) - removed SetNextWindowContentWidth(), prefer using SetNextWindowContentSize(). Kept redirection function (will obsolete). 495 - 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. 496 - 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. 497 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. 498 - 2017/11/18 (1.53) - Style: removed ImGuiCol_ComboBg in favor of combo boxes using ImGuiCol_PopupBg for consistency. 499 - 2017/11/18 (1.53) - Style: renamed ImGuiCol_ChildWindowBg to ImGuiCol_ChildBg. 500 - 2017/11/18 (1.53) - Style: renamed style.ChildWindowRounding to style.ChildRounding, ImGuiStyleVar_ChildWindowRounding to ImGuiStyleVar_ChildRounding. 501 - 2017/11/02 (1.53) - obsoleted IsRootWindowOrAnyChildHovered() in favor of using IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows); 502 - 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. 503 - 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. 504 - 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. 505 removed the IsItemRectHovered()/IsWindowRectHovered() names introduced in 1.51 since they were merely more consistent names for the two functions we are now obsoleting. 506 IsItemHoveredRect() --> IsItemHovered(ImGuiHoveredFlags_RectOnly) 507 IsMouseHoveringAnyWindow() --> IsWindowHovered(ImGuiHoveredFlags_AnyWindow) 508 IsMouseHoveringWindow() --> IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) [weird, old behavior] 509 - 2017/10/17 (1.52) - marked the old 5-parameters version of Begin() as obsolete (still available). Use SetNextWindowSize()+Begin() instead! 510 - 2017/10/11 (1.52) - renamed AlignFirstTextHeightToWidgets() to AlignTextToFramePadding(). Kept inline redirection function (will obsolete). 511 - 2017/09/26 (1.52) - renamed ImFont::Glyph to ImFontGlyph. Kept redirection typedef (will obsolete). 512 - 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). 513 - 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)". 514 - 2017/08/22 (1.51) - renamed IsItemHoveredRect() to IsItemRectHovered(). Kept inline redirection function (will obsolete). -> (1.52) use IsItemHovered(ImGuiHoveredFlags_RectOnly)! 515 - renamed IsMouseHoveringAnyWindow() to IsAnyWindowHovered() for consistency. Kept inline redirection function (will obsolete). 516 - renamed IsMouseHoveringWindow() to IsWindowRectHovered() for consistency. Kept inline redirection function (will obsolete). 517 - 2017/08/20 (1.51) - renamed GetStyleColName() to GetStyleColorName() for consistency. 518 - 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. 519 - 2017/08/15 (1.51) - marked the weird IMGUI_ONCE_UPON_A_FRAME helper macro as obsolete. prefer using the more explicit ImGuiOnceUponAFrame type. 520 - 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. 521 - 2017/08/13 (1.51) - renamed ImGuiCol_Column to ImGuiCol_Separator, ImGuiCol_ColumnHovered to ImGuiCol_SeparatorHovered, ImGuiCol_ColumnActive to ImGuiCol_SeparatorActive. Kept redirection enums (will obsolete). 522 - 2017/08/11 (1.51) - renamed ImGuiSetCond_Always to ImGuiCond_Always, ImGuiSetCond_Once to ImGuiCond_Once, ImGuiSetCond_FirstUseEver to ImGuiCond_FirstUseEver, ImGuiSetCond_Appearing to ImGuiCond_Appearing. Kept redirection enums (will obsolete). 523 - 2017/08/09 (1.51) - removed ValueColor() helpers, they are equivalent to calling Text(label) + SameLine() + ColorButton(). 524 - 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. 525 - 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. 526 - 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))' 527 - 2017/07/20 (1.51) - removed IsPosHoveringAnyWindow(ImVec2), which was partly broken and misleading. ASSERT + redirect user to io.WantCaptureMouse 528 - 2017/05/26 (1.50) - removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset. 529 - 2017/05/01 (1.50) - renamed ImDrawList::PathFill() (rarely used directly) to ImDrawList::PathFillConvex() for clarity. 530 - 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(). 531 - 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it. 532 - 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. 533 - 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. 534 - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore. 535 If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you, otherwise if <1.0f you need tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar. 536 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: 537 ImVec4 ConvertTitleBgCol(const ImVec4& win_bg_col, const ImVec4& title_bg_col) { float new_a = 1.0f - ((1.0f - win_bg_col.w) * (1.0f - title_bg_col.w)), k = title_bg_col.w / new_a; return ImVec4((win_bg_col.x * win_bg_col.w + title_bg_col.x) * k, (win_bg_col.y * win_bg_col.w + title_bg_col.y) * k, (win_bg_col.z * win_bg_col.w + title_bg_col.z) * k, new_a); } 538 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. 539 - 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext(). 540 - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection. 541 - 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). 542 - 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. 543 - 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). 544 - 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) 545 - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete). 546 - 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. 547 - 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. 548 - 2015/12/27 (1.48) - fixed ImDrawList::AddRect() which used to render a rectangle 1 px too large on each axis. 549 - 2015/12/04 (1.47) - renamed Color() helpers to ValueColor() - dangerously named, rarely used and probably to be made obsolete. 550 - 2015/08/29 (1.45) - with the addition of horizontal scrollbar we made various fixes to inconsistencies with dealing with cursor position. 551 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. 552 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! 553 - 2015/08/29 (1.45) - renamed style.ScrollbarWidth to style.ScrollbarSize 554 - 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. 555 - 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 556 - 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. 557 you need to render your textured triangles with bilinear filtering to benefit from sub-pixel positioning of text. 558 - 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. 559 this necessary change will break your rendering function! the fix should be very easy. sorry for that :( 560 - 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. 561 - the signature of the io.RenderDrawListsFn handler has changed! 562 old: ImGui_XXXX_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count) 563 new: ImGui_XXXX_RenderDrawLists(ImDrawData* draw_data). 564 parameters: 'cmd_lists' becomes 'draw_data->CmdLists', 'cmd_lists_count' becomes 'draw_data->CmdListsCount' 565 ImDrawList: 'commands' becomes 'CmdBuffer', 'vtx_buffer' becomes 'VtxBuffer', 'IdxBuffer' is new. 566 ImDrawCmd: 'vtx_count' becomes 'ElemCount', 'clip_rect' becomes 'ClipRect', 'user_callback' becomes 'UserCallback', 'texture_id' becomes 'TextureId'. 567 - 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. 568 - 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! 569 - refer to code in the examples/ folder or ask on the GitHub if you are unsure of how to upgrade. please upgrade! 570 - 2015/07/10 (1.43) - changed SameLine() parameters from int to float. 571 - 2015/07/02 (1.42) - renamed SetScrollPosHere() to SetScrollFromCursorPos(). Kept inline redirection function (will obsolete). 572 - 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. 573 - 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 574 - 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! 575 - 2015/05/31 (1.40) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete). 576 - 2015/05/31 (1.40) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete). 577 - 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. 578 - 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. 579 - 2015/05/03 (1.40) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same). 580 - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function until 1.50. 581 - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API 582 - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive. 583 - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead. 584 - 2015/03/17 (1.36) - renamed GetItemBoxMin()/GetItemBoxMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function until 1.50. 585 - 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing 586 - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function until 1.50. 587 - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth (casing) 588 - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function until 1.50. 589 - 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once. 590 - 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now. 591 - 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior 592 - 2015/02/08 (1.31) - renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing() 593 - 2015/02/01 (1.31) - removed IO.MemReallocFn (unused) 594 - 2015/01/19 (1.30) - renamed ImGuiStorage::GetIntPtr()/GetFloatPtr() to GetIntRef()/GetIntRef() because Ptr was conflicting with actual pointer storage functions. 595 - 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader. 596 - 2015/01/11 (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels. 597 - old: const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); [..Upload texture to GPU..]; 598 - new: unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); [..Upload texture to GPU..]; io.Fonts->TexId = YourTexIdentifier; 599 you now have more flexibility to load multiple TTF fonts and manage the texture buffer for internal needs. It is now recommended that you sample the font texture with bilinear interpolation. 600 - 2015/01/11 (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to set io.Fonts->TexID. 601 - 2015/01/11 (1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix) 602 - 2015/01/11 (1.30) - removed ImGui::IsItemFocused() in favor of ImGui::IsItemActive() which handles all widgets 603 - 2014/12/10 (1.18) - removed SetNewWindowDefaultPos() in favor of new generic API SetNextWindowPos(pos, ImGuiSetCondition_FirstUseEver) 604 - 2014/11/28 (1.17) - moved IO.Font*** options to inside the IO.Font-> structure (FontYOffset, FontTexUvForWhite, FontBaseScale, FontFallbackGlyph) 605 - 2014/11/26 (1.17) - reworked syntax of IMGUI_ONCE_UPON_A_FRAME helper macro to increase compiler compatibility 606 - 2014/11/07 (1.15) - renamed IsHovered() to IsItemHovered() 607 - 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) 608 - 2014/09/25 (1.13) - removed 'text_end' parameter from IO.SetClipboardTextFn (the string is now always zero-terminated for simplicity) 609 - 2014/09/24 (1.12) - renamed SetFontScale() to SetWindowFontScale() 610 - 2014/09/24 (1.12) - moved IM_MALLOC/IM_REALLOC/IM_FREE preprocessor defines to IO.MemAllocFn/IO.MemReallocFn/IO.MemFreeFn 611 - 2014/08/30 (1.09) - removed IO.FontHeight (now computed automatically) 612 - 2014/08/30 (1.09) - moved IMGUI_FONT_TEX_UV_FOR_WHITE preprocessor define to IO.FontTexUvForWhite 613 - 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes 614 615 616 FREQUENTLY ASKED QUESTIONS (FAQ) 617 ================================ 618 619 Read all answers online: 620 https://www.dearimgui.org/faq or https://github.com/ocornut/imgui/blob/master/docs/FAQ.md (same url) 621 Read all answers locally (with a text editor or ideally a Markdown viewer): 622 docs/FAQ.md 623 Some answers are copied down here to facilitate searching in code. 624 625 Q&A: Basics 626 =========== 627 628 Q: Where is the documentation? 629 A: This library is poorly documented at the moment and expects of the user to be acquainted with C/C++. 630 - Run the examples/ and explore them. 631 - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function. 632 - The demo covers most features of Dear ImGui, so you can read the code and see its output. 633 - See documentation and comments at the top of imgui.cpp + effectively imgui.h. 634 - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the 635 examples/ folder to explain how to integrate Dear ImGui with your own engine/application. 636 - The Wiki (https://github.com/ocornut/imgui/wiki) has many resources and links. 637 - The Glossary (https://github.com/ocornut/imgui/wiki/Glossary) page also may be useful. 638 - Your programming IDE is your friend, find the type or function declaration to find comments 639 associated to it. 640 641 Q: What is this library called? 642 Q: Which version should I get? 643 >> This library is called "Dear ImGui", please don't call it "ImGui" :) 644 >> See https://www.dearimgui.org/faq for details. 645 646 Q&A: Integration 647 ================ 648 649 Q: How to get started? 650 A: Read 'PROGRAMMER GUIDE' above. Read examples/README.txt. 651 652 Q: How can I tell whether to dispatch mouse/keyboard to Dear ImGui or to my application? 653 A: You should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags! 654 >> See https://www.dearimgui.org/faq for fully detailed answer. You really want to read this. 655 656 Q. How can I enable keyboard controls? 657 Q: How can I use this without a mouse, without a keyboard or without a screen? (gamepad, input share, remote display) 658 Q: I integrated Dear ImGui in my engine and little squares are showing instead of text.. 659 Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around.. 660 Q: I integrated Dear ImGui in my engine and some elements are displaying outside their expected windows boundaries.. 661 >> See https://www.dearimgui.org/faq 662 663 Q&A: Usage 664 ---------- 665 666 Q: Why is my widget not reacting when I click on it? 667 Q: How can I have widgets with an empty label? 668 Q: How can I have multiple widgets with the same label? 669 Q: How can I display an image? What is ImTextureID, how does it works? 670 Q: How can I use my own math types instead of ImVec2/ImVec4? 671 Q: How can I interact with standard C++ types (such as std::string and std::vector)? 672 Q: How can I display custom shapes? (using low-level ImDrawList API) 673 >> See https://www.dearimgui.org/faq 674 675 Q&A: Fonts, Text 676 ================ 677 678 Q: How should I handle DPI in my application? 679 Q: How can I load a different font than the default? 680 Q: How can I easily use icons in my application? 681 Q: How can I load multiple fonts? 682 Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic? 683 >> See https://www.dearimgui.org/faq and https://github.com/ocornut/imgui/edit/master/docs/FONTS.md 684 685 Q&A: Concerns 686 ============= 687 688 Q: Who uses Dear ImGui? 689 Q: Can you create elaborate/serious tools with Dear ImGui? 690 Q: Can you reskin the look of Dear ImGui? 691 Q: Why using C++ (as opposed to C)? 692 >> See https://www.dearimgui.org/faq 693 694 Q&A: Community 695 ============== 696 697 Q: How can I help? 698 A: - Businesses: please reach out to "contact AT dearimgui.org" if you work in a place using Dear ImGui! 699 We can discuss ways for your company to fund development via invoiced technical support, maintenance or sponsoring contacts. 700 This is among the most useful thing you can do for Dear ImGui. With increased funding we can hire more people working on this project. 701 - Individuals: you can support continued development via PayPal donations. See README. 702 - If you are experienced with Dear ImGui and C++, look at the github issues, look at the Wiki, read docs/TODO.txt 703 and see how you want to help and can help! 704 - Disclose your usage of Dear ImGui via a dev blog post, a tweet, a screenshot, a mention somewhere etc. 705 You may post screenshot or links in the gallery threads (github.com/ocornut/imgui/issues/3488). Visuals are ideal as they inspire other programmers. 706 But even without visuals, disclosing your use of dear imgui help the library grow credibility, and help other teams and programmers with taking decisions. 707 - 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). 708 709 */ 710 711 //------------------------------------------------------------------------- 712 // [SECTION] INCLUDES 713 //------------------------------------------------------------------------- 656 714 657 715 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) … … 660 718 661 719 #include "imgui.h" 720 #ifndef IMGUI_DISABLE 721 722 #ifndef IMGUI_DEFINE_MATH_OPERATORS 662 723 #define IMGUI_DEFINE_MATH_OPERATORS 724 #endif 663 725 #include "imgui_internal.h" 664 726 665 #include <ctype.h> // toupper, isprint 666 #include < stdlib.h> // NULL, malloc, free, qsort, atoi727 // System includes 728 #include <ctype.h> // toupper 667 729 #include <stdio.h> // vsnprintf, sscanf, printf 668 730 #if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier … … 672 734 #endif 673 735 674 #define IMGUI_DEBUG_NAV_SCORING 0 675 #define IMGUI_DEBUG_NAV_RECTS 0 736 // [Windows] OS specific includes (optional) 737 #if defined(_WIN32) && defined(IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS) && defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) && defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) 738 #define IMGUI_DISABLE_WIN32_FUNCTIONS 739 #endif 740 #if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) 741 #ifndef WIN32_LEAN_AND_MEAN 742 #define WIN32_LEAN_AND_MEAN 743 #endif 744 #ifndef NOMINMAX 745 #define NOMINMAX 746 #endif 747 #ifndef __MINGW32__ 748 #include <Windows.h> // _wfopen, OpenClipboard 749 #else 750 #include <windows.h> 751 #endif 752 #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) // UWP doesn't have all Win32 functions 753 #define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS 754 #define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS 755 #endif 756 #endif 757 758 // [Apple] OS specific includes 759 #if defined(__APPLE__) 760 #include <TargetConditionals.h> 761 #endif 676 762 677 763 // Visual Studio warnings 678 764 #ifdef _MSC_VER 679 #pragma warning (disable: 4127) // condition expression is constant 680 #pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff) 681 #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen 765 #pragma warning (disable: 4127) // condition expression is constant 766 #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen 767 #if defined(_MSC_VER) && _MSC_VER >= 1922 // MSVC 2019 16.2 or later 768 #pragma warning (disable: 5054) // operator '|': deprecated between enumerations of different types 682 769 #endif 683 684 // Clang warnings with -Weverything 685 #ifdef __clang__ 686 #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! 687 #pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse. 688 #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. 689 #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. 690 #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. 691 #pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it. 692 #pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness // 693 #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. 694 #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int' 770 #endif 771 772 // Clang/GCC warnings with -Weverything 773 #if defined(__clang__) 774 #if __has_warning("-Wunknown-warning-option") 775 #pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great! 776 #endif 777 #pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' 778 #pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. 779 #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. 780 #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. 781 #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. 782 #pragma clang diagnostic ignored "-Wglobal-constructors" // warning: declaration requires a global destructor // similar to above, not sure what the exact difference is. 783 #pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness 784 #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. 785 #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning: cast to 'void *' from smaller integer type 'int' 786 #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0 787 #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. 788 #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision 695 789 #elif defined(__GNUC__) 790 // We disable -Wpragmas because GCC doesn't provide an has_warning equivalent and some forks/patches may not following the warning/version association. 791 #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind 696 792 #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used 697 793 #pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size … … 701 797 #pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked 702 798 #pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when assuming that (X - c) > X is always false 799 #pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead 703 800 #endif 704 801 705 // Enforce cdecl calling convention for functions called by the standard library, in case compilation settings changed the default to e.g. __vectorcall 706 #ifdef _MSC_VER 707 #define IMGUI_CDECL __cdecl 708 #else 709 #define IMGUI_CDECL 710 #endif 802 // Debug options 803 #define IMGUI_DEBUG_NAV_SCORING 0 // Display navigation scoring preview when hovering items. Display last moving direction matches when holding CTRL 804 #define IMGUI_DEBUG_NAV_RECTS 0 // Display the reference navigation rectangle for each window 805 #define IMGUI_DEBUG_INI_SETTINGS 0 // Save additional comments in .ini file (particularly helps for Docking, but makes saving slower) 806 807 // 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. 808 static const float NAV_WINDOWING_HIGHLIGHT_DELAY = 0.20f; // Time before the highlight and screen dimming starts fading in 809 static const float NAV_WINDOWING_LIST_APPEAR_DELAY = 0.15f; // Time before the window list starts to appear 810 811 // Window resizing from edges (when io.ConfigWindowsResizeFromEdges = true and ImGuiBackendFlags_HasMouseCursors is set in io.BackendFlags by back-end) 812 static const float WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS = 4.0f; // Extend outside and inside windows. Affect FindHoveredWindow(). 813 static const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04f; // Reduce visual noise by only highlighting the border after a certain time. 814 static const float WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER = 2.00f; // Lock scrolled window (so it doesn't pick child windows that are scrolling through) for a certain time, unless mouse moved. 711 815 712 816 //------------------------------------------------------------------------- 713 // Forward Declarations817 // [SECTION] FORWARD DECLARATIONS 714 818 //------------------------------------------------------------------------- 715 819 716 static bool IsKeyPressedMap(ImGuiKey key, bool repeat = true);717 718 static ImFont* GetDefaultFont();719 820 static void SetCurrentWindow(ImGuiWindow* window); 720 static void SetWindowScrollX(ImGuiWindow* window, float new_scroll_x); 721 static void SetWindowScrollY(ImGuiWindow* window, float new_scroll_y); 722 static void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond); 723 static void SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond); 724 static void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond); 725 static ImGuiWindow* FindHoveredWindow(); 726 static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFlags flags); 727 static void CheckStacksSize(ImGuiWindow* window, bool write); 821 static void FindHoveredWindow(); 822 static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags); 728 823 static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window); 729 824 730 825 static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* draw_list); 731 static void AddWindowToDrawData(ImVector<ImDrawList*>* out_list, ImGuiWindow* window); 732 static void AddWindowToSortedBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window); 733 734 static ImGuiWindowSettings* AddWindowSettings(const char* name); 735 736 static void LoadIniSettingsFromDisk(const char* ini_filename); 737 static void LoadIniSettingsFromMemory(const char* buf); 738 static void SaveIniSettingsToDisk(const char* ini_filename); 739 static void SaveIniSettingsToMemory(ImVector<char>& out_buf); 740 static void MarkIniSettingsDirty(ImGuiWindow* window); 826 static void AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window); 741 827 742 828 static ImRect GetViewportRect(); 743 829 744 static void ClosePopupToLevel(int remaining); 745 746 static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data); 747 static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end); 748 static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false); 749 750 static inline int DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* data_ptr, const char* format); 751 static void DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, void* arg_1, const void* arg_2); 752 static bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* data_ptr, const char* format); 753 754 namespace ImGui 755 { 756 static void NavUpdate(); 757 static void NavUpdateWindowing(); 758 static void NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, const ImGuiID id); 759 760 static void UpdateMovingWindow(); 761 static void UpdateMouseInputs(); 762 static void UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]); 763 static void FocusFrontMostActiveWindow(ImGuiWindow* ignore_window); 764 } 765 766 //----------------------------------------------------------------------------- 767 // Platform dependent default implementations 768 //----------------------------------------------------------------------------- 769 830 // Settings 831 static void WindowSettingsHandler_ClearAll(ImGuiContext*, ImGuiSettingsHandler*); 832 static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name); 833 static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line); 834 static void WindowSettingsHandler_ApplyAll(ImGuiContext*, ImGuiSettingsHandler*); 835 static void WindowSettingsHandler_WriteAll(ImGuiContext*, ImGuiSettingsHandler*, ImGuiTextBuffer* buf); 836 837 // Platform Dependents default implementation for IO functions 770 838 static const char* GetClipboardTextFn_DefaultImpl(void* user_data); 771 839 static void SetClipboardTextFn_DefaultImpl(void* user_data, const char* text); 772 840 static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y); 773 841 842 namespace ImGui 843 { 844 // Navigation 845 static void NavUpdate(); 846 static void NavUpdateWindowing(); 847 static void NavUpdateWindowingOverlay(); 848 static void NavUpdateMoveResult(); 849 static void NavUpdateInitResult(); 850 static float NavUpdatePageUpPageDown(); 851 static inline void NavUpdateAnyRequestFlag(); 852 static void NavEndFrame(); 853 static bool NavScoreItem(ImGuiNavMoveResult* result, ImRect cand); 854 static void NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, ImGuiID id); 855 static ImVec2 NavCalcPreferredRefPos(); 856 static void NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window); 857 static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window); 858 static int FindWindowFocusIndex(ImGuiWindow* window); 859 860 // Error Checking 861 static void ErrorCheckNewFrameSanityChecks(); 862 static void ErrorCheckEndFrameSanityChecks(); 863 static void ErrorCheckBeginEndCompareStacksSize(ImGuiWindow* window, bool write); 864 865 // Misc 866 static void UpdateSettings(); 867 static void UpdateMouseInputs(); 868 static void UpdateMouseWheel(); 869 static void UpdateTabFocus(); 870 static void UpdateDebugToolItemPicker(); 871 static bool UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect); 872 static void RenderWindowOuterBorders(ImGuiWindow* window); 873 static void RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size); 874 static void RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open); 875 876 } 877 774 878 //----------------------------------------------------------------------------- 775 // Context879 // [SECTION] CONTEXT AND MEMORY ALLOCATORS 776 880 //----------------------------------------------------------------------------- 777 881 778 // Current context pointer. Implicitly used by all ImGui functions. Always assumed to be != NULL. 779 // CreateContext() will automatically set this pointer if it is NULL. Change to a different context by calling ImGui::SetCurrentContext(). 780 // If you use DLL hotreloading you might need to call SetCurrentContext() after reloading code from this file. 781 // ImGui functions are not thread-safe because of this pointer. If you want thread-safety to allow N threads to access N different contexts, you can: 782 // - Change this variable to use thread local storage. You may #define GImGui in imconfig.h for that purpose. Future development aim to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586 783 // - Having multiple instances of the ImGui code compiled inside different namespace (easiest/safest, if you have a finite number of contexts) 882 // Current context pointer. Implicitly used by all Dear ImGui functions. Always assumed to be != NULL. 883 // ImGui::CreateContext() will automatically set this pointer if it is NULL. Change to a different context by calling ImGui::SetCurrentContext(). 884 // 1) Important: globals are not shared across DLL boundaries! If you use DLLs or any form of hot-reloading: you will need to call 885 // SetCurrentContext() (with the pointer you got from CreateContext) from each unique static/DLL boundary, and after each hot-reloading. 886 // In your debugger, add GImGui to your watch window and notice how its value changes depending on which location you are currently stepping into. 887 // 2) Important: Dear ImGui functions are not thread-safe because of this pointer. 888 // If you want thread-safety to allow N threads to access N different contexts, you can: 889 // - Change this variable to use thread local storage so each thread can refer to a different context, in imconfig.h: 890 // struct ImGuiContext; 891 // extern thread_local ImGuiContext* MyImGuiTLS; 892 // #define GImGui MyImGuiTLS 893 // 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. 894 // - Future development aim to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586 895 // - If you need a finite number of contexts, you may compile and use multiple instances of the ImGui code from different namespace. 784 896 #ifndef GImGui 785 897 ImGuiContext* GImGui = NULL; … … 787 899 788 900 // Memory Allocator functions. Use SetAllocatorFunctions() to change them. 789 // If you use DLL hotreloading you might need to call SetAllocatorFunctions() after reloading code from this file. 901 // If you use DLL hotreloading you might need to call SetAllocatorFunctions() after reloading code from this file. 790 902 // 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. 791 903 #ifndef IMGUI_DISABLE_DEFAULT_ALLOCATORS 792 static void* MallocWrapper(size_t size, void* user_data) { (void)user_data; return malloc(size); }793 static void FreeWrapper(void* ptr, void* user_data) { (void)user_data; free(ptr); }904 static void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); return malloc(size); } 905 static void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); free(ptr); } 794 906 #else 795 static void* MallocWrapper(size_t size, void* user_data) { (void)user_data; (void)size; IM_ASSERT(0); return NULL; }796 static void FreeWrapper(void* ptr, void* user_data) { (void)user_data; (void)ptr; IM_ASSERT(0); }907 static void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); IM_UNUSED(size); IM_ASSERT(0); return NULL; } 908 static void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); IM_UNUSED(ptr); IM_ASSERT(0); } 797 909 #endif 798 910 799 911 static void* (*GImAllocatorAllocFunc)(size_t size, void* user_data) = MallocWrapper; 800 static void (*GImAllocatorFreeFunc)(void* ptr, void* user_data) = FreeWrapper;912 static void (*GImAllocatorFreeFunc)(void* ptr, void* user_data) = FreeWrapper; 801 913 static void* GImAllocatorUserData = NULL; 802 static size_t GImAllocatorActiveAllocationsCount = 0;803 914 804 915 //----------------------------------------------------------------------------- 805 // User facing structures916 // [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO) 806 917 //----------------------------------------------------------------------------- 807 918 808 919 ImGuiStyle::ImGuiStyle() 809 920 { 810 Alpha = 1.0f; // Global alpha applies to everything in ImGui 811 WindowPadding = ImVec2(8, 8); // Padding within a window 812 WindowRounding = 7.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows 813 WindowBorderSize = 1.0f; // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested. 814 WindowMinSize = ImVec2(32, 32); // Minimum window size 815 WindowTitleAlign = ImVec2(0.0f, 0.5f);// Alignment for title bar text 816 ChildRounding = 0.0f; // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows 817 ChildBorderSize = 1.0f; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. Other values not well tested. 818 PopupRounding = 0.0f; // Radius of popup window corners rounding. Set to 0.0f to have rectangular child windows 819 PopupBorderSize = 1.0f; // Thickness of border around popup or tooltip windows. Generally set to 0.0f or 1.0f. Other values not well tested. 820 FramePadding = ImVec2(4, 3); // Padding within a framed rectangle (used by most widgets) 821 FrameRounding = 0.0f; // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets). 822 FrameBorderSize = 0.0f; // Thickness of border around frames. Generally set to 0.0f or 1.0f. Other values not well tested. 823 ItemSpacing = ImVec2(8, 4); // Horizontal and vertical spacing between widgets/lines 824 ItemInnerSpacing = ImVec2(4, 4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label) 825 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! 826 IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). 827 ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns 828 ScrollbarSize = 16.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar 829 ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar 830 GrabMinSize = 10.0f; // Minimum width/height of a grab box for slider/scrollbar 831 GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. 832 ButtonTextAlign = ImVec2(0.5f, 0.5f);// Alignment of button text when button is larger than text. 833 DisplayWindowPadding = ImVec2(20, 20); // Window positions are clamped to be visible within the display area by at least this amount. Only covers regular windows. 834 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. 835 MouseCursorScale = 1.0f; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later. 836 AntiAliasedLines = true; // Enable anti-aliasing on lines/borders. Disable if you are really short on CPU/GPU. 837 AntiAliasedFill = true; // Enable anti-aliasing on filled shapes (rounded rectangles, circles, etc.) 838 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. 839 840 // Default theme 841 ImGui::StyleColorsDark(this); 921 Alpha = 1.0f; // Global alpha applies to everything in ImGui 922 WindowPadding = ImVec2(8,8); // Padding within a window 923 WindowRounding = 7.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended. 924 WindowBorderSize = 1.0f; // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested. 925 WindowMinSize = ImVec2(32,32); // Minimum window size 926 WindowTitleAlign = ImVec2(0.0f,0.5f);// Alignment for title bar text 927 WindowMenuButtonPosition= ImGuiDir_Left; // Position of the collapsing/docking button in the title bar (left/right). Defaults to ImGuiDir_Left. 928 ChildRounding = 0.0f; // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows 929 ChildBorderSize = 1.0f; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. Other values not well tested. 930 PopupRounding = 0.0f; // Radius of popup window corners rounding. Set to 0.0f to have rectangular child windows 931 PopupBorderSize = 1.0f; // Thickness of border around popup or tooltip windows. Generally set to 0.0f or 1.0f. Other values not well tested. 932 FramePadding = ImVec2(4,3); // Padding within a framed rectangle (used by most widgets) 933 FrameRounding = 0.0f; // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets). 934 FrameBorderSize = 0.0f; // Thickness of border around frames. Generally set to 0.0f or 1.0f. Other values not well tested. 935 ItemSpacing = ImVec2(8,4); // Horizontal and vertical spacing between widgets/lines 936 ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label) 937 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! 938 IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). 939 ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1). 940 ScrollbarSize = 14.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar 941 ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar 942 GrabMinSize = 10.0f; // Minimum width/height of a grab box for slider/scrollbar 943 GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. 944 LogSliderDeadzone = 4.0f; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero. 945 TabRounding = 4.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. 946 TabBorderSize = 0.0f; // Thickness of border around tabs. 947 TabMinWidthForCloseButton = 0.0f; // Minimum width for close button to appears on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected. 948 ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. 949 ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text. 950 SelectableTextAlign = ImVec2(0.0f,0.0f);// Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. 951 DisplayWindowPadding = ImVec2(19,19); // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows. 952 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. 953 MouseCursorScale = 1.0f; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later. 954 AntiAliasedLines = true; // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU. 955 AntiAliasedLinesUseTex = true; // Enable anti-aliased lines/borders using textures where possible. Require back-end to render with bilinear filtering. 956 AntiAliasedFill = true; // Enable anti-aliased filled shapes (rounded rectangles, circles, etc.). 957 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. 958 CircleSegmentMaxError = 1.60f; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry. 959 960 // Default theme 961 ImGui::StyleColorsDark(this); 842 962 } 843 963 … … 846 966 void ImGuiStyle::ScaleAllSizes(float scale_factor) 847 967 { 848 WindowPadding = ImFloor(WindowPadding * scale_factor); 849 WindowRounding = ImFloor(WindowRounding * scale_factor); 850 WindowMinSize = ImFloor(WindowMinSize * scale_factor); 851 ChildRounding = ImFloor(ChildRounding * scale_factor); 852 PopupRounding = ImFloor(PopupRounding * scale_factor); 853 FramePadding = ImFloor(FramePadding * scale_factor); 854 FrameRounding = ImFloor(FrameRounding * scale_factor); 855 ItemSpacing = ImFloor(ItemSpacing * scale_factor); 856 ItemInnerSpacing = ImFloor(ItemInnerSpacing * scale_factor); 857 TouchExtraPadding = ImFloor(TouchExtraPadding * scale_factor); 858 IndentSpacing = ImFloor(IndentSpacing * scale_factor); 859 ColumnsMinSpacing = ImFloor(ColumnsMinSpacing * scale_factor); 860 ScrollbarSize = ImFloor(ScrollbarSize * scale_factor); 861 ScrollbarRounding = ImFloor(ScrollbarRounding * scale_factor); 862 GrabMinSize = ImFloor(GrabMinSize * scale_factor); 863 GrabRounding = ImFloor(GrabRounding * scale_factor); 864 DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor); 865 DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor); 866 MouseCursorScale = ImFloor(MouseCursorScale * scale_factor); 968 WindowPadding = ImFloor(WindowPadding * scale_factor); 969 WindowRounding = ImFloor(WindowRounding * scale_factor); 970 WindowMinSize = ImFloor(WindowMinSize * scale_factor); 971 ChildRounding = ImFloor(ChildRounding * scale_factor); 972 PopupRounding = ImFloor(PopupRounding * scale_factor); 973 FramePadding = ImFloor(FramePadding * scale_factor); 974 FrameRounding = ImFloor(FrameRounding * scale_factor); 975 ItemSpacing = ImFloor(ItemSpacing * scale_factor); 976 ItemInnerSpacing = ImFloor(ItemInnerSpacing * scale_factor); 977 TouchExtraPadding = ImFloor(TouchExtraPadding * scale_factor); 978 IndentSpacing = ImFloor(IndentSpacing * scale_factor); 979 ColumnsMinSpacing = ImFloor(ColumnsMinSpacing * scale_factor); 980 ScrollbarSize = ImFloor(ScrollbarSize * scale_factor); 981 ScrollbarRounding = ImFloor(ScrollbarRounding * scale_factor); 982 GrabMinSize = ImFloor(GrabMinSize * scale_factor); 983 GrabRounding = ImFloor(GrabRounding * scale_factor); 984 LogSliderDeadzone = ImFloor(LogSliderDeadzone * scale_factor); 985 TabRounding = ImFloor(TabRounding * scale_factor); 986 TabMinWidthForCloseButton = (TabMinWidthForCloseButton != FLT_MAX) ? ImFloor(TabMinWidthForCloseButton * scale_factor) : FLT_MAX; 987 DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor); 988 DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor); 989 MouseCursorScale = ImFloor(MouseCursorScale * scale_factor); 867 990 } 868 991 869 992 ImGuiIO::ImGuiIO() 870 993 { 871 // Most fields are initialized with zero 872 memset(this, 0, sizeof(*this)); 873 874 // Settings 875 ConfigFlags = 0x00; 876 BackendFlags = 0x00; 877 DisplaySize = ImVec2(-1.0f, -1.0f); 878 DeltaTime = 1.0f / 60.0f; 879 IniSavingRate = 5.0f; 880 IniFilename = "imgui.ini"; 881 LogFilename = "imgui_log.txt"; 882 MouseDoubleClickTime = 0.30f; 883 MouseDoubleClickMaxDist = 6.0f; 884 for (int i = 0; i < ImGuiKey_COUNT; i++) 885 KeyMap[i] = -1; 886 KeyRepeatDelay = 0.250f; 887 KeyRepeatRate = 0.050f; 888 UserData = NULL; 889 890 Fonts = NULL; 891 FontGlobalScale = 1.0f; 892 FontDefault = NULL; 893 FontAllowUserScaling = false; 894 DisplayFramebufferScale = ImVec2(1.0f, 1.0f); 895 DisplayVisibleMin = DisplayVisibleMax = ImVec2(0.0f, 0.0f); 896 897 // Advanced/subtle behaviors 994 // Most fields are initialized with zero 995 memset(this, 0, sizeof(*this)); 996 IM_ASSERT(IM_ARRAYSIZE(ImGuiIO::MouseDown) == ImGuiMouseButton_COUNT && IM_ARRAYSIZE(ImGuiIO::MouseClicked) == ImGuiMouseButton_COUNT); // Our pre-C++11 IM_STATIC_ASSERT() macros triggers warning on modern compilers so we don't use it here. 997 998 // Settings 999 ConfigFlags = ImGuiConfigFlags_None; 1000 BackendFlags = ImGuiBackendFlags_None; 1001 DisplaySize = ImVec2(-1.0f, -1.0f); 1002 DeltaTime = 1.0f / 60.0f; 1003 IniSavingRate = 5.0f; 1004 IniFilename = "imgui.ini"; 1005 LogFilename = "imgui_log.txt"; 1006 MouseDoubleClickTime = 0.30f; 1007 MouseDoubleClickMaxDist = 6.0f; 1008 for (int i = 0; i < ImGuiKey_COUNT; i++) 1009 KeyMap[i] = -1; 1010 KeyRepeatDelay = 0.275f; 1011 KeyRepeatRate = 0.050f; 1012 UserData = NULL; 1013 1014 Fonts = NULL; 1015 FontGlobalScale = 1.0f; 1016 FontDefault = NULL; 1017 FontAllowUserScaling = false; 1018 DisplayFramebufferScale = ImVec2(1.0f, 1.0f); 1019 1020 // Miscellaneous options 1021 MouseDrawCursor = false; 898 1022 #ifdef __APPLE__ 899 OptMacOSXBehaviors = true; // Set Mac OS X style defaults based on __APPLE__ compile time flag1023 ConfigMacOSXBehaviors = true; // Set Mac OS X style defaults based on __APPLE__ compile time flag 900 1024 #else 901 OptMacOSXBehaviors = false;1025 ConfigMacOSXBehaviors = false; 902 1026 #endif 903 OptCursorBlink = true; 904 905 // Settings (User Functions) 906 GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations 907 SetClipboardTextFn = SetClipboardTextFn_DefaultImpl; 908 ClipboardUserData = NULL; 909 ImeSetInputScreenPosFn = ImeSetInputScreenPosFn_DefaultImpl; 910 ImeWindowHandle = NULL; 1027 ConfigInputTextCursorBlink = true; 1028 ConfigWindowsResizeFromEdges = true; 1029 ConfigWindowsMoveFromTitleBarOnly = false; 1030 ConfigWindowsMemoryCompactTimer = 60.0f; 1031 1032 // Platform Functions 1033 BackendPlatformName = BackendRendererName = NULL; 1034 BackendPlatformUserData = BackendRendererUserData = BackendLanguageUserData = NULL; 1035 GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations 1036 SetClipboardTextFn = SetClipboardTextFn_DefaultImpl; 1037 ClipboardUserData = NULL; 1038 ImeSetInputScreenPosFn = ImeSetInputScreenPosFn_DefaultImpl; 1039 ImeWindowHandle = NULL; 911 1040 912 1041 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS 913 RenderDrawListsFn = NULL;1042 RenderDrawListsFn = NULL; 914 1043 #endif 915 1044 916 // Input (NB: we already have memset zero the entire structure)917 MousePos = ImVec2(-FLT_MAX, -FLT_MAX);918 MousePosPrev = ImVec2(-FLT_MAX, -FLT_MAX);919 MouseDragThreshold = 6.0f;920 for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[i] = MouseDownDurationPrev[i] = -1.0f;921 for (int i = 0; i < IM_ARRAYSIZE(KeysDownDuration); i++) KeysDownDuration[i]= KeysDownDurationPrev[i] = -1.0f;922 for (int i = 0; i < IM_ARRAYSIZE(NavInputsDownDuration); i++) NavInputsDownDuration[i] = -1.0f;1045 // Input (NB: we already have memset zero the entire structure!) 1046 MousePos = ImVec2(-FLT_MAX, -FLT_MAX); 1047 MousePosPrev = ImVec2(-FLT_MAX, -FLT_MAX); 1048 MouseDragThreshold = 6.0f; 1049 for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[i] = MouseDownDurationPrev[i] = -1.0f; 1050 for (int i = 0; i < IM_ARRAYSIZE(KeysDownDuration); i++) KeysDownDuration[i] = KeysDownDurationPrev[i] = -1.0f; 1051 for (int i = 0; i < IM_ARRAYSIZE(NavInputsDownDuration); i++) NavInputsDownDuration[i] = -1.0f; 923 1052 } 924 1053 … … 926 1055 // - with glfw you can get those from the callback set in glfwSetCharCallback() 927 1056 // - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message 928 void ImGuiIO::AddInputCharacter(ImWchar c) 929 { 930 const int n = ImStrlenW(InputCharacters); 931 if (n + 1 < IM_ARRAYSIZE(InputCharacters)) 932 { 933 InputCharacters[n] = c; 934 InputCharacters[n + 1] = '\0'; 935 } 1057 void ImGuiIO::AddInputCharacter(unsigned int c) 1058 { 1059 if (c != 0) 1060 InputQueueCharacters.push_back(c <= IM_UNICODE_CODEPOINT_MAX ? (ImWchar)c : IM_UNICODE_CODEPOINT_INVALID); 1061 } 1062 1063 // UTF16 strings use surrogate pairs to encode codepoints >= 0x10000, so 1064 // we should save the high surrogate. 1065 void ImGuiIO::AddInputCharacterUTF16(ImWchar16 c) 1066 { 1067 if (c == 0 && InputQueueSurrogate == 0) 1068 return; 1069 1070 if ((c & 0xFC00) == 0xD800) // High surrogate, must save 1071 { 1072 if (InputQueueSurrogate != 0) 1073 InputQueueCharacters.push_back(IM_UNICODE_CODEPOINT_INVALID); 1074 InputQueueSurrogate = c; 1075 return; 1076 } 1077 1078 ImWchar cp = c; 1079 if (InputQueueSurrogate != 0) 1080 { 1081 if ((c & 0xFC00) != 0xDC00) // Invalid low surrogate 1082 InputQueueCharacters.push_back(IM_UNICODE_CODEPOINT_INVALID); 1083 else if (IM_UNICODE_CODEPOINT_MAX == (0xFFFF)) // Codepoint will not fit in ImWchar (extra parenthesis around 0xFFFF somehow fixes -Wunreachable-code with Clang) 1084 cp = IM_UNICODE_CODEPOINT_INVALID; 1085 else 1086 cp = (ImWchar)(((InputQueueSurrogate - 0xD800) << 10) + (c - 0xDC00) + 0x10000); 1087 InputQueueSurrogate = 0; 1088 } 1089 InputQueueCharacters.push_back(cp); 936 1090 } 937 1091 938 1092 void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars) 939 1093 { 940 // We can't pass more wchars than ImGuiIO::InputCharacters[] can hold so don't convert more 941 const int wchars_buf_len = sizeof(ImGuiIO::InputCharacters) / sizeof(ImWchar); 942 ImWchar wchars[wchars_buf_len]; 943 ImTextStrFromUtf8(wchars, wchars_buf_len, utf8_chars, NULL); 944 for (int i = 0; i < wchars_buf_len && wchars[i] != 0; i++) 945 AddInputCharacter(wchars[i]); 1094 while (*utf8_chars != 0) 1095 { 1096 unsigned int c = 0; 1097 utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL); 1098 if (c != 0) 1099 InputQueueCharacters.push_back((ImWchar)c); 1100 } 1101 } 1102 1103 void ImGuiIO::ClearInputCharacters() 1104 { 1105 InputQueueCharacters.resize(0); 946 1106 } 947 1107 948 1108 //----------------------------------------------------------------------------- 949 // HELPERS1109 // [SECTION] MISC HELPERS/UTILITIES (Geometry functions) 950 1110 //----------------------------------------------------------------------------- 951 1111 952 #define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) // Unsaturated, for display purpose 953 #define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255 1112 ImVec2 ImBezierClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, int num_segments) 1113 { 1114 IM_ASSERT(num_segments > 0); // Use ImBezierClosestPointCasteljau() 1115 ImVec2 p_last = p1; 1116 ImVec2 p_closest; 1117 float p_closest_dist2 = FLT_MAX; 1118 float t_step = 1.0f / (float)num_segments; 1119 for (int i_step = 1; i_step <= num_segments; i_step++) 1120 { 1121 ImVec2 p_current = ImBezierCalc(p1, p2, p3, p4, t_step * i_step); 1122 ImVec2 p_line = ImLineClosestPoint(p_last, p_current, p); 1123 float dist2 = ImLengthSqr(p - p_line); 1124 if (dist2 < p_closest_dist2) 1125 { 1126 p_closest = p_line; 1127 p_closest_dist2 = dist2; 1128 } 1129 p_last = p_current; 1130 } 1131 return p_closest; 1132 } 1133 1134 // Closely mimics PathBezierToCasteljau() in imgui_draw.cpp 1135 static void BezierClosestPointCasteljauStep(const ImVec2& p, ImVec2& p_closest, ImVec2& p_last, float& p_closest_dist2, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level) 1136 { 1137 float dx = x4 - x1; 1138 float dy = y4 - y1; 1139 float d2 = ((x2 - x4) * dy - (y2 - y4) * dx); 1140 float d3 = ((x3 - x4) * dy - (y3 - y4) * dx); 1141 d2 = (d2 >= 0) ? d2 : -d2; 1142 d3 = (d3 >= 0) ? d3 : -d3; 1143 if ((d2 + d3) * (d2 + d3) < tess_tol * (dx * dx + dy * dy)) 1144 { 1145 ImVec2 p_current(x4, y4); 1146 ImVec2 p_line = ImLineClosestPoint(p_last, p_current, p); 1147 float dist2 = ImLengthSqr(p - p_line); 1148 if (dist2 < p_closest_dist2) 1149 { 1150 p_closest = p_line; 1151 p_closest_dist2 = dist2; 1152 } 1153 p_last = p_current; 1154 } 1155 else if (level < 10) 1156 { 1157 float x12 = (x1 + x2)*0.5f, y12 = (y1 + y2)*0.5f; 1158 float x23 = (x2 + x3)*0.5f, y23 = (y2 + y3)*0.5f; 1159 float x34 = (x3 + x4)*0.5f, y34 = (y3 + y4)*0.5f; 1160 float x123 = (x12 + x23)*0.5f, y123 = (y12 + y23)*0.5f; 1161 float x234 = (x23 + x34)*0.5f, y234 = (y23 + y34)*0.5f; 1162 float x1234 = (x123 + x234)*0.5f, y1234 = (y123 + y234)*0.5f; 1163 BezierClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1); 1164 BezierClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1); 1165 } 1166 } 1167 1168 // tess_tol is generally the same value you would find in ImGui::GetStyle().CurveTessellationTol 1169 // Because those ImXXX functions are lower-level than ImGui:: we cannot access this value automatically. 1170 ImVec2 ImBezierClosestPointCasteljau(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float tess_tol) 1171 { 1172 IM_ASSERT(tess_tol > 0.0f); 1173 ImVec2 p_last = p1; 1174 ImVec2 p_closest; 1175 float p_closest_dist2 = FLT_MAX; 1176 BezierClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, tess_tol, 0); 1177 return p_closest; 1178 } 954 1179 955 1180 ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p) 956 1181 { 957 ImVec2 ap = p - a;958 ImVec2 ab_dir = b - a;959 float dot = ap.x * ab_dir.x + ap.y * ab_dir.y;960 if (dot < 0.0f)961 return a;962 float ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y;963 if (dot > ab_len_sqr)964 return b;965 return a + ab_dir * dot / ab_len_sqr;1182 ImVec2 ap = p - a; 1183 ImVec2 ab_dir = b - a; 1184 float dot = ap.x * ab_dir.x + ap.y * ab_dir.y; 1185 if (dot < 0.0f) 1186 return a; 1187 float ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y; 1188 if (dot > ab_len_sqr) 1189 return b; 1190 return a + ab_dir * dot / ab_len_sqr; 966 1191 } 967 1192 968 1193 bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p) 969 1194 { 970 bool b1 = ((p.x - b.x) * (a.y - b.y) - (p.y - b.y) * (a.x - b.x)) < 0.0f;971 bool b2 = ((p.x - c.x) * (b.y - c.y) - (p.y - c.y) * (b.x - c.x)) < 0.0f;972 bool b3 = ((p.x - a.x) * (c.y - a.y) - (p.y - a.y) * (c.x - a.x)) < 0.0f;973 return ((b1 == b2) && (b2 == b3));1195 bool b1 = ((p.x - b.x) * (a.y - b.y) - (p.y - b.y) * (a.x - b.x)) < 0.0f; 1196 bool b2 = ((p.x - c.x) * (b.y - c.y) - (p.y - c.y) * (b.x - c.x)) < 0.0f; 1197 bool b3 = ((p.x - a.x) * (c.y - a.y) - (p.y - a.y) * (c.x - a.x)) < 0.0f; 1198 return ((b1 == b2) && (b2 == b3)); 974 1199 } 975 1200 976 1201 void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w) 977 1202 { 978 ImVec2 v0 = b - a;979 ImVec2 v1 = c - a;980 ImVec2 v2 = p - a;981 const float denom = v0.x * v1.y - v1.x * v0.y;982 out_v = (v2.x * v1.y - v1.x * v2.y) / denom;983 out_w = (v0.x * v2.y - v2.x * v0.y) / denom;984 out_u = 1.0f - out_v - out_w;1203 ImVec2 v0 = b - a; 1204 ImVec2 v1 = c - a; 1205 ImVec2 v2 = p - a; 1206 const float denom = v0.x * v1.y - v1.x * v0.y; 1207 out_v = (v2.x * v1.y - v1.x * v2.y) / denom; 1208 out_w = (v0.x * v2.y - v2.x * v0.y) / denom; 1209 out_u = 1.0f - out_v - out_w; 985 1210 } 986 1211 987 1212 ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p) 988 1213 { 989 ImVec2 proj_ab = ImLineClosestPoint(a, b, p); 990 ImVec2 proj_bc = ImLineClosestPoint(b, c, p); 991 ImVec2 proj_ca = ImLineClosestPoint(c, a, p); 992 float dist2_ab = ImLengthSqr(p - proj_ab); 993 float dist2_bc = ImLengthSqr(p - proj_bc); 994 float dist2_ca = ImLengthSqr(p - proj_ca); 995 float m = ImMin(dist2_ab, ImMin(dist2_bc, dist2_ca)); 996 if (m == dist2_ab) 997 return proj_ab; 998 if (m == dist2_bc) 999 return proj_bc; 1000 return proj_ca; 1001 } 1002 1214 ImVec2 proj_ab = ImLineClosestPoint(a, b, p); 1215 ImVec2 proj_bc = ImLineClosestPoint(b, c, p); 1216 ImVec2 proj_ca = ImLineClosestPoint(c, a, p); 1217 float dist2_ab = ImLengthSqr(p - proj_ab); 1218 float dist2_bc = ImLengthSqr(p - proj_bc); 1219 float dist2_ca = ImLengthSqr(p - proj_ca); 1220 float m = ImMin(dist2_ab, ImMin(dist2_bc, dist2_ca)); 1221 if (m == dist2_ab) 1222 return proj_ab; 1223 if (m == dist2_bc) 1224 return proj_bc; 1225 return proj_ca; 1226 } 1227 1228 //----------------------------------------------------------------------------- 1229 // [SECTION] MISC HELPERS/UTILITIES (String, Format, Hash functions) 1230 //----------------------------------------------------------------------------- 1231 1232 // Consider using _stricmp/_strnicmp under Windows or strcasecmp/strncasecmp. We don't actually use either ImStricmp/ImStrnicmp in the codebase any more. 1003 1233 int ImStricmp(const char* str1, const char* str2) 1004 1234 { 1005 int d;1006 while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; }1007 return d;1235 int d; 1236 while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; } 1237 return d; 1008 1238 } 1009 1239 1010 1240 int ImStrnicmp(const char* str1, const char* str2, size_t count) 1011 1241 { 1012 int d = 0;1013 while (count > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; count--; }1014 return d;1242 int d = 0; 1243 while (count > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; count--; } 1244 return d; 1015 1245 } 1016 1246 1017 1247 void ImStrncpy(char* dst, const char* src, size_t count) 1018 1248 { 1019 if (count < 1) return; 1020 strncpy(dst, src, count); 1021 dst[count - 1] = 0; 1022 } 1023 1024 char* ImStrdup(const char *str) 1025 { 1026 size_t len = strlen(str) + 1; 1027 void* buf = ImGui::MemAlloc(len); 1028 return (char*)memcpy(buf, (const void*)str, len); 1249 if (count < 1) 1250 return; 1251 if (count > 1) 1252 strncpy(dst, src, count - 1); 1253 dst[count - 1] = 0; 1254 } 1255 1256 char* ImStrdup(const char* str) 1257 { 1258 size_t len = strlen(str); 1259 void* buf = IM_ALLOC(len + 1); 1260 return (char*)memcpy(buf, (const void*)str, len + 1); 1261 } 1262 1263 char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* src) 1264 { 1265 size_t dst_buf_size = p_dst_size ? *p_dst_size : strlen(dst) + 1; 1266 size_t src_size = strlen(src) + 1; 1267 if (dst_buf_size < src_size) 1268 { 1269 IM_FREE(dst); 1270 dst = (char*)IM_ALLOC(src_size); 1271 if (p_dst_size) 1272 *p_dst_size = src_size; 1273 } 1274 return (char*)memcpy(dst, (const void*)src, src_size); 1029 1275 } 1030 1276 1031 1277 const char* ImStrchrRange(const char* str, const char* str_end, char c) 1032 1278 { 1033 for (; str < str_end; str++) 1034 if (*str == c) 1035 return str; 1036 return NULL; 1279 const char* p = (const char*)memchr(str, (int)c, str_end - str); 1280 return p; 1037 1281 } 1038 1282 1039 1283 int ImStrlenW(const ImWchar* str) 1040 1284 { 1041 int n = 0; 1042 while (*str++) n++; 1043 return n; 1285 //return (int)wcslen((const wchar_t*)str); // FIXME-OPT: Could use this when wchar_t are 16-bit 1286 int n = 0; 1287 while (*str++) n++; 1288 return n; 1289 } 1290 1291 // Find end-of-line. Return pointer will point to either first \n, either str_end. 1292 const char* ImStreolRange(const char* str, const char* str_end) 1293 { 1294 const char* p = (const char*)memchr(str, '\n', str_end - str); 1295 return p ? p : str_end; 1044 1296 } 1045 1297 1046 1298 const ImWchar* ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin) // find beginning-of-line 1047 1299 { 1048 while (buf_mid_line > buf_begin && buf_mid_line[-1] != '\n')1049 buf_mid_line--;1050 return buf_mid_line;1300 while (buf_mid_line > buf_begin && buf_mid_line[-1] != '\n') 1301 buf_mid_line--; 1302 return buf_mid_line; 1051 1303 } 1052 1304 1053 1305 const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end) 1054 1306 { 1055 if (!needle_end) 1056 needle_end = needle + strlen(needle); 1057 1058 const char un0 = (char)toupper(*needle); 1059 while ((!haystack_end && *haystack) || (haystack_end && haystack < haystack_end)) 1060 { 1061 if (toupper(*haystack) == un0) 1062 { 1063 const char* b = needle + 1; 1064 for (const char* a = haystack + 1; b < needle_end; a++, b++) 1065 if (toupper(*a) != toupper(*b)) 1066 break; 1067 if (b == needle_end) 1068 return haystack; 1069 } 1070 haystack++; 1071 } 1072 return NULL; 1073 } 1074 1075 static const char* ImAtoi(const char* src, int* output) 1076 { 1077 int negative = 0; 1078 if (*src == '-') { negative = 1; src++; } 1079 if (*src == '+') { src++; } 1080 int v = 0; 1081 while (*src >= '0' && *src <= '9') 1082 v = (v * 10) + (*src++ - '0'); 1083 *output = negative ? -v : v; 1084 return src; 1085 } 1086 1087 // A) MSVC version appears to return -1 on overflow, whereas glibc appears to return total count (which may be >= buf_size). 1307 if (!needle_end) 1308 needle_end = needle + strlen(needle); 1309 1310 const char un0 = (char)toupper(*needle); 1311 while ((!haystack_end && *haystack) || (haystack_end && haystack < haystack_end)) 1312 { 1313 if (toupper(*haystack) == un0) 1314 { 1315 const char* b = needle + 1; 1316 for (const char* a = haystack + 1; b < needle_end; a++, b++) 1317 if (toupper(*a) != toupper(*b)) 1318 break; 1319 if (b == needle_end) 1320 return haystack; 1321 } 1322 haystack++; 1323 } 1324 return NULL; 1325 } 1326 1327 // 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. 1328 void ImStrTrimBlanks(char* buf) 1329 { 1330 char* p = buf; 1331 while (p[0] == ' ' || p[0] == '\t') // Leading blanks 1332 p++; 1333 char* p_start = p; 1334 while (*p != 0) // Find end of string 1335 p++; 1336 while (p > p_start && (p[-1] == ' ' || p[-1] == '\t')) // Trailing blanks 1337 p--; 1338 if (p_start != buf) // Copy memory if we had leading blanks 1339 memmove(buf, p_start, p - p_start); 1340 buf[p - p_start] = 0; // Zero terminate 1341 } 1342 1343 const char* ImStrSkipBlank(const char* str) 1344 { 1345 while (str[0] == ' ' || str[0] == '\t') 1346 str++; 1347 return str; 1348 } 1349 1350 // A) MSVC version appears to return -1 on overflow, whereas glibc appears to return total count (which may be >= buf_size). 1088 1351 // 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. 1089 1352 // B) When buf==NULL vsnprintf() will return the output size. 1090 #ifndef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS 1353 #ifndef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS 1354 1355 // We support stb_sprintf which is much faster (see: https://github.com/nothings/stb/blob/master/stb_sprintf.h) 1356 // You may set IMGUI_USE_STB_SPRINTF to use our default wrapper, or set IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS 1357 // and setup the wrapper yourself. (FIXME-OPT: Some of our high-level operations such as ImGuiTextBuffer::appendfv() are 1358 // designed using two-passes worst case, which probably could be improved using the stbsp_vsprintfcb() function.) 1359 #ifdef IMGUI_USE_STB_SPRINTF 1360 #define STB_SPRINTF_IMPLEMENTATION 1361 #include "stb_sprintf.h" 1362 #endif 1363 1364 #if defined(_MSC_VER) && !defined(vsnprintf) 1365 #define vsnprintf _vsnprintf 1366 #endif 1367 1091 1368 int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...) 1092 1369 { 1093 va_list args; 1094 va_start(args, fmt); 1095 int w = vsnprintf(buf, buf_size, fmt, args); 1096 va_end(args); 1097 if (buf == NULL) 1098 return w; 1099 if (w == -1 || w >= (int)buf_size) 1100 w = (int)buf_size - 1; 1101 buf[w] = 0; 1102 return w; 1370 va_list args; 1371 va_start(args, fmt); 1372 #ifdef IMGUI_USE_STB_SPRINTF 1373 int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args); 1374 #else 1375 int w = vsnprintf(buf, buf_size, fmt, args); 1376 #endif 1377 va_end(args); 1378 if (buf == NULL) 1379 return w; 1380 if (w == -1 || w >= (int)buf_size) 1381 w = (int)buf_size - 1; 1382 buf[w] = 0; 1383 return w; 1103 1384 } 1104 1385 1105 1386 int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) 1106 1387 { 1107 int w = vsnprintf(buf, buf_size, fmt, args); 1108 if (buf == NULL) 1109 return w; 1110 if (w == -1 || w >= (int)buf_size) 1111 w = (int)buf_size - 1; 1112 buf[w] = 0; 1113 return w; 1114 } 1115 #endif // #ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS 1116 1117 // Pass data_size==0 for zero-terminated strings 1388 #ifdef IMGUI_USE_STB_SPRINTF 1389 int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args); 1390 #else 1391 int w = vsnprintf(buf, buf_size, fmt, args); 1392 #endif 1393 if (buf == NULL) 1394 return w; 1395 if (w == -1 || w >= (int)buf_size) 1396 w = (int)buf_size - 1; 1397 buf[w] = 0; 1398 return w; 1399 } 1400 #endif // #ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS 1401 1402 // CRC32 needs a 1KB lookup table (not cache friendly) 1403 // Although the code to generate the table is simple and shorter than the table itself, using a const table allows us to easily: 1404 // - avoid an unnecessary branch/memory tap, - keep the ImHashXXX functions usable by static constructors, - make it thread-safe. 1405 static const ImU32 GCrc32LookupTable[256] = 1406 { 1407 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91, 1408 0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5, 1409 0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59, 1410 0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F,0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D, 1411 0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01, 1412 0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65, 1413 0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9, 1414 0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD, 1415 0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1, 1416 0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5, 1417 0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79, 1418 0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D, 1419 0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21, 1420 0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45, 1421 0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9, 1422 0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D, 1423 }; 1424 1425 // Known size hash 1426 // It is ok to call ImHashData on a string with known length but the ### operator won't be supported. 1118 1427 // FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements. 1119 ImU32 ImHash(const void* data, int data_size, ImU32 seed) 1120 { 1121 static ImU32 crc32_lut[256] = { 0 }; 1122 if (!crc32_lut[1]) 1123 { 1124 const ImU32 polynomial = 0xEDB88320; 1125 for (ImU32 i = 0; i < 256; i++) 1126 { 1127 ImU32 crc = i; 1128 for (ImU32 j = 0; j < 8; j++) 1129 crc = (crc >> 1) ^ (ImU32(-int(crc & 1)) & polynomial); 1130 crc32_lut[i] = crc; 1131 } 1132 } 1133 1134 seed = ~seed; 1135 ImU32 crc = seed; 1136 const unsigned char* current = (const unsigned char*)data; 1137 1138 if (data_size > 0) 1139 { 1140 // Known size 1141 while (data_size--) 1142 crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *current++]; 1143 } 1144 else 1145 { 1146 // Zero-terminated string 1147 while (unsigned char c = *current++) 1148 { 1149 // We support a syntax of "label###id" where only "###id" is included in the hash, and only "label" gets displayed. 1150 // Because this syntax is rarely used we are optimizing for the common case. 1151 // - If we reach ### in the string we discard the hash so far and reset to the seed. 1152 // - We don't do 'current += 2; continue;' after handling ### to keep the code smaller. 1153 if (c == '#' && current[0] == '#' && current[1] == '#') 1154 crc = seed; 1155 crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c]; 1156 } 1157 } 1158 return ~crc; 1428 ImU32 ImHashData(const void* data_p, size_t data_size, ImU32 seed) 1429 { 1430 ImU32 crc = ~seed; 1431 const unsigned char* data = (const unsigned char*)data_p; 1432 const ImU32* crc32_lut = GCrc32LookupTable; 1433 while (data_size-- != 0) 1434 crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *data++]; 1435 return ~crc; 1436 } 1437 1438 // Zero-terminated string hash, with support for ### to reset back to seed value 1439 // We support a syntax of "label###id" where only "###id" is included in the hash, and only "label" gets displayed. 1440 // Because this syntax is rarely used we are optimizing for the common case. 1441 // - If we reach ### in the string we discard the hash so far and reset to the seed. 1442 // - We don't do 'current += 2; continue;' after handling ### to keep the code smaller/faster (measured ~10% diff in Debug build) 1443 // FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements. 1444 ImU32 ImHashStr(const char* data_p, size_t data_size, ImU32 seed) 1445 { 1446 seed = ~seed; 1447 ImU32 crc = seed; 1448 const unsigned char* data = (const unsigned char*)data_p; 1449 const ImU32* crc32_lut = GCrc32LookupTable; 1450 if (data_size != 0) 1451 { 1452 while (data_size-- != 0) 1453 { 1454 unsigned char c = *data++; 1455 if (c == '#' && data_size >= 2 && data[0] == '#' && data[1] == '#') 1456 crc = seed; 1457 crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c]; 1458 } 1459 } 1460 else 1461 { 1462 while (unsigned char c = *data++) 1463 { 1464 if (c == '#' && data[0] == '#' && data[1] == '#') 1465 crc = seed; 1466 crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c]; 1467 } 1468 } 1469 return ~crc; 1159 1470 } 1160 1471 1161 1472 //----------------------------------------------------------------------------- 1162 // ImText* helpers1473 // [SECTION] MISC HELPERS/UTILITIES (File functions) 1163 1474 //----------------------------------------------------------------------------- 1164 1475 1165 // Convert UTF-8 to 32-bits character, process single character input. 1476 // Default file functions 1477 #ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS 1478 1479 ImFileHandle ImFileOpen(const char* filename, const char* mode) 1480 { 1481 #if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(__CYGWIN__) && !defined(__GNUC__) 1482 // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames. 1483 // Previously we used ImTextCountCharsFromUtf8/ImTextStrFromUtf8 here but we now need to support ImWchar16 and ImWchar32! 1484 const int filename_wsize = ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0); 1485 const int mode_wsize = ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0); 1486 ImVector<ImWchar> buf; 1487 buf.resize(filename_wsize + mode_wsize); 1488 ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, (wchar_t*)&buf[0], filename_wsize); 1489 ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, (wchar_t*)&buf[filename_wsize], mode_wsize); 1490 return ::_wfopen((const wchar_t*)&buf[0], (const wchar_t*)&buf[filename_wsize]); 1491 #else 1492 return fopen(filename, mode); 1493 #endif 1494 } 1495 1496 // We should in theory be using fseeko()/ftello() with off_t and _fseeki64()/_ftelli64() with __int64, waiting for the PR that does that in a very portable pre-C++11 zero-warnings way. 1497 bool ImFileClose(ImFileHandle f) { return fclose(f) == 0; } 1498 ImU64 ImFileGetSize(ImFileHandle f) { long off = 0, sz = 0; return ((off = ftell(f)) != -1 && !fseek(f, 0, SEEK_END) && (sz = ftell(f)) != -1 && !fseek(f, off, SEEK_SET)) ? (ImU64)sz : (ImU64)-1; } 1499 ImU64 ImFileRead(void* data, ImU64 sz, ImU64 count, ImFileHandle f) { return fread(data, (size_t)sz, (size_t)count, f); } 1500 ImU64 ImFileWrite(const void* data, ImU64 sz, ImU64 count, ImFileHandle f) { return fwrite(data, (size_t)sz, (size_t)count, f); } 1501 #endif // #ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS 1502 1503 // Helper: Load file content into memory 1504 // Memory allocated with IM_ALLOC(), must be freed by user using IM_FREE() == ImGui::MemFree() 1505 // This can't really be used with "rt" because fseek size won't match read size. 1506 void* ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_file_size, int padding_bytes) 1507 { 1508 IM_ASSERT(filename && mode); 1509 if (out_file_size) 1510 *out_file_size = 0; 1511 1512 ImFileHandle f; 1513 if ((f = ImFileOpen(filename, mode)) == NULL) 1514 return NULL; 1515 1516 size_t file_size = (size_t)ImFileGetSize(f); 1517 if (file_size == (size_t)-1) 1518 { 1519 ImFileClose(f); 1520 return NULL; 1521 } 1522 1523 void* file_data = IM_ALLOC(file_size + padding_bytes); 1524 if (file_data == NULL) 1525 { 1526 ImFileClose(f); 1527 return NULL; 1528 } 1529 if (ImFileRead(file_data, 1, file_size, f) != file_size) 1530 { 1531 ImFileClose(f); 1532 IM_FREE(file_data); 1533 return NULL; 1534 } 1535 if (padding_bytes > 0) 1536 memset((void*)(((char*)file_data) + file_size), 0, (size_t)padding_bytes); 1537 1538 ImFileClose(f); 1539 if (out_file_size) 1540 *out_file_size = file_size; 1541 1542 return file_data; 1543 } 1544 1545 //----------------------------------------------------------------------------- 1546 // [SECTION] MISC HELPERS/UTILITIES (ImText* functions) 1547 //----------------------------------------------------------------------------- 1548 1549 // Convert UTF-8 to 32-bit character, process single character input. 1166 1550 // Based on stb_from_utf8() from github.com/nothings/stb/ 1167 1551 // We handle UTF-8 decoding error by skipping forward. 1168 1552 int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end) 1169 1553 { 1170 unsigned int c = (unsigned int)-1; 1171 const unsigned char* str = (const unsigned char*)in_text; 1172 if (!(*str & 0x80)) 1173 { 1174 c = (unsigned int)(*str++); 1175 *out_char = c; 1176 return 1; 1177 } 1178 if ((*str & 0xe0) == 0xc0) 1179 { 1180 *out_char = 0xFFFD; // will be invalid but not end of string 1181 if (in_text_end && in_text_end - (const char*)str < 2) return 1; 1182 if (*str < 0xc2) return 2; 1183 c = (unsigned int)((*str++ & 0x1f) << 6); 1184 if ((*str & 0xc0) != 0x80) return 2; 1185 c += (*str++ & 0x3f); 1186 *out_char = c; 1187 return 2; 1188 } 1189 if ((*str & 0xf0) == 0xe0) 1190 { 1191 *out_char = 0xFFFD; // will be invalid but not end of string 1192 if (in_text_end && in_text_end - (const char*)str < 3) return 1; 1193 if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return 3; 1194 if (*str == 0xed && str[1] > 0x9f) return 3; // str[1] < 0x80 is checked below 1195 c = (unsigned int)((*str++ & 0x0f) << 12); 1196 if ((*str & 0xc0) != 0x80) return 3; 1197 c += (unsigned int)((*str++ & 0x3f) << 6); 1198 if ((*str & 0xc0) != 0x80) return 3; 1199 c += (*str++ & 0x3f); 1200 *out_char = c; 1201 return 3; 1202 } 1203 if ((*str & 0xf8) == 0xf0) 1204 { 1205 *out_char = 0xFFFD; // will be invalid but not end of string 1206 if (in_text_end && in_text_end - (const char*)str < 4) return 1; 1207 if (*str > 0xf4) return 4; 1208 if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return 4; 1209 if (*str == 0xf4 && str[1] > 0x8f) return 4; // str[1] < 0x80 is checked below 1210 c = (unsigned int)((*str++ & 0x07) << 18); 1211 if ((*str & 0xc0) != 0x80) return 4; 1212 c += (unsigned int)((*str++ & 0x3f) << 12); 1213 if ((*str & 0xc0) != 0x80) return 4; 1214 c += (unsigned int)((*str++ & 0x3f) << 6); 1215 if ((*str & 0xc0) != 0x80) return 4; 1216 c += (*str++ & 0x3f); 1217 // utf-8 encodings of values used in surrogate pairs are invalid 1218 if ((c & 0xFFFFF800) == 0xD800) return 4; 1219 *out_char = c; 1220 return 4; 1221 } 1222 *out_char = 0; 1223 return 0; 1554 unsigned int c = (unsigned int)-1; 1555 const unsigned char* str = (const unsigned char*)in_text; 1556 if (!(*str & 0x80)) 1557 { 1558 c = (unsigned int)(*str++); 1559 *out_char = c; 1560 return 1; 1561 } 1562 if ((*str & 0xe0) == 0xc0) 1563 { 1564 *out_char = IM_UNICODE_CODEPOINT_INVALID; // will be invalid but not end of string 1565 if (in_text_end && in_text_end - (const char*)str < 2) return 1; 1566 if (*str < 0xc2) return 2; 1567 c = (unsigned int)((*str++ & 0x1f) << 6); 1568 if ((*str & 0xc0) != 0x80) return 2; 1569 c += (*str++ & 0x3f); 1570 *out_char = c; 1571 return 2; 1572 } 1573 if ((*str & 0xf0) == 0xe0) 1574 { 1575 *out_char = IM_UNICODE_CODEPOINT_INVALID; // will be invalid but not end of string 1576 if (in_text_end && in_text_end - (const char*)str < 3) return 1; 1577 if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return 3; 1578 if (*str == 0xed && str[1] > 0x9f) return 3; // str[1] < 0x80 is checked below 1579 c = (unsigned int)((*str++ & 0x0f) << 12); 1580 if ((*str & 0xc0) != 0x80) return 3; 1581 c += (unsigned int)((*str++ & 0x3f) << 6); 1582 if ((*str & 0xc0) != 0x80) return 3; 1583 c += (*str++ & 0x3f); 1584 *out_char = c; 1585 return 3; 1586 } 1587 if ((*str & 0xf8) == 0xf0) 1588 { 1589 *out_char = IM_UNICODE_CODEPOINT_INVALID; // will be invalid but not end of string 1590 if (in_text_end && in_text_end - (const char*)str < 4) return 1; 1591 if (*str > 0xf4) return 4; 1592 if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return 4; 1593 if (*str == 0xf4 && str[1] > 0x8f) return 4; // str[1] < 0x80 is checked below 1594 c = (unsigned int)((*str++ & 0x07) << 18); 1595 if ((*str & 0xc0) != 0x80) return 4; 1596 c += (unsigned int)((*str++ & 0x3f) << 12); 1597 if ((*str & 0xc0) != 0x80) return 4; 1598 c += (unsigned int)((*str++ & 0x3f) << 6); 1599 if ((*str & 0xc0) != 0x80) return 4; 1600 c += (*str++ & 0x3f); 1601 // utf-8 encodings of values used in surrogate pairs are invalid 1602 if ((c & 0xFFFFF800) == 0xD800) return 4; 1603 // If codepoint does not fit in ImWchar, use replacement character U+FFFD instead 1604 if (c > IM_UNICODE_CODEPOINT_MAX) c = IM_UNICODE_CODEPOINT_INVALID; 1605 *out_char = c; 1606 return 4; 1607 } 1608 *out_char = 0; 1609 return 0; 1224 1610 } 1225 1611 1226 1612 int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_text_remaining) 1227 1613 { 1228 ImWchar* buf_out = buf; 1229 ImWchar* buf_end = buf + buf_size; 1230 while (buf_out < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text) 1231 { 1232 unsigned int c; 1233 in_text += ImTextCharFromUtf8(&c, in_text, in_text_end); 1234 if (c == 0) 1235 break; 1236 if (c < 0x10000) // FIXME: Losing characters that don't fit in 2 bytes 1237 *buf_out++ = (ImWchar)c; 1238 } 1239 *buf_out = 0; 1240 if (in_text_remaining) 1241 *in_text_remaining = in_text; 1242 return (int)(buf_out - buf); 1614 ImWchar* buf_out = buf; 1615 ImWchar* buf_end = buf + buf_size; 1616 while (buf_out < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text) 1617 { 1618 unsigned int c; 1619 in_text += ImTextCharFromUtf8(&c, in_text, in_text_end); 1620 if (c == 0) 1621 break; 1622 *buf_out++ = (ImWchar)c; 1623 } 1624 *buf_out = 0; 1625 if (in_text_remaining) 1626 *in_text_remaining = in_text; 1627 return (int)(buf_out - buf); 1243 1628 } 1244 1629 1245 1630 int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end) 1246 1631 { 1247 int char_count = 0; 1248 while ((!in_text_end || in_text < in_text_end) && *in_text) 1249 { 1250 unsigned int c; 1251 in_text += ImTextCharFromUtf8(&c, in_text, in_text_end); 1252 if (c == 0) 1253 break; 1254 if (c < 0x10000) 1255 char_count++; 1256 } 1257 return char_count; 1632 int char_count = 0; 1633 while ((!in_text_end || in_text < in_text_end) && *in_text) 1634 { 1635 unsigned int c; 1636 in_text += ImTextCharFromUtf8(&c, in_text, in_text_end); 1637 if (c == 0) 1638 break; 1639 char_count++; 1640 } 1641 return char_count; 1258 1642 } 1259 1643 … … 1261 1645 static inline int ImTextCharToUtf8(char* buf, int buf_size, unsigned int c) 1262 1646 { 1263 if (c < 0x80) 1264 { 1265 buf[0] = (char)c; 1266 return 1; 1267 } 1268 if (c < 0x800) 1269 { 1270 if (buf_size < 2) return 0; 1271 buf[0] = (char)(0xc0 + (c >> 6)); 1272 buf[1] = (char)(0x80 + (c & 0x3f)); 1273 return 2; 1274 } 1275 if (c >= 0xdc00 && c < 0xe000) 1276 { 1277 return 0; 1278 } 1279 if (c >= 0xd800 && c < 0xdc00) 1280 { 1281 if (buf_size < 4) return 0; 1282 buf[0] = (char)(0xf0 + (c >> 18)); 1283 buf[1] = (char)(0x80 + ((c >> 12) & 0x3f)); 1284 buf[2] = (char)(0x80 + ((c >> 6) & 0x3f)); 1285 buf[3] = (char)(0x80 + ((c) & 0x3f)); 1286 return 4; 1287 } 1288 //else if (c < 0x10000) 1289 { 1290 if (buf_size < 3) return 0; 1291 buf[0] = (char)(0xe0 + (c >> 12)); 1292 buf[1] = (char)(0x80 + ((c >> 6) & 0x3f)); 1293 buf[2] = (char)(0x80 + ((c) & 0x3f)); 1294 return 3; 1295 } 1647 if (c < 0x80) 1648 { 1649 buf[0] = (char)c; 1650 return 1; 1651 } 1652 if (c < 0x800) 1653 { 1654 if (buf_size < 2) return 0; 1655 buf[0] = (char)(0xc0 + (c >> 6)); 1656 buf[1] = (char)(0x80 + (c & 0x3f)); 1657 return 2; 1658 } 1659 if (c < 0x10000) 1660 { 1661 if (buf_size < 3) return 0; 1662 buf[0] = (char)(0xe0 + (c >> 12)); 1663 buf[1] = (char)(0x80 + ((c >> 6) & 0x3f)); 1664 buf[2] = (char)(0x80 + ((c ) & 0x3f)); 1665 return 3; 1666 } 1667 if (c <= 0x10FFFF) 1668 { 1669 if (buf_size < 4) return 0; 1670 buf[0] = (char)(0xf0 + (c >> 18)); 1671 buf[1] = (char)(0x80 + ((c >> 12) & 0x3f)); 1672 buf[2] = (char)(0x80 + ((c >> 6) & 0x3f)); 1673 buf[3] = (char)(0x80 + ((c ) & 0x3f)); 1674 return 4; 1675 } 1676 // Invalid code point, the max unicode is 0x10FFFF 1677 return 0; 1678 } 1679 1680 // Not optimal but we very rarely use this function. 1681 int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end) 1682 { 1683 unsigned int unused = 0; 1684 return ImTextCharFromUtf8(&unused, in_text, in_text_end); 1296 1685 } 1297 1686 1298 1687 static inline int ImTextCountUtf8BytesFromChar(unsigned int c) 1299 1688 { 1300 if (c < 0x80) return 1;1301 if (c < 0x800) return 2;1302 if (c >= 0xdc00 && c < 0xe000) return 0;1303 if (c >= 0xd800 && c < 0xdc00) return 4;1304 return 3;1689 if (c < 0x80) return 1; 1690 if (c < 0x800) return 2; 1691 if (c < 0x10000) return 3; 1692 if (c <= 0x10FFFF) return 4; 1693 return 3; 1305 1694 } 1306 1695 1307 1696 int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end) 1308 1697 { 1309 char* buf_out = buf;1310 const char* buf_end = buf + buf_size;1311 while (buf_out < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text)1312 {1313 unsigned int c = (unsigned int)(*in_text++);1314 if (c < 0x80)1315 *buf_out++ = (char)c;1316 else1317 buf_out += ImTextCharToUtf8(buf_out, (int)(buf_end - buf_out - 1), c);1318 }1319 *buf_out = 0;1320 return (int)(buf_out - buf);1698 char* buf_out = buf; 1699 const char* buf_end = buf + buf_size; 1700 while (buf_out < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text) 1701 { 1702 unsigned int c = (unsigned int)(*in_text++); 1703 if (c < 0x80) 1704 *buf_out++ = (char)c; 1705 else 1706 buf_out += ImTextCharToUtf8(buf_out, (int)(buf_end - buf_out - 1), c); 1707 } 1708 *buf_out = 0; 1709 return (int)(buf_out - buf); 1321 1710 } 1322 1711 1323 1712 int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end) 1324 1713 { 1325 int bytes_count = 0; 1326 while ((!in_text_end || in_text < in_text_end) && *in_text) 1327 { 1328 unsigned int c = (unsigned int)(*in_text++); 1329 if (c < 0x80) 1330 bytes_count++; 1331 else 1332 bytes_count += ImTextCountUtf8BytesFromChar(c); 1333 } 1334 return bytes_count; 1714 int bytes_count = 0; 1715 while ((!in_text_end || in_text < in_text_end) && *in_text) 1716 { 1717 unsigned int c = (unsigned int)(*in_text++); 1718 if (c < 0x80) 1719 bytes_count++; 1720 else 1721 bytes_count += ImTextCountUtf8BytesFromChar(c); 1722 } 1723 return bytes_count; 1724 } 1725 1726 //----------------------------------------------------------------------------- 1727 // [SECTION] MISC HELPERS/UTILITIES (Color functions) 1728 // Note: The Convert functions are early design which are not consistent with other API. 1729 //----------------------------------------------------------------------------- 1730 1731 IMGUI_API ImU32 ImAlphaBlendColors(ImU32 col_a, ImU32 col_b) 1732 { 1733 float t = ((col_b >> IM_COL32_A_SHIFT) & 0xFF) / 255.f; 1734 int r = ImLerp((int)(col_a >> IM_COL32_R_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_R_SHIFT) & 0xFF, t); 1735 int g = ImLerp((int)(col_a >> IM_COL32_G_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_G_SHIFT) & 0xFF, t); 1736 int b = ImLerp((int)(col_a >> IM_COL32_B_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_B_SHIFT) & 0xFF, t); 1737 return IM_COL32(r, g, b, 0xFF); 1335 1738 } 1336 1739 1337 1740 ImVec4 ImGui::ColorConvertU32ToFloat4(ImU32 in) 1338 1741 { 1339 float s = 1.0f / 255.0f;1340 return ImVec4(1341 ((in >> IM_COL32_R_SHIFT) & 0xFF) * s,1342 ((in >> IM_COL32_G_SHIFT) & 0xFF) * s,1343 ((in >> IM_COL32_B_SHIFT) & 0xFF) * s,1344 ((in >> IM_COL32_A_SHIFT) & 0xFF) * s);1742 float s = 1.0f / 255.0f; 1743 return ImVec4( 1744 ((in >> IM_COL32_R_SHIFT) & 0xFF) * s, 1745 ((in >> IM_COL32_G_SHIFT) & 0xFF) * s, 1746 ((in >> IM_COL32_B_SHIFT) & 0xFF) * s, 1747 ((in >> IM_COL32_A_SHIFT) & 0xFF) * s); 1345 1748 } 1346 1749 1347 1750 ImU32 ImGui::ColorConvertFloat4ToU32(const ImVec4& in) 1348 1751 { 1349 ImU32 out; 1350 out = ((ImU32)IM_F32_TO_INT8_SAT(in.x)) << IM_COL32_R_SHIFT; 1351 out |= ((ImU32)IM_F32_TO_INT8_SAT(in.y)) << IM_COL32_G_SHIFT; 1352 out |= ((ImU32)IM_F32_TO_INT8_SAT(in.z)) << IM_COL32_B_SHIFT; 1353 out |= ((ImU32)IM_F32_TO_INT8_SAT(in.w)) << IM_COL32_A_SHIFT; 1354 return out; 1355 } 1356 1357 ImU32 ImGui::GetColorU32(ImGuiCol idx, float alpha_mul) 1358 { 1359 ImGuiStyle& style = GImGui->Style; 1360 ImVec4 c = style.Colors[idx]; 1361 c.w *= style.Alpha * alpha_mul; 1362 return ColorConvertFloat4ToU32(c); 1363 } 1364 1365 ImU32 ImGui::GetColorU32(const ImVec4& col) 1366 { 1367 ImGuiStyle& style = GImGui->Style; 1368 ImVec4 c = col; 1369 c.w *= style.Alpha; 1370 return ColorConvertFloat4ToU32(c); 1371 } 1372 1373 const ImVec4& ImGui::GetStyleColorVec4(ImGuiCol idx) 1374 { 1375 ImGuiStyle& style = GImGui->Style; 1376 return style.Colors[idx]; 1377 } 1378 1379 ImU32 ImGui::GetColorU32(ImU32 col) 1380 { 1381 float style_alpha = GImGui->Style.Alpha; 1382 if (style_alpha >= 1.0f) 1383 return col; 1384 ImU32 a = (col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT; 1385 a = (ImU32)(a * style_alpha); // We don't need to clamp 0..255 because Style.Alpha is in 0..1 range. 1386 return (col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT); 1752 ImU32 out; 1753 out = ((ImU32)IM_F32_TO_INT8_SAT(in.x)) << IM_COL32_R_SHIFT; 1754 out |= ((ImU32)IM_F32_TO_INT8_SAT(in.y)) << IM_COL32_G_SHIFT; 1755 out |= ((ImU32)IM_F32_TO_INT8_SAT(in.z)) << IM_COL32_B_SHIFT; 1756 out |= ((ImU32)IM_F32_TO_INT8_SAT(in.w)) << IM_COL32_A_SHIFT; 1757 return out; 1387 1758 } 1388 1759 … … 1391 1762 void ImGui::ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v) 1392 1763 { 1393 float K = 0.f;1394 if (g < b)1395 {1396 ImSwap(g, b);1397 K = -1.f;1398 }1399 if (r < g)1400 {1401 ImSwap(r, g);1402 K = -2.f / 6.f - K;1403 }1404 1405 const float chroma = r - (g < b ? g : b);1406 out_h = fabsf(K + (g - b) / (6.f * chroma + 1e-20f));1407 out_s = chroma / (r + 1e-20f);1408 out_v = r;1764 float K = 0.f; 1765 if (g < b) 1766 { 1767 ImSwap(g, b); 1768 K = -1.f; 1769 } 1770 if (r < g) 1771 { 1772 ImSwap(r, g); 1773 K = -2.f / 6.f - K; 1774 } 1775 1776 const float chroma = r - (g < b ? g : b); 1777 out_h = ImFabs(K + (g - b) / (6.f * chroma + 1e-20f)); 1778 out_s = chroma / (r + 1e-20f); 1779 out_v = r; 1409 1780 } 1410 1781 … … 1413 1784 void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b) 1414 1785 { 1415 if (s == 0.0f) 1416 { 1417 // gray 1418 out_r = out_g = out_b = v; 1419 return; 1420 } 1421 1422 h = fmodf(h, 1.0f) / (60.0f / 360.0f); 1423 int i = (int)h; 1424 float f = h - (float)i; 1425 float p = v * (1.0f - s); 1426 float q = v * (1.0f - s * f); 1427 float t = v * (1.0f - s * (1.0f - f)); 1428 1429 switch (i) 1430 { 1431 case 0: out_r = v; out_g = t; out_b = p; break; 1432 case 1: out_r = q; out_g = v; out_b = p; break; 1433 case 2: out_r = p; out_g = v; out_b = t; break; 1434 case 3: out_r = p; out_g = q; out_b = v; break; 1435 case 4: out_r = t; out_g = p; out_b = v; break; 1436 case 5: default: out_r = v; out_g = p; out_b = q; break; 1437 } 1438 } 1439 1440 FILE* ImFileOpen(const char* filename, const char* mode) 1441 { 1442 #if defined(_WIN32) && !defined(__CYGWIN__) 1443 // 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) 1444 const int filename_wsize = ImTextCountCharsFromUtf8(filename, NULL) + 1; 1445 const int mode_wsize = ImTextCountCharsFromUtf8(mode, NULL) + 1; 1446 ImVector<ImWchar> buf; 1447 buf.resize(filename_wsize + mode_wsize); 1448 ImTextStrFromUtf8(&buf[0], filename_wsize, filename, NULL); 1449 ImTextStrFromUtf8(&buf[filename_wsize], mode_wsize, mode, NULL); 1450 return _wfopen((wchar_t*)&buf[0], (wchar_t*)&buf[filename_wsize]); 1451 #else 1452 return fopen(filename, mode); 1453 #endif 1454 } 1455 1456 // Load file content into memory 1457 // Memory allocated with ImGui::MemAlloc(), must be freed by user using ImGui::MemFree() 1458 void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, int* out_file_size, int padding_bytes) 1459 { 1460 IM_ASSERT(filename && file_open_mode); 1461 if (out_file_size) 1462 *out_file_size = 0; 1463 1464 FILE* f; 1465 if ((f = ImFileOpen(filename, file_open_mode)) == NULL) 1466 return NULL; 1467 1468 long file_size_signed; 1469 if (fseek(f, 0, SEEK_END) || (file_size_signed = ftell(f)) == -1 || fseek(f, 0, SEEK_SET)) 1470 { 1471 fclose(f); 1472 return NULL; 1473 } 1474 1475 int file_size = (int)file_size_signed; 1476 void* file_data = ImGui::MemAlloc((size_t)(file_size + padding_bytes)); 1477 if (file_data == NULL) 1478 { 1479 fclose(f); 1480 return NULL; 1481 } 1482 if (fread(file_data, 1, (size_t)file_size, f) != (size_t)file_size) 1483 { 1484 fclose(f); 1485 ImGui::MemFree(file_data); 1486 return NULL; 1487 } 1488 if (padding_bytes > 0) 1489 memset((void *)(((char*)file_data) + file_size), 0, (size_t)padding_bytes); 1490 1491 fclose(f); 1492 if (out_file_size) 1493 *out_file_size = file_size; 1494 1495 return file_data; 1786 if (s == 0.0f) 1787 { 1788 // gray 1789 out_r = out_g = out_b = v; 1790 return; 1791 } 1792 1793 h = ImFmod(h, 1.0f) / (60.0f / 360.0f); 1794 int i = (int)h; 1795 float f = h - (float)i; 1796 float p = v * (1.0f - s); 1797 float q = v * (1.0f - s * f); 1798 float t = v * (1.0f - s * (1.0f - f)); 1799 1800 switch (i) 1801 { 1802 case 0: out_r = v; out_g = t; out_b = p; break; 1803 case 1: out_r = q; out_g = v; out_b = p; break; 1804 case 2: out_r = p; out_g = v; out_b = t; break; 1805 case 3: out_r = p; out_g = q; out_b = v; break; 1806 case 4: out_r = t; out_g = p; out_b = v; break; 1807 case 5: default: out_r = v; out_g = p; out_b = q; break; 1808 } 1496 1809 } 1497 1810 1498 1811 //----------------------------------------------------------------------------- 1499 // ImGuiStorage1812 // [SECTION] ImGuiStorage 1500 1813 // Helper: Key->value storage 1501 1814 //----------------------------------------------------------------------------- 1502 1815 1503 1816 // std::lower_bound but without the bullshit 1504 static Im Vector<ImGuiStorage::Pair>::iterator LowerBound(ImVector<ImGuiStorage::Pair>& data, ImGuiID key)1505 { 1506 ImVector<ImGuiStorage::Pair>::iterator first = data.begin();1507 ImVector<ImGuiStorage::Pair>::iterator last = data.end();1508 size_t count = (size_t)(last - first);1509 while (count > 0)1510 {1511 size_t count2 = count >> 1;1512 ImVector<ImGuiStorage::Pair>::iteratormid = first + count2;1513 if (mid->key < key)1514 {1515 first = ++mid;1516 count -= count2 + 1;1517 }1518 else1519 {1520 count = count2;1521 }1522 }1523 return first;1817 static ImGuiStorage::ImGuiStoragePair* LowerBound(ImVector<ImGuiStorage::ImGuiStoragePair>& data, ImGuiID key) 1818 { 1819 ImGuiStorage::ImGuiStoragePair* first = data.Data; 1820 ImGuiStorage::ImGuiStoragePair* last = data.Data + data.Size; 1821 size_t count = (size_t)(last - first); 1822 while (count > 0) 1823 { 1824 size_t count2 = count >> 1; 1825 ImGuiStorage::ImGuiStoragePair* mid = first + count2; 1826 if (mid->key < key) 1827 { 1828 first = ++mid; 1829 count -= count2 + 1; 1830 } 1831 else 1832 { 1833 count = count2; 1834 } 1835 } 1836 return first; 1524 1837 } 1525 1838 … … 1527 1840 void ImGuiStorage::BuildSortByKey() 1528 1841 { 1529 struct StaticFunc1530 {1531 static int IMGUI_CDECL PairCompareByID(const void* lhs, const void* rhs)1532 {1533 // We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that.1534 if (((const Pair*)lhs)->key > ((constPair*)rhs)->key) return +1;1535 if (((const Pair*)lhs)->key < ((constPair*)rhs)->key) return -1;1536 return 0;1537 }1538 };1539 if (Data.Size > 1)1540 qsort(Data.Data, (size_t)Data.Size, sizeof(Pair), StaticFunc::PairCompareByID);1842 struct StaticFunc 1843 { 1844 static int IMGUI_CDECL PairCompareByID(const void* lhs, const void* rhs) 1845 { 1846 // We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that. 1847 if (((const ImGuiStoragePair*)lhs)->key > ((const ImGuiStoragePair*)rhs)->key) return +1; 1848 if (((const ImGuiStoragePair*)lhs)->key < ((const ImGuiStoragePair*)rhs)->key) return -1; 1849 return 0; 1850 } 1851 }; 1852 if (Data.Size > 1) 1853 ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), StaticFunc::PairCompareByID); 1541 1854 } 1542 1855 1543 1856 int ImGuiStorage::GetInt(ImGuiID key, int default_val) const 1544 1857 { 1545 ImVector<Pair>::iterator it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);1546 if (it == Data.end() || it->key != key)1547 return default_val;1548 return it->val_i;1858 ImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key); 1859 if (it == Data.end() || it->key != key) 1860 return default_val; 1861 return it->val_i; 1549 1862 } 1550 1863 1551 1864 bool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const 1552 1865 { 1553 return GetInt(key, default_val ? 1 : 0) != 0;1866 return GetInt(key, default_val ? 1 : 0) != 0; 1554 1867 } 1555 1868 1556 1869 float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const 1557 1870 { 1558 ImVector<Pair>::iterator it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);1559 if (it == Data.end() || it->key != key)1560 return default_val;1561 return it->val_f;1871 ImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key); 1872 if (it == Data.end() || it->key != key) 1873 return default_val; 1874 return it->val_f; 1562 1875 } 1563 1876 1564 1877 void* ImGuiStorage::GetVoidPtr(ImGuiID key) const 1565 1878 { 1566 ImVector<Pair>::iterator it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);1567 if (it == Data.end() || it->key != key)1568 return NULL;1569 return it->val_p;1879 ImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key); 1880 if (it == Data.end() || it->key != key) 1881 return NULL; 1882 return it->val_p; 1570 1883 } 1571 1884 … … 1573 1886 int* ImGuiStorage::GetIntRef(ImGuiID key, int default_val) 1574 1887 { 1575 ImVector<Pair>::iteratorit = LowerBound(Data, key);1576 if (it == Data.end() || it->key != key)1577 it = Data.insert(it,Pair(key, default_val));1578 return &it->val_i;1888 ImGuiStoragePair* it = LowerBound(Data, key); 1889 if (it == Data.end() || it->key != key) 1890 it = Data.insert(it, ImGuiStoragePair(key, default_val)); 1891 return &it->val_i; 1579 1892 } 1580 1893 1581 1894 bool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val) 1582 1895 { 1583 return (bool*)GetIntRef(key, default_val ? 1 : 0);1896 return (bool*)GetIntRef(key, default_val ? 1 : 0); 1584 1897 } 1585 1898 1586 1899 float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val) 1587 1900 { 1588 ImVector<Pair>::iteratorit = LowerBound(Data, key);1589 if (it == Data.end() || it->key != key)1590 it = Data.insert(it,Pair(key, default_val));1591 return &it->val_f;1901 ImGuiStoragePair* it = LowerBound(Data, key); 1902 if (it == Data.end() || it->key != key) 1903 it = Data.insert(it, ImGuiStoragePair(key, default_val)); 1904 return &it->val_f; 1592 1905 } 1593 1906 1594 1907 void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val) 1595 1908 { 1596 ImVector<Pair>::iteratorit = LowerBound(Data, key);1597 if (it == Data.end() || it->key != key)1598 it = Data.insert(it,Pair(key, default_val));1599 return &it->val_p;1909 ImGuiStoragePair* it = LowerBound(Data, key); 1910 if (it == Data.end() || it->key != key) 1911 it = Data.insert(it, ImGuiStoragePair(key, default_val)); 1912 return &it->val_p; 1600 1913 } 1601 1914 … … 1603 1916 void ImGuiStorage::SetInt(ImGuiID key, int val) 1604 1917 { 1605 ImVector<Pair>::iteratorit = LowerBound(Data, key);1606 if (it == Data.end() || it->key != key)1607 {1608 Data.insert(it,Pair(key, val));1609 return;1610 }1611 it->val_i = val;1918 ImGuiStoragePair* it = LowerBound(Data, key); 1919 if (it == Data.end() || it->key != key) 1920 { 1921 Data.insert(it, ImGuiStoragePair(key, val)); 1922 return; 1923 } 1924 it->val_i = val; 1612 1925 } 1613 1926 1614 1927 void ImGuiStorage::SetBool(ImGuiID key, bool val) 1615 1928 { 1616 SetInt(key, val ? 1 : 0);1929 SetInt(key, val ? 1 : 0); 1617 1930 } 1618 1931 1619 1932 void ImGuiStorage::SetFloat(ImGuiID key, float val) 1620 1933 { 1621 ImVector<Pair>::iteratorit = LowerBound(Data, key);1622 if (it == Data.end() || it->key != key)1623 {1624 Data.insert(it,Pair(key, val));1625 return;1626 }1627 it->val_f = val;1934 ImGuiStoragePair* it = LowerBound(Data, key); 1935 if (it == Data.end() || it->key != key) 1936 { 1937 Data.insert(it, ImGuiStoragePair(key, val)); 1938 return; 1939 } 1940 it->val_f = val; 1628 1941 } 1629 1942 1630 1943 void ImGuiStorage::SetVoidPtr(ImGuiID key, void* val) 1631 1944 { 1632 ImVector<Pair>::iteratorit = LowerBound(Data, key);1633 if (it == Data.end() || it->key != key)1634 {1635 Data.insert(it,Pair(key, val));1636 return;1637 }1638 it->val_p = val;1945 ImGuiStoragePair* it = LowerBound(Data, key); 1946 if (it == Data.end() || it->key != key) 1947 { 1948 Data.insert(it, ImGuiStoragePair(key, val)); 1949 return; 1950 } 1951 it->val_p = val; 1639 1952 } 1640 1953 1641 1954 void ImGuiStorage::SetAllInt(int v) 1642 1955 { 1643 for (int i = 0; i < Data.Size; i++)1644 Data[i].val_i = v;1956 for (int i = 0; i < Data.Size; i++) 1957 Data[i].val_i = v; 1645 1958 } 1646 1959 1647 1960 //----------------------------------------------------------------------------- 1648 // ImGuiTextFilter1961 // [SECTION] ImGuiTextFilter 1649 1962 //----------------------------------------------------------------------------- 1650 1963 … … 1652 1965 ImGuiTextFilter::ImGuiTextFilter(const char* default_filter) 1653 1966 { 1654 if (default_filter)1655 {1656 ImStrncpy(InputBuf, default_filter, IM_ARRAYSIZE(InputBuf));1657 Build();1658 }1659 else1660 {1661 InputBuf[0] = 0;1662 CountGrep = 0;1663 }1967 if (default_filter) 1968 { 1969 ImStrncpy(InputBuf, default_filter, IM_ARRAYSIZE(InputBuf)); 1970 Build(); 1971 } 1972 else 1973 { 1974 InputBuf[0] = 0; 1975 CountGrep = 0; 1976 } 1664 1977 } 1665 1978 1666 1979 bool ImGuiTextFilter::Draw(const char* label, float width) 1667 1980 { 1668 if (width != 0.0f) 1669 ImGui::PushItemWidth(width); 1670 bool value_changed = ImGui::InputText(label, InputBuf, IM_ARRAYSIZE(InputBuf)); 1671 if (width != 0.0f) 1672 ImGui::PopItemWidth(); 1673 if (value_changed) 1674 Build(); 1675 return value_changed; 1676 } 1677 1678 void ImGuiTextFilter::TextRange::split(char separator, ImVector<TextRange>& out) 1679 { 1680 out.resize(0); 1681 const char* wb = b; 1682 const char* we = wb; 1683 while (we < e) 1684 { 1685 if (*we == separator) 1686 { 1687 out.push_back(TextRange(wb, we)); 1688 wb = we + 1; 1689 } 1690 we++; 1691 } 1692 if (wb != we) 1693 out.push_back(TextRange(wb, we)); 1981 if (width != 0.0f) 1982 ImGui::SetNextItemWidth(width); 1983 bool value_changed = ImGui::InputText(label, InputBuf, IM_ARRAYSIZE(InputBuf)); 1984 if (value_changed) 1985 Build(); 1986 return value_changed; 1987 } 1988 1989 void ImGuiTextFilter::ImGuiTextRange::split(char separator, ImVector<ImGuiTextRange>* out) const 1990 { 1991 out->resize(0); 1992 const char* wb = b; 1993 const char* we = wb; 1994 while (we < e) 1995 { 1996 if (*we == separator) 1997 { 1998 out->push_back(ImGuiTextRange(wb, we)); 1999 wb = we + 1; 2000 } 2001 we++; 2002 } 2003 if (wb != we) 2004 out->push_back(ImGuiTextRange(wb, we)); 1694 2005 } 1695 2006 1696 2007 void ImGuiTextFilter::Build() 1697 2008 { 1698 Filters.resize(0); 1699 TextRange input_range(InputBuf, InputBuf + strlen(InputBuf)); 1700 input_range.split(',', Filters); 1701 1702 CountGrep = 0; 1703 for (int i = 0; i != Filters.Size; i++) 1704 { 1705 Filters[i].trim_blanks(); 1706 if (Filters[i].empty()) 1707 continue; 1708 if (Filters[i].front() != '-') 1709 CountGrep += 1; 1710 } 2009 Filters.resize(0); 2010 ImGuiTextRange input_range(InputBuf, InputBuf + strlen(InputBuf)); 2011 input_range.split(',', &Filters); 2012 2013 CountGrep = 0; 2014 for (int i = 0; i != Filters.Size; i++) 2015 { 2016 ImGuiTextRange& f = Filters[i]; 2017 while (f.b < f.e && ImCharIsBlankA(f.b[0])) 2018 f.b++; 2019 while (f.e > f.b && ImCharIsBlankA(f.e[-1])) 2020 f.e--; 2021 if (f.empty()) 2022 continue; 2023 if (Filters[i].b[0] != '-') 2024 CountGrep += 1; 2025 } 1711 2026 } 1712 2027 1713 2028 bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const 1714 2029 { 1715 if (Filters.empty())1716 return true;1717 1718 if (text == NULL)1719 text = "";1720 1721 for (int i = 0; i != Filters.Size; i++)1722 {1723 constTextRange& f = Filters[i];1724 if (f.empty())1725 continue;1726 if (f.front()== '-')1727 {1728 // Subtract1729 if (ImStristr(text, text_end, f.begin() + 1, f.end()) != NULL)1730 return false;1731 }1732 else1733 {1734 // Grep1735 if (ImStristr(text, text_end, f.begin(), f.end()) != NULL)1736 return true;1737 }1738 }1739 1740 // Implicit * grep1741 if (CountGrep == 0)1742 return true;1743 1744 return false;2030 if (Filters.empty()) 2031 return true; 2032 2033 if (text == NULL) 2034 text = ""; 2035 2036 for (int i = 0; i != Filters.Size; i++) 2037 { 2038 const ImGuiTextRange& f = Filters[i]; 2039 if (f.empty()) 2040 continue; 2041 if (f.b[0] == '-') 2042 { 2043 // Subtract 2044 if (ImStristr(text, text_end, f.b + 1, f.e) != NULL) 2045 return false; 2046 } 2047 else 2048 { 2049 // Grep 2050 if (ImStristr(text, text_end, f.b, f.e) != NULL) 2051 return true; 2052 } 2053 } 2054 2055 // Implicit * grep 2056 if (CountGrep == 0) 2057 return true; 2058 2059 return false; 1745 2060 } 1746 2061 1747 2062 //----------------------------------------------------------------------------- 1748 // ImGuiTextBuffer2063 // [SECTION] ImGuiTextBuffer 1749 2064 //----------------------------------------------------------------------------- 1750 2065 … … 1752 2067 // va_copy is the 'correct' way to copy a va_list but Visual Studio prior to 2013 doesn't have it. 1753 2068 #ifndef va_copy 2069 #if defined(__GNUC__) || defined(__clang__) 2070 #define va_copy(dest, src) __builtin_va_copy(dest, src) 2071 #else 1754 2072 #define va_copy(dest, src) (dest = src) 1755 2073 #endif 2074 #endif 2075 2076 char ImGuiTextBuffer::EmptyString[1] = { 0 }; 2077 2078 void ImGuiTextBuffer::append(const char* str, const char* str_end) 2079 { 2080 int len = str_end ? (int)(str_end - str) : (int)strlen(str); 2081 2082 // Add zero-terminator the first time 2083 const int write_off = (Buf.Size != 0) ? Buf.Size : 1; 2084 const int needed_sz = write_off + len; 2085 if (write_off + len >= Buf.Capacity) 2086 { 2087 int new_capacity = Buf.Capacity * 2; 2088 Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity); 2089 } 2090 2091 Buf.resize(needed_sz); 2092 memcpy(&Buf[write_off - 1], str, (size_t)len); 2093 Buf[write_off - 1 + len] = 0; 2094 } 2095 2096 void ImGuiTextBuffer::appendf(const char* fmt, ...) 2097 { 2098 va_list args; 2099 va_start(args, fmt); 2100 appendfv(fmt, args); 2101 va_end(args); 2102 } 1756 2103 1757 2104 // Helper: Text buffer for logging/accumulating text 1758 2105 void ImGuiTextBuffer::appendfv(const char* fmt, va_list args) 1759 2106 { 1760 va_list args_copy; 1761 va_copy(args_copy, args); 1762 1763 int len = ImFormatStringV(NULL, 0, fmt, args); // FIXME-OPT: could do a first pass write attempt, likely successful on first pass. 1764 if (len <= 0) 1765 { 1766 va_end(args_copy); 1767 return; 1768 } 1769 1770 const int write_off = Buf.Size; 1771 const int needed_sz = write_off + len; 1772 if (write_off + len >= Buf.Capacity) 1773 { 1774 int double_capacity = Buf.Capacity * 2; 1775 Buf.reserve(needed_sz > double_capacity ? needed_sz : double_capacity); 1776 } 1777 1778 Buf.resize(needed_sz); 1779 ImFormatStringV(&Buf[write_off - 1], (size_t)len + 1, fmt, args_copy); 1780 va_end(args_copy); 1781 } 1782 1783 void ImGuiTextBuffer::appendf(const char* fmt, ...) 1784 { 1785 va_list args; 1786 va_start(args, fmt); 1787 appendfv(fmt, args); 1788 va_end(args); 2107 va_list args_copy; 2108 va_copy(args_copy, args); 2109 2110 int len = ImFormatStringV(NULL, 0, fmt, args); // FIXME-OPT: could do a first pass write attempt, likely successful on first pass. 2111 if (len <= 0) 2112 { 2113 va_end(args_copy); 2114 return; 2115 } 2116 2117 // Add zero-terminator the first time 2118 const int write_off = (Buf.Size != 0) ? Buf.Size : 1; 2119 const int needed_sz = write_off + len; 2120 if (write_off + len >= Buf.Capacity) 2121 { 2122 int new_capacity = Buf.Capacity * 2; 2123 Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity); 2124 } 2125 2126 Buf.resize(needed_sz); 2127 ImFormatStringV(&Buf[write_off - 1], (size_t)len + 1, fmt, args_copy); 2128 va_end(args_copy); 1789 2129 } 1790 2130 1791 2131 //----------------------------------------------------------------------------- 1792 // ImGuiSimpleColumns (internal use only) 2132 // [SECTION] ImGuiListClipper 2133 // This is currently not as flexible/powerful as it should be and really confusing/spaghetti, mostly because we changed 2134 // the API mid-way through development and support two ways to using the clipper, needs some rework (see TODO) 1793 2135 //----------------------------------------------------------------------------- 1794 2136 1795 ImGuiMenuColumns::ImGuiMenuColumns() 1796 { 1797 Count = 0; 1798 Spacing = Width = NextWidth = 0.0f; 1799 memset(Pos, 0, sizeof(Pos)); 1800 memset(NextWidths, 0, sizeof(NextWidths)); 1801 } 1802 1803 void ImGuiMenuColumns::Update(int count, float spacing, bool clear) 1804 { 1805 IM_ASSERT(Count <= IM_ARRAYSIZE(Pos)); 1806 Count = count; 1807 Width = NextWidth = 0.0f; 1808 Spacing = spacing; 1809 if (clear) memset(NextWidths, 0, sizeof(NextWidths)); 1810 for (int i = 0; i < Count; i++) 1811 { 1812 if (i > 0 && NextWidths[i] > 0.0f) 1813 Width += Spacing; 1814 Pos[i] = (float)(int)Width; 1815 Width += NextWidths[i]; 1816 NextWidths[i] = 0.0f; 1817 } 1818 } 1819 1820 float ImGuiMenuColumns::DeclColumns(float w0, float w1, float w2) // not using va_arg because they promote float to double 1821 { 1822 NextWidth = 0.0f; 1823 NextWidths[0] = ImMax(NextWidths[0], w0); 1824 NextWidths[1] = ImMax(NextWidths[1], w1); 1825 NextWidths[2] = ImMax(NextWidths[2], w2); 1826 for (int i = 0; i < 3; i++) 1827 NextWidth += NextWidths[i] + ((i > 0 && NextWidths[i] > 0.0f) ? Spacing : 0.0f); 1828 return ImMax(Width, NextWidth); 1829 } 1830 1831 float ImGuiMenuColumns::CalcExtraSpace(float avail_w) 1832 { 1833 return ImMax(0.0f, avail_w - Width); 1834 } 1835 1836 //----------------------------------------------------------------------------- 1837 // ImGuiListClipper 1838 //----------------------------------------------------------------------------- 1839 1840 static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height) 1841 { 1842 // Set cursor position and a few other things so that SetScrollHere() and Columns() can work when seeking cursor. 1843 // FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue. 1844 // The clipper should probably have a 4th step to display the last item in a regular manner. 1845 ImGui::SetCursorPosY(pos_y); 1846 ImGuiWindow* window = ImGui::GetCurrentWindow(); 1847 window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height; // Setting those fields so that SetScrollHere() can properly function after the end of our clipper usage. 1848 window->DC.PrevLineHeight = (line_height - GImGui->Style.ItemSpacing.y); // If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list. 1849 if (window->DC.ColumnsSet) 1850 window->DC.ColumnsSet->LineMinY = window->DC.CursorPos.y; // Setting this so that cell Y position are set properly 1851 } 1852 1853 // Use case A: Begin() called from constructor with items_height<0, then called again from Sync() in StepNo 1 2137 // Helper to calculate coarse clipping of large list of evenly sized items. 2138 // NB: Prefer using the ImGuiListClipper higher-level helper if you can! Read comments and instructions there on how those use this sort of pattern. 2139 // NB: 'items_count' is only used to clamp the result, if you don't know your count you can use INT_MAX 2140 void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end) 2141 { 2142 ImGuiContext& g = *GImGui; 2143 ImGuiWindow* window = g.CurrentWindow; 2144 if (g.LogEnabled) 2145 { 2146 // If logging is active, do not perform any clipping 2147 *out_items_display_start = 0; 2148 *out_items_display_end = items_count; 2149 return; 2150 } 2151 if (window->SkipItems) 2152 { 2153 *out_items_display_start = *out_items_display_end = 0; 2154 return; 2155 } 2156 2157 // We create the union of the ClipRect and the NavScoringRect which at worst should be 1 page away from ClipRect 2158 ImRect unclipped_rect = window->ClipRect; 2159 if (g.NavMoveRequest) 2160 unclipped_rect.Add(g.NavScoringRect); 2161 if (g.NavJustMovedToId && window->NavLastIds[0] == g.NavJustMovedToId) 2162 unclipped_rect.Add(ImRect(window->Pos + window->NavRectRel[0].Min, window->Pos + window->NavRectRel[0].Max)); 2163 2164 const ImVec2 pos = window->DC.CursorPos; 2165 int start = (int)((unclipped_rect.Min.y - pos.y) / items_height); 2166 int end = (int)((unclipped_rect.Max.y - pos.y) / items_height); 2167 2168 // When performing a navigation request, ensure we have one item extra in the direction we are moving to 2169 if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Up) 2170 start--; 2171 if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Down) 2172 end++; 2173 2174 start = ImClamp(start, 0, items_count); 2175 end = ImClamp(end + 1, start, items_count); 2176 *out_items_display_start = start; 2177 *out_items_display_end = end; 2178 } 2179 2180 static void SetCursorPosYAndSetupForPrevLine(float pos_y, float line_height) 2181 { 2182 // Set cursor position and a few other things so that SetScrollHereY() and Columns() can work when seeking cursor. 2183 // FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue. 2184 // The clipper should probably have a 4th step to display the last item in a regular manner. 2185 ImGuiContext& g = *GImGui; 2186 ImGuiWindow* window = g.CurrentWindow; 2187 window->DC.CursorPos.y = pos_y; 2188 window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, pos_y); 2189 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. 2190 window->DC.PrevLineSize.y = (line_height - g.Style.ItemSpacing.y); // If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list. 2191 if (ImGuiColumns* columns = window->DC.CurrentColumns) 2192 columns->LineMinY = window->DC.CursorPos.y; // Setting this so that cell Y position are set properly 2193 } 2194 2195 ImGuiListClipper::ImGuiListClipper() 2196 { 2197 memset(this, 0, sizeof(*this)); 2198 ItemsCount = -1; 2199 } 2200 2201 ImGuiListClipper::~ImGuiListClipper() 2202 { 2203 IM_ASSERT(ItemsCount == -1 && "Forgot to call End(), or to Step() until false?"); 2204 } 2205 2206 // Use case A: Begin() called from constructor with items_height<0, then called again from Step() in StepNo 1 1854 2207 // Use case B: Begin() called from constructor with items_height>0 1855 2208 // 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. 1856 void ImGuiListClipper::Begin(int count, float items_height) 1857 { 1858 StartPosY = ImGui::GetCursorPosY(); 1859 ItemsHeight = items_height; 1860 ItemsCount = count; 1861 StepNo = 0; 1862 DisplayEnd = DisplayStart = -1; 1863 if (ItemsHeight > 0.0f) 1864 { 1865 ImGui::CalcListClipping(ItemsCount, ItemsHeight, &DisplayStart, &DisplayEnd); // calculate how many to clip/display 1866 if (DisplayStart > 0) 1867 SetCursorPosYAndSetupDummyPrevLine(StartPosY + DisplayStart * ItemsHeight, ItemsHeight); // advance cursor 1868 StepNo = 2; 1869 } 2209 void ImGuiListClipper::Begin(int items_count, float items_height) 2210 { 2211 ImGuiContext& g = *GImGui; 2212 ImGuiWindow* window = g.CurrentWindow; 2213 2214 StartPosY = window->DC.CursorPos.y; 2215 ItemsHeight = items_height; 2216 ItemsCount = items_count; 2217 StepNo = 0; 2218 DisplayStart = -1; 2219 DisplayEnd = 0; 1870 2220 } 1871 2221 1872 2222 void ImGuiListClipper::End() 1873 2223 { 1874 if (ItemsCount < 0) 1875 return; 1876 // 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. 1877 if (ItemsCount < INT_MAX) 1878 SetCursorPosYAndSetupDummyPrevLine(StartPosY + ItemsCount * ItemsHeight, ItemsHeight); // advance cursor 1879 ItemsCount = -1; 1880 StepNo = 3; 2224 if (ItemsCount < 0) // Already ended 2225 return; 2226 2227 // 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. 2228 if (ItemsCount < INT_MAX && DisplayStart >= 0) 2229 SetCursorPosYAndSetupForPrevLine(StartPosY + ItemsCount * ItemsHeight, ItemsHeight); 2230 ItemsCount = -1; 2231 StepNo = 3; 1881 2232 } 1882 2233 1883 2234 bool ImGuiListClipper::Step() 1884 2235 { 1885 if (ItemsCount == 0 || ImGui::GetCurrentWindowRead()->SkipItems) 1886 { 1887 ItemsCount = -1; 1888 return false; 1889 } 1890 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. 1891 { 1892 DisplayStart = 0; 1893 DisplayEnd = 1; 1894 StartPosY = ImGui::GetCursorPosY(); 1895 StepNo = 1; 1896 return true; 1897 } 1898 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. 1899 { 1900 if (ItemsCount == 1) { ItemsCount = -1; return false; } 1901 float items_height = ImGui::GetCursorPosY() - StartPosY; 1902 IM_ASSERT(items_height > 0.0f); // If this triggers, it means Item 0 hasn't moved the cursor vertically 1903 Begin(ItemsCount - 1, items_height); 1904 DisplayStart++; 1905 DisplayEnd++; 1906 StepNo = 3; 1907 return true; 1908 } 1909 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. 1910 { 1911 IM_ASSERT(DisplayStart >= 0 && DisplayEnd >= 0); 1912 StepNo = 3; 1913 return true; 1914 } 1915 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. 1916 End(); 1917 return false; 2236 ImGuiContext& g = *GImGui; 2237 ImGuiWindow* window = g.CurrentWindow; 2238 2239 // Reached end of list 2240 if (DisplayEnd >= ItemsCount || window->SkipItems) 2241 { 2242 End(); 2243 return false; 2244 } 2245 2246 // Step 0: Let you process the first element (regardless of it being visible or not, so we can measure the element height) 2247 if (StepNo == 0) 2248 { 2249 StartPosY = window->DC.CursorPos.y; 2250 if (ItemsHeight <= 0.0f) 2251 { 2252 // Submit the first item so we can measure its height (generally it is 0..1) 2253 DisplayStart = 0; 2254 DisplayEnd = 1; 2255 StepNo = 1; 2256 return true; 2257 } 2258 2259 // Already has item height (given by user in Begin): skip to calculating step 2260 DisplayStart = DisplayEnd; 2261 StepNo = 2; 2262 } 2263 2264 // Step 1: the clipper infer height from first element 2265 if (StepNo == 1) 2266 { 2267 IM_ASSERT(ItemsHeight <= 0.0f); 2268 ItemsHeight = window->DC.CursorPos.y - StartPosY; 2269 IM_ASSERT(ItemsHeight > 0.0f && "Unable to calculate item height! First item hasn't moved the cursor vertically!"); 2270 StepNo = 2; 2271 } 2272 2273 // Step 2: calculate the actual range of elements to display, and position the cursor before the first element 2274 if (StepNo == 2) 2275 { 2276 IM_ASSERT(ItemsHeight > 0.0f); 2277 2278 int already_submitted = DisplayEnd; 2279 ImGui::CalcListClipping(ItemsCount - already_submitted, ItemsHeight, &DisplayStart, &DisplayEnd); 2280 DisplayStart += already_submitted; 2281 DisplayEnd += already_submitted; 2282 2283 // Seek cursor 2284 if (DisplayStart > already_submitted) 2285 SetCursorPosYAndSetupForPrevLine(StartPosY + DisplayStart * ItemsHeight, ItemsHeight); 2286 2287 StepNo = 3; 2288 return true; 2289 } 2290 2291 // Step 3: the clipper validate that we have reached the expected Y position (corresponding to element DisplayEnd), 2292 // Advance the cursor to the end of the list and then returns 'false' to end the loop. 2293 if (StepNo == 3) 2294 { 2295 // Seek cursor 2296 if (ItemsCount < INT_MAX) 2297 SetCursorPosYAndSetupForPrevLine(StartPosY + ItemsCount * ItemsHeight, ItemsHeight); // advance cursor 2298 ItemsCount = -1; 2299 return false; 2300 } 2301 2302 IM_ASSERT(0); 2303 return false; 1918 2304 } 1919 2305 1920 2306 //----------------------------------------------------------------------------- 1921 // ImGuiWindow2307 // [SECTION] STYLING 1922 2308 //----------------------------------------------------------------------------- 1923 2309 2310 ImGuiStyle& ImGui::GetStyle() 2311 { 2312 IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?"); 2313 return GImGui->Style; 2314 } 2315 2316 ImU32 ImGui::GetColorU32(ImGuiCol idx, float alpha_mul) 2317 { 2318 ImGuiStyle& style = GImGui->Style; 2319 ImVec4 c = style.Colors[idx]; 2320 c.w *= style.Alpha * alpha_mul; 2321 return ColorConvertFloat4ToU32(c); 2322 } 2323 2324 ImU32 ImGui::GetColorU32(const ImVec4& col) 2325 { 2326 ImGuiStyle& style = GImGui->Style; 2327 ImVec4 c = col; 2328 c.w *= style.Alpha; 2329 return ColorConvertFloat4ToU32(c); 2330 } 2331 2332 const ImVec4& ImGui::GetStyleColorVec4(ImGuiCol idx) 2333 { 2334 ImGuiStyle& style = GImGui->Style; 2335 return style.Colors[idx]; 2336 } 2337 2338 ImU32 ImGui::GetColorU32(ImU32 col) 2339 { 2340 ImGuiStyle& style = GImGui->Style; 2341 if (style.Alpha >= 1.0f) 2342 return col; 2343 ImU32 a = (col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT; 2344 a = (ImU32)(a * style.Alpha); // We don't need to clamp 0..255 because Style.Alpha is in 0..1 range. 2345 return (col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT); 2346 } 2347 2348 // 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 2349 void ImGui::PushStyleColor(ImGuiCol idx, ImU32 col) 2350 { 2351 ImGuiContext& g = *GImGui; 2352 ImGuiColorMod backup; 2353 backup.Col = idx; 2354 backup.BackupValue = g.Style.Colors[idx]; 2355 g.ColorModifiers.push_back(backup); 2356 g.Style.Colors[idx] = ColorConvertU32ToFloat4(col); 2357 } 2358 2359 void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col) 2360 { 2361 ImGuiContext& g = *GImGui; 2362 ImGuiColorMod backup; 2363 backup.Col = idx; 2364 backup.BackupValue = g.Style.Colors[idx]; 2365 g.ColorModifiers.push_back(backup); 2366 g.Style.Colors[idx] = col; 2367 } 2368 2369 void ImGui::PopStyleColor(int count) 2370 { 2371 ImGuiContext& g = *GImGui; 2372 while (count > 0) 2373 { 2374 ImGuiColorMod& backup = g.ColorModifiers.back(); 2375 g.Style.Colors[backup.Col] = backup.BackupValue; 2376 g.ColorModifiers.pop_back(); 2377 count--; 2378 } 2379 } 2380 2381 struct ImGuiStyleVarInfo 2382 { 2383 ImGuiDataType Type; 2384 ImU32 Count; 2385 ImU32 Offset; 2386 void* GetVarPtr(ImGuiStyle* style) const { return (void*)((unsigned char*)style + Offset); } 2387 }; 2388 2389 static const ImGuiStyleVarInfo GStyleVarInfo[] = 2390 { 2391 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, Alpha) }, // ImGuiStyleVar_Alpha 2392 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowPadding) }, // ImGuiStyleVar_WindowPadding 2393 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowRounding) }, // ImGuiStyleVar_WindowRounding 2394 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowBorderSize) }, // ImGuiStyleVar_WindowBorderSize 2395 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowMinSize) }, // ImGuiStyleVar_WindowMinSize 2396 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowTitleAlign) }, // ImGuiStyleVar_WindowTitleAlign 2397 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildRounding) }, // ImGuiStyleVar_ChildRounding 2398 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildBorderSize) }, // ImGuiStyleVar_ChildBorderSize 2399 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupRounding) }, // ImGuiStyleVar_PopupRounding 2400 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupBorderSize) }, // ImGuiStyleVar_PopupBorderSize 2401 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, FramePadding) }, // ImGuiStyleVar_FramePadding 2402 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameRounding) }, // ImGuiStyleVar_FrameRounding 2403 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameBorderSize) }, // ImGuiStyleVar_FrameBorderSize 2404 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemSpacing) }, // ImGuiStyleVar_ItemSpacing 2405 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemInnerSpacing) }, // ImGuiStyleVar_ItemInnerSpacing 2406 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, IndentSpacing) }, // ImGuiStyleVar_IndentSpacing 2407 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarSize) }, // ImGuiStyleVar_ScrollbarSize 2408 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarRounding) }, // ImGuiStyleVar_ScrollbarRounding 2409 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) }, // ImGuiStyleVar_GrabMinSize 2410 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabRounding) }, // ImGuiStyleVar_GrabRounding 2411 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, TabRounding) }, // ImGuiStyleVar_TabRounding 2412 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign 2413 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign 2414 }; 2415 2416 static const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx) 2417 { 2418 IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_COUNT); 2419 IM_ASSERT(IM_ARRAYSIZE(GStyleVarInfo) == ImGuiStyleVar_COUNT); 2420 return &GStyleVarInfo[idx]; 2421 } 2422 2423 void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) 2424 { 2425 const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); 2426 if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1) 2427 { 2428 ImGuiContext& g = *GImGui; 2429 float* pvar = (float*)var_info->GetVarPtr(&g.Style); 2430 g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); 2431 *pvar = val; 2432 return; 2433 } 2434 IM_ASSERT(0 && "Called PushStyleVar() float variant but variable is not a float!"); 2435 } 2436 2437 void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val) 2438 { 2439 const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); 2440 if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2) 2441 { 2442 ImGuiContext& g = *GImGui; 2443 ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style); 2444 g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); 2445 *pvar = val; 2446 return; 2447 } 2448 IM_ASSERT(0 && "Called PushStyleVar() ImVec2 variant but variable is not a ImVec2!"); 2449 } 2450 2451 void ImGui::PopStyleVar(int count) 2452 { 2453 ImGuiContext& g = *GImGui; 2454 while (count > 0) 2455 { 2456 // We avoid a generic memcpy(data, &backup.Backup.., GDataTypeSize[info->Type] * info->Count), the overhead in Debug is not worth it. 2457 ImGuiStyleMod& backup = g.StyleModifiers.back(); 2458 const ImGuiStyleVarInfo* info = GetStyleVarInfo(backup.VarIdx); 2459 void* data = info->GetVarPtr(&g.Style); 2460 if (info->Type == ImGuiDataType_Float && info->Count == 1) { ((float*)data)[0] = backup.BackupFloat[0]; } 2461 else if (info->Type == ImGuiDataType_Float && info->Count == 2) { ((float*)data)[0] = backup.BackupFloat[0]; ((float*)data)[1] = backup.BackupFloat[1]; } 2462 g.StyleModifiers.pop_back(); 2463 count--; 2464 } 2465 } 2466 2467 const char* ImGui::GetStyleColorName(ImGuiCol idx) 2468 { 2469 // Create switch-case from enum with regexp: ImGuiCol_{.*}, --> case ImGuiCol_\1: return "\1"; 2470 switch (idx) 2471 { 2472 case ImGuiCol_Text: return "Text"; 2473 case ImGuiCol_TextDisabled: return "TextDisabled"; 2474 case ImGuiCol_WindowBg: return "WindowBg"; 2475 case ImGuiCol_ChildBg: return "ChildBg"; 2476 case ImGuiCol_PopupBg: return "PopupBg"; 2477 case ImGuiCol_Border: return "Border"; 2478 case ImGuiCol_BorderShadow: return "BorderShadow"; 2479 case ImGuiCol_FrameBg: return "FrameBg"; 2480 case ImGuiCol_FrameBgHovered: return "FrameBgHovered"; 2481 case ImGuiCol_FrameBgActive: return "FrameBgActive"; 2482 case ImGuiCol_TitleBg: return "TitleBg"; 2483 case ImGuiCol_TitleBgActive: return "TitleBgActive"; 2484 case ImGuiCol_TitleBgCollapsed: return "TitleBgCollapsed"; 2485 case ImGuiCol_MenuBarBg: return "MenuBarBg"; 2486 case ImGuiCol_ScrollbarBg: return "ScrollbarBg"; 2487 case ImGuiCol_ScrollbarGrab: return "ScrollbarGrab"; 2488 case ImGuiCol_ScrollbarGrabHovered: return "ScrollbarGrabHovered"; 2489 case ImGuiCol_ScrollbarGrabActive: return "ScrollbarGrabActive"; 2490 case ImGuiCol_CheckMark: return "CheckMark"; 2491 case ImGuiCol_SliderGrab: return "SliderGrab"; 2492 case ImGuiCol_SliderGrabActive: return "SliderGrabActive"; 2493 case ImGuiCol_Button: return "Button"; 2494 case ImGuiCol_ButtonHovered: return "ButtonHovered"; 2495 case ImGuiCol_ButtonActive: return "ButtonActive"; 2496 case ImGuiCol_Header: return "Header"; 2497 case ImGuiCol_HeaderHovered: return "HeaderHovered"; 2498 case ImGuiCol_HeaderActive: return "HeaderActive"; 2499 case ImGuiCol_Separator: return "Separator"; 2500 case ImGuiCol_SeparatorHovered: return "SeparatorHovered"; 2501 case ImGuiCol_SeparatorActive: return "SeparatorActive"; 2502 case ImGuiCol_ResizeGrip: return "ResizeGrip"; 2503 case ImGuiCol_ResizeGripHovered: return "ResizeGripHovered"; 2504 case ImGuiCol_ResizeGripActive: return "ResizeGripActive"; 2505 case ImGuiCol_Tab: return "Tab"; 2506 case ImGuiCol_TabHovered: return "TabHovered"; 2507 case ImGuiCol_TabActive: return "TabActive"; 2508 case ImGuiCol_TabUnfocused: return "TabUnfocused"; 2509 case ImGuiCol_TabUnfocusedActive: return "TabUnfocusedActive"; 2510 case ImGuiCol_PlotLines: return "PlotLines"; 2511 case ImGuiCol_PlotLinesHovered: return "PlotLinesHovered"; 2512 case ImGuiCol_PlotHistogram: return "PlotHistogram"; 2513 case ImGuiCol_PlotHistogramHovered: return "PlotHistogramHovered"; 2514 case ImGuiCol_TextSelectedBg: return "TextSelectedBg"; 2515 case ImGuiCol_DragDropTarget: return "DragDropTarget"; 2516 case ImGuiCol_NavHighlight: return "NavHighlight"; 2517 case ImGuiCol_NavWindowingHighlight: return "NavWindowingHighlight"; 2518 case ImGuiCol_NavWindowingDimBg: return "NavWindowingDimBg"; 2519 case ImGuiCol_ModalWindowDimBg: return "ModalWindowDimBg"; 2520 } 2521 IM_ASSERT(0); 2522 return "Unknown"; 2523 } 2524 2525 2526 //----------------------------------------------------------------------------- 2527 // [SECTION] RENDER HELPERS 2528 // Some of those (internal) functions are currently quite a legacy mess - their signature and behavior will change, 2529 // we need a nicer separation between low-level functions and high-level functions relying on the ImGui context. 2530 // Also see imgui_draw.cpp for some more which have been reworked to not rely on ImGui:: context. 2531 //----------------------------------------------------------------------------- 2532 2533 const char* ImGui::FindRenderedTextEnd(const char* text, const char* text_end) 2534 { 2535 const char* text_display_end = text; 2536 if (!text_end) 2537 text_end = (const char*)-1; 2538 2539 while (text_display_end < text_end && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#')) 2540 text_display_end++; 2541 return text_display_end; 2542 } 2543 2544 // Internal ImGui functions to render text 2545 // RenderText***() functions calls ImDrawList::AddText() calls ImBitmapFont::RenderText() 2546 void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool hide_text_after_hash) 2547 { 2548 ImGuiContext& g = *GImGui; 2549 ImGuiWindow* window = g.CurrentWindow; 2550 2551 // Hide anything after a '##' string 2552 const char* text_display_end; 2553 if (hide_text_after_hash) 2554 { 2555 text_display_end = FindRenderedTextEnd(text, text_end); 2556 } 2557 else 2558 { 2559 if (!text_end) 2560 text_end = text + strlen(text); // FIXME-OPT 2561 text_display_end = text_end; 2562 } 2563 2564 if (text != text_display_end) 2565 { 2566 window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end); 2567 if (g.LogEnabled) 2568 LogRenderedText(&pos, text, text_display_end); 2569 } 2570 } 2571 2572 void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width) 2573 { 2574 ImGuiContext& g = *GImGui; 2575 ImGuiWindow* window = g.CurrentWindow; 2576 2577 if (!text_end) 2578 text_end = text + strlen(text); // FIXME-OPT 2579 2580 if (text != text_end) 2581 { 2582 window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_end, wrap_width); 2583 if (g.LogEnabled) 2584 LogRenderedText(&pos, text, text_end); 2585 } 2586 } 2587 2588 // Default clip_rect uses (pos_min,pos_max) 2589 // Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges) 2590 void 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) 2591 { 2592 // Perform CPU side clipping for single clipped element to avoid using scissor state 2593 ImVec2 pos = pos_min; 2594 const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_display_end, false, 0.0f); 2595 2596 const ImVec2* clip_min = clip_rect ? &clip_rect->Min : &pos_min; 2597 const ImVec2* clip_max = clip_rect ? &clip_rect->Max : &pos_max; 2598 bool need_clipping = (pos.x + text_size.x >= clip_max->x) || (pos.y + text_size.y >= clip_max->y); 2599 if (clip_rect) // If we had no explicit clipping rectangle then pos==clip_min 2600 need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y); 2601 2602 // Align whole block. We should defer that to the better rendering function when we'll have support for individual line alignment. 2603 if (align.x > 0.0f) pos.x = ImMax(pos.x, pos.x + (pos_max.x - pos.x - text_size.x) * align.x); 2604 if (align.y > 0.0f) pos.y = ImMax(pos.y, pos.y + (pos_max.y - pos.y - text_size.y) * align.y); 2605 2606 // Render 2607 if (need_clipping) 2608 { 2609 ImVec4 fine_clip_rect(clip_min->x, clip_min->y, clip_max->x, clip_max->y); 2610 draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, &fine_clip_rect); 2611 } 2612 else 2613 { 2614 draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL); 2615 } 2616 } 2617 2618 void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect) 2619 { 2620 // Hide anything after a '##' string 2621 const char* text_display_end = FindRenderedTextEnd(text, text_end); 2622 const int text_len = (int)(text_display_end - text); 2623 if (text_len == 0) 2624 return; 2625 2626 ImGuiContext& g = *GImGui; 2627 ImGuiWindow* window = g.CurrentWindow; 2628 RenderTextClippedEx(window->DrawList, pos_min, pos_max, text, text_display_end, text_size_if_known, align, clip_rect); 2629 if (g.LogEnabled) 2630 LogRenderedText(&pos_min, text, text_display_end); 2631 } 2632 2633 2634 // Another overly complex function until we reorganize everything into a nice all-in-one helper. 2635 // This is made more complex because we have dissociated the layout rectangle (pos_min..pos_max) which define _where_ the ellipsis is, from actual clipping of text and limit of the ellipsis display. 2636 // This is because in the context of tabs we selectively hide part of the text when the Close Button appears, but we don't want the ellipsis to move. 2637 void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end_full, const ImVec2* text_size_if_known) 2638 { 2639 ImGuiContext& g = *GImGui; 2640 if (text_end_full == NULL) 2641 text_end_full = FindRenderedTextEnd(text); 2642 const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_end_full, false, 0.0f); 2643 2644 //draw_list->AddLine(ImVec2(pos_max.x, pos_min.y - 4), ImVec2(pos_max.x, pos_max.y + 4), IM_COL32(0, 0, 255, 255)); 2645 //draw_list->AddLine(ImVec2(ellipsis_max_x, pos_min.y-2), ImVec2(ellipsis_max_x, pos_max.y+2), IM_COL32(0, 255, 0, 255)); 2646 //draw_list->AddLine(ImVec2(clip_max_x, pos_min.y), ImVec2(clip_max_x, pos_max.y), IM_COL32(255, 0, 0, 255)); 2647 // FIXME: We could technically remove (last_glyph->AdvanceX - last_glyph->X1) from text_size.x here and save a few pixels. 2648 if (text_size.x > pos_max.x - pos_min.x) 2649 { 2650 // Hello wo... 2651 // | | | 2652 // min max ellipsis_max 2653 // <-> this is generally some padding value 2654 2655 const ImFont* font = draw_list->_Data->Font; 2656 const float font_size = draw_list->_Data->FontSize; 2657 const char* text_end_ellipsis = NULL; 2658 2659 ImWchar ellipsis_char = font->EllipsisChar; 2660 int ellipsis_char_count = 1; 2661 if (ellipsis_char == (ImWchar)-1) 2662 { 2663 ellipsis_char = (ImWchar)'.'; 2664 ellipsis_char_count = 3; 2665 } 2666 const ImFontGlyph* glyph = font->FindGlyph(ellipsis_char); 2667 2668 float ellipsis_glyph_width = glyph->X1; // Width of the glyph with no padding on either side 2669 float ellipsis_total_width = ellipsis_glyph_width; // Full width of entire ellipsis 2670 2671 if (ellipsis_char_count > 1) 2672 { 2673 // Full ellipsis size without free spacing after it. 2674 const float spacing_between_dots = 1.0f * (draw_list->_Data->FontSize / font->FontSize); 2675 ellipsis_glyph_width = glyph->X1 - glyph->X0 + spacing_between_dots; 2676 ellipsis_total_width = ellipsis_glyph_width * (float)ellipsis_char_count - spacing_between_dots; 2677 } 2678 2679 // We can now claim the space between pos_max.x and ellipsis_max.x 2680 const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_total_width) - pos_min.x, 1.0f); 2681 float text_size_clipped_x = font->CalcTextSizeA(font_size, text_avail_width, 0.0f, text, text_end_full, &text_end_ellipsis).x; 2682 if (text == text_end_ellipsis && text_end_ellipsis < text_end_full) 2683 { 2684 // Always display at least 1 character if there's no room for character + ellipsis 2685 text_end_ellipsis = text + ImTextCountUtf8BytesFromChar(text, text_end_full); 2686 text_size_clipped_x = font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text, text_end_ellipsis).x; 2687 } 2688 while (text_end_ellipsis > text && ImCharIsBlankA(text_end_ellipsis[-1])) 2689 { 2690 // Trim trailing space before ellipsis (FIXME: Supporting non-ascii blanks would be nice, for this we need a function to backtrack in UTF-8 text) 2691 text_end_ellipsis--; 2692 text_size_clipped_x -= font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text_end_ellipsis, text_end_ellipsis + 1).x; // Ascii blanks are always 1 byte 2693 } 2694 2695 // Render text, render ellipsis 2696 RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f)); 2697 float ellipsis_x = pos_min.x + text_size_clipped_x; 2698 if (ellipsis_x + ellipsis_total_width <= ellipsis_max_x) 2699 for (int i = 0; i < ellipsis_char_count; i++) 2700 { 2701 font->RenderChar(draw_list, font_size, ImVec2(ellipsis_x, pos_min.y), GetColorU32(ImGuiCol_Text), ellipsis_char); 2702 ellipsis_x += ellipsis_glyph_width; 2703 } 2704 } 2705 else 2706 { 2707 RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_full, &text_size, ImVec2(0.0f, 0.0f)); 2708 } 2709 2710 if (g.LogEnabled) 2711 LogRenderedText(&pos_min, text, text_end_full); 2712 } 2713 2714 // Render a rectangle shaped with optional rounding and borders 2715 void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, float rounding) 2716 { 2717 ImGuiContext& g = *GImGui; 2718 ImGuiWindow* window = g.CurrentWindow; 2719 window->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding); 2720 const float border_size = g.Style.FrameBorderSize; 2721 if (border && border_size > 0.0f) 2722 { 2723 window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size); 2724 window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size); 2725 } 2726 } 2727 2728 void ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding) 2729 { 2730 ImGuiContext& g = *GImGui; 2731 ImGuiWindow* window = g.CurrentWindow; 2732 const float border_size = g.Style.FrameBorderSize; 2733 if (border_size > 0.0f) 2734 { 2735 window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size); 2736 window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size); 2737 } 2738 } 2739 2740 void ImGui::RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags) 2741 { 2742 ImGuiContext& g = *GImGui; 2743 if (id != g.NavId) 2744 return; 2745 if (g.NavDisableHighlight && !(flags & ImGuiNavHighlightFlags_AlwaysDraw)) 2746 return; 2747 ImGuiWindow* window = g.CurrentWindow; 2748 if (window->DC.NavHideHighlightOneFrame) 2749 return; 2750 2751 float rounding = (flags & ImGuiNavHighlightFlags_NoRounding) ? 0.0f : g.Style.FrameRounding; 2752 ImRect display_rect = bb; 2753 display_rect.ClipWith(window->ClipRect); 2754 if (flags & ImGuiNavHighlightFlags_TypeDefault) 2755 { 2756 const float THICKNESS = 2.0f; 2757 const float DISTANCE = 3.0f + THICKNESS * 0.5f; 2758 display_rect.Expand(ImVec2(DISTANCE, DISTANCE)); 2759 bool fully_visible = window->ClipRect.Contains(display_rect); 2760 if (!fully_visible) 2761 window->DrawList->PushClipRect(display_rect.Min, display_rect.Max); 2762 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); 2763 if (!fully_visible) 2764 window->DrawList->PopClipRect(); 2765 } 2766 if (flags & ImGuiNavHighlightFlags_TypeThin) 2767 { 2768 window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavHighlight), rounding, ~0, 1.0f); 2769 } 2770 } 2771 2772 //----------------------------------------------------------------------------- 2773 // [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!) 2774 //----------------------------------------------------------------------------- 2775 2776 // ImGuiWindow is mostly a dumb struct. It merely has a constructor and a few helper methods 1924 2777 ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name) 1925 : DrawListInst(&context->DrawListSharedData) 1926 { 1927 Name = ImStrdup(name); 1928 ID = ImHash(name, 0); 1929 IDStack.push_back(ID); 1930 Flags = 0; 1931 Pos = ImVec2(0.0f, 0.0f); 1932 Size = SizeFull = ImVec2(0.0f, 0.0f); 1933 SizeContents = SizeContentsExplicit = ImVec2(0.0f, 0.0f); 1934 WindowPadding = ImVec2(0.0f, 0.0f); 1935 WindowRounding = 0.0f; 1936 WindowBorderSize = 0.0f; 1937 MoveId = GetID("#MOVE"); 1938 ChildId = 0; 1939 Scroll = ImVec2(0.0f, 0.0f); 1940 ScrollTarget = ImVec2(FLT_MAX, FLT_MAX); 1941 ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f); 1942 ScrollbarSizes = ImVec2(0.0f, 0.0f); 1943 ScrollbarX = ScrollbarY = false; 1944 Active = WasActive = false; 1945 WriteAccessed = false; 1946 Collapsed = false; 1947 CollapseToggleWanted = false; 1948 SkipItems = false; 1949 Appearing = false; 1950 CloseButton = false; 1951 BeginOrderWithinParent = -1; 1952 BeginOrderWithinContext = -1; 1953 BeginCount = 0; 1954 PopupId = 0; 1955 AutoFitFramesX = AutoFitFramesY = -1; 1956 AutoFitOnlyGrows = false; 1957 AutoFitChildAxises = 0x00; 1958 AutoPosLastDirection = ImGuiDir_None; 1959 HiddenFrames = 0; 1960 SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing; 1961 SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX); 1962 1963 LastFrameActive = -1; 1964 ItemWidthDefault = 0.0f; 1965 FontWindowScale = 1.0f; 1966 1967 DrawList = &DrawListInst; 1968 DrawList->_OwnerName = Name; 1969 ParentWindow = NULL; 1970 RootWindow = NULL; 1971 RootWindowForTitleBarHighlight = NULL; 1972 RootWindowForTabbing = NULL; 1973 RootWindowForNav = NULL; 1974 1975 NavLastIds[0] = NavLastIds[1] = 0; 1976 NavRectRel[0] = NavRectRel[1] = ImRect(); 1977 NavLastChildNavWindow = NULL; 1978 1979 FocusIdxAllCounter = FocusIdxTabCounter = -1; 1980 FocusIdxAllRequestCurrent = FocusIdxTabRequestCurrent = INT_MAX; 1981 FocusIdxAllRequestNext = FocusIdxTabRequestNext = INT_MAX; 2778 : DrawListInst(&context->DrawListSharedData) 2779 { 2780 Name = ImStrdup(name); 2781 ID = ImHashStr(name); 2782 IDStack.push_back(ID); 2783 Flags = ImGuiWindowFlags_None; 2784 Pos = ImVec2(0.0f, 0.0f); 2785 Size = SizeFull = ImVec2(0.0f, 0.0f); 2786 ContentSize = ContentSizeExplicit = ImVec2(0.0f, 0.0f); 2787 WindowPadding = ImVec2(0.0f, 0.0f); 2788 WindowRounding = 0.0f; 2789 WindowBorderSize = 0.0f; 2790 NameBufLen = (int)strlen(name) + 1; 2791 MoveId = GetID("#MOVE"); 2792 ChildId = 0; 2793 Scroll = ImVec2(0.0f, 0.0f); 2794 ScrollTarget = ImVec2(FLT_MAX, FLT_MAX); 2795 ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f); 2796 ScrollbarSizes = ImVec2(0.0f, 0.0f); 2797 ScrollbarX = ScrollbarY = false; 2798 Active = WasActive = false; 2799 WriteAccessed = false; 2800 Collapsed = false; 2801 WantCollapseToggle = false; 2802 SkipItems = false; 2803 Appearing = false; 2804 Hidden = false; 2805 IsFallbackWindow = false; 2806 HasCloseButton = false; 2807 ResizeBorderHeld = -1; 2808 BeginCount = 0; 2809 BeginOrderWithinParent = -1; 2810 BeginOrderWithinContext = -1; 2811 PopupId = 0; 2812 AutoFitFramesX = AutoFitFramesY = -1; 2813 AutoFitChildAxises = 0x00; 2814 AutoFitOnlyGrows = false; 2815 AutoPosLastDirection = ImGuiDir_None; 2816 HiddenFramesCanSkipItems = HiddenFramesCannotSkipItems = 0; 2817 SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing; 2818 SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX); 2819 2820 InnerRect = ImRect(0.0f, 0.0f, 0.0f, 0.0f); // Clear so the InnerRect.GetSize() code in Begin() doesn't lead to overflow even if the result isn't used. 2821 2822 LastFrameActive = -1; 2823 LastTimeActive = -1.0f; 2824 ItemWidthDefault = 0.0f; 2825 FontWindowScale = 1.0f; 2826 SettingsOffset = -1; 2827 2828 DrawList = &DrawListInst; 2829 DrawList->_OwnerName = Name; 2830 ParentWindow = NULL; 2831 RootWindow = NULL; 2832 RootWindowForTitleBarHighlight = NULL; 2833 RootWindowForNav = NULL; 2834 2835 NavLastIds[0] = NavLastIds[1] = 0; 2836 NavRectRel[0] = NavRectRel[1] = ImRect(); 2837 NavLastChildNavWindow = NULL; 2838 2839 MemoryCompacted = false; 2840 MemoryDrawListIdxCapacity = MemoryDrawListVtxCapacity = 0; 1982 2841 } 1983 2842 1984 2843 ImGuiWindow::~ImGuiWindow() 1985 2844 { 1986 IM_ASSERT(DrawList == &DrawListInst);1987 IM_DELETE(Name);1988 for (int i = 0; i != ColumnsStorage.Size; i++)1989 ColumnsStorage[i].~ImGuiColumnsSet();2845 IM_ASSERT(DrawList == &DrawListInst); 2846 IM_DELETE(Name); 2847 for (int i = 0; i != ColumnsStorage.Size; i++) 2848 ColumnsStorage[i].~ImGuiColumns(); 1990 2849 } 1991 2850 1992 2851 ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end) 1993 2852 { 1994 ImGuiID seed = IDStack.back(); 1995 ImGuiID id = ImHash(str, str_end ? (int)(str_end - str) : 0, seed); 1996 ImGui::KeepAliveID(id); 1997 return id; 2853 ImGuiID seed = IDStack.back(); 2854 ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed); 2855 ImGui::KeepAliveID(id); 2856 #ifdef IMGUI_ENABLE_TEST_ENGINE 2857 ImGuiContext& g = *GImGui; 2858 IMGUI_TEST_ENGINE_ID_INFO2(id, ImGuiDataType_String, str, str_end); 2859 #endif 2860 return id; 1998 2861 } 1999 2862 2000 2863 ImGuiID ImGuiWindow::GetID(const void* ptr) 2001 2864 { 2002 ImGuiID seed = IDStack.back(); 2003 ImGuiID id = ImHash(&ptr, sizeof(void*), seed); 2004 ImGui::KeepAliveID(id); 2005 return id; 2865 ImGuiID seed = IDStack.back(); 2866 ImGuiID id = ImHashData(&ptr, sizeof(void*), seed); 2867 ImGui::KeepAliveID(id); 2868 #ifdef IMGUI_ENABLE_TEST_ENGINE 2869 ImGuiContext& g = *GImGui; 2870 IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_Pointer, ptr); 2871 #endif 2872 return id; 2873 } 2874 2875 ImGuiID ImGuiWindow::GetID(int n) 2876 { 2877 ImGuiID seed = IDStack.back(); 2878 ImGuiID id = ImHashData(&n, sizeof(n), seed); 2879 ImGui::KeepAliveID(id); 2880 #ifdef IMGUI_ENABLE_TEST_ENGINE 2881 ImGuiContext& g = *GImGui; 2882 IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_S32, (intptr_t)n); 2883 #endif 2884 return id; 2006 2885 } 2007 2886 2008 2887 ImGuiID ImGuiWindow::GetIDNoKeepAlive(const char* str, const char* str_end) 2009 2888 { 2010 ImGuiID seed = IDStack.back(); 2011 return ImHash(str, str_end ? (int)(str_end - str) : 0, seed); 2889 ImGuiID seed = IDStack.back(); 2890 ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed); 2891 #ifdef IMGUI_ENABLE_TEST_ENGINE 2892 ImGuiContext& g = *GImGui; 2893 IMGUI_TEST_ENGINE_ID_INFO2(id, ImGuiDataType_String, str, str_end); 2894 #endif 2895 return id; 2896 } 2897 2898 ImGuiID ImGuiWindow::GetIDNoKeepAlive(const void* ptr) 2899 { 2900 ImGuiID seed = IDStack.back(); 2901 ImGuiID id = ImHashData(&ptr, sizeof(void*), seed); 2902 #ifdef IMGUI_ENABLE_TEST_ENGINE 2903 ImGuiContext& g = *GImGui; 2904 IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_Pointer, ptr); 2905 #endif 2906 return id; 2907 } 2908 2909 ImGuiID ImGuiWindow::GetIDNoKeepAlive(int n) 2910 { 2911 ImGuiID seed = IDStack.back(); 2912 ImGuiID id = ImHashData(&n, sizeof(n), seed); 2913 #ifdef IMGUI_ENABLE_TEST_ENGINE 2914 ImGuiContext& g = *GImGui; 2915 IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_S32, (intptr_t)n); 2916 #endif 2917 return id; 2012 2918 } 2013 2919 … … 2015 2921 ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs) 2016 2922 { 2017 ImGuiID seed = IDStack.back(); 2018 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) }; 2019 ImGuiID id = ImHash(&r_rel, sizeof(r_rel), seed); 2020 ImGui::KeepAliveID(id); 2021 return id; 2022 } 2023 2024 //----------------------------------------------------------------------------- 2025 // Internal API exposed in imgui_internal.h 2026 //----------------------------------------------------------------------------- 2923 ImGuiID seed = IDStack.back(); 2924 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) }; 2925 ImGuiID id = ImHashData(&r_rel, sizeof(r_rel), seed); 2926 ImGui::KeepAliveID(id); 2927 return id; 2928 } 2027 2929 2028 2930 static void SetCurrentWindow(ImGuiWindow* window) 2029 2931 { 2030 ImGuiContext& g = *GImGui; 2031 g.CurrentWindow = window; 2032 if (window) 2033 g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize(); 2034 } 2035 2036 static void SetNavID(ImGuiID id, int nav_layer) 2037 { 2038 ImGuiContext& g = *GImGui; 2039 IM_ASSERT(g.NavWindow); 2040 IM_ASSERT(nav_layer == 0 || nav_layer == 1); 2041 g.NavId = id; 2042 g.NavWindow->NavLastIds[nav_layer] = id; 2043 } 2044 2045 static void SetNavIDWithRectRel(ImGuiID id, int nav_layer, const ImRect& rect_rel) 2046 { 2047 ImGuiContext& g = *GImGui; 2048 SetNavID(id, nav_layer); 2049 g.NavWindow->NavRectRel[nav_layer] = rect_rel; 2050 g.NavMousePosDirty = true; 2051 g.NavDisableHighlight = false; 2052 g.NavDisableMouseHover = true; 2932 ImGuiContext& g = *GImGui; 2933 g.CurrentWindow = window; 2934 if (window) 2935 g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize(); 2936 } 2937 2938 // Free up/compact internal window buffers, we can use this when a window becomes unused. 2939 // This is currently unused by the library, but you may call this yourself for easy GC. 2940 // Not freed: 2941 // - ImGuiWindow, ImGuiWindowSettings, Name 2942 // - StateStorage, ColumnsStorage (may hold useful data) 2943 // This should have no noticeable visual effect. When the window reappear however, expect new allocation/buffer growth/copy cost. 2944 void ImGui::GcCompactTransientWindowBuffers(ImGuiWindow* window) 2945 { 2946 window->MemoryCompacted = true; 2947 window->MemoryDrawListIdxCapacity = window->DrawList->IdxBuffer.Capacity; 2948 window->MemoryDrawListVtxCapacity = window->DrawList->VtxBuffer.Capacity; 2949 window->IDStack.clear(); 2950 window->DrawList->_ClearFreeMemory(); 2951 window->DC.ChildWindows.clear(); 2952 window->DC.ItemFlagsStack.clear(); 2953 window->DC.ItemWidthStack.clear(); 2954 window->DC.TextWrapPosStack.clear(); 2955 window->DC.GroupStack.clear(); 2956 } 2957 2958 void ImGui::GcAwakeTransientWindowBuffers(ImGuiWindow* window) 2959 { 2960 // We stored capacity of the ImDrawList buffer to reduce growth-caused allocation/copy when awakening. 2961 // The other buffers tends to amortize much faster. 2962 window->MemoryCompacted = false; 2963 window->DrawList->IdxBuffer.reserve(window->MemoryDrawListIdxCapacity); 2964 window->DrawList->VtxBuffer.reserve(window->MemoryDrawListVtxCapacity); 2965 window->MemoryDrawListIdxCapacity = window->MemoryDrawListVtxCapacity = 0; 2053 2966 } 2054 2967 2055 2968 void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window) 2056 2969 { 2057 ImGuiContext& g = *GImGui; 2058 g.ActiveIdIsJustActivated = (g.ActiveId != id); 2059 if (g.ActiveIdIsJustActivated) 2060 g.ActiveIdTimer = 0.0f; 2061 g.ActiveId = id; 2062 g.ActiveIdAllowNavDirFlags = 0; 2063 g.ActiveIdAllowOverlap = false; 2064 g.ActiveIdWindow = window; 2065 if (id) 2066 { 2067 g.ActiveIdIsAlive = true; 2068 g.ActiveIdSource = (g.NavActivateId == id || g.NavInputId == id || g.NavJustTabbedId == id || g.NavJustMovedToId == id) ? ImGuiInputSource_Nav : ImGuiInputSource_Mouse; 2069 } 2070 } 2071 2072 ImGuiID ImGui::GetActiveID() 2073 { 2074 ImGuiContext& g = *GImGui; 2075 return g.ActiveId; 2076 } 2077 2078 void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window) 2079 { 2080 ImGuiContext& g = *GImGui; 2081 IM_ASSERT(id != 0); 2082 2083 // Assume that SetFocusID() is called in the context where its NavLayer is the current layer, which is the case everywhere we call it. 2084 const int nav_layer = window->DC.NavLayerCurrent; 2085 if (g.NavWindow != window) 2086 g.NavInitRequest = false; 2087 g.NavId = id; 2088 g.NavWindow = window; 2089 g.NavLayer = nav_layer; 2090 window->NavLastIds[nav_layer] = id; 2091 if (window->DC.LastItemId == id) 2092 window->NavRectRel[nav_layer] = ImRect(window->DC.LastItemRect.Min - window->Pos, window->DC.LastItemRect.Max - window->Pos); 2093 2094 if (g.ActiveIdSource == ImGuiInputSource_Nav) 2095 g.NavDisableMouseHover = true; 2096 else 2097 g.NavDisableHighlight = true; 2970 ImGuiContext& g = *GImGui; 2971 g.ActiveIdIsJustActivated = (g.ActiveId != id); 2972 if (g.ActiveIdIsJustActivated) 2973 { 2974 g.ActiveIdTimer = 0.0f; 2975 g.ActiveIdHasBeenPressedBefore = false; 2976 g.ActiveIdHasBeenEditedBefore = false; 2977 if (id != 0) 2978 { 2979 g.LastActiveId = id; 2980 g.LastActiveIdTimer = 0.0f; 2981 } 2982 } 2983 g.ActiveId = id; 2984 g.ActiveIdAllowOverlap = false; 2985 g.ActiveIdNoClearOnFocusLoss = false; 2986 g.ActiveIdWindow = window; 2987 g.ActiveIdHasBeenEditedThisFrame = false; 2988 if (id) 2989 { 2990 g.ActiveIdIsAlive = id; 2991 g.ActiveIdSource = (g.NavActivateId == id || g.NavInputId == id || g.NavJustTabbedId == id || g.NavJustMovedToId == id) ? ImGuiInputSource_Nav : ImGuiInputSource_Mouse; 2992 } 2993 2994 // Clear declaration of inputs claimed by the widget 2995 // (Please note that this is WIP and not all keys/inputs are thoroughly declared by all widgets yet) 2996 g.ActiveIdUsingNavDirMask = 0x00; 2997 g.ActiveIdUsingNavInputMask = 0x00; 2998 g.ActiveIdUsingKeyInputMask = 0x00; 2098 2999 } 2099 3000 2100 3001 void ImGui::ClearActiveID() 2101 3002 { 2102 SetActiveID(0, NULL);3003 SetActiveID(0, NULL); // g.ActiveId = 0; 2103 3004 } 2104 3005 2105 3006 void ImGui::SetHoveredID(ImGuiID id) 2106 3007 { 2107 ImGuiContext& g = *GImGui; 2108 g.HoveredId = id; 2109 g.HoveredIdAllowOverlap = false; 2110 g.HoveredIdTimer = (id != 0 && g.HoveredIdPreviousFrame == id) ? (g.HoveredIdTimer + g.IO.DeltaTime) : 0.0f; 3008 ImGuiContext& g = *GImGui; 3009 g.HoveredId = id; 3010 g.HoveredIdAllowOverlap = false; 3011 if (id != 0 && g.HoveredIdPreviousFrame != id) 3012 g.HoveredIdTimer = g.HoveredIdNotActiveTimer = 0.0f; 2111 3013 } 2112 3014 2113 3015 ImGuiID ImGui::GetHoveredID() 2114 3016 { 2115 ImGuiContext& g = *GImGui;2116 return g.HoveredId ? g.HoveredId : g.HoveredIdPreviousFrame;3017 ImGuiContext& g = *GImGui; 3018 return g.HoveredId ? g.HoveredId : g.HoveredIdPreviousFrame; 2117 3019 } 2118 3020 2119 3021 void ImGui::KeepAliveID(ImGuiID id) 2120 3022 { 2121 ImGuiContext& g = *GImGui; 2122 if (g.ActiveId == id) 2123 g.ActiveIdIsAlive = true; 3023 ImGuiContext& g = *GImGui; 3024 if (g.ActiveId == id) 3025 g.ActiveIdIsAlive = id; 3026 if (g.ActiveIdPreviousFrame == id) 3027 g.ActiveIdPreviousFrameIsAlive = true; 3028 } 3029 3030 void ImGui::MarkItemEdited(ImGuiID id) 3031 { 3032 // This marking is solely to be able to provide info for IsItemDeactivatedAfterEdit(). 3033 // 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. 3034 ImGuiContext& g = *GImGui; 3035 IM_ASSERT(g.ActiveId == id || g.ActiveId == 0 || g.DragDropActive); 3036 IM_UNUSED(id); // Avoid unused variable warnings when asserts are compiled out. 3037 //IM_ASSERT(g.CurrentWindow->DC.LastItemId == id); 3038 g.ActiveIdHasBeenEditedThisFrame = true; 3039 g.ActiveIdHasBeenEditedBefore = true; 3040 g.CurrentWindow->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited; 2124 3041 } 2125 3042 2126 3043 static inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags) 2127 3044 { 2128 // An active popup disable hovering on other windows (apart from its own children) 2129 // FIXME-OPT: This could be cached/stored within the window. 2130 ImGuiContext& g = *GImGui; 2131 if (g.NavWindow) 2132 if (ImGuiWindow* focused_root_window = g.NavWindow->RootWindow) 2133 if (focused_root_window->WasActive && focused_root_window != window->RootWindow) 2134 { 2135 // For the purpose of those flags we differentiate "standard popup" from "modal popup" 2136 // NB: The order of those two tests is important because Modal windows are also Popups. 2137 if (focused_root_window->Flags & ImGuiWindowFlags_Modal) 2138 return false; 2139 if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiHoveredFlags_AllowWhenBlockedByPopup)) 2140 return false; 2141 } 2142 2143 return true; 2144 } 2145 2146 // Advance cursor given item size for layout. 2147 void ImGui::ItemSize(const ImVec2& size, float text_offset_y) 2148 { 2149 ImGuiContext& g = *GImGui; 2150 ImGuiWindow* window = g.CurrentWindow; 2151 if (window->SkipItems) 2152 return; 2153 2154 // Always align ourselves on pixel boundaries 2155 const float line_height = ImMax(window->DC.CurrentLineHeight, size.y); 2156 const float text_base_offset = ImMax(window->DC.CurrentLineTextBaseOffset, text_offset_y); 2157 //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] 2158 window->DC.CursorPosPrevLine = ImVec2(window->DC.CursorPos.x + size.x, window->DC.CursorPos.y); 2159 window->DC.CursorPos = ImVec2((float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX), (float)(int)(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y)); 2160 window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x); 2161 window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y); 2162 //if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG] 2163 2164 window->DC.PrevLineHeight = line_height; 2165 window->DC.PrevLineTextBaseOffset = text_base_offset; 2166 window->DC.CurrentLineHeight = window->DC.CurrentLineTextBaseOffset = 0.0f; 2167 2168 // Horizontal layout mode 2169 if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) 2170 SameLine(); 2171 } 2172 2173 void ImGui::ItemSize(const ImRect& bb, float text_offset_y) 2174 { 2175 ItemSize(bb.GetSize(), text_offset_y); 2176 } 2177 2178 static ImGuiDir NavScoreItemGetQuadrant(float dx, float dy) 2179 { 2180 if (fabsf(dx) > fabsf(dy)) 2181 return (dx > 0.0f) ? ImGuiDir_Right : ImGuiDir_Left; 2182 return (dy > 0.0f) ? ImGuiDir_Down : ImGuiDir_Up; 2183 } 2184 2185 static float NavScoreItemDistInterval(float a0, float a1, float b0, float b1) 2186 { 2187 if (a1 < b0) 2188 return a1 - b0; 2189 if (b1 < a0) 2190 return a0 - b1; 2191 return 0.0f; 2192 } 2193 2194 // Scoring function for directional navigation. Based on https://gist.github.com/rygorous/6981057 2195 static bool NavScoreItem(ImGuiNavMoveResult* result, ImRect cand) 2196 { 2197 ImGuiContext& g = *GImGui; 2198 ImGuiWindow* window = g.CurrentWindow; 2199 if (g.NavLayer != window->DC.NavLayerCurrent) 2200 return false; 2201 2202 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) 2203 g.NavScoringCount++; 2204 2205 // We perform scoring on items bounding box clipped by their parent window on the other axis (clipping on our movement axis would give us equal scores for all clipped items) 2206 if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) 2207 { 2208 cand.Min.y = ImClamp(cand.Min.y, window->ClipRect.Min.y, window->ClipRect.Max.y); 2209 cand.Max.y = ImClamp(cand.Max.y, window->ClipRect.Min.y, window->ClipRect.Max.y); 2210 } 2211 else 2212 { 2213 cand.Min.x = ImClamp(cand.Min.x, window->ClipRect.Min.x, window->ClipRect.Max.x); 2214 cand.Max.x = ImClamp(cand.Max.x, window->ClipRect.Min.x, window->ClipRect.Max.x); 2215 } 2216 2217 // Compute distance between boxes 2218 // FIXME-NAV: Introducing biases for vertical navigation, needs to be removed. 2219 float dbx = NavScoreItemDistInterval(cand.Min.x, cand.Max.x, curr.Min.x, curr.Max.x); 2220 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 2221 if (dby != 0.0f && dbx != 0.0f) 2222 dbx = (dbx / 1000.0f) + ((dbx > 0.0f) ? +1.0f : -1.0f); 2223 float dist_box = fabsf(dbx) + fabsf(dby); 2224 2225 // 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) 2226 float dcx = (cand.Min.x + cand.Max.x) - (curr.Min.x + curr.Max.x); 2227 float dcy = (cand.Min.y + cand.Max.y) - (curr.Min.y + curr.Max.y); 2228 float dist_center = fabsf(dcx) + fabsf(dcy); // L1 metric (need this for our connectedness guarantee) 2229 2230 // Determine which quadrant of 'curr' our candidate item 'cand' lies in based on distance 2231 ImGuiDir quadrant; 2232 float dax = 0.0f, day = 0.0f, dist_axial = 0.0f; 2233 if (dbx != 0.0f || dby != 0.0f) 2234 { 2235 // For non-overlapping boxes, use distance between boxes 2236 dax = dbx; 2237 day = dby; 2238 dist_axial = dist_box; 2239 quadrant = NavScoreItemGetQuadrant(dbx, dby); 2240 } 2241 else if (dcx != 0.0f || dcy != 0.0f) 2242 { 2243 // For overlapping boxes with different centers, use distance between centers 2244 dax = dcx; 2245 day = dcy; 2246 dist_axial = dist_center; 2247 quadrant = NavScoreItemGetQuadrant(dcx, dcy); 2248 } 2249 else 2250 { 2251 // 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) 2252 quadrant = (window->DC.LastItemId < g.NavId) ? ImGuiDir_Left : ImGuiDir_Right; 2253 } 2254 2255 #if IMGUI_DEBUG_NAV_SCORING 2256 char buf[128]; 2257 if (ImGui::IsMouseHoveringRect(cand.Min, cand.Max)) 2258 { 2259 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]); 2260 ImDrawList* draw_list = ImGui::GetOverlayDrawList(); 2261 draw_list->AddRect(curr.Min, curr.Max, IM_COL32(255, 200, 0, 100)); 2262 draw_list->AddRect(cand.Min, cand.Max, IM_COL32(255, 255, 0, 200)); 2263 draw_list->AddRectFilled(cand.Max - ImVec2(4, 4), cand.Max + ImGui::CalcTextSize(buf) + ImVec2(4, 4), IM_COL32(40, 0, 0, 150)); 2264 draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Max, ~0U, buf); 2265 } 2266 else if (g.IO.KeyCtrl) // Hold to preview score in matching quadrant. Press C to rotate. 2267 { 2268 if (IsKeyPressedMap(ImGuiKey_C)) { g.NavMoveDirLast = (ImGuiDir)((g.NavMoveDirLast + 1) & 3); g.IO.KeysDownDuration[g.IO.KeyMap[ImGuiKey_C]] = 0.01f; } 2269 if (quadrant == g.NavMoveDir) 2270 { 2271 ImFormatString(buf, IM_ARRAYSIZE(buf), "%.0f/%.0f", dist_box, dist_center); 2272 ImDrawList* draw_list = ImGui::GetOverlayDrawList(); 2273 draw_list->AddRectFilled(cand.Min, cand.Max, IM_COL32(255, 0, 0, 200)); 2274 draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Min, IM_COL32(255, 255, 255, 255), buf); 2275 } 2276 } 2277 #endif 2278 2279 // Is it in the quadrant we're interesting in moving to? 2280 bool new_best = false; 2281 if (quadrant == g.NavMoveDir) 2282 { 2283 // Does it beat the current best candidate? 2284 if (dist_box < result->DistBox) 2285 { 2286 result->DistBox = dist_box; 2287 result->DistCenter = dist_center; 2288 return true; 2289 } 2290 if (dist_box == result->DistBox) 2291 { 2292 // Try using distance between center points to break ties 2293 if (dist_center < result->DistCenter) 2294 { 2295 result->DistCenter = dist_center; 2296 new_best = true; 2297 } 2298 else if (dist_center == result->DistCenter) 2299 { 2300 // Still tied! we need to be extra-careful to make sure everything gets linked properly. We consistently break ties by symbolically moving "later" items 2301 // (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), 2302 // 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. 2303 if (((g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? dby : dbx) < 0.0f) // moving bj to the right/down decreases distance 2304 new_best = true; 2305 } 2306 } 2307 } 2308 2309 // 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 2310 // are found, so it only augments the graph produced by the above method using extra links. (important, since it doesn't guarantee strong connectedness) 2311 // 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. 2312 // 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. 2313 // Disabling it may however lead to disconnected graphs when nodes are very spaced out on different axis. Perhaps consider offering this as an option? 2314 if (result->DistBox == FLT_MAX && dist_axial < result->DistAxial) // Check axial match 2315 if (g.NavLayer == 1 && !(g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu)) 2316 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)) 2317 { 2318 result->DistAxial = dist_axial; 2319 new_best = true; 2320 } 2321 2322 return new_best; 2323 } 2324 2325 static void NavSaveLastChildNavWindow(ImGuiWindow* child_window) 2326 { 2327 ImGuiWindow* parent_window = child_window; 2328 while (parent_window && (parent_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 && (parent_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0) 2329 parent_window = parent_window->ParentWindow; 2330 if (parent_window && parent_window != child_window) 2331 parent_window->NavLastChildNavWindow = child_window; 2332 } 2333 2334 // Call when we are expected to land on Layer 0 after FocusWindow() 2335 static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window) 2336 { 2337 return window->NavLastChildNavWindow ? window->NavLastChildNavWindow : window; 2338 } 2339 2340 static void NavRestoreLayer(int layer) 2341 { 2342 ImGuiContext& g = *GImGui; 2343 g.NavLayer = layer; 2344 if (layer == 0) 2345 g.NavWindow = NavRestoreLastChildNavWindow(g.NavWindow); 2346 if (layer == 0 && g.NavWindow->NavLastIds[0] != 0) 2347 SetNavIDWithRectRel(g.NavWindow->NavLastIds[0], layer, g.NavWindow->NavRectRel[0]); 2348 else 2349 ImGui::NavInitWindow(g.NavWindow, true); 2350 } 2351 2352 static inline void NavUpdateAnyRequestFlag() 2353 { 2354 ImGuiContext& g = *GImGui; 2355 g.NavAnyRequest = g.NavMoveRequest || g.NavInitRequest || (IMGUI_DEBUG_NAV_SCORING && g.NavWindow != NULL); 2356 if (g.NavAnyRequest) 2357 IM_ASSERT(g.NavWindow != NULL); 2358 } 2359 2360 static bool NavMoveRequestButNoResultYet() 2361 { 2362 ImGuiContext& g = *GImGui; 2363 return g.NavMoveRequest && g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0; 2364 } 2365 2366 void ImGui::NavMoveRequestCancel() 2367 { 2368 ImGuiContext& g = *GImGui; 2369 g.NavMoveRequest = false; 2370 NavUpdateAnyRequestFlag(); 2371 } 2372 2373 // We get there when either NavId == id, or when g.NavAnyRequest is set (which is updated by NavUpdateAnyRequestFlag above) 2374 static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, const ImGuiID id) 2375 { 2376 ImGuiContext& g = *GImGui; 2377 //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. 2378 // return; 2379 2380 const ImGuiItemFlags item_flags = window->DC.ItemFlags; 2381 const ImRect nav_bb_rel(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos); 2382 if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent) 2383 { 2384 // Even if 'ImGuiItemFlags_NoNavDefaultFocus' is on (typically collapse/close button) we record the first ResultId so they can be used as a fallback 2385 if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus) || g.NavInitResultId == 0) 2386 { 2387 g.NavInitResultId = id; 2388 g.NavInitResultRectRel = nav_bb_rel; 2389 } 2390 if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus)) 2391 { 2392 g.NavInitRequest = false; // Found a match, clear request 2393 NavUpdateAnyRequestFlag(); 2394 } 2395 } 2396 2397 // Scoring for navigation 2398 if (g.NavId != id && !(item_flags & ImGuiItemFlags_NoNav)) 2399 { 2400 ImGuiNavMoveResult* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther; 2401 #if IMGUI_DEBUG_NAV_SCORING 2402 // [DEBUG] Score all items in NavWindow at all times 2403 if (!g.NavMoveRequest) 2404 g.NavMoveDir = g.NavMoveDirLast; 2405 bool new_best = NavScoreItem(result, nav_bb) && g.NavMoveRequest; 2406 #else 2407 bool new_best = g.NavMoveRequest && NavScoreItem(result, nav_bb); 2408 #endif 2409 if (new_best) 2410 { 2411 result->ID = id; 2412 result->ParentID = window->IDStack.back(); 2413 result->Window = window; 2414 result->RectRel = nav_bb_rel; 2415 } 2416 } 2417 2418 // Update window-relative bounding box of navigated item 2419 if (g.NavId == id) 2420 { 2421 g.NavWindow = window; // Always refresh g.NavWindow, because some operations such as FocusItem() don't have a window. 2422 g.NavLayer = window->DC.NavLayerCurrent; 2423 g.NavIdIsAlive = true; 2424 g.NavIdTabCounter = window->FocusIdxTabCounter; 2425 window->NavRectRel[window->DC.NavLayerCurrent] = nav_bb_rel; // Store item bounding box (relative to window position) 2426 } 2427 } 2428 2429 // Declare item bounding box for clipping and interaction. 2430 // Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface 2431 // declare their minimum size requirement to ItemSize() and then use a larger region for drawing/interaction, which is passed to ItemAdd(). 2432 bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg) 2433 { 2434 ImGuiContext& g = *GImGui; 2435 ImGuiWindow* window = g.CurrentWindow; 2436 2437 if (id != 0) 2438 { 2439 // Navigation processing runs prior to clipping early-out 2440 // (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget 2441 // (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. 2442 // 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. 2443 // 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) 2444 window->DC.NavLayerActiveMaskNext |= window->DC.NavLayerCurrentMask; 2445 if (g.NavId == id || g.NavAnyRequest) 2446 if (g.NavWindow->RootWindowForNav == window->RootWindowForNav) 2447 if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened)) 2448 NavProcessItem(window, nav_bb_arg ? *nav_bb_arg : bb, id); 2449 } 2450 2451 window->DC.LastItemId = id; 2452 window->DC.LastItemRect = bb; 2453 window->DC.LastItemStatusFlags = 0; 2454 2455 // Clipping test 2456 const bool is_clipped = IsClippedEx(bb, id, false); 2457 if (is_clipped) 2458 return false; 2459 //if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG] 2460 2461 // We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them) 2462 if (IsMouseHoveringRect(bb.Min, bb.Max)) 2463 window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredRect; 2464 return true; 3045 // An active popup disable hovering on other windows (apart from its own children) 3046 // FIXME-OPT: This could be cached/stored within the window. 3047 ImGuiContext& g = *GImGui; 3048 if (g.NavWindow) 3049 if (ImGuiWindow* focused_root_window = g.NavWindow->RootWindow) 3050 if (focused_root_window->WasActive && focused_root_window != window->RootWindow) 3051 { 3052 // For the purpose of those flags we differentiate "standard popup" from "modal popup" 3053 // NB: The order of those two tests is important because Modal windows are also Popups. 3054 if (focused_root_window->Flags & ImGuiWindowFlags_Modal) 3055 return false; 3056 if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiHoveredFlags_AllowWhenBlockedByPopup)) 3057 return false; 3058 } 3059 return true; 2465 3060 } 2466 3061 … … 2470 3065 bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) 2471 3066 { 2472 ImGuiContext& g = *GImGui; 2473 ImGuiWindow* window = g.CurrentWindow; 2474 if (g.NavDisableMouseHover && !g.NavDisableHighlight) 2475 return IsItemFocused(); 2476 2477 // Test for bounding box overlap, as updated as ItemAdd() 2478 if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect)) 2479 return false; 2480 IM_ASSERT((flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) == 0); // Flags not supported by this function 2481 2482 // Test if we are hovering the right window (our window could be behind another window) 2483 // [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. 2484 // 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. 2485 //if (g.HoveredWindow != window) 2486 // return false; 2487 if (g.HoveredRootWindow != window->RootWindow && !(flags & ImGuiHoveredFlags_AllowWhenOverlapped)) 2488 return false; 2489 2490 // Test if another item is active (e.g. being dragged) 2491 if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) 2492 if (g.ActiveId != 0 && g.ActiveId != window->DC.LastItemId && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId) 2493 return false; 2494 2495 // Test if interactions on this window are blocked by an active popup or modal 2496 if (!IsWindowContentHoverable(window, flags)) 2497 return false; 2498 2499 // Test if the item is disabled 2500 if (window->DC.ItemFlags & ImGuiItemFlags_Disabled) 2501 return false; 2502 2503 // Special handling for the 1st item after Begin() which represent the title bar. When the window is collapsed (SkipItems==true) that last item will never be overwritten so we need to detect tht case. 2504 if (window->DC.LastItemId == window->MoveId && window->WriteAccessed) 2505 return false; 2506 return true; 3067 ImGuiContext& g = *GImGui; 3068 ImGuiWindow* window = g.CurrentWindow; 3069 if (g.NavDisableMouseHover && !g.NavDisableHighlight) 3070 return IsItemFocused(); 3071 3072 // Test for bounding box overlap, as updated as ItemAdd() 3073 if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect)) 3074 return false; 3075 IM_ASSERT((flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) == 0); // Flags not supported by this function 3076 3077 // Test if we are hovering the right window (our window could be behind another window) 3078 // [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. 3079 // 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. 3080 //if (g.HoveredWindow != window) 3081 // return false; 3082 if (g.HoveredRootWindow != window->RootWindow && !(flags & ImGuiHoveredFlags_AllowWhenOverlapped)) 3083 return false; 3084 3085 // Test if another item is active (e.g. being dragged) 3086 if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) 3087 if (g.ActiveId != 0 && g.ActiveId != window->DC.LastItemId && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId) 3088 return false; 3089 3090 // Test if interactions on this window are blocked by an active popup or modal. 3091 // The ImGuiHoveredFlags_AllowWhenBlockedByPopup flag will be tested here. 3092 if (!IsWindowContentHoverable(window, flags)) 3093 return false; 3094 3095 // Test if the item is disabled 3096 if ((window->DC.ItemFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled)) 3097 return false; 3098 3099 // Special handling for calling after Begin() which represent the title bar or tab. 3100 // When the window is collapsed (SkipItems==true) that last item will never be overwritten so we need to detect the case. 3101 if (window->DC.LastItemId == window->MoveId && window->WriteAccessed) 3102 return false; 3103 return true; 2507 3104 } 2508 3105 … … 2510 3107 bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id) 2511 3108 { 2512 ImGuiContext& g = *GImGui; 2513 if (g.HoveredId != 0 && g.HoveredId != id && !g.HoveredIdAllowOverlap) 2514 return false; 2515 2516 ImGuiWindow* window = g.CurrentWindow; 2517 if (g.HoveredWindow != window) 2518 return false; 2519 if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap) 2520 return false; 2521 if (!IsMouseHoveringRect(bb.Min, bb.Max)) 2522 return false; 2523 if (g.NavDisableMouseHover || !IsWindowContentHoverable(window, ImGuiHoveredFlags_Default)) 2524 return false; 2525 if (window->DC.ItemFlags & ImGuiItemFlags_Disabled) 2526 return false; 2527 2528 SetHoveredID(id); 2529 return true; 3109 ImGuiContext& g = *GImGui; 3110 if (g.HoveredId != 0 && g.HoveredId != id && !g.HoveredIdAllowOverlap) 3111 return false; 3112 3113 ImGuiWindow* window = g.CurrentWindow; 3114 if (g.HoveredWindow != window) 3115 return false; 3116 if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap) 3117 return false; 3118 if (!IsMouseHoveringRect(bb.Min, bb.Max)) 3119 return false; 3120 if (g.NavDisableMouseHover) 3121 return false; 3122 if (!IsWindowContentHoverable(window, ImGuiHoveredFlags_None) || (window->DC.ItemFlags & ImGuiItemFlags_Disabled)) 3123 { 3124 g.HoveredIdDisabled = true; 3125 return false; 3126 } 3127 3128 // We exceptionally allow this function to be called with id==0 to allow using it for easy high-level 3129 // hover test in widgets code. We could also decide to split this function is two. 3130 if (id != 0) 3131 { 3132 SetHoveredID(id); 3133 3134 // [DEBUG] Item Picker tool! 3135 // We perform the check here because SetHoveredID() is not frequently called (1~ time a frame), making 3136 // the cost of this tool near-zero. We can get slightly better call-stack and support picking non-hovered 3137 // items if we perform the test in ItemAdd(), but that would incur a small runtime cost. 3138 // #define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX in imconfig.h if you want this check to also be performed in ItemAdd(). 3139 if (g.DebugItemPickerActive && g.HoveredIdPreviousFrame == id) 3140 GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(255, 255, 0, 255)); 3141 if (g.DebugItemPickerBreakId == id) 3142 IM_DEBUG_BREAK(); 3143 } 3144 3145 return true; 2530 3146 } 2531 3147 2532 3148 bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged) 2533 3149 { 2534 ImGuiContext& g = *GImGui; 2535 ImGuiWindow* window = g.CurrentWindow; 2536 if (!bb.Overlaps(window->ClipRect)) 2537 if (id == 0 || id != g.ActiveId) 2538 if (clip_even_when_logged || !g.LogEnabled) 3150 ImGuiContext& g = *GImGui; 3151 ImGuiWindow* window = g.CurrentWindow; 3152 if (!bb.Overlaps(window->ClipRect)) 3153 if (id == 0 || (id != g.ActiveId && id != g.NavId)) 3154 if (clip_even_when_logged || !g.LogEnabled) 3155 return true; 3156 return false; 3157 } 3158 3159 // This is also inlined in ItemAdd() 3160 // Note: if ImGuiItemStatusFlags_HasDisplayRect is set, user needs to set window->DC.LastItemDisplayRect! 3161 void ImGui::SetLastItemData(ImGuiWindow* window, ImGuiID item_id, ImGuiItemStatusFlags item_flags, const ImRect& item_rect) 3162 { 3163 window->DC.LastItemId = item_id; 3164 window->DC.LastItemStatusFlags = item_flags; 3165 window->DC.LastItemRect = item_rect; 3166 } 3167 3168 // Process TAB/Shift+TAB. Be mindful that this function may _clear_ the ActiveID when tabbing out. 3169 bool ImGui::FocusableItemRegister(ImGuiWindow* window, ImGuiID id) 3170 { 3171 ImGuiContext& g = *GImGui; 3172 3173 // Increment counters 3174 const bool is_tab_stop = (window->DC.ItemFlags & (ImGuiItemFlags_NoTabStop | ImGuiItemFlags_Disabled)) == 0; 3175 window->DC.FocusCounterRegular++; 3176 if (is_tab_stop) 3177 window->DC.FocusCounterTabStop++; 3178 3179 // Process TAB/Shift-TAB to tab *OUT* of the currently focused item. 3180 // (Note that we can always TAB out of a widget that doesn't allow tabbing in) 3181 if (g.ActiveId == id && g.FocusTabPressed && !IsActiveIdUsingKey(ImGuiKey_Tab) && g.FocusRequestNextWindow == NULL) 3182 { 3183 g.FocusRequestNextWindow = window; 3184 g.FocusRequestNextCounterTabStop = window->DC.FocusCounterTabStop + (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. 3185 } 3186 3187 // Handle focus requests 3188 if (g.FocusRequestCurrWindow == window) 3189 { 3190 if (window->DC.FocusCounterRegular == g.FocusRequestCurrCounterRegular) 2539 3191 return true; 2540 return false; 2541 } 2542 2543 bool ImGui::FocusableItemRegister(ImGuiWindow* window, ImGuiID id, bool tab_stop) 2544 { 2545 ImGuiContext& g = *GImGui; 2546 2547 const bool allow_keyboard_focus = (window->DC.ItemFlags & (ImGuiItemFlags_AllowKeyboardFocus | ImGuiItemFlags_Disabled)) == ImGuiItemFlags_AllowKeyboardFocus; 2548 window->FocusIdxAllCounter++; 2549 if (allow_keyboard_focus) 2550 window->FocusIdxTabCounter++; 2551 2552 // Process keyboard input at this point: TAB/Shift-TAB to tab out of the currently focused item. 2553 // Note that we can always TAB out of a widget that doesn't allow tabbing in. 2554 if (tab_stop && (g.ActiveId == id) && window->FocusIdxAllRequestNext == INT_MAX && window->FocusIdxTabRequestNext == INT_MAX && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab)) 2555 window->FocusIdxTabRequestNext = window->FocusIdxTabCounter + (g.IO.KeyShift ? (allow_keyboard_focus ? -1 : 0) : +1); // Modulo on index will be applied at the end of frame once we've got the total counter of items. 2556 2557 if (window->FocusIdxAllCounter == window->FocusIdxAllRequestCurrent) 2558 return true; 2559 if (allow_keyboard_focus && window->FocusIdxTabCounter == window->FocusIdxTabRequestCurrent) 2560 { 2561 g.NavJustTabbedId = id; 2562 return true; 2563 } 2564 2565 return false; 3192 if (is_tab_stop && window->DC.FocusCounterTabStop == g.FocusRequestCurrCounterTabStop) 3193 { 3194 g.NavJustTabbedId = id; 3195 return true; 3196 } 3197 3198 // If another item is about to be focused, we clear our own active id 3199 if (g.ActiveId == id) 3200 ClearActiveID(); 3201 } 3202 3203 return false; 2566 3204 } 2567 3205 2568 3206 void ImGui::FocusableItemUnregister(ImGuiWindow* window) 2569 3207 { 2570 window->FocusIdxAllCounter--; 2571 window->FocusIdxTabCounter--; 2572 } 2573 2574 ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_x, float default_y) 2575 { 2576 ImGuiContext& g = *GImGui; 2577 ImVec2 content_max; 2578 if (size.x < 0.0f || size.y < 0.0f) 2579 content_max = g.CurrentWindow->Pos + GetContentRegionMax(); 2580 if (size.x <= 0.0f) 2581 size.x = (size.x == 0.0f) ? default_x : ImMax(content_max.x - g.CurrentWindow->DC.CursorPos.x, 4.0f) + size.x; 2582 if (size.y <= 0.0f) 2583 size.y = (size.y == 0.0f) ? default_y : ImMax(content_max.y - g.CurrentWindow->DC.CursorPos.y, 4.0f) + size.y; 2584 return size; 3208 window->DC.FocusCounterRegular--; 3209 window->DC.FocusCounterTabStop--; 2585 3210 } 2586 3211 2587 3212 float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x) 2588 3213 { 2589 if (wrap_pos_x < 0.0f) 2590 return 0.0f; 2591 2592 ImGuiWindow* window = GetCurrentWindowRead(); 2593 if (wrap_pos_x == 0.0f) 2594 wrap_pos_x = GetContentRegionMax().x + window->Pos.x; 2595 else if (wrap_pos_x > 0.0f) 2596 wrap_pos_x += window->Pos.x - window->Scroll.x; // wrap_pos_x is provided is window local space 2597 2598 return ImMax(wrap_pos_x - pos.x, 1.0f); 2599 } 2600 2601 //----------------------------------------------------------------------------- 2602 2603 void* ImGui::MemAlloc(size_t sz) 2604 { 2605 GImAllocatorActiveAllocationsCount++; 2606 return GImAllocatorAllocFunc(sz, GImAllocatorUserData); 2607 } 2608 3214 if (wrap_pos_x < 0.0f) 3215 return 0.0f; 3216 3217 ImGuiContext& g = *GImGui; 3218 ImGuiWindow* window = g.CurrentWindow; 3219 if (wrap_pos_x == 0.0f) 3220 { 3221 // We could decide to setup a default wrapping max point for auto-resizing windows, 3222 // or have auto-wrap (with unspecified wrapping pos) behave as a ContentSize extending function? 3223 //if (window->Hidden && (window->Flags & ImGuiWindowFlags_AlwaysAutoResize)) 3224 // wrap_pos_x = ImMax(window->WorkRect.Min.x + g.FontSize * 10.0f, window->WorkRect.Max.x); 3225 //else 3226 wrap_pos_x = window->WorkRect.Max.x; 3227 } 3228 else if (wrap_pos_x > 0.0f) 3229 { 3230 wrap_pos_x += window->Pos.x - window->Scroll.x; // wrap_pos_x is provided is window local space 3231 } 3232 3233 return ImMax(wrap_pos_x - pos.x, 1.0f); 3234 } 3235 3236 // IM_ALLOC() == ImGui::MemAlloc() 3237 void* ImGui::MemAlloc(size_t size) 3238 { 3239 if (ImGuiContext* ctx = GImGui) 3240 ctx->IO.MetricsActiveAllocations++; 3241 return GImAllocatorAllocFunc(size, GImAllocatorUserData); 3242 } 3243 3244 // IM_FREE() == ImGui::MemFree() 2609 3245 void ImGui::MemFree(void* ptr) 2610 3246 { 2611 if (ptr) GImAllocatorActiveAllocationsCount--; 2612 return GImAllocatorFreeFunc(ptr, GImAllocatorUserData); 3247 if (ptr) 3248 if (ImGuiContext* ctx = GImGui) 3249 ctx->IO.MetricsActiveAllocations--; 3250 return GImAllocatorFreeFunc(ptr, GImAllocatorUserData); 2613 3251 } 2614 3252 2615 3253 const char* ImGui::GetClipboardText() 2616 3254 { 2617 return GImGui->IO.GetClipboardTextFn ? GImGui->IO.GetClipboardTextFn(GImGui->IO.ClipboardUserData) : ""; 3255 ImGuiContext& g = *GImGui; 3256 return g.IO.GetClipboardTextFn ? g.IO.GetClipboardTextFn(g.IO.ClipboardUserData) : ""; 2618 3257 } 2619 3258 2620 3259 void ImGui::SetClipboardText(const char* text) 2621 3260 { 2622 if (GImGui->IO.SetClipboardTextFn) 2623 GImGui->IO.SetClipboardTextFn(GImGui->IO.ClipboardUserData, text); 3261 ImGuiContext& g = *GImGui; 3262 if (g.IO.SetClipboardTextFn) 3263 g.IO.SetClipboardTextFn(g.IO.ClipboardUserData, text); 2624 3264 } 2625 3265 2626 3266 const char* ImGui::GetVersion() 2627 3267 { 2628 return IMGUI_VERSION;2629 } 2630 2631 // Internal state access - if you want to share ImGui state between modules (e.g. DLL) or allocate it yourself3268 return IMGUI_VERSION; 3269 } 3270 3271 // Internal state access - if you want to share Dear ImGui state between modules (e.g. DLL) or allocate it yourself 2632 3272 // 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 2633 3273 ImGuiContext* ImGui::GetCurrentContext() 2634 3274 { 2635 return GImGui;3275 return GImGui; 2636 3276 } 2637 3277 … … 2639 3279 { 2640 3280 #ifdef IMGUI_SET_CURRENT_CONTEXT_FUNC 2641 IMGUI_SET_CURRENT_CONTEXT_FUNC(ctx); // For custom thread-based hackery you may want to have control over this.3281 IMGUI_SET_CURRENT_CONTEXT_FUNC(ctx); // For custom thread-based hackery you may want to have control over this. 2642 3282 #else 2643 GImGui = ctx;3283 GImGui = ctx; 2644 3284 #endif 2645 3285 } 2646 3286 2647 // Helper function to verify that the type sizes are matching between the calling file's compilation unit and imgui.cpp's compilation unit 2648 // 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. 2649 bool 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) 2650 { 2651 bool error = false; 2652 if (strcmp(version, IMGUI_VERSION) != 0) { error = true; IM_ASSERT(strcmp(version, IMGUI_VERSION) == 0 && "Mismatch version string!"); } 2653 if (sz_io != sizeof(ImGuiIO)) { error = true; IM_ASSERT(sz_io == sizeof(ImGuiIO) && "Mismatched struct layout!"); } 2654 if (sz_style != sizeof(ImGuiStyle)) { error = true; IM_ASSERT(sz_style == sizeof(ImGuiStyle) && "Mismatched struct layout!"); } 2655 if (sz_vec2 != sizeof(ImVec2)) { error = true; IM_ASSERT(sz_vec2 == sizeof(ImVec2) && "Mismatched struct layout!"); } 2656 if (sz_vec4 != sizeof(ImVec4)) { error = true; IM_ASSERT(sz_vec4 == sizeof(ImVec4) && "Mismatched struct layout!"); } 2657 if (sz_vert != sizeof(ImDrawVert)) { error = true; IM_ASSERT(sz_vert == sizeof(ImDrawVert) && "Mismatched struct layout!"); } 2658 return !error; 2659 } 2660 2661 void ImGui::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void(*free_func)(void* ptr, void* user_data), void* user_data) 2662 { 2663 GImAllocatorAllocFunc = alloc_func; 2664 GImAllocatorFreeFunc = free_func; 2665 GImAllocatorUserData = user_data; 3287 void ImGui::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data) 3288 { 3289 GImAllocatorAllocFunc = alloc_func; 3290 GImAllocatorFreeFunc = free_func; 3291 GImAllocatorUserData = user_data; 2666 3292 } 2667 3293 2668 3294 ImGuiContext* ImGui::CreateContext(ImFontAtlas* shared_font_atlas) 2669 3295 { 2670 ImGuiContext* ctx = IM_NEW(ImGuiContext)(shared_font_atlas);2671 if (GImGui == NULL)2672 SetCurrentContext(ctx);2673 Initialize(ctx);2674 return ctx;3296 ImGuiContext* ctx = IM_NEW(ImGuiContext)(shared_font_atlas); 3297 if (GImGui == NULL) 3298 SetCurrentContext(ctx); 3299 Initialize(ctx); 3300 return ctx; 2675 3301 } 2676 3302 2677 3303 void ImGui::DestroyContext(ImGuiContext* ctx) 2678 3304 { 2679 if (ctx == NULL)2680 ctx = GImGui;2681 Shutdown(ctx);2682 if (GImGui == ctx)2683 SetCurrentContext(NULL);2684 IM_DELETE(ctx);3305 if (ctx == NULL) 3306 ctx = GImGui; 3307 Shutdown(ctx); 3308 if (GImGui == ctx) 3309 SetCurrentContext(NULL); 3310 IM_DELETE(ctx); 2685 3311 } 2686 3312 2687 3313 ImGuiIO& ImGui::GetIO() 2688 3314 { 2689 IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?"); 2690 return GImGui->IO; 2691 } 2692 2693 ImGuiStyle& ImGui::GetStyle() 2694 { 2695 IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?"); 2696 return GImGui->Style; 3315 IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?"); 3316 return GImGui->IO; 2697 3317 } 2698 3318 … … 2700 3320 ImDrawData* ImGui::GetDrawData() 2701 3321 { 2702 ImGuiContext& g = *GImGui;2703 return g.DrawData.Valid ? &g.DrawData : NULL;2704 } 2705 2706 floatImGui::GetTime()2707 { 2708 return GImGui->Time;3322 ImGuiContext& g = *GImGui; 3323 return g.DrawData.Valid ? &g.DrawData : NULL; 3324 } 3325 3326 double ImGui::GetTime() 3327 { 3328 return GImGui->Time; 2709 3329 } 2710 3330 2711 3331 int ImGui::GetFrameCount() 2712 3332 { 2713 return GImGui->FrameCount; 2714 } 2715 2716 ImDrawList* ImGui::GetOverlayDrawList() 2717 { 2718 return &GImGui->OverlayDrawList; 3333 return GImGui->FrameCount; 3334 } 3335 3336 ImDrawList* ImGui::GetBackgroundDrawList() 3337 { 3338 return &GImGui->BackgroundDrawList; 3339 } 3340 3341 ImDrawList* ImGui::GetForegroundDrawList() 3342 { 3343 return &GImGui->ForegroundDrawList; 2719 3344 } 2720 3345 2721 3346 ImDrawListSharedData* ImGui::GetDrawListSharedData() 2722 3347 { 2723 return &GImGui->DrawListSharedData; 2724 } 2725 2726 // This needs to be called before we submit any widget (aka in or before Begin) 2727 void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit) 2728 { 2729 ImGuiContext& g = *GImGui; 2730 IM_ASSERT(window == g.NavWindow); 2731 bool init_for_nav = false; 2732 if (!(window->Flags & ImGuiWindowFlags_NoNavInputs)) 2733 if (!(window->Flags & ImGuiWindowFlags_ChildWindow) || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit) 2734 init_for_nav = true; 2735 if (init_for_nav) 2736 { 2737 SetNavID(0, g.NavLayer); 2738 g.NavInitRequest = true; 2739 g.NavInitRequestFromMove = false; 2740 g.NavInitResultId = 0; 2741 g.NavInitResultRectRel = ImRect(); 2742 NavUpdateAnyRequestFlag(); 2743 } 2744 else 2745 { 2746 g.NavId = window->NavLastIds[0]; 2747 } 2748 } 2749 2750 static ImVec2 NavCalcPreferredRefPos() 2751 { 2752 ImGuiContext& g = *GImGui; 2753 if (g.NavDisableHighlight || !g.NavDisableMouseHover || !g.NavWindow) 2754 return ImFloor(g.IO.MousePos); 2755 2756 // When navigation is active and mouse is disabled, decide on an arbitrary position around the bottom left of the currently navigated item 2757 const ImRect& rect_rel = g.NavWindow->NavRectRel[g.NavLayer]; 2758 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())); 2759 ImRect visible_rect = GetViewportRect(); 2760 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. 2761 } 2762 2763 static int FindWindowIndex(ImGuiWindow* window) // FIXME-OPT O(N) 2764 { 2765 ImGuiContext& g = *GImGui; 2766 for (int i = g.Windows.Size - 1; i >= 0; i--) 2767 if (g.Windows[i] == window) 2768 return i; 2769 return -1; 2770 } 2771 2772 static ImGuiWindow* FindWindowNavigable(int i_start, int i_stop, int dir) // FIXME-OPT O(N) 2773 { 2774 ImGuiContext& g = *GImGui; 2775 for (int i = i_start; i >= 0 && i < g.Windows.Size && i != i_stop; i += dir) 2776 if (ImGui::IsWindowNavFocusable(g.Windows[i])) 2777 return g.Windows[i]; 2778 return NULL; 2779 } 2780 2781 float ImGui::GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode) 2782 { 2783 ImGuiContext& g = *GImGui; 2784 if (mode == ImGuiInputReadMode_Down) 2785 return g.IO.NavInputs[n]; // Instant, read analog input (0.0f..1.0f, as provided by user) 2786 2787 const float t = g.IO.NavInputsDownDuration[n]; 2788 if (t < 0.0f && mode == ImGuiInputReadMode_Released) // Return 1.0f when just released, no repeat, ignore analog input. 2789 return (g.IO.NavInputsDownDurationPrev[n] >= 0.0f ? 1.0f : 0.0f); 2790 if (t < 0.0f) 2791 return 0.0f; 2792 if (mode == ImGuiInputReadMode_Pressed) // Return 1.0f when just pressed, no repeat, ignore analog input. 2793 return (t == 0.0f) ? 1.0f : 0.0f; 2794 if (mode == ImGuiInputReadMode_Repeat) 2795 return (float)CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 0.80f, g.IO.KeyRepeatRate * 0.80f); 2796 if (mode == ImGuiInputReadMode_RepeatSlow) 2797 return (float)CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 1.00f, g.IO.KeyRepeatRate * 2.00f); 2798 if (mode == ImGuiInputReadMode_RepeatFast) 2799 return (float)CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 0.80f, g.IO.KeyRepeatRate * 0.30f); 2800 return 0.0f; 2801 } 2802 2803 // Equivalent of IsKeyDown() for NavInputs[] 2804 static bool IsNavInputDown(ImGuiNavInput n) 2805 { 2806 return GImGui->IO.NavInputs[n] > 0.0f; 2807 } 2808 2809 // Equivalent of IsKeyPressed() for NavInputs[] 2810 static bool IsNavInputPressed(ImGuiNavInput n, ImGuiInputReadMode mode) 2811 { 2812 return ImGui::GetNavInputAmount(n, mode) > 0.0f; 2813 } 2814 2815 static bool IsNavInputPressedAnyOfTwo(ImGuiNavInput n1, ImGuiNavInput n2, ImGuiInputReadMode mode) 2816 { 2817 return (ImGui::GetNavInputAmount(n1, mode) + ImGui::GetNavInputAmount(n2, mode)) > 0.0f; 2818 } 2819 2820 ImVec2 ImGui::GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor, float fast_factor) 2821 { 2822 ImVec2 delta(0.0f, 0.0f); 2823 if (dir_sources & ImGuiNavDirSourceFlags_Keyboard) 2824 delta += ImVec2(GetNavInputAmount(ImGuiNavInput_KeyRight_, mode) - GetNavInputAmount(ImGuiNavInput_KeyLeft_, mode), GetNavInputAmount(ImGuiNavInput_KeyDown_, mode) - GetNavInputAmount(ImGuiNavInput_KeyUp_, mode)); 2825 if (dir_sources & ImGuiNavDirSourceFlags_PadDPad) 2826 delta += ImVec2(GetNavInputAmount(ImGuiNavInput_DpadRight, mode) - GetNavInputAmount(ImGuiNavInput_DpadLeft, mode), GetNavInputAmount(ImGuiNavInput_DpadDown, mode) - GetNavInputAmount(ImGuiNavInput_DpadUp, mode)); 2827 if (dir_sources & ImGuiNavDirSourceFlags_PadLStick) 2828 delta += ImVec2(GetNavInputAmount(ImGuiNavInput_LStickRight, mode) - GetNavInputAmount(ImGuiNavInput_LStickLeft, mode), GetNavInputAmount(ImGuiNavInput_LStickDown, mode) - GetNavInputAmount(ImGuiNavInput_LStickUp, mode)); 2829 if (slow_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakSlow)) 2830 delta *= slow_factor; 2831 if (fast_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakFast)) 2832 delta *= fast_factor; 2833 return delta; 2834 } 2835 2836 static void NavUpdateWindowingHighlightWindow(int focus_change_dir) 2837 { 2838 ImGuiContext& g = *GImGui; 2839 IM_ASSERT(g.NavWindowingTarget); 2840 if (g.NavWindowingTarget->Flags & ImGuiWindowFlags_Modal) 2841 return; 2842 2843 const int i_current = FindWindowIndex(g.NavWindowingTarget); 2844 ImGuiWindow* window_target = FindWindowNavigable(i_current + focus_change_dir, -INT_MAX, focus_change_dir); 2845 if (!window_target) 2846 window_target = FindWindowNavigable((focus_change_dir < 0) ? (g.Windows.Size - 1) : 0, i_current, focus_change_dir); 2847 g.NavWindowingTarget = window_target; 2848 g.NavWindowingToggleLayer = false; 2849 } 2850 2851 // Window management mode (hold to: change focus/move/resize, tap to: toggle menu layer) 2852 static void ImGui::NavUpdateWindowing() 2853 { 2854 ImGuiContext& g = *GImGui; 2855 ImGuiWindow* apply_focus_window = NULL; 2856 bool apply_toggle_layer = false; 2857 2858 bool start_windowing_with_gamepad = !g.NavWindowingTarget && IsNavInputPressed(ImGuiNavInput_Menu, ImGuiInputReadMode_Pressed); 2859 bool start_windowing_with_keyboard = !g.NavWindowingTarget && g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab) && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard); 2860 if (start_windowing_with_gamepad || start_windowing_with_keyboard) 2861 if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavigable(g.Windows.Size - 1, -INT_MAX, -1)) 2862 { 2863 g.NavWindowingTarget = window->RootWindowForTabbing; 2864 g.NavWindowingHighlightTimer = g.NavWindowingHighlightAlpha = 0.0f; 2865 g.NavWindowingToggleLayer = start_windowing_with_keyboard ? false : true; 2866 g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_NavKeyboard : ImGuiInputSource_NavGamepad; 2867 } 2868 2869 // Gamepad update 2870 g.NavWindowingHighlightTimer += g.IO.DeltaTime; 2871 if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavGamepad) 2872 { 2873 // 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 2874 g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingHighlightTimer - 0.20f) / 0.05f)); 2875 2876 // Select window to focus 2877 const int focus_change_dir = (int)IsNavInputPressed(ImGuiNavInput_FocusPrev, ImGuiInputReadMode_RepeatSlow) - (int)IsNavInputPressed(ImGuiNavInput_FocusNext, ImGuiInputReadMode_RepeatSlow); 2878 if (focus_change_dir != 0) 2879 { 2880 NavUpdateWindowingHighlightWindow(focus_change_dir); 2881 g.NavWindowingHighlightAlpha = 1.0f; 2882 } 2883 2884 // Single press toggles NavLayer, long press with L/R apply actual focus on release (until then the window was merely rendered front-most) 2885 if (!IsNavInputDown(ImGuiNavInput_Menu)) 2886 { 2887 g.NavWindowingToggleLayer &= (g.NavWindowingHighlightAlpha < 1.0f); // Once button was held long enough we don't consider it a tap-to-toggle-layer press anymore. 2888 if (g.NavWindowingToggleLayer && g.NavWindow) 2889 apply_toggle_layer = true; 2890 else if (!g.NavWindowingToggleLayer) 2891 apply_focus_window = g.NavWindowingTarget; 2892 g.NavWindowingTarget = NULL; 2893 } 2894 } 2895 2896 // Keyboard: Focus 2897 if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavKeyboard) 2898 { 2899 // Visuals only appears after a brief time after pressing TAB the first time, so that a fast CTRL+TAB doesn't add visual noise 2900 g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingHighlightTimer - 0.15f) / 0.04f)); // 1.0f 2901 if (IsKeyPressedMap(ImGuiKey_Tab, true)) 2902 NavUpdateWindowingHighlightWindow(g.IO.KeyShift ? +1 : -1); 2903 if (!g.IO.KeyCtrl) 2904 apply_focus_window = g.NavWindowingTarget; 2905 } 2906 2907 // Keyboard: Press and Release ALT to toggle menu layer 2908 // 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 2909 if ((g.ActiveId == 0 || g.ActiveIdAllowOverlap) && IsNavInputPressed(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Released)) 2910 if (IsMousePosValid(&g.IO.MousePos) == IsMousePosValid(&g.IO.MousePosPrev)) 2911 apply_toggle_layer = true; 2912 2913 // Move window 2914 if (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoMove)) 2915 { 2916 ImVec2 move_delta; 2917 if (g.NavInputSource == ImGuiInputSource_NavKeyboard && !g.IO.KeyShift) 2918 move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down); 2919 if (g.NavInputSource == ImGuiInputSource_NavGamepad) 2920 move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down); 2921 if (move_delta.x != 0.0f || move_delta.y != 0.0f) 2922 { 2923 const float NAV_MOVE_SPEED = 800.0f; 2924 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 2925 g.NavWindowingTarget->Pos += move_delta * move_speed; 2926 g.NavDisableMouseHover = true; 2927 MarkIniSettingsDirty(g.NavWindowingTarget); 2928 } 2929 } 2930 2931 // Apply final focus 2932 if (apply_focus_window && (g.NavWindow == NULL || apply_focus_window != g.NavWindow->RootWindowForTabbing)) 2933 { 2934 g.NavDisableHighlight = false; 2935 g.NavDisableMouseHover = true; 2936 apply_focus_window = NavRestoreLastChildNavWindow(apply_focus_window); 2937 ClosePopupsOverWindow(apply_focus_window); 2938 FocusWindow(apply_focus_window); 2939 if (apply_focus_window->NavLastIds[0] == 0) 2940 NavInitWindow(apply_focus_window, false); 2941 2942 // If the window only has a menu layer, select it directly 2943 if (apply_focus_window->DC.NavLayerActiveMask == (1 << 1)) 2944 g.NavLayer = 1; 2945 } 2946 if (apply_focus_window) 2947 g.NavWindowingTarget = NULL; 2948 2949 // Apply menu/layer toggle 2950 if (apply_toggle_layer && g.NavWindow) 2951 { 2952 ImGuiWindow* new_nav_window = g.NavWindow; 2953 while ((new_nav_window->DC.NavLayerActiveMask & (1 << 1)) == 0 && (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 && (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0) 2954 new_nav_window = new_nav_window->ParentWindow; 2955 if (new_nav_window != g.NavWindow) 2956 { 2957 ImGuiWindow* old_nav_window = g.NavWindow; 2958 FocusWindow(new_nav_window); 2959 new_nav_window->NavLastChildNavWindow = old_nav_window; 2960 } 2961 g.NavDisableHighlight = false; 2962 g.NavDisableMouseHover = true; 2963 NavRestoreLayer((g.NavWindow->DC.NavLayerActiveMask & (1 << 1)) ? (g.NavLayer ^ 1) : 0); 2964 } 2965 } 2966 2967 // NB: We modify rect_rel by the amount we scrolled for, so it is immediately updated. 2968 static void NavScrollToBringItemIntoView(ImGuiWindow* window, ImRect& item_rect_rel) 2969 { 2970 // Scroll to keep newly navigated item fully into view 2971 ImRect window_rect_rel(window->InnerRect.Min - window->Pos - ImVec2(1, 1), window->InnerRect.Max - window->Pos + ImVec2(1, 1)); 2972 //g.OverlayDrawList.AddRect(window->Pos + window_rect_rel.Min, window->Pos + window_rect_rel.Max, IM_COL32_WHITE); // [DEBUG] 2973 if (window_rect_rel.Contains(item_rect_rel)) 2974 return; 2975 2976 ImGuiContext& g = *GImGui; 2977 if (window->ScrollbarX && item_rect_rel.Min.x < window_rect_rel.Min.x) 2978 { 2979 window->ScrollTarget.x = item_rect_rel.Min.x + window->Scroll.x - g.Style.ItemSpacing.x; 2980 window->ScrollTargetCenterRatio.x = 0.0f; 2981 } 2982 else if (window->ScrollbarX && item_rect_rel.Max.x >= window_rect_rel.Max.x) 2983 { 2984 window->ScrollTarget.x = item_rect_rel.Max.x + window->Scroll.x + g.Style.ItemSpacing.x; 2985 window->ScrollTargetCenterRatio.x = 1.0f; 2986 } 2987 if (item_rect_rel.Min.y < window_rect_rel.Min.y) 2988 { 2989 window->ScrollTarget.y = item_rect_rel.Min.y + window->Scroll.y - g.Style.ItemSpacing.y; 2990 window->ScrollTargetCenterRatio.y = 0.0f; 2991 } 2992 else if (item_rect_rel.Max.y >= window_rect_rel.Max.y) 2993 { 2994 window->ScrollTarget.y = item_rect_rel.Max.y + window->Scroll.y + g.Style.ItemSpacing.y; 2995 window->ScrollTargetCenterRatio.y = 1.0f; 2996 } 2997 2998 // Estimate upcoming scroll so we can offset our relative mouse position so mouse position can be applied immediately (under this block) 2999 ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window); 3000 item_rect_rel.Translate(window->Scroll - next_scroll); 3001 } 3002 3003 static void ImGui::NavUpdate() 3004 { 3005 ImGuiContext& g = *GImGui; 3006 g.IO.WantSetMousePos = false; 3007 3008 #if 0 3009 if (g.NavScoringCount > 0) printf("[%05d] 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); 3348 return &GImGui->DrawListSharedData; 3349 } 3350 3351 void ImGui::StartMouseMovingWindow(ImGuiWindow* window) 3352 { 3353 // Set ActiveId even if the _NoMove flag is set. Without it, dragging away from a window with _NoMove would activate hover on other windows. 3354 // We _also_ call this when clicking in a window empty space when io.ConfigWindowsMoveFromTitleBarOnly is set, but clear g.MovingWindow afterward. 3355 // This is because we want ActiveId to be set even when the window is not permitted to move. 3356 ImGuiContext& g = *GImGui; 3357 FocusWindow(window); 3358 SetActiveID(window->MoveId, window); 3359 g.NavDisableHighlight = true; 3360 g.ActiveIdNoClearOnFocusLoss = true; 3361 g.ActiveIdClickOffset = g.IO.MousePos - window->RootWindow->Pos; 3362 3363 bool can_move_window = true; 3364 if ((window->Flags & ImGuiWindowFlags_NoMove) || (window->RootWindow->Flags & ImGuiWindowFlags_NoMove)) 3365 can_move_window = false; 3366 if (can_move_window) 3367 g.MovingWindow = window; 3368 } 3369 3370 // Handle mouse moving window 3371 // Note: moving window with the navigation keys (Square + d-pad / CTRL+TAB + Arrows) are processed in NavUpdateWindowing() 3372 // FIXME: We don't have strong guarantee that g.MovingWindow stay synched with g.ActiveId == g.MovingWindow->MoveId. 3373 // This is currently enforced by the fact that BeginDragDropSource() is setting all g.ActiveIdUsingXXXX flags to inhibit navigation inputs, 3374 // but if we should more thoroughly test cases where g.ActiveId or g.MovingWindow gets changed and not the other. 3375 void ImGui::UpdateMouseMovingWindowNewFrame() 3376 { 3377 ImGuiContext& g = *GImGui; 3378 if (g.MovingWindow != NULL) 3379 { 3380 // We actually want to move the root window. g.MovingWindow == window we clicked on (could be a child window). 3381 // We track it to preserve Focus and so that generally ActiveIdWindow == MovingWindow and ActiveId == MovingWindow->MoveId for consistency. 3382 KeepAliveID(g.ActiveId); 3383 IM_ASSERT(g.MovingWindow && g.MovingWindow->RootWindow); 3384 ImGuiWindow* moving_window = g.MovingWindow->RootWindow; 3385 if (g.IO.MouseDown[0] && IsMousePosValid(&g.IO.MousePos)) 3386 { 3387 ImVec2 pos = g.IO.MousePos - g.ActiveIdClickOffset; 3388 if (moving_window->Pos.x != pos.x || moving_window->Pos.y != pos.y) 3389 { 3390 MarkIniSettingsDirty(moving_window); 3391 SetWindowPos(moving_window, pos, ImGuiCond_Always); 3392 } 3393 FocusWindow(g.MovingWindow); 3394 } 3395 else 3396 { 3397 ClearActiveID(); 3398 g.MovingWindow = NULL; 3399 } 3400 } 3401 else 3402 { 3403 // When clicking/dragging from a window that has the _NoMove flag, we still set the ActiveId in order to prevent hovering others. 3404 if (g.ActiveIdWindow && g.ActiveIdWindow->MoveId == g.ActiveId) 3405 { 3406 KeepAliveID(g.ActiveId); 3407 if (!g.IO.MouseDown[0]) 3408 ClearActiveID(); 3409 } 3410 } 3411 } 3412 3413 // Initiate moving window when clicking on empty space or title bar. 3414 // Handle left-click and right-click focus. 3415 void ImGui::UpdateMouseMovingWindowEndFrame() 3416 { 3417 ImGuiContext& g = *GImGui; 3418 if (g.ActiveId != 0 || g.HoveredId != 0) 3419 return; 3420 3421 // Unless we just made a window/popup appear 3422 if (g.NavWindow && g.NavWindow->Appearing) 3423 return; 3424 3425 // Click on empty space to focus window and start moving (after we're done with all our widgets) 3426 if (g.IO.MouseClicked[0]) 3427 { 3428 // Handle the edge case of a popup being closed while clicking in its empty space. 3429 // If we try to focus it, FocusWindow() > ClosePopupsOverWindow() will accidentally close any parent popups because they are not linked together any more. 3430 ImGuiWindow* root_window = g.HoveredRootWindow; 3431 const bool is_closed_popup = root_window && (root_window->Flags & ImGuiWindowFlags_Popup) && !IsPopupOpen(root_window->PopupId, ImGuiPopupFlags_AnyPopupLevel); 3432 3433 if (root_window != NULL && !is_closed_popup) 3434 { 3435 StartMouseMovingWindow(g.HoveredWindow); 3436 3437 // Cancel moving if clicked outside of title bar 3438 if (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(root_window->Flags & ImGuiWindowFlags_NoTitleBar)) 3439 if (!root_window->TitleBarRect().Contains(g.IO.MouseClickedPos[0])) 3440 g.MovingWindow = NULL; 3441 3442 // Cancel moving if clicked over an item which was disabled or inhibited by popups (note that we know HoveredId == 0 already) 3443 if (g.HoveredIdDisabled) 3444 g.MovingWindow = NULL; 3445 } 3446 else if (root_window == NULL && g.NavWindow != NULL && GetTopMostPopupModal() == NULL) 3447 { 3448 // Clicking on void disable focus 3449 FocusWindow(NULL); 3450 } 3451 } 3452 3453 // With right mouse button we close popups without changing focus based on where the mouse is aimed 3454 // Instead, focus will be restored to the window under the bottom-most closed popup. 3455 // (The left mouse button path calls FocusWindow on the hovered window, which will lead NewFrame->ClosePopupsOverWindow to trigger) 3456 if (g.IO.MouseClicked[1]) 3457 { 3458 // Find the top-most window between HoveredWindow and the top-most Modal Window. 3459 // This is where we can trim the popup stack. 3460 ImGuiWindow* modal = GetTopMostPopupModal(); 3461 bool hovered_window_above_modal = false; 3462 if (modal == NULL) 3463 hovered_window_above_modal = true; 3464 for (int i = g.Windows.Size - 1; i >= 0 && hovered_window_above_modal == false; i--) 3465 { 3466 ImGuiWindow* window = g.Windows[i]; 3467 if (window == modal) 3468 break; 3469 if (window == g.HoveredWindow) 3470 hovered_window_above_modal = true; 3471 } 3472 ClosePopupsOverWindow(hovered_window_above_modal ? g.HoveredWindow : modal, true); 3473 } 3474 } 3475 3476 static bool IsWindowActiveAndVisible(ImGuiWindow* window) 3477 { 3478 return (window->Active) && (!window->Hidden); 3479 } 3480 3481 static void ImGui::UpdateMouseInputs() 3482 { 3483 ImGuiContext& g = *GImGui; 3484 3485 // Round mouse position to avoid spreading non-rounded position (e.g. UpdateManualResize doesn't support them well) 3486 if (IsMousePosValid(&g.IO.MousePos)) 3487 g.IO.MousePos = g.LastValidMousePos = ImFloor(g.IO.MousePos); 3488 3489 // If mouse just appeared or disappeared (usually denoted by -FLT_MAX components) we cancel out movement in MouseDelta 3490 if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MousePosPrev)) 3491 g.IO.MouseDelta = g.IO.MousePos - g.IO.MousePosPrev; 3492 else 3493 g.IO.MouseDelta = ImVec2(0.0f, 0.0f); 3494 if (g.IO.MouseDelta.x != 0.0f || g.IO.MouseDelta.y != 0.0f) 3495 g.NavDisableMouseHover = false; 3496 3497 g.IO.MousePosPrev = g.IO.MousePos; 3498 for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++) 3499 { 3500 g.IO.MouseClicked[i] = g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] < 0.0f; 3501 g.IO.MouseReleased[i] = !g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] >= 0.0f; 3502 g.IO.MouseDownDurationPrev[i] = g.IO.MouseDownDuration[i]; 3503 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; 3504 g.IO.MouseDoubleClicked[i] = false; 3505 if (g.IO.MouseClicked[i]) 3506 { 3507 if ((float)(g.Time - g.IO.MouseClickedTime[i]) < g.IO.MouseDoubleClickTime) 3508 { 3509 ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f); 3510 if (ImLengthSqr(delta_from_click_pos) < g.IO.MouseDoubleClickMaxDist * g.IO.MouseDoubleClickMaxDist) 3511 g.IO.MouseDoubleClicked[i] = true; 3512 g.IO.MouseClickedTime[i] = -g.IO.MouseDoubleClickTime * 2.0f; // Mark as "old enough" so the third click isn't turned into a double-click 3513 } 3514 else 3515 { 3516 g.IO.MouseClickedTime[i] = g.Time; 3517 } 3518 g.IO.MouseClickedPos[i] = g.IO.MousePos; 3519 g.IO.MouseDownWasDoubleClick[i] = g.IO.MouseDoubleClicked[i]; 3520 g.IO.MouseDragMaxDistanceAbs[i] = ImVec2(0.0f, 0.0f); 3521 g.IO.MouseDragMaxDistanceSqr[i] = 0.0f; 3522 } 3523 else if (g.IO.MouseDown[i]) 3524 { 3525 // Maintain the maximum distance we reaching from the initial click position, which is used with dragging threshold 3526 ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f); 3527 g.IO.MouseDragMaxDistanceSqr[i] = ImMax(g.IO.MouseDragMaxDistanceSqr[i], ImLengthSqr(delta_from_click_pos)); 3528 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); 3529 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); 3530 } 3531 if (!g.IO.MouseDown[i] && !g.IO.MouseReleased[i]) 3532 g.IO.MouseDownWasDoubleClick[i] = false; 3533 if (g.IO.MouseClicked[i]) // Clicking any mouse button reactivate mouse hovering which may have been deactivated by gamepad/keyboard navigation 3534 g.NavDisableMouseHover = false; 3535 } 3536 } 3537 3538 static void StartLockWheelingWindow(ImGuiWindow* window) 3539 { 3540 ImGuiContext& g = *GImGui; 3541 if (g.WheelingWindow == window) 3542 return; 3543 g.WheelingWindow = window; 3544 g.WheelingWindowRefMousePos = g.IO.MousePos; 3545 g.WheelingWindowTimer = WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER; 3546 } 3547 3548 void ImGui::UpdateMouseWheel() 3549 { 3550 ImGuiContext& g = *GImGui; 3551 3552 // Reset the locked window if we move the mouse or after the timer elapses 3553 if (g.WheelingWindow != NULL) 3554 { 3555 g.WheelingWindowTimer -= g.IO.DeltaTime; 3556 if (IsMousePosValid() && ImLengthSqr(g.IO.MousePos - g.WheelingWindowRefMousePos) > g.IO.MouseDragThreshold * g.IO.MouseDragThreshold) 3557 g.WheelingWindowTimer = 0.0f; 3558 if (g.WheelingWindowTimer <= 0.0f) 3559 { 3560 g.WheelingWindow = NULL; 3561 g.WheelingWindowTimer = 0.0f; 3562 } 3563 } 3564 3565 if (g.IO.MouseWheel == 0.0f && g.IO.MouseWheelH == 0.0f) 3566 return; 3567 3568 ImGuiWindow* window = g.WheelingWindow ? g.WheelingWindow : g.HoveredWindow; 3569 if (!window || window->Collapsed) 3570 return; 3571 3572 // Zoom / Scale window 3573 // FIXME-OBSOLETE: This is an old feature, it still works but pretty much nobody is using it and may be best redesigned. 3574 if (g.IO.MouseWheel != 0.0f && g.IO.KeyCtrl && g.IO.FontAllowUserScaling) 3575 { 3576 StartLockWheelingWindow(window); 3577 const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f); 3578 const float scale = new_font_scale / window->FontWindowScale; 3579 window->FontWindowScale = new_font_scale; 3580 if (!(window->Flags & ImGuiWindowFlags_ChildWindow)) 3581 { 3582 const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size; 3583 SetWindowPos(window, window->Pos + offset, 0); 3584 window->Size = ImFloor(window->Size * scale); 3585 window->SizeFull = ImFloor(window->SizeFull * scale); 3586 } 3587 return; 3588 } 3589 3590 // Mouse wheel scrolling 3591 // If a child window has the ImGuiWindowFlags_NoScrollWithMouse flag, we give a chance to scroll its parent 3592 3593 // Vertical Mouse Wheel scrolling 3594 const float wheel_y = (g.IO.MouseWheel != 0.0f && !g.IO.KeyShift) ? g.IO.MouseWheel : 0.0f; 3595 if (wheel_y != 0.0f && !g.IO.KeyCtrl) 3596 { 3597 StartLockWheelingWindow(window); 3598 while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.y == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)))) 3599 window = window->ParentWindow; 3600 if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)) 3601 { 3602 float max_step = window->InnerRect.GetHeight() * 0.67f; 3603 float scroll_step = ImFloor(ImMin(5 * window->CalcFontSize(), max_step)); 3604 SetScrollY(window, window->Scroll.y - wheel_y * scroll_step); 3605 } 3606 } 3607 3608 // Horizontal Mouse Wheel scrolling, or Vertical Mouse Wheel w/ Shift held 3609 const float wheel_x = (g.IO.MouseWheelH != 0.0f && !g.IO.KeyShift) ? g.IO.MouseWheelH : (g.IO.MouseWheel != 0.0f && g.IO.KeyShift) ? g.IO.MouseWheel : 0.0f; 3610 if (wheel_x != 0.0f && !g.IO.KeyCtrl) 3611 { 3612 StartLockWheelingWindow(window); 3613 while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.x == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)))) 3614 window = window->ParentWindow; 3615 if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)) 3616 { 3617 float max_step = window->InnerRect.GetWidth() * 0.67f; 3618 float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step)); 3619 SetScrollX(window, window->Scroll.x - wheel_x * scroll_step); 3620 } 3621 } 3622 } 3623 3624 void ImGui::UpdateTabFocus() 3625 { 3626 ImGuiContext& g = *GImGui; 3627 3628 // Pressing TAB activate widget focus 3629 g.FocusTabPressed = (g.NavWindow && g.NavWindow->Active && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab)); 3630 if (g.ActiveId == 0 && g.FocusTabPressed) 3631 { 3632 // Note that SetKeyboardFocusHere() sets the Next fields mid-frame. To be consistent we also 3633 // manipulate the Next fields even, even though they will be turned into Curr fields by the code below. 3634 g.FocusRequestNextWindow = g.NavWindow; 3635 g.FocusRequestNextCounterRegular = INT_MAX; 3636 if (g.NavId != 0 && g.NavIdTabCounter != INT_MAX) 3637 g.FocusRequestNextCounterTabStop = g.NavIdTabCounter + 1 + (g.IO.KeyShift ? -1 : 1); 3638 else 3639 g.FocusRequestNextCounterTabStop = g.IO.KeyShift ? -1 : 0; 3640 } 3641 3642 // Turn queued focus request into current one 3643 g.FocusRequestCurrWindow = NULL; 3644 g.FocusRequestCurrCounterRegular = g.FocusRequestCurrCounterTabStop = INT_MAX; 3645 if (g.FocusRequestNextWindow != NULL) 3646 { 3647 ImGuiWindow* window = g.FocusRequestNextWindow; 3648 g.FocusRequestCurrWindow = window; 3649 if (g.FocusRequestNextCounterRegular != INT_MAX && window->DC.FocusCounterRegular != -1) 3650 g.FocusRequestCurrCounterRegular = ImModPositive(g.FocusRequestNextCounterRegular, window->DC.FocusCounterRegular + 1); 3651 if (g.FocusRequestNextCounterTabStop != INT_MAX && window->DC.FocusCounterTabStop != -1) 3652 g.FocusRequestCurrCounterTabStop = ImModPositive(g.FocusRequestNextCounterTabStop, window->DC.FocusCounterTabStop + 1); 3653 g.FocusRequestNextWindow = NULL; 3654 g.FocusRequestNextCounterRegular = g.FocusRequestNextCounterTabStop = INT_MAX; 3655 } 3656 3657 g.NavIdTabCounter = INT_MAX; 3658 } 3659 3660 // 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) 3661 void ImGui::UpdateHoveredWindowAndCaptureFlags() 3662 { 3663 ImGuiContext& g = *GImGui; 3664 3665 // Find the window hovered by mouse: 3666 // - Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow. 3667 // - 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. 3668 // - 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. 3669 bool clear_hovered_windows = false; 3670 FindHoveredWindow(); 3671 3672 // Modal windows prevents mouse from hovering behind them. 3673 ImGuiWindow* modal_window = GetTopMostPopupModal(); 3674 if (modal_window && g.HoveredRootWindow && !IsWindowChildOf(g.HoveredRootWindow, modal_window)) 3675 clear_hovered_windows = true; 3676 3677 // Disabled mouse? 3678 if (g.IO.ConfigFlags & ImGuiConfigFlags_NoMouse) 3679 clear_hovered_windows = true; 3680 3681 // 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. 3682 int mouse_earliest_button_down = -1; 3683 bool mouse_any_down = false; 3684 for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++) 3685 { 3686 if (g.IO.MouseClicked[i]) 3687 g.IO.MouseDownOwned[i] = (g.HoveredWindow != NULL) || (g.OpenPopupStack.Size > 0); 3688 mouse_any_down |= g.IO.MouseDown[i]; 3689 if (g.IO.MouseDown[i]) 3690 if (mouse_earliest_button_down == -1 || g.IO.MouseClickedTime[i] < g.IO.MouseClickedTime[mouse_earliest_button_down]) 3691 mouse_earliest_button_down = i; 3692 } 3693 const bool mouse_avail_to_imgui = (mouse_earliest_button_down == -1) || g.IO.MouseDownOwned[mouse_earliest_button_down]; 3694 3695 // If mouse was first clicked outside of ImGui bounds we also cancel out hovering. 3696 // FIXME: For patterns of drag and drop across OS windows, we may need to rework/remove this test (first committed 311c0ca9 on 2015/02) 3697 const bool mouse_dragging_extern_payload = g.DragDropActive && (g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) != 0; 3698 if (!mouse_avail_to_imgui && !mouse_dragging_extern_payload) 3699 clear_hovered_windows = true; 3700 3701 if (clear_hovered_windows) 3702 g.HoveredWindow = g.HoveredRootWindow = g.HoveredWindowUnderMovingWindow = NULL; 3703 3704 // Update io.WantCaptureMouse for the user application (true = dispatch mouse info to imgui, false = dispatch mouse info to Dear ImGui + app) 3705 if (g.WantCaptureMouseNextFrame != -1) 3706 g.IO.WantCaptureMouse = (g.WantCaptureMouseNextFrame != 0); 3707 else 3708 g.IO.WantCaptureMouse = (mouse_avail_to_imgui && (g.HoveredWindow != NULL || mouse_any_down)) || (g.OpenPopupStack.Size > 0); 3709 3710 // Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to imgui, false = dispatch keyboard info to Dear ImGui + app) 3711 if (g.WantCaptureKeyboardNextFrame != -1) 3712 g.IO.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != 0); 3713 else 3714 g.IO.WantCaptureKeyboard = (g.ActiveId != 0) || (modal_window != NULL); 3715 if (g.IO.NavActive && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard)) 3716 g.IO.WantCaptureKeyboard = true; 3717 3718 // Update io.WantTextInput flag, this is to allow systems without a keyboard (e.g. mobile, hand-held) to show a software keyboard if possible 3719 g.IO.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false; 3720 } 3721 3722 ImGuiKeyModFlags ImGui::GetMergedKeyModFlags() 3723 { 3724 ImGuiContext& g = *GImGui; 3725 ImGuiKeyModFlags key_mod_flags = ImGuiKeyModFlags_None; 3726 if (g.IO.KeyCtrl) { key_mod_flags |= ImGuiKeyModFlags_Ctrl; } 3727 if (g.IO.KeyShift) { key_mod_flags |= ImGuiKeyModFlags_Shift; } 3728 if (g.IO.KeyAlt) { key_mod_flags |= ImGuiKeyModFlags_Alt; } 3729 if (g.IO.KeySuper) { key_mod_flags |= ImGuiKeyModFlags_Super; } 3730 return key_mod_flags; 3731 } 3732 3733 void ImGui::NewFrame() 3734 { 3735 IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?"); 3736 ImGuiContext& g = *GImGui; 3737 3738 #ifdef IMGUI_ENABLE_TEST_ENGINE 3739 ImGuiTestEngineHook_PreNewFrame(&g); 3010 3740 #endif 3011 3741 3012 if ((g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) && (g.IO.BackendFlags & ImGuiBackendFlags_HasGamepad)) 3013 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) 3014 g.NavInputSource = ImGuiInputSource_NavGamepad; 3015 3016 // Update Keyboard->Nav inputs mapping 3017 if (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) 3018 { 3019 #define NAV_MAP_KEY(_KEY, _NAV_INPUT) if (IsKeyDown(g.IO.KeyMap[_KEY])) { g.IO.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_NavKeyboard; } 3020 NAV_MAP_KEY(ImGuiKey_Space, ImGuiNavInput_Activate); 3021 NAV_MAP_KEY(ImGuiKey_Enter, ImGuiNavInput_Input); 3022 NAV_MAP_KEY(ImGuiKey_Escape, ImGuiNavInput_Cancel); 3023 NAV_MAP_KEY(ImGuiKey_LeftArrow, ImGuiNavInput_KeyLeft_); 3024 NAV_MAP_KEY(ImGuiKey_RightArrow, ImGuiNavInput_KeyRight_); 3025 NAV_MAP_KEY(ImGuiKey_UpArrow, ImGuiNavInput_KeyUp_); 3026 NAV_MAP_KEY(ImGuiKey_DownArrow, ImGuiNavInput_KeyDown_); 3027 if (g.IO.KeyCtrl) g.IO.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f; 3028 if (g.IO.KeyShift) g.IO.NavInputs[ImGuiNavInput_TweakFast] = 1.0f; 3029 if (g.IO.KeyAlt) g.IO.NavInputs[ImGuiNavInput_KeyMenu_] = 1.0f; 3030 #undef NAV_MAP_KEY 3031 } 3032 3033 memcpy(g.IO.NavInputsDownDurationPrev, g.IO.NavInputsDownDuration, sizeof(g.IO.NavInputsDownDuration)); 3034 for (int i = 0; i < IM_ARRAYSIZE(g.IO.NavInputs); i++) 3035 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; 3036 3037 // Process navigation init request (select first/default focus) 3038 if (g.NavInitResultId != 0 && (!g.NavDisableHighlight || g.NavInitRequestFromMove)) 3039 { 3040 // Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called) 3041 IM_ASSERT(g.NavWindow); 3042 if (g.NavInitRequestFromMove) 3043 SetNavIDWithRectRel(g.NavInitResultId, g.NavLayer, g.NavInitResultRectRel); 3044 else 3045 SetNavID(g.NavInitResultId, g.NavLayer); 3046 g.NavWindow->NavRectRel[g.NavLayer] = g.NavInitResultRectRel; 3047 } 3048 g.NavInitRequest = false; 3049 g.NavInitRequestFromMove = false; 3050 g.NavInitResultId = 0; 3051 g.NavJustMovedToId = 0; 3052 3053 // Process navigation move request 3054 if (g.NavMoveRequest && (g.NavMoveResultLocal.ID != 0 || g.NavMoveResultOther.ID != 0)) 3055 { 3056 // Select which result to use 3057 ImGuiNavMoveResult* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : &g.NavMoveResultOther; 3058 if (g.NavMoveResultOther.ID != 0 && g.NavMoveResultOther.Window->ParentWindow == g.NavWindow) // Maybe entering a flattened child? In this case solve the tie using the regular scoring rules 3059 if ((g.NavMoveResultOther.DistBox < g.NavMoveResultLocal.DistBox) || (g.NavMoveResultOther.DistBox == g.NavMoveResultLocal.DistBox && g.NavMoveResultOther.DistCenter < g.NavMoveResultLocal.DistCenter)) 3060 result = &g.NavMoveResultOther; 3061 3062 IM_ASSERT(g.NavWindow && result->Window); 3063 3064 // Scroll to keep newly navigated item fully into view 3065 if (g.NavLayer == 0) 3066 NavScrollToBringItemIntoView(result->Window, result->RectRel); 3067 3068 // Apply result from previous frame navigation directional move request 3069 ClearActiveID(); 3070 g.NavWindow = result->Window; 3071 SetNavIDWithRectRel(result->ID, g.NavLayer, result->RectRel); 3072 g.NavJustMovedToId = result->ID; 3073 g.NavMoveFromClampedRefRect = false; 3074 } 3075 3076 // When a forwarded move request failed, we restore the highlight that we disabled during the forward frame 3077 if (g.NavMoveRequestForward == ImGuiNavForward_ForwardActive) 3078 { 3079 IM_ASSERT(g.NavMoveRequest); 3080 if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0) 3081 g.NavDisableHighlight = false; 3082 g.NavMoveRequestForward = ImGuiNavForward_None; 3083 } 3084 3085 // Apply application mouse position movement, after we had a chance to process move request result. 3086 if (g.NavMousePosDirty && g.NavIdIsAlive) 3087 { 3088 // Set mouse position given our knowledge of the navigated item position from last frame 3089 if ((g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) && (g.IO.BackendFlags & ImGuiBackendFlags_HasSetMousePos)) 3090 { 3091 IM_ASSERT(!g.NavDisableHighlight && g.NavDisableMouseHover); 3092 g.IO.MousePos = g.IO.MousePosPrev = NavCalcPreferredRefPos(); 3093 g.IO.WantSetMousePos = true; 3094 } 3095 g.NavMousePosDirty = false; 3096 } 3097 g.NavIdIsAlive = false; 3098 g.NavJustTabbedId = 0; 3099 IM_ASSERT(g.NavLayer == 0 || g.NavLayer == 1); 3100 3101 // 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 3102 if (g.NavWindow) 3103 NavSaveLastChildNavWindow(g.NavWindow); 3104 if (g.NavWindow && g.NavWindow->NavLastChildNavWindow != NULL && g.NavLayer == 0) 3105 g.NavWindow->NavLastChildNavWindow = NULL; 3106 3107 NavUpdateWindowing(); 3108 3109 // Set output flags for user application 3110 bool nav_keyboard_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; 3111 bool nav_gamepad_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (g.IO.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; 3112 g.IO.NavActive = (nav_keyboard_active || nav_gamepad_active) && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs); 3113 g.IO.NavVisible = (g.IO.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL) || g.NavInitRequest; 3114 3115 // Process NavCancel input (to close a popup, get back to parent, clear focus) 3116 if (IsNavInputPressed(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed)) 3117 { 3118 if (g.ActiveId != 0) 3119 { 3120 ClearActiveID(); 3121 } 3122 else if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow) && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow) 3123 { 3124 // Exit child window 3125 ImGuiWindow* child_window = g.NavWindow; 3126 ImGuiWindow* parent_window = g.NavWindow->ParentWindow; 3127 IM_ASSERT(child_window->ChildId != 0); 3128 FocusWindow(parent_window); 3129 SetNavID(child_window->ChildId, 0); 3130 g.NavIdIsAlive = false; 3131 if (g.NavDisableMouseHover) 3132 g.NavMousePosDirty = true; 3133 } 3134 else if (g.OpenPopupStack.Size > 0) 3135 { 3136 // Close open popup/menu 3137 if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal)) 3138 ClosePopupToLevel(g.OpenPopupStack.Size - 1); 3139 } 3140 else if (g.NavLayer != 0) 3141 { 3142 // Leave the "menu" layer 3143 NavRestoreLayer(0); 3144 } 3145 else 3146 { 3147 // Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were 3148 if (g.NavWindow && ((g.NavWindow->Flags & ImGuiWindowFlags_Popup) || !(g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow))) 3149 g.NavWindow->NavLastIds[0] = 0; 3150 g.NavId = 0; 3151 } 3152 } 3153 3154 // Process manual activation request 3155 g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = 0; 3156 if (g.NavId != 0 && !g.NavDisableHighlight && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) 3157 { 3158 bool activate_down = IsNavInputDown(ImGuiNavInput_Activate); 3159 bool activate_pressed = activate_down && IsNavInputPressed(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed); 3160 if (g.ActiveId == 0 && activate_pressed) 3161 g.NavActivateId = g.NavId; 3162 if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_down) 3163 g.NavActivateDownId = g.NavId; 3164 if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_pressed) 3165 g.NavActivatePressedId = g.NavId; 3166 if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && IsNavInputPressed(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed)) 3167 g.NavInputId = g.NavId; 3168 } 3169 if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) 3170 g.NavDisableHighlight = true; 3171 if (g.NavActivateId != 0) 3172 IM_ASSERT(g.NavActivateDownId == g.NavActivateId); 3173 g.NavMoveRequest = false; 3174 3175 // Process programmatic activation request 3176 if (g.NavNextActivateId != 0) 3177 g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = g.NavNextActivateId; 3178 g.NavNextActivateId = 0; 3179 3180 // Initiate directional inputs request 3181 const int allowed_dir_flags = (g.ActiveId == 0) ? ~0 : g.ActiveIdAllowNavDirFlags; 3182 if (g.NavMoveRequestForward == ImGuiNavForward_None) 3183 { 3184 g.NavMoveDir = ImGuiDir_None; 3185 if (g.NavWindow && !g.NavWindowingTarget && allowed_dir_flags && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) 3186 { 3187 if ((allowed_dir_flags & (1 << ImGuiDir_Left)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadLeft, ImGuiNavInput_KeyLeft_, ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Left; 3188 if ((allowed_dir_flags & (1 << ImGuiDir_Right)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadRight, ImGuiNavInput_KeyRight_, ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Right; 3189 if ((allowed_dir_flags & (1 << ImGuiDir_Up)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadUp, ImGuiNavInput_KeyUp_, ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Up; 3190 if ((allowed_dir_flags & (1 << ImGuiDir_Down)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadDown, ImGuiNavInput_KeyDown_, ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Down; 3191 } 3192 } 3193 else 3194 { 3195 // 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) 3196 IM_ASSERT(g.NavMoveDir != ImGuiDir_None); 3197 IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_ForwardQueued); 3198 g.NavMoveRequestForward = ImGuiNavForward_ForwardActive; 3199 } 3200 3201 if (g.NavMoveDir != ImGuiDir_None) 3202 { 3203 g.NavMoveRequest = true; 3204 g.NavMoveDirLast = g.NavMoveDir; 3205 } 3206 3207 // 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 3208 if (g.NavMoveRequest && g.NavId == 0) 3209 { 3210 g.NavInitRequest = g.NavInitRequestFromMove = true; 3211 g.NavInitResultId = 0; 3212 g.NavDisableHighlight = false; 3213 } 3214 3215 NavUpdateAnyRequestFlag(); 3216 3217 // Scrolling 3218 if (g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget) 3219 { 3220 // *Fallback* manual-scroll with NavUp/NavDown when window has no navigable item 3221 ImGuiWindow* window = g.NavWindow; 3222 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. 3223 if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest) 3224 { 3225 if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) 3226 SetWindowScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed)); 3227 if (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) 3228 SetWindowScrollY(window, ImFloor(window->Scroll.y + ((g.NavMoveDir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed)); 3229 } 3230 3231 // *Normal* Manual scroll with NavScrollXXX keys 3232 // Next movement request will clamp the NavId reference rectangle to the visible area, so navigation will resume within those bounds. 3233 ImVec2 scroll_dir = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down, 1.0f / 10.0f, 10.0f); 3234 if (scroll_dir.x != 0.0f && window->ScrollbarX) 3235 { 3236 SetWindowScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed)); 3237 g.NavMoveFromClampedRefRect = true; 3238 } 3239 if (scroll_dir.y != 0.0f) 3240 { 3241 SetWindowScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed)); 3242 g.NavMoveFromClampedRefRect = true; 3243 } 3244 } 3245 3246 // Reset search results 3247 g.NavMoveResultLocal.Clear(); 3248 g.NavMoveResultOther.Clear(); 3249 3250 // 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 3251 if (g.NavMoveRequest && g.NavMoveFromClampedRefRect && g.NavLayer == 0) 3252 { 3253 ImGuiWindow* window = g.NavWindow; 3254 ImRect window_rect_rel(window->InnerRect.Min - window->Pos - ImVec2(1, 1), window->InnerRect.Max - window->Pos + ImVec2(1, 1)); 3255 if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer])) 3256 { 3257 float pad = window->CalcFontSize() * 0.5f; 3258 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 3259 window->NavRectRel[g.NavLayer].ClipWith(window_rect_rel); 3260 g.NavId = 0; 3261 } 3262 g.NavMoveFromClampedRefRect = false; 3263 } 3264 3265 // 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) 3266 ImRect nav_rect_rel = (g.NavWindow && !g.NavWindow->NavRectRel[g.NavLayer].IsInverted()) ? g.NavWindow->NavRectRel[g.NavLayer] : ImRect(0, 0, 0, 0); 3267 g.NavScoringRectScreen = g.NavWindow ? ImRect(g.NavWindow->Pos + nav_rect_rel.Min, g.NavWindow->Pos + nav_rect_rel.Max) : GetViewportRect(); 3268 g.NavScoringRectScreen.Min.x = ImMin(g.NavScoringRectScreen.Min.x + 1.0f, g.NavScoringRectScreen.Max.x); 3269 g.NavScoringRectScreen.Max.x = g.NavScoringRectScreen.Min.x; 3270 IM_ASSERT(!g.NavScoringRectScreen.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allows us to remove extraneous fabsf() calls in NavScoreItem(). 3271 //g.OverlayDrawList.AddRect(g.NavScoringRectScreen.Min, g.NavScoringRectScreen.Max, IM_COL32(255,200,0,255)); // [DEBUG] 3272 g.NavScoringCount = 0; 3273 #if IMGUI_DEBUG_NAV_RECTS 3274 if (g.NavWindow) { for (int layer = 0; layer < 2; layer++) GetOverlayDrawList()->AddRect(g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Min, g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Max, IM_COL32(255, 200, 0, 255)); } // [DEBUG] 3275 if (g.NavWindow) { ImU32 col = (g.NavWindow->HiddenFrames == 0) ? IM_COL32(255, 0, 255, 255) : IM_COL32(255, 0, 0, 255); ImVec2 p = NavCalcPreferredMousePos(); char buf[32]; ImFormatString(buf, 32, "%d", g.NavLayer); g.OverlayDrawList.AddCircleFilled(p, 3.0f, col); g.OverlayDrawList.AddText(NULL, 13.0f, p + ImVec2(8, -4), col, buf); } 3742 // Check and assert for various common IO and Configuration mistakes 3743 ErrorCheckNewFrameSanityChecks(); 3744 3745 // Load settings on first frame, save settings when modified (after a delay) 3746 UpdateSettings(); 3747 3748 g.Time += g.IO.DeltaTime; 3749 g.WithinFrameScope = true; 3750 g.FrameCount += 1; 3751 g.TooltipOverrideCount = 0; 3752 g.WindowsActiveCount = 0; 3753 g.MenusIdSubmittedThisFrame.resize(0); 3754 3755 // Calculate frame-rate for the user, as a purely luxurious feature 3756 g.FramerateSecPerFrameAccum += g.IO.DeltaTime - g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx]; 3757 g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx] = g.IO.DeltaTime; 3758 g.FramerateSecPerFrameIdx = (g.FramerateSecPerFrameIdx + 1) % IM_ARRAYSIZE(g.FramerateSecPerFrame); 3759 g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)IM_ARRAYSIZE(g.FramerateSecPerFrame))) : FLT_MAX; 3760 3761 // Setup current font and draw list shared data 3762 g.IO.Fonts->Locked = true; 3763 SetCurrentFont(GetDefaultFont()); 3764 IM_ASSERT(g.Font->IsLoaded()); 3765 g.DrawListSharedData.ClipRectFullscreen = ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y); 3766 g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol; 3767 g.DrawListSharedData.SetCircleSegmentMaxError(g.Style.CircleSegmentMaxError); 3768 g.DrawListSharedData.InitialFlags = ImDrawListFlags_None; 3769 if (g.Style.AntiAliasedLines) 3770 g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLines; 3771 if (g.Style.AntiAliasedLinesUseTex && !(g.Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoBakedLines)) 3772 g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLinesUseTex; 3773 if (g.Style.AntiAliasedFill) 3774 g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedFill; 3775 if (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) 3776 g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AllowVtxOffset; 3777 3778 g.BackgroundDrawList._ResetForNewFrame(); 3779 g.BackgroundDrawList.PushTextureID(g.IO.Fonts->TexID); 3780 g.BackgroundDrawList.PushClipRectFullScreen(); 3781 3782 g.ForegroundDrawList._ResetForNewFrame(); 3783 g.ForegroundDrawList.PushTextureID(g.IO.Fonts->TexID); 3784 g.ForegroundDrawList.PushClipRectFullScreen(); 3785 3786 // Mark rendering data as invalid to prevent user who may have a handle on it to use it. 3787 g.DrawData.Clear(); 3788 3789 // Drag and drop keep the source ID alive so even if the source disappear our state is consistent 3790 if (g.DragDropActive && g.DragDropPayload.SourceId == g.ActiveId) 3791 KeepAliveID(g.DragDropPayload.SourceId); 3792 3793 // Update HoveredId data 3794 if (!g.HoveredIdPreviousFrame) 3795 g.HoveredIdTimer = 0.0f; 3796 if (!g.HoveredIdPreviousFrame || (g.HoveredId && g.ActiveId == g.HoveredId)) 3797 g.HoveredIdNotActiveTimer = 0.0f; 3798 if (g.HoveredId) 3799 g.HoveredIdTimer += g.IO.DeltaTime; 3800 if (g.HoveredId && g.ActiveId != g.HoveredId) 3801 g.HoveredIdNotActiveTimer += g.IO.DeltaTime; 3802 g.HoveredIdPreviousFrame = g.HoveredId; 3803 g.HoveredId = 0; 3804 g.HoveredIdAllowOverlap = false; 3805 g.HoveredIdDisabled = false; 3806 3807 // Update ActiveId data (clear reference to active widget if the widget isn't alive anymore) 3808 if (g.ActiveIdIsAlive != g.ActiveId && g.ActiveIdPreviousFrame == g.ActiveId && g.ActiveId != 0) 3809 ClearActiveID(); 3810 if (g.ActiveId) 3811 g.ActiveIdTimer += g.IO.DeltaTime; 3812 g.LastActiveIdTimer += g.IO.DeltaTime; 3813 g.ActiveIdPreviousFrame = g.ActiveId; 3814 g.ActiveIdPreviousFrameWindow = g.ActiveIdWindow; 3815 g.ActiveIdPreviousFrameHasBeenEditedBefore = g.ActiveIdHasBeenEditedBefore; 3816 g.ActiveIdIsAlive = 0; 3817 g.ActiveIdHasBeenEditedThisFrame = false; 3818 g.ActiveIdPreviousFrameIsAlive = false; 3819 g.ActiveIdIsJustActivated = false; 3820 if (g.TempInputId != 0 && g.ActiveId != g.TempInputId) 3821 g.TempInputId = 0; 3822 if (g.ActiveId == 0) 3823 { 3824 g.ActiveIdUsingNavDirMask = 0x00; 3825 g.ActiveIdUsingNavInputMask = 0x00; 3826 g.ActiveIdUsingKeyInputMask = 0x00; 3827 } 3828 3829 // Drag and drop 3830 g.DragDropAcceptIdPrev = g.DragDropAcceptIdCurr; 3831 g.DragDropAcceptIdCurr = 0; 3832 g.DragDropAcceptIdCurrRectSurface = FLT_MAX; 3833 g.DragDropWithinSource = false; 3834 g.DragDropWithinTarget = false; 3835 g.DragDropHoldJustPressedId = 0; 3836 3837 // Update keyboard input state 3838 // Synchronize io.KeyMods with individual modifiers io.KeyXXX bools 3839 g.IO.KeyMods = GetMergedKeyModFlags(); 3840 memcpy(g.IO.KeysDownDurationPrev, g.IO.KeysDownDuration, sizeof(g.IO.KeysDownDuration)); 3841 for (int i = 0; i < IM_ARRAYSIZE(g.IO.KeysDown); i++) 3842 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; 3843 3844 // Update gamepad/keyboard navigation 3845 NavUpdate(); 3846 3847 // Update mouse input state 3848 UpdateMouseInputs(); 3849 3850 // Find hovered window 3851 // (needs to be before UpdateMouseMovingWindowNewFrame so we fill g.HoveredWindowUnderMovingWindow on the mouse release frame) 3852 UpdateHoveredWindowAndCaptureFlags(); 3853 3854 // Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering) 3855 UpdateMouseMovingWindowNewFrame(); 3856 3857 // Background darkening/whitening 3858 if (GetTopMostPopupModal() != NULL || (g.NavWindowingTarget != NULL && g.NavWindowingHighlightAlpha > 0.0f)) 3859 g.DimBgRatio = ImMin(g.DimBgRatio + g.IO.DeltaTime * 6.0f, 1.0f); 3860 else 3861 g.DimBgRatio = ImMax(g.DimBgRatio - g.IO.DeltaTime * 10.0f, 0.0f); 3862 3863 g.MouseCursor = ImGuiMouseCursor_Arrow; 3864 g.WantCaptureMouseNextFrame = g.WantCaptureKeyboardNextFrame = g.WantTextInputNextFrame = -1; 3865 g.PlatformImePos = ImVec2(1.0f, 1.0f); // OS Input Method Editor showing on top-left of our window by default 3866 3867 // Mouse wheel scrolling, scale 3868 UpdateMouseWheel(); 3869 3870 // Update legacy TAB focus 3871 UpdateTabFocus(); 3872 3873 // Mark all windows as not visible and compact unused memory. 3874 IM_ASSERT(g.WindowsFocusOrder.Size == g.Windows.Size); 3875 const float memory_compact_start_time = (g.IO.ConfigWindowsMemoryCompactTimer >= 0.0f) ? (float)g.Time - g.IO.ConfigWindowsMemoryCompactTimer : FLT_MAX; 3876 for (int i = 0; i != g.Windows.Size; i++) 3877 { 3878 ImGuiWindow* window = g.Windows[i]; 3879 window->WasActive = window->Active; 3880 window->BeginCount = 0; 3881 window->Active = false; 3882 window->WriteAccessed = false; 3883 3884 // Garbage collect transient buffers of recently unused windows 3885 if (!window->WasActive && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time) 3886 GcCompactTransientWindowBuffers(window); 3887 } 3888 3889 // Closing the focused window restore focus to the first active root window in descending z-order 3890 if (g.NavWindow && !g.NavWindow->WasActive) 3891 FocusTopMostWindowUnderOne(NULL, NULL); 3892 3893 // No window should be open at the beginning of the frame. 3894 // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear. 3895 g.CurrentWindowStack.resize(0); 3896 g.BeginPopupStack.resize(0); 3897 ClosePopupsOverWindow(g.NavWindow, false); 3898 3899 // [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visually select an item and break into its call-stack. 3900 UpdateDebugToolItemPicker(); 3901 3902 // Create implicit/fallback window - which we will only render it if the user has added something to it. 3903 // We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags. 3904 // This fallback is particularly important as it avoid ImGui:: calls from crashing. 3905 g.WithinFrameScopeWithImplicitWindow = true; 3906 SetNextWindowSize(ImVec2(400, 400), ImGuiCond_FirstUseEver); 3907 Begin("Debug##Default"); 3908 IM_ASSERT(g.CurrentWindow->IsFallbackWindow == true); 3909 3910 #ifdef IMGUI_ENABLE_TEST_ENGINE 3911 ImGuiTestEngineHook_PostNewFrame(&g); 3276 3912 #endif 3277 3913 } 3278 3914 3279 static void ImGui::UpdateMovingWindow() 3280 { 3281 ImGuiContext& g = *GImGui; 3282 if (g.MovingWindow != NULL) 3283 { 3284 // We actually want to move the root window. g.MovingWindow == window we clicked on (could be a child window). 3285 // We track it to preserve Focus and so that generally ActiveIdWindow == MovingWindow and ActiveId == MovingWindow->MoveId for consistency. 3286 KeepAliveID(g.ActiveId); 3287 IM_ASSERT(g.MovingWindow && g.MovingWindow->RootWindow); 3288 ImGuiWindow* moving_window = g.MovingWindow->RootWindow; 3289 if (g.IO.MouseDown[0] && IsMousePosValid(&g.IO.MousePos)) 3290 { 3291 ImVec2 pos = g.IO.MousePos - g.ActiveIdClickOffset; 3292 if (moving_window->Pos.x != pos.x || moving_window->Pos.y != pos.y) 3293 { 3294 MarkIniSettingsDirty(moving_window); 3295 SetWindowPos(moving_window, pos, ImGuiCond_Always); 3296 } 3297 FocusWindow(g.MovingWindow); 3298 } 3299 else 3300 { 3301 ClearActiveID(); 3302 g.MovingWindow = NULL; 3303 } 3304 } 3305 else 3306 { 3307 // When clicking/dragging from a window that has the _NoMove flag, we still set the ActiveId in order to prevent hovering others. 3308 if (g.ActiveIdWindow && g.ActiveIdWindow->MoveId == g.ActiveId) 3309 { 3310 KeepAliveID(g.ActiveId); 3311 if (!g.IO.MouseDown[0]) 3312 ClearActiveID(); 3313 } 3314 } 3315 } 3316 3317 static void ImGui::UpdateMouseInputs() 3318 { 3319 ImGuiContext& g = *GImGui; 3320 3321 // If mouse just appeared or disappeared (usually denoted by -FLT_MAX component, but in reality we test for -256000.0f) we cancel out movement in MouseDelta 3322 if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MousePosPrev)) 3323 g.IO.MouseDelta = g.IO.MousePos - g.IO.MousePosPrev; 3324 else 3325 g.IO.MouseDelta = ImVec2(0.0f, 0.0f); 3326 if (g.IO.MouseDelta.x != 0.0f || g.IO.MouseDelta.y != 0.0f) 3327 g.NavDisableMouseHover = false; 3328 3329 g.IO.MousePosPrev = g.IO.MousePos; 3330 for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++) 3331 { 3332 g.IO.MouseClicked[i] = g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] < 0.0f; 3333 g.IO.MouseReleased[i] = !g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] >= 0.0f; 3334 g.IO.MouseDownDurationPrev[i] = g.IO.MouseDownDuration[i]; 3335 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; 3336 g.IO.MouseDoubleClicked[i] = false; 3337 if (g.IO.MouseClicked[i]) 3338 { 3339 if (g.Time - g.IO.MouseClickedTime[i] < g.IO.MouseDoubleClickTime) 3340 { 3341 if (ImLengthSqr(g.IO.MousePos - g.IO.MouseClickedPos[i]) < g.IO.MouseDoubleClickMaxDist * g.IO.MouseDoubleClickMaxDist) 3342 g.IO.MouseDoubleClicked[i] = true; 3343 g.IO.MouseClickedTime[i] = -FLT_MAX; // so the third click isn't turned into a double-click 3344 } 3345 else 3346 { 3347 g.IO.MouseClickedTime[i] = g.Time; 3348 } 3349 g.IO.MouseClickedPos[i] = g.IO.MousePos; 3350 g.IO.MouseDragMaxDistanceAbs[i] = ImVec2(0.0f, 0.0f); 3351 g.IO.MouseDragMaxDistanceSqr[i] = 0.0f; 3352 } 3353 else if (g.IO.MouseDown[i]) 3354 { 3355 ImVec2 mouse_delta = g.IO.MousePos - g.IO.MouseClickedPos[i]; 3356 g.IO.MouseDragMaxDistanceAbs[i].x = ImMax(g.IO.MouseDragMaxDistanceAbs[i].x, mouse_delta.x < 0.0f ? -mouse_delta.x : mouse_delta.x); 3357 g.IO.MouseDragMaxDistanceAbs[i].y = ImMax(g.IO.MouseDragMaxDistanceAbs[i].y, mouse_delta.y < 0.0f ? -mouse_delta.y : mouse_delta.y); 3358 g.IO.MouseDragMaxDistanceSqr[i] = ImMax(g.IO.MouseDragMaxDistanceSqr[i], ImLengthSqr(mouse_delta)); 3359 } 3360 if (g.IO.MouseClicked[i]) // Clicking any mouse button reactivate mouse hovering which may have been deactivated by gamepad/keyboard navigation 3361 g.NavDisableMouseHover = false; 3362 } 3363 } 3364 3365 // 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) 3366 void ImGui::NewFrameUpdateHoveredWindowAndCaptureFlags() 3367 { 3368 ImGuiContext& g = *GImGui; 3369 3370 // Find the window hovered by mouse: 3371 // - Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow. 3372 // - 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. 3373 // - 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. 3374 g.HoveredWindow = (g.MovingWindow && !(g.MovingWindow->Flags & ImGuiWindowFlags_NoInputs)) ? g.MovingWindow : FindHoveredWindow(); 3375 g.HoveredRootWindow = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL; 3376 3377 // Modal windows prevents cursor from hovering behind them. 3378 ImGuiWindow* modal_window = GetFrontMostPopupModal(); 3379 if (modal_window) 3380 if (g.HoveredRootWindow && !IsWindowChildOf(g.HoveredRootWindow, modal_window)) 3381 g.HoveredRootWindow = g.HoveredWindow = NULL; 3382 3383 // Disabled mouse? 3384 if (g.IO.ConfigFlags & ImGuiConfigFlags_NoMouse) 3385 g.HoveredWindow = g.HoveredRootWindow = NULL; 3386 3387 // 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. 3388 int mouse_earliest_button_down = -1; 3389 bool mouse_any_down = false; 3390 for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++) 3391 { 3392 if (g.IO.MouseClicked[i]) 3393 g.IO.MouseDownOwned[i] = (g.HoveredWindow != NULL) || (!g.OpenPopupStack.empty()); 3394 mouse_any_down |= g.IO.MouseDown[i]; 3395 if (g.IO.MouseDown[i]) 3396 if (mouse_earliest_button_down == -1 || g.IO.MouseClickedTime[i] < g.IO.MouseClickedTime[mouse_earliest_button_down]) 3397 mouse_earliest_button_down = i; 3398 } 3399 const bool mouse_avail_to_imgui = (mouse_earliest_button_down == -1) || g.IO.MouseDownOwned[mouse_earliest_button_down]; 3400 3401 // If mouse was first clicked outside of ImGui bounds we also cancel out hovering. 3402 // FIXME: For patterns of drag and drop across OS windows, we may need to rework/remove this test (first committed 311c0ca9 on 2015/02) 3403 const bool mouse_dragging_extern_payload = g.DragDropActive && (g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) != 0; 3404 if (!mouse_avail_to_imgui && !mouse_dragging_extern_payload) 3405 g.HoveredWindow = g.HoveredRootWindow = NULL; 3406 3407 // Update io.WantCaptureMouse for the user application (true = dispatch mouse info to imgui, false = dispatch mouse info to imgui + app) 3408 if (g.WantCaptureMouseNextFrame != -1) 3409 g.IO.WantCaptureMouse = (g.WantCaptureMouseNextFrame != 0); 3410 else 3411 g.IO.WantCaptureMouse = (mouse_avail_to_imgui && (g.HoveredWindow != NULL || mouse_any_down)) || (!g.OpenPopupStack.empty()); 3412 3413 // Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to imgui, false = dispatch keyboard info to imgui + app) 3414 if (g.WantCaptureKeyboardNextFrame != -1) 3415 g.IO.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != 0); 3416 else 3417 g.IO.WantCaptureKeyboard = (g.ActiveId != 0) || (modal_window != NULL); 3418 if (g.IO.NavActive && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard)) 3419 g.IO.WantCaptureKeyboard = true; 3420 3421 // Update io.WantTextInput flag, this is to allow systems without a keyboard (e.g. mobile, hand-held) to show a software keyboard if possible 3422 g.IO.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false; 3423 } 3424 3425 void ImGui::NewFrame() 3426 { 3427 IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?"); 3428 ImGuiContext& g = *GImGui; 3429 3430 // Check user data 3431 // (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) 3432 IM_ASSERT(g.Initialized); 3433 IM_ASSERT(g.IO.DeltaTime >= 0.0f && "Need a positive DeltaTime (zero is tolerated but will cause some timing issues)"); 3434 IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f && "Invalid DisplaySize value"); 3435 IM_ASSERT(g.IO.Fonts->Fonts.Size > 0 && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8() ?"); 3436 IM_ASSERT(g.IO.Fonts->Fonts[0]->IsLoaded() && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8() ?"); 3437 IM_ASSERT(g.Style.CurveTessellationTol > 0.0f && "Invalid style setting"); 3438 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)"); 3439 IM_ASSERT((g.FrameCount == 0 || g.FrameCountEnded == g.FrameCount) && "Forgot to call Render() or EndFrame() at the end of the previous frame?"); 3440 for (int n = 0; n < ImGuiKey_COUNT; n++) 3441 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)"); 3442 3443 // Perform simple check for 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) 3444 if (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) 3445 IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation."); 3446 3447 // Load settings on first frame 3448 if (!g.SettingsLoaded) 3449 { 3450 IM_ASSERT(g.SettingsWindows.empty()); 3451 LoadIniSettingsFromDisk(g.IO.IniFilename); 3452 g.SettingsLoaded = true; 3453 } 3454 3455 // Save settings (with a delay so we don't spam disk too much) 3456 if (g.SettingsDirtyTimer > 0.0f) 3457 { 3458 g.SettingsDirtyTimer -= g.IO.DeltaTime; 3459 if (g.SettingsDirtyTimer <= 0.0f) 3460 SaveIniSettingsToDisk(g.IO.IniFilename); 3461 } 3462 3463 g.Time += g.IO.DeltaTime; 3464 g.FrameCount += 1; 3465 g.TooltipOverrideCount = 0; 3466 g.WindowsActiveCount = 0; 3467 3468 SetCurrentFont(GetDefaultFont()); 3469 IM_ASSERT(g.Font->IsLoaded()); 3470 g.DrawListSharedData.ClipRectFullscreen = ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y); 3471 g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol; 3472 3473 g.OverlayDrawList.Clear(); 3474 g.OverlayDrawList.PushTextureID(g.IO.Fonts->TexID); 3475 g.OverlayDrawList.PushClipRectFullScreen(); 3476 g.OverlayDrawList.Flags = (g.Style.AntiAliasedLines ? ImDrawListFlags_AntiAliasedLines : 0) | (g.Style.AntiAliasedFill ? ImDrawListFlags_AntiAliasedFill : 0); 3477 3478 // Mark rendering data as invalid to prevent user who may have a handle on it to use it 3479 g.DrawData.Clear(); 3480 3481 // Clear reference to active widget if the widget isn't alive anymore 3482 if (!g.HoveredIdPreviousFrame) 3483 g.HoveredIdTimer = 0.0f; 3484 g.HoveredIdPreviousFrame = g.HoveredId; 3485 g.HoveredId = 0; 3486 g.HoveredIdAllowOverlap = false; 3487 if (!g.ActiveIdIsAlive && g.ActiveIdPreviousFrame == g.ActiveId && g.ActiveId != 0) 3488 ClearActiveID(); 3489 if (g.ActiveId) 3490 g.ActiveIdTimer += g.IO.DeltaTime; 3491 g.ActiveIdPreviousFrame = g.ActiveId; 3492 g.ActiveIdIsAlive = false; 3493 g.ActiveIdIsJustActivated = false; 3494 if (g.ScalarAsInputTextId && g.ActiveId != g.ScalarAsInputTextId) 3495 g.ScalarAsInputTextId = 0; 3496 3497 // Elapse drag & drop payload 3498 if (g.DragDropActive && g.DragDropPayload.DataFrameCount + 1 < g.FrameCount) 3499 { 3500 ClearDragDrop(); 3501 g.DragDropPayloadBufHeap.clear(); 3502 memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal)); 3503 } 3504 g.DragDropAcceptIdPrev = g.DragDropAcceptIdCurr; 3505 g.DragDropAcceptIdCurr = 0; 3506 g.DragDropAcceptIdCurrRectSurface = FLT_MAX; 3507 3508 // Update keyboard input state 3509 memcpy(g.IO.KeysDownDurationPrev, g.IO.KeysDownDuration, sizeof(g.IO.KeysDownDuration)); 3510 for (int i = 0; i < IM_ARRAYSIZE(g.IO.KeysDown); i++) 3511 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; 3512 3513 // Update gamepad/keyboard directional navigation 3514 NavUpdate(); 3515 3516 // Update mouse input state 3517 UpdateMouseInputs(); 3518 3519 // Calculate frame-rate for the user, as a purely luxurious feature 3520 g.FramerateSecPerFrameAccum += g.IO.DeltaTime - g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx]; 3521 g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx] = g.IO.DeltaTime; 3522 g.FramerateSecPerFrameIdx = (g.FramerateSecPerFrameIdx + 1) % IM_ARRAYSIZE(g.FramerateSecPerFrame); 3523 g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)IM_ARRAYSIZE(g.FramerateSecPerFrame))) : FLT_MAX; 3524 3525 // Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering) 3526 UpdateMovingWindow(); 3527 NewFrameUpdateHoveredWindowAndCaptureFlags(); 3528 3529 if (GetFrontMostPopupModal() != NULL) 3530 g.ModalWindowDarkeningRatio = ImMin(g.ModalWindowDarkeningRatio + g.IO.DeltaTime * 6.0f, 1.0f); 3531 else 3532 g.ModalWindowDarkeningRatio = 0.0f; 3533 3534 g.MouseCursor = ImGuiMouseCursor_Arrow; 3535 g.WantCaptureMouseNextFrame = g.WantCaptureKeyboardNextFrame = g.WantTextInputNextFrame = -1; 3536 g.PlatformImePos = ImVec2(1.0f, 1.0f); // OS Input Method Editor showing on top-left of our window by default 3537 3538 // Mouse wheel scrolling, scale 3539 if (g.HoveredWindow && !g.HoveredWindow->Collapsed && (g.IO.MouseWheel != 0.0f || g.IO.MouseWheelH != 0.0f)) 3540 { 3541 // 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). 3542 ImGuiWindow* window = g.HoveredWindow; 3543 ImGuiWindow* scroll_window = window; 3544 while ((scroll_window->Flags & ImGuiWindowFlags_ChildWindow) && (scroll_window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(scroll_window->Flags & ImGuiWindowFlags_NoScrollbar) && !(scroll_window->Flags & ImGuiWindowFlags_NoInputs) && scroll_window->ParentWindow) 3545 scroll_window = scroll_window->ParentWindow; 3546 const bool scroll_allowed = !(scroll_window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(scroll_window->Flags & ImGuiWindowFlags_NoInputs); 3547 3548 if (g.IO.MouseWheel != 0.0f) 3549 { 3550 if (g.IO.KeyCtrl && g.IO.FontAllowUserScaling) 3551 { 3552 // Zoom / Scale window 3553 const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f); 3554 const float scale = new_font_scale / window->FontWindowScale; 3555 window->FontWindowScale = new_font_scale; 3556 3557 const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size; 3558 window->Pos += offset; 3559 window->Size *= scale; 3560 window->SizeFull *= scale; 3561 } 3562 else if (!g.IO.KeyCtrl && scroll_allowed) 3563 { 3564 // Mouse wheel vertical scrolling 3565 float scroll_amount = 5 * scroll_window->CalcFontSize(); 3566 scroll_amount = (float)(int)ImMin(scroll_amount, (scroll_window->ContentsRegionRect.GetHeight() + scroll_window->WindowPadding.y * 2.0f) * 0.67f); 3567 SetWindowScrollY(scroll_window, scroll_window->Scroll.y - g.IO.MouseWheel * scroll_amount); 3568 } 3569 } 3570 if (g.IO.MouseWheelH != 0.0f && scroll_allowed) 3571 { 3572 // Mouse wheel horizontal scrolling (for hardware that supports it) 3573 float scroll_amount = scroll_window->CalcFontSize(); 3574 if (!g.IO.KeyCtrl && !(window->Flags & ImGuiWindowFlags_NoScrollWithMouse)) 3575 SetWindowScrollX(window, window->Scroll.x - g.IO.MouseWheelH * scroll_amount); 3576 } 3577 } 3578 3579 // Pressing TAB activate widget focus 3580 if (g.ActiveId == 0 && g.NavWindow != NULL && g.NavWindow->Active && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab, false)) 3581 { 3582 if (g.NavId != 0 && g.NavIdTabCounter != INT_MAX) 3583 g.NavWindow->FocusIdxTabRequestNext = g.NavIdTabCounter + 1 + (g.IO.KeyShift ? -1 : 1); 3584 else 3585 g.NavWindow->FocusIdxTabRequestNext = g.IO.KeyShift ? -1 : 0; 3586 } 3587 g.NavIdTabCounter = INT_MAX; 3588 3589 // Mark all windows as not visible 3590 for (int i = 0; i != g.Windows.Size; i++) 3591 { 3592 ImGuiWindow* window = g.Windows[i]; 3593 window->WasActive = window->Active; 3594 window->Active = false; 3595 window->WriteAccessed = false; 3596 } 3597 3598 // Closing the focused window restore focus to the first active root window in descending z-order 3599 if (g.NavWindow && !g.NavWindow->WasActive) 3600 FocusFrontMostActiveWindow(NULL); 3601 3602 // No window should be open at the beginning of the frame. 3603 // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear. 3604 g.CurrentWindowStack.resize(0); 3605 g.CurrentPopupStack.resize(0); 3606 ClosePopupsOverWindow(g.NavWindow); 3607 3608 // Create implicit window - we will only render it if the user has added something to it. 3609 // We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags. 3610 SetNextWindowSize(ImVec2(400, 400), ImGuiCond_FirstUseEver); 3611 Begin("Debug##Default"); 3612 } 3613 3614 static void* SettingsHandlerWindow_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name) 3615 { 3616 ImGuiWindowSettings* settings = ImGui::FindWindowSettings(ImHash(name, 0)); 3617 if (!settings) 3618 settings = AddWindowSettings(name); 3619 return (void*)settings; 3620 } 3621 3622 static void SettingsHandlerWindow_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line) 3623 { 3624 ImGuiWindowSettings* settings = (ImGuiWindowSettings*)entry; 3625 float x, y; 3626 int i; 3627 if (sscanf(line, "Pos=%f,%f", &x, &y) == 2) settings->Pos = ImVec2(x, y); 3628 else if (sscanf(line, "Size=%f,%f", &x, &y) == 2) settings->Size = ImMax(ImVec2(x, y), GImGui->Style.WindowMinSize); 3629 else if (sscanf(line, "Collapsed=%d", &i) == 1) settings->Collapsed = (i != 0); 3630 } 3631 3632 static void SettingsHandlerWindow_WriteAll(ImGuiContext* imgui_ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf) 3633 { 3634 // Gather data from windows that were active during this session 3635 ImGuiContext& g = *imgui_ctx; 3636 for (int i = 0; i != g.Windows.Size; i++) 3637 { 3638 ImGuiWindow* window = g.Windows[i]; 3639 if (window->Flags & ImGuiWindowFlags_NoSavedSettings) 3640 continue; 3641 ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID); 3642 if (!settings) 3643 settings = AddWindowSettings(window->Name); 3644 settings->Pos = window->Pos; 3645 settings->Size = window->SizeFull; 3646 settings->Collapsed = window->Collapsed; 3647 } 3648 3649 // Write a buffer 3650 // If a window wasn't opened in this session we preserve its settings 3651 buf->reserve(buf->size() + g.SettingsWindows.Size * 96); // ballpark reserve 3652 for (int i = 0; i != g.SettingsWindows.Size; i++) 3653 { 3654 const ImGuiWindowSettings* settings = &g.SettingsWindows[i]; 3655 if (settings->Pos.x == FLT_MAX) 3656 continue; 3657 const char* name = settings->Name; 3658 if (const char* p = strstr(name, "###")) // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID() 3659 name = p; 3660 buf->appendf("[%s][%s]\n", handler->TypeName, name); 3661 buf->appendf("Pos=%d,%d\n", (int)settings->Pos.x, (int)settings->Pos.y); 3662 buf->appendf("Size=%d,%d\n", (int)settings->Size.x, (int)settings->Size.y); 3663 buf->appendf("Collapsed=%d\n", settings->Collapsed); 3664 buf->appendf("\n"); 3665 } 3915 // [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visually select an item and break into its call-stack. 3916 void ImGui::UpdateDebugToolItemPicker() 3917 { 3918 ImGuiContext& g = *GImGui; 3919 g.DebugItemPickerBreakId = 0; 3920 if (g.DebugItemPickerActive) 3921 { 3922 const ImGuiID hovered_id = g.HoveredIdPreviousFrame; 3923 ImGui::SetMouseCursor(ImGuiMouseCursor_Hand); 3924 if (ImGui::IsKeyPressedMap(ImGuiKey_Escape)) 3925 g.DebugItemPickerActive = false; 3926 if (ImGui::IsMouseClicked(0) && hovered_id) 3927 { 3928 g.DebugItemPickerBreakId = hovered_id; 3929 g.DebugItemPickerActive = false; 3930 } 3931 ImGui::SetNextWindowBgAlpha(0.60f); 3932 ImGui::BeginTooltip(); 3933 ImGui::Text("HoveredId: 0x%08X", hovered_id); 3934 ImGui::Text("Press ESC to abort picking."); 3935 ImGui::TextColored(GetStyleColorVec4(hovered_id ? ImGuiCol_Text : ImGuiCol_TextDisabled), "Click to break in debugger!"); 3936 ImGui::EndTooltip(); 3937 } 3666 3938 } 3667 3939 3668 3940 void ImGui::Initialize(ImGuiContext* context) 3669 3941 { 3670 ImGuiContext& g = *context; 3671 IM_ASSERT(!g.Initialized && !g.SettingsLoaded); 3672 g.LogClipboard = IM_NEW(ImGuiTextBuffer)(); 3673 3674 // Add .ini handle for ImGuiWindow type 3675 ImGuiSettingsHandler ini_handler; 3676 ini_handler.TypeName = "Window"; 3677 ini_handler.TypeHash = ImHash("Window", 0, 0); 3678 ini_handler.ReadOpenFn = SettingsHandlerWindow_ReadOpen; 3679 ini_handler.ReadLineFn = SettingsHandlerWindow_ReadLine; 3680 ini_handler.WriteAllFn = SettingsHandlerWindow_WriteAll; 3681 g.SettingsHandlers.push_front(ini_handler); 3682 3683 g.Initialized = true; 3942 ImGuiContext& g = *context; 3943 IM_ASSERT(!g.Initialized && !g.SettingsLoaded); 3944 3945 // Add .ini handle for ImGuiWindow type 3946 { 3947 ImGuiSettingsHandler ini_handler; 3948 ini_handler.TypeName = "Window"; 3949 ini_handler.TypeHash = ImHashStr("Window"); 3950 ini_handler.ClearAllFn = WindowSettingsHandler_ClearAll; 3951 ini_handler.ReadOpenFn = WindowSettingsHandler_ReadOpen; 3952 ini_handler.ReadLineFn = WindowSettingsHandler_ReadLine; 3953 ini_handler.ApplyAllFn = WindowSettingsHandler_ApplyAll; 3954 ini_handler.WriteAllFn = WindowSettingsHandler_WriteAll; 3955 g.SettingsHandlers.push_back(ini_handler); 3956 } 3957 3958 #ifdef IMGUI_HAS_TABLE 3959 // Add .ini handle for ImGuiTable type 3960 { 3961 ImGuiSettingsHandler ini_handler; 3962 ini_handler.TypeName = "Table"; 3963 ini_handler.TypeHash = ImHashStr("Table"); 3964 ini_handler.ReadOpenFn = TableSettingsHandler_ReadOpen; 3965 ini_handler.ReadLineFn = TableSettingsHandler_ReadLine; 3966 ini_handler.WriteAllFn = TableSettingsHandler_WriteAll; 3967 g.SettingsHandlers.push_back(ini_handler); 3968 } 3969 #endif // #ifdef IMGUI_HAS_TABLE 3970 3971 #ifdef IMGUI_HAS_DOCK 3972 #endif // #ifdef IMGUI_HAS_DOCK 3973 3974 g.Initialized = true; 3684 3975 } 3685 3976 … … 3687 3978 void ImGui::Shutdown(ImGuiContext* context) 3688 3979 { 3689 ImGuiContext& g = *context; 3690 3691 // 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) 3692 if (g.IO.Fonts && g.FontAtlasOwnedByContext) 3693 IM_DELETE(g.IO.Fonts); 3694 g.IO.Fonts = NULL; 3695 3696 // Cleanup of other data are conditional on actually having initialize ImGui. 3697 if (!g.Initialized) 3698 return; 3699 3700 // Save settings (unless we haven't attempted to load them: CreateContext/DestroyContext without a call to NewFrame shouldn't save an empty file) 3701 if (g.SettingsLoaded) 3702 SaveIniSettingsToDisk(g.IO.IniFilename); 3703 3704 // Clear everything else 3705 for (int i = 0; i < g.Windows.Size; i++) 3706 IM_DELETE(g.Windows[i]); 3707 g.Windows.clear(); 3708 g.WindowsSortBuffer.clear(); 3709 g.CurrentWindow = NULL; 3710 g.CurrentWindowStack.clear(); 3711 g.WindowsById.Clear(); 3712 g.NavWindow = NULL; 3713 g.HoveredWindow = NULL; 3714 g.HoveredRootWindow = NULL; 3715 g.ActiveIdWindow = NULL; 3716 g.MovingWindow = NULL; 3717 g.ColorModifiers.clear(); 3718 g.StyleModifiers.clear(); 3719 g.FontStack.clear(); 3720 g.OpenPopupStack.clear(); 3721 g.CurrentPopupStack.clear(); 3722 g.DrawDataBuilder.ClearFreeMemory(); 3723 g.OverlayDrawList.ClearFreeMemory(); 3724 g.PrivateClipboard.clear(); 3725 g.InputTextState.Text.clear(); 3726 g.InputTextState.InitialText.clear(); 3727 g.InputTextState.TempTextBuffer.clear(); 3728 3729 for (int i = 0; i < g.SettingsWindows.Size; i++) 3730 IM_DELETE(g.SettingsWindows[i].Name); 3731 g.SettingsWindows.clear(); 3732 g.SettingsHandlers.clear(); 3733 3734 if (g.LogFile && g.LogFile != stdout) 3735 { 3736 fclose(g.LogFile); 3737 g.LogFile = NULL; 3738 } 3739 if (g.LogClipboard) 3740 IM_DELETE(g.LogClipboard); 3741 g.LogClipboard = NULL; 3742 3743 g.Initialized = false; 3744 } 3745 3746 ImGuiWindowSettings* ImGui::FindWindowSettings(ImGuiID id) 3747 { 3748 ImGuiContext& g = *GImGui; 3749 for (int i = 0; i != g.SettingsWindows.Size; i++) 3750 if (g.SettingsWindows[i].Id == id) 3751 return &g.SettingsWindows[i]; 3752 return NULL; 3753 } 3754 3755 static ImGuiWindowSettings* AddWindowSettings(const char* name) 3756 { 3757 ImGuiContext& g = *GImGui; 3758 g.SettingsWindows.push_back(ImGuiWindowSettings()); 3759 ImGuiWindowSettings* settings = &g.SettingsWindows.back(); 3760 settings->Name = ImStrdup(name); 3761 settings->Id = ImHash(name, 0); 3762 return settings; 3763 } 3764 3765 static void LoadIniSettingsFromDisk(const char* ini_filename) 3766 { 3767 if (!ini_filename) 3768 return; 3769 char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", NULL, +1); 3770 if (!file_data) 3771 return; 3772 LoadIniSettingsFromMemory(file_data); 3773 ImGui::MemFree(file_data); 3774 } 3775 3776 ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name) 3777 { 3778 ImGuiContext& g = *GImGui; 3779 const ImGuiID type_hash = ImHash(type_name, 0, 0); 3780 for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) 3781 if (g.SettingsHandlers[handler_n].TypeHash == type_hash) 3782 return &g.SettingsHandlers[handler_n]; 3783 return NULL; 3784 } 3785 3786 // Zero-tolerance, no error reporting, cheap .ini parsing 3787 static void LoadIniSettingsFromMemory(const char* buf_readonly) 3788 { 3789 // For convenience and to make the code simpler, we'll write zero terminators inside the buffer. So let's create a writable copy. 3790 char* buf = ImStrdup(buf_readonly); 3791 char* buf_end = buf + strlen(buf); 3792 3793 ImGuiContext& g = *GImGui; 3794 void* entry_data = NULL; 3795 ImGuiSettingsHandler* entry_handler = NULL; 3796 3797 char* line_end = NULL; 3798 for (char* line = buf; line < buf_end; line = line_end + 1) 3799 { 3800 // Skip new lines markers, then find end of the line 3801 while (*line == '\n' || *line == '\r') 3802 line++; 3803 line_end = line; 3804 while (line_end < buf_end && *line_end != '\n' && *line_end != '\r') 3805 line_end++; 3806 line_end[0] = 0; 3807 3808 if (line[0] == '[' && line_end > line && line_end[-1] == ']') 3809 { 3810 // Parse "[Type][Name]". Note that 'Name' can itself contains [] characters, which is acceptable with the current format and parsing code. 3811 line_end[-1] = 0; 3812 const char* name_end = line_end - 1; 3813 const char* type_start = line + 1; 3814 char* type_end = (char*)(intptr_t)ImStrchrRange(type_start, name_end, ']'); 3815 const char* name_start = type_end ? ImStrchrRange(type_end + 1, name_end, '[') : NULL; 3816 if (!type_end || !name_start) 3817 { 3818 name_start = type_start; // Import legacy entries that have no type 3819 type_start = "Window"; 3820 } 3821 else 3822 { 3823 *type_end = 0; // Overwrite first ']' 3824 name_start++; // Skip second '[' 3825 } 3826 entry_handler = ImGui::FindSettingsHandler(type_start); 3827 entry_data = entry_handler ? entry_handler->ReadOpenFn(&g, entry_handler, name_start) : NULL; 3828 } 3829 else if (entry_handler != NULL && entry_data != NULL) 3830 { 3831 // Let type handler parse the line 3832 entry_handler->ReadLineFn(&g, entry_handler, entry_data, line); 3833 } 3834 } 3835 ImGui::MemFree(buf); 3836 g.SettingsLoaded = true; 3837 } 3838 3839 static void SaveIniSettingsToDisk(const char* ini_filename) 3840 { 3841 ImGuiContext& g = *GImGui; 3842 g.SettingsDirtyTimer = 0.0f; 3843 if (!ini_filename) 3844 return; 3845 3846 ImVector<char> buf; 3847 SaveIniSettingsToMemory(buf); 3848 3849 FILE* f = ImFileOpen(ini_filename, "wt"); 3850 if (!f) 3851 return; 3852 fwrite(buf.Data, sizeof(char), (size_t)buf.Size, f); 3853 fclose(f); 3854 } 3855 3856 static void SaveIniSettingsToMemory(ImVector<char>& out_buf) 3857 { 3858 ImGuiContext& g = *GImGui; 3859 g.SettingsDirtyTimer = 0.0f; 3860 3861 ImGuiTextBuffer buf; 3862 for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) 3863 { 3864 ImGuiSettingsHandler* handler = &g.SettingsHandlers[handler_n]; 3865 handler->WriteAllFn(&g, handler, &buf); 3866 } 3867 3868 buf.Buf.pop_back(); // Remove extra zero-terminator used by ImGuiTextBuffer 3869 out_buf.swap(buf.Buf); 3870 } 3871 3872 void ImGui::MarkIniSettingsDirty() 3873 { 3874 ImGuiContext& g = *GImGui; 3875 if (g.SettingsDirtyTimer <= 0.0f) 3876 g.SettingsDirtyTimer = g.IO.IniSavingRate; 3877 } 3878 3879 static void MarkIniSettingsDirty(ImGuiWindow* window) 3880 { 3881 ImGuiContext& g = *GImGui; 3882 if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings)) 3883 if (g.SettingsDirtyTimer <= 0.0f) 3884 g.SettingsDirtyTimer = g.IO.IniSavingRate; 3980 // 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) 3981 ImGuiContext& g = *context; 3982 if (g.IO.Fonts && g.FontAtlasOwnedByContext) 3983 { 3984 g.IO.Fonts->Locked = false; 3985 IM_DELETE(g.IO.Fonts); 3986 } 3987 g.IO.Fonts = NULL; 3988 3989 // Cleanup of other data are conditional on actually having initialized Dear ImGui. 3990 if (!g.Initialized) 3991 return; 3992 3993 // Save settings (unless we haven't attempted to load them: CreateContext/DestroyContext without a call to NewFrame shouldn't save an empty file) 3994 if (g.SettingsLoaded && g.IO.IniFilename != NULL) 3995 { 3996 ImGuiContext* backup_context = GImGui; 3997 SetCurrentContext(context); 3998 SaveIniSettingsToDisk(g.IO.IniFilename); 3999 SetCurrentContext(backup_context); 4000 } 4001 4002 // Notify hooked test engine, if any 4003 #ifdef IMGUI_ENABLE_TEST_ENGINE 4004 ImGuiTestEngineHook_Shutdown(context); 4005 #endif 4006 4007 // Clear everything else 4008 for (int i = 0; i < g.Windows.Size; i++) 4009 IM_DELETE(g.Windows[i]); 4010 g.Windows.clear(); 4011 g.WindowsFocusOrder.clear(); 4012 g.WindowsTempSortBuffer.clear(); 4013 g.CurrentWindow = NULL; 4014 g.CurrentWindowStack.clear(); 4015 g.WindowsById.Clear(); 4016 g.NavWindow = NULL; 4017 g.HoveredWindow = g.HoveredRootWindow = g.HoveredWindowUnderMovingWindow = NULL; 4018 g.ActiveIdWindow = g.ActiveIdPreviousFrameWindow = NULL; 4019 g.MovingWindow = NULL; 4020 g.ColorModifiers.clear(); 4021 g.StyleModifiers.clear(); 4022 g.FontStack.clear(); 4023 g.OpenPopupStack.clear(); 4024 g.BeginPopupStack.clear(); 4025 g.DrawDataBuilder.ClearFreeMemory(); 4026 g.BackgroundDrawList._ClearFreeMemory(); 4027 g.ForegroundDrawList._ClearFreeMemory(); 4028 4029 g.TabBars.Clear(); 4030 g.CurrentTabBarStack.clear(); 4031 g.ShrinkWidthBuffer.clear(); 4032 4033 g.ClipboardHandlerData.clear(); 4034 g.MenusIdSubmittedThisFrame.clear(); 4035 g.InputTextState.ClearFreeMemory(); 4036 4037 g.SettingsWindows.clear(); 4038 g.SettingsHandlers.clear(); 4039 4040 if (g.LogFile) 4041 { 4042 #ifndef IMGUI_DISABLE_TTY_FUNCTIONS 4043 if (g.LogFile != stdout) 4044 #endif 4045 ImFileClose(g.LogFile); 4046 g.LogFile = NULL; 4047 } 4048 g.LogBuffer.clear(); 4049 4050 g.Initialized = false; 3885 4051 } 3886 4052 … … 3888 4054 static int IMGUI_CDECL ChildWindowComparer(const void* lhs, const void* rhs) 3889 4055 { 3890 const ImGuiWindow* const a = *(const ImGuiWindow* const *)lhs;3891 const ImGuiWindow* const b = *(const ImGuiWindow* const *)rhs;3892 if (int d = (a->Flags & ImGuiWindowFlags_Popup) - (b->Flags & ImGuiWindowFlags_Popup))3893 return d;3894 if (int d = (a->Flags & ImGuiWindowFlags_Tooltip) - (b->Flags & ImGuiWindowFlags_Tooltip))3895 return d;3896 return (a->BeginOrderWithinParent - b->BeginOrderWithinParent);3897 } 3898 3899 static void AddWindowToSort edBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window)3900 { 3901 out_sorted_windows->push_back(window);3902 if (window->Active)3903 {3904 int count = window->DC.ChildWindows.Size;3905 if (count > 1)3906 qsort(window->DC.ChildWindows.begin(), (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer);3907 for (int i = 0; i < count; i++)3908 {3909 ImGuiWindow* child = window->DC.ChildWindows[i];3910 if (child->Active)3911 AddWindowToSortedBuffer(out_sorted_windows, child);3912 }3913 }4056 const ImGuiWindow* const a = *(const ImGuiWindow* const *)lhs; 4057 const ImGuiWindow* const b = *(const ImGuiWindow* const *)rhs; 4058 if (int d = (a->Flags & ImGuiWindowFlags_Popup) - (b->Flags & ImGuiWindowFlags_Popup)) 4059 return d; 4060 if (int d = (a->Flags & ImGuiWindowFlags_Tooltip) - (b->Flags & ImGuiWindowFlags_Tooltip)) 4061 return d; 4062 return (a->BeginOrderWithinParent - b->BeginOrderWithinParent); 4063 } 4064 4065 static void AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window) 4066 { 4067 out_sorted_windows->push_back(window); 4068 if (window->Active) 4069 { 4070 int count = window->DC.ChildWindows.Size; 4071 if (count > 1) 4072 ImQsort(window->DC.ChildWindows.Data, (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer); 4073 for (int i = 0; i < count; i++) 4074 { 4075 ImGuiWindow* child = window->DC.ChildWindows[i]; 4076 if (child->Active) 4077 AddWindowToSortBuffer(out_sorted_windows, child); 4078 } 4079 } 3914 4080 } 3915 4081 3916 4082 static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* draw_list) 3917 4083 { 3918 if (draw_list->CmdBuffer.empty()) 3919 return; 3920 3921 // Remove trailing command if unused 3922 ImDrawCmd& last_cmd = draw_list->CmdBuffer.back(); 3923 if (last_cmd.ElemCount == 0 && last_cmd.UserCallback == NULL) 3924 { 3925 draw_list->CmdBuffer.pop_back(); 3926 if (draw_list->CmdBuffer.empty()) 3927 return; 3928 } 3929 3930 // 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. 3931 IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size); 3932 IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size); 3933 IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size); 3934 3935 // Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window) 3936 // If this assert triggers because you are drawing lots of stuff manually: 3937 // 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. 3938 // 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. 3939 // 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: 3940 // glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset); 3941 // 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. 3942 // 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. 3943 if (sizeof(ImDrawIdx) == 2) 3944 IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above"); 3945 3946 out_list->push_back(draw_list); 4084 // Remove trailing command if unused. 4085 // Technically we could return directly instead of popping, but this make things looks neat in Metrics window as well. 4086 draw_list->_PopUnusedDrawCmd(); 4087 if (draw_list->CmdBuffer.Size == 0) 4088 return; 4089 4090 // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc. 4091 // May trigger for you if you are using PrimXXX functions incorrectly. 4092 IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size); 4093 IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size); 4094 if (!(draw_list->Flags & ImDrawListFlags_AllowVtxOffset)) 4095 IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size); 4096 4097 // Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window) 4098 // If this assert triggers because you are drawing lots of stuff manually: 4099 // - First, make sure you are coarse clipping yourself and not trying to draw many things outside visible bounds. 4100 // Be mindful that the ImDrawList API doesn't filter vertices. Use the Metrics window to inspect draw list contents. 4101 // - If you want large meshes with more than 64K vertices, you can either: 4102 // (A) Handle the ImDrawCmd::VtxOffset value in your renderer back-end, and set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset'. 4103 // Most example back-ends already support this from 1.71. Pre-1.71 back-ends won't. 4104 // Some graphics API such as GL ES 1/2 don't have a way to offset the starting vertex so it is not supported for them. 4105 // (B) Or handle 32-bit indices in your renderer back-end, and uncomment '#define ImDrawIdx unsigned int' line in imconfig.h. 4106 // Most example back-ends already support this. For example, the OpenGL example code detect index size at compile-time: 4107 // glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset); 4108 // Your own engine or render API may use different parameters or function calls to specify index sizes. 4109 // 2 and 4 bytes indices are generally supported by most graphics API. 4110 // - If for some reason neither of those solutions works for you, a workaround is to call BeginChild()/EndChild() before reaching 4111 // the 64K limit to split your draw commands in multiple draw lists. 4112 if (sizeof(ImDrawIdx) == 2) 4113 IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above"); 4114 4115 out_list->push_back(draw_list); 3947 4116 } 3948 4117 3949 4118 static void AddWindowToDrawData(ImVector<ImDrawList*>* out_render_list, ImGuiWindow* window) 3950 4119 { 3951 AddDrawListToDrawData(out_render_list, window->DrawList);3952 for (int i = 0; i < window->DC.ChildWindows.Size; i++)3953 {3954 ImGuiWindow* child = window->DC.ChildWindows[i];3955 if (child->Active && child->HiddenFrames == 0) // clipped children may have been marked not active3956 AddWindowToDrawData(out_render_list, child);3957 }3958 } 3959 3960 static void AddWindowToDrawDataSelectLayer(ImGuiWindow* window) 3961 { 3962 ImGuiContext& g = *GImGui; 3963 g.IO.MetricsActiveWindows++; 3964 if (window->Flags & ImGuiWindowFlags_Tooltip) 3965 AddWindowToDrawData(&g.DrawDataBuilder.Layers[1], window);3966 else3967 AddWindowToDrawData(&g.DrawDataBuilder.Layers[0], window);4120 ImGuiContext& g = *GImGui; 4121 g.IO.MetricsRenderWindows++; 4122 AddDrawListToDrawData(out_render_list, window->DrawList); 4123 for (int i = 0; i < window->DC.ChildWindows.Size; i++) 4124 { 4125 ImGuiWindow* child = window->DC.ChildWindows[i]; 4126 if (IsWindowActiveAndVisible(child)) // clipped children may have been marked not active 4127 AddWindowToDrawData(out_render_list, child); 4128 } 4129 } 4130 4131 // Layer is locked for the root window, however child windows may use a different viewport (e.g. extruding menu) 4132 static void AddRootWindowToDrawData(ImGuiWindow* window) 4133 { 4134 ImGuiContext& g = *GImGui; 4135 int layer = (window->Flags & ImGuiWindowFlags_Tooltip) ? 1 : 0; 4136 AddWindowToDrawData(&g.DrawDataBuilder.Layers[layer], window); 3968 4137 } 3969 4138 3970 4139 void ImDrawDataBuilder::FlattenIntoSingleLayer() 3971 4140 { 3972 int n = Layers[0].Size; 3973 int size = n; 3974 for (int i = 1; i < IM_ARRAYSIZE(Layers); i++) 3975 size += Layers[i].Size; 3976 Layers[0].resize(size); 3977 for (int layer_n = 1; layer_n < IM_ARRAYSIZE(Layers); layer_n++) 3978 { 3979 ImVector<ImDrawList*>& layer = Layers[layer_n]; 3980 if (layer.empty()) 3981 continue; 3982 memcpy(&Layers[0][n], &layer[0], layer.Size * sizeof(ImDrawList*)); 3983 n += layer.Size; 3984 layer.resize(0); 3985 } 3986 } 3987 3988 static void SetupDrawData(ImVector<ImDrawList*>* draw_lists, ImDrawData* out_draw_data) 3989 { 3990 out_draw_data->Valid = true; 3991 out_draw_data->CmdLists = (draw_lists->Size > 0) ? draw_lists->Data : NULL; 3992 out_draw_data->CmdListsCount = draw_lists->Size; 3993 out_draw_data->TotalVtxCount = out_draw_data->TotalIdxCount = 0; 3994 for (int n = 0; n < draw_lists->Size; n++) 3995 { 3996 out_draw_data->TotalVtxCount += draw_lists->Data[n]->VtxBuffer.Size; 3997 out_draw_data->TotalIdxCount += draw_lists->Data[n]->IdxBuffer.Size; 3998 } 3999 } 4000 4001 // 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. 4141 int n = Layers[0].Size; 4142 int size = n; 4143 for (int i = 1; i < IM_ARRAYSIZE(Layers); i++) 4144 size += Layers[i].Size; 4145 Layers[0].resize(size); 4146 for (int layer_n = 1; layer_n < IM_ARRAYSIZE(Layers); layer_n++) 4147 { 4148 ImVector<ImDrawList*>& layer = Layers[layer_n]; 4149 if (layer.empty()) 4150 continue; 4151 memcpy(&Layers[0][n], &layer[0], layer.Size * sizeof(ImDrawList*)); 4152 n += layer.Size; 4153 layer.resize(0); 4154 } 4155 } 4156 4157 static void SetupDrawData(ImVector<ImDrawList*>* draw_lists, ImDrawData* draw_data) 4158 { 4159 ImGuiIO& io = ImGui::GetIO(); 4160 draw_data->Valid = true; 4161 draw_data->CmdLists = (draw_lists->Size > 0) ? draw_lists->Data : NULL; 4162 draw_data->CmdListsCount = draw_lists->Size; 4163 draw_data->TotalVtxCount = draw_data->TotalIdxCount = 0; 4164 draw_data->DisplayPos = ImVec2(0.0f, 0.0f); 4165 draw_data->DisplaySize = io.DisplaySize; 4166 draw_data->FramebufferScale = io.DisplayFramebufferScale; 4167 for (int n = 0; n < draw_lists->Size; n++) 4168 { 4169 draw_data->TotalVtxCount += draw_lists->Data[n]->VtxBuffer.Size; 4170 draw_data->TotalIdxCount += draw_lists->Data[n]->IdxBuffer.Size; 4171 } 4172 } 4173 4174 // Push a clipping rectangle for both ImGui logic (hit-testing etc.) and low-level ImDrawList rendering. 4175 // - When using this function it is sane to ensure that float are perfectly rounded to integer values, 4176 // so that e.g. (int)(max.x-min.x) in user's render produce correct result. 4177 // - If the code here changes, may need to update code of functions like NextColumn() and PushColumnClipRect(): 4178 // some frequently called functions which to modify both channels and clipping simultaneously tend to use the 4179 // more specialized SetWindowClipRectBeforeSetChannel() to avoid extraneous updates of underlying ImDrawCmds. 4002 4180 void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect) 4003 4181 { 4004 ImGuiWindow* window = GetCurrentWindow();4005 window->DrawList->PushClipRect(clip_rect_min, clip_rect_max, intersect_with_current_clip_rect);4006 window->ClipRect = window->DrawList->_ClipRectStack.back();4182 ImGuiWindow* window = GetCurrentWindow(); 4183 window->DrawList->PushClipRect(clip_rect_min, clip_rect_max, intersect_with_current_clip_rect); 4184 window->ClipRect = window->DrawList->_ClipRectStack.back(); 4007 4185 } 4008 4186 4009 4187 void ImGui::PopClipRect() 4010 4188 { 4011 ImGuiWindow* window = GetCurrentWindow();4012 window->DrawList->PopClipRect();4013 window->ClipRect = window->DrawList->_ClipRectStack.back();4189 ImGuiWindow* window = GetCurrentWindow(); 4190 window->DrawList->PopClipRect(); 4191 window->ClipRect = window->DrawList->_ClipRectStack.back(); 4014 4192 } 4015 4193 … … 4017 4195 void ImGui::EndFrame() 4018 4196 { 4019 ImGuiContext& g = *GImGui; 4020 IM_ASSERT(g.Initialized); // Forgot to call ImGui::NewFrame() 4021 if (g.FrameCountEnded == g.FrameCount) // Don't process EndFrame() multiple times. 4022 return; 4023 4024 // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME) 4025 if (g.IO.ImeSetInputScreenPosFn && ImLengthSqr(g.PlatformImeLastPos - g.PlatformImePos) > 0.0001f) 4026 { 4027 g.IO.ImeSetInputScreenPosFn((int)g.PlatformImePos.x, (int)g.PlatformImePos.y); 4028 g.PlatformImeLastPos = g.PlatformImePos; 4029 } 4030 4031 // Hide implicit "Debug" window if it hasn't been used 4032 IM_ASSERT(g.CurrentWindowStack.Size == 1); // Mismatched Begin()/End() calls 4033 if (g.CurrentWindow && !g.CurrentWindow->WriteAccessed) 4034 g.CurrentWindow->Active = false; 4035 End(); 4036 4037 if (g.ActiveId == 0 && g.HoveredId == 0) 4038 { 4039 if (!g.NavWindow || !g.NavWindow->Appearing) // Unless we just made a window/popup appear 4040 { 4041 // Click to focus window and start moving (after we're done with all our widgets) 4042 if (g.IO.MouseClicked[0]) 4043 { 4044 if (g.HoveredRootWindow != NULL) 4045 { 4046 // Set ActiveId even if the _NoMove flag is set, without it dragging away from a window with _NoMove would activate hover on other windows. 4047 FocusWindow(g.HoveredWindow); 4048 SetActiveID(g.HoveredWindow->MoveId, g.HoveredWindow); 4049 g.NavDisableHighlight = true; 4050 g.ActiveIdClickOffset = g.IO.MousePos - g.HoveredRootWindow->Pos; 4051 if (!(g.HoveredWindow->Flags & ImGuiWindowFlags_NoMove) && !(g.HoveredRootWindow->Flags & ImGuiWindowFlags_NoMove)) 4052 g.MovingWindow = g.HoveredWindow; 4053 } 4054 else if (g.NavWindow != NULL && GetFrontMostPopupModal() == NULL) 4055 { 4056 // Clicking on void disable focus 4057 FocusWindow(NULL); 4058 } 4059 } 4060 4061 // With right mouse button we close popups without changing focus 4062 // (The left mouse button path calls FocusWindow which will lead NewFrame->ClosePopupsOverWindow to trigger) 4063 if (g.IO.MouseClicked[1]) 4064 { 4065 // Find the top-most window between HoveredWindow and the front most Modal Window. 4066 // This is where we can trim the popup stack. 4067 ImGuiWindow* modal = GetFrontMostPopupModal(); 4068 bool hovered_window_above_modal = false; 4069 if (modal == NULL) 4070 hovered_window_above_modal = true; 4071 for (int i = g.Windows.Size - 1; i >= 0 && hovered_window_above_modal == false; i--) 4072 { 4073 ImGuiWindow* window = g.Windows[i]; 4074 if (window == modal) 4075 break; 4076 if (window == g.HoveredWindow) 4077 hovered_window_above_modal = true; 4078 } 4079 ClosePopupsOverWindow(hovered_window_above_modal ? g.HoveredWindow : modal); 4080 } 4081 } 4082 } 4083 4084 // Sort the window list so that all child windows are after their parent 4085 // We cannot do that on FocusWindow() because childs may not exist yet 4086 g.WindowsSortBuffer.resize(0); 4087 g.WindowsSortBuffer.reserve(g.Windows.Size); 4088 for (int i = 0; i != g.Windows.Size; i++) 4089 { 4090 ImGuiWindow* window = g.Windows[i]; 4091 if (window->Active && (window->Flags & ImGuiWindowFlags_ChildWindow)) // if a child is active its parent will add it 4092 continue; 4093 AddWindowToSortedBuffer(&g.WindowsSortBuffer, window); 4094 } 4095 4096 IM_ASSERT(g.Windows.Size == g.WindowsSortBuffer.Size); // we done something wrong 4097 g.Windows.swap(g.WindowsSortBuffer); 4098 4099 // Clear Input data for next frame 4100 g.IO.MouseWheel = g.IO.MouseWheelH = 0.0f; 4101 memset(g.IO.InputCharacters, 0, sizeof(g.IO.InputCharacters)); 4102 memset(g.IO.NavInputs, 0, sizeof(g.IO.NavInputs)); 4103 4104 g.FrameCountEnded = g.FrameCount; 4197 ImGuiContext& g = *GImGui; 4198 IM_ASSERT(g.Initialized); 4199 4200 // Don't process EndFrame() multiple times. 4201 if (g.FrameCountEnded == g.FrameCount) 4202 return; 4203 IM_ASSERT(g.WithinFrameScope && "Forgot to call ImGui::NewFrame()?"); 4204 4205 ErrorCheckEndFrameSanityChecks(); 4206 4207 // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME) 4208 if (g.IO.ImeSetInputScreenPosFn && (g.PlatformImeLastPos.x == FLT_MAX || ImLengthSqr(g.PlatformImeLastPos - g.PlatformImePos) > 0.0001f)) 4209 { 4210 g.IO.ImeSetInputScreenPosFn((int)g.PlatformImePos.x, (int)g.PlatformImePos.y); 4211 g.PlatformImeLastPos = g.PlatformImePos; 4212 } 4213 4214 // Hide implicit/fallback "Debug" window if it hasn't been used 4215 g.WithinFrameScopeWithImplicitWindow = false; 4216 if (g.CurrentWindow && !g.CurrentWindow->WriteAccessed) 4217 g.CurrentWindow->Active = false; 4218 End(); 4219 4220 // Update navigation: CTRL+Tab, wrap-around requests 4221 NavEndFrame(); 4222 4223 // Drag and Drop: Elapse payload (if delivered, or if source stops being submitted) 4224 if (g.DragDropActive) 4225 { 4226 bool is_delivered = g.DragDropPayload.Delivery; 4227 bool is_elapsed = (g.DragDropPayload.DataFrameCount + 1 < g.FrameCount) && ((g.DragDropSourceFlags & ImGuiDragDropFlags_SourceAutoExpirePayload) || !IsMouseDown(g.DragDropMouseButton)); 4228 if (is_delivered || is_elapsed) 4229 ClearDragDrop(); 4230 } 4231 4232 // Drag and Drop: Fallback for source tooltip. This is not ideal but better than nothing. 4233 if (g.DragDropActive && g.DragDropSourceFrameCount < g.FrameCount && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip)) 4234 { 4235 g.DragDropWithinSource = true; 4236 SetTooltip("..."); 4237 g.DragDropWithinSource = false; 4238 } 4239 4240 // End frame 4241 g.WithinFrameScope = false; 4242 g.FrameCountEnded = g.FrameCount; 4243 4244 // Initiate moving window + handle left-click and right-click focus 4245 UpdateMouseMovingWindowEndFrame(); 4246 4247 // Sort the window list so that all child windows are after their parent 4248 // We cannot do that on FocusWindow() because children may not exist yet 4249 g.WindowsTempSortBuffer.resize(0); 4250 g.WindowsTempSortBuffer.reserve(g.Windows.Size); 4251 for (int i = 0; i != g.Windows.Size; i++) 4252 { 4253 ImGuiWindow* window = g.Windows[i]; 4254 if (window->Active && (window->Flags & ImGuiWindowFlags_ChildWindow)) // if a child is active its parent will add it 4255 continue; 4256 AddWindowToSortBuffer(&g.WindowsTempSortBuffer, window); 4257 } 4258 4259 // 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. 4260 IM_ASSERT(g.Windows.Size == g.WindowsTempSortBuffer.Size); 4261 g.Windows.swap(g.WindowsTempSortBuffer); 4262 g.IO.MetricsActiveWindows = g.WindowsActiveCount; 4263 4264 // Unlock font atlas 4265 g.IO.Fonts->Locked = false; 4266 4267 // Clear Input data for next frame 4268 g.IO.MouseWheel = g.IO.MouseWheelH = 0.0f; 4269 g.IO.InputQueueCharacters.resize(0); 4270 memset(g.IO.NavInputs, 0, sizeof(g.IO.NavInputs)); 4105 4271 } 4106 4272 4107 4273 void ImGui::Render() 4108 4274 { 4109 ImGuiContext& g = *GImGui; 4110 IM_ASSERT(g.Initialized); // Forgot to call ImGui::NewFrame() 4111 4112 if (g.FrameCountEnded != g.FrameCount) 4113 ImGui::EndFrame(); 4114 g.FrameCountRendered = g.FrameCount; 4115 4116 // Gather windows to render 4117 g.IO.MetricsRenderVertices = g.IO.MetricsRenderIndices = g.IO.MetricsActiveWindows = 0; 4118 g.DrawDataBuilder.Clear(); 4119 ImGuiWindow* window_to_render_front_most = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget : NULL; 4120 for (int n = 0; n != g.Windows.Size; n++) 4121 { 4122 ImGuiWindow* window = g.Windows[n]; 4123 if (window->Active && window->HiddenFrames == 0 && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != window_to_render_front_most) 4124 AddWindowToDrawDataSelectLayer(window); 4125 } 4126 if (window_to_render_front_most && window_to_render_front_most->Active && window_to_render_front_most->HiddenFrames == 0) // NavWindowingTarget is always temporarily displayed as the front-most window 4127 AddWindowToDrawDataSelectLayer(window_to_render_front_most); 4128 g.DrawDataBuilder.FlattenIntoSingleLayer(); 4129 4130 // Draw software mouse cursor if requested 4131 ImVec2 offset, size, uv[4]; 4132 if (g.IO.MouseDrawCursor && g.IO.Fonts->GetMouseCursorTexData(g.MouseCursor, &offset, &size, &uv[0], &uv[2])) 4133 { 4134 const ImVec2 pos = g.IO.MousePos - offset; 4135 const ImTextureID tex_id = g.IO.Fonts->TexID; 4136 const float sc = g.Style.MouseCursorScale; 4137 g.OverlayDrawList.PushTextureID(tex_id); 4138 g.OverlayDrawList.AddImage(tex_id, pos + ImVec2(1, 0)*sc, pos + ImVec2(1, 0)*sc + size * sc, uv[2], uv[3], IM_COL32(0, 0, 0, 48)); // Shadow 4139 g.OverlayDrawList.AddImage(tex_id, pos + ImVec2(2, 0)*sc, pos + ImVec2(2, 0)*sc + size * sc, uv[2], uv[3], IM_COL32(0, 0, 0, 48)); // Shadow 4140 g.OverlayDrawList.AddImage(tex_id, pos, pos + size * sc, uv[2], uv[3], IM_COL32(0, 0, 0, 255)); // Black border 4141 g.OverlayDrawList.AddImage(tex_id, pos, pos + size * sc, uv[0], uv[1], IM_COL32(255, 255, 255, 255)); // White fill 4142 g.OverlayDrawList.PopTextureID(); 4143 } 4144 if (!g.OverlayDrawList.VtxBuffer.empty()) 4145 AddDrawListToDrawData(&g.DrawDataBuilder.Layers[0], &g.OverlayDrawList); 4146 4147 // Setup ImDrawData structure for end-user 4148 SetupDrawData(&g.DrawDataBuilder.Layers[0], &g.DrawData); 4149 g.IO.MetricsRenderVertices = g.DrawData.TotalVtxCount; 4150 g.IO.MetricsRenderIndices = g.DrawData.TotalIdxCount; 4151 4152 // Render. If user hasn't set a callback then they may retrieve the draw data via GetDrawData() 4275 ImGuiContext& g = *GImGui; 4276 IM_ASSERT(g.Initialized); 4277 4278 if (g.FrameCountEnded != g.FrameCount) 4279 EndFrame(); 4280 g.FrameCountRendered = g.FrameCount; 4281 g.IO.MetricsRenderWindows = 0; 4282 g.DrawDataBuilder.Clear(); 4283 4284 // Add background ImDrawList 4285 if (!g.BackgroundDrawList.VtxBuffer.empty()) 4286 AddDrawListToDrawData(&g.DrawDataBuilder.Layers[0], &g.BackgroundDrawList); 4287 4288 // Add ImDrawList to render 4289 ImGuiWindow* windows_to_render_top_most[2]; 4290 windows_to_render_top_most[0] = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget->RootWindow : NULL; 4291 windows_to_render_top_most[1] = (g.NavWindowingTarget ? g.NavWindowingListWindow : NULL); 4292 for (int n = 0; n != g.Windows.Size; n++) 4293 { 4294 ImGuiWindow* window = g.Windows[n]; 4295 if (IsWindowActiveAndVisible(window) && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != windows_to_render_top_most[0] && window != windows_to_render_top_most[1]) 4296 AddRootWindowToDrawData(window); 4297 } 4298 for (int n = 0; n < IM_ARRAYSIZE(windows_to_render_top_most); n++) 4299 if (windows_to_render_top_most[n] && IsWindowActiveAndVisible(windows_to_render_top_most[n])) // NavWindowingTarget is always temporarily displayed as the top-most window 4300 AddRootWindowToDrawData(windows_to_render_top_most[n]); 4301 g.DrawDataBuilder.FlattenIntoSingleLayer(); 4302 4303 // Draw software mouse cursor if requested 4304 if (g.IO.MouseDrawCursor) 4305 RenderMouseCursor(&g.ForegroundDrawList, g.IO.MousePos, g.Style.MouseCursorScale, g.MouseCursor, IM_COL32_WHITE, IM_COL32_BLACK, IM_COL32(0, 0, 0, 48)); 4306 4307 // Add foreground ImDrawList 4308 if (!g.ForegroundDrawList.VtxBuffer.empty()) 4309 AddDrawListToDrawData(&g.DrawDataBuilder.Layers[0], &g.ForegroundDrawList); 4310 4311 // Setup ImDrawData structure for end-user 4312 SetupDrawData(&g.DrawDataBuilder.Layers[0], &g.DrawData); 4313 g.IO.MetricsRenderVertices = g.DrawData.TotalVtxCount; 4314 g.IO.MetricsRenderIndices = g.DrawData.TotalIdxCount; 4315 4316 // (Legacy) Call the Render callback function. The current prefer way is to let the user retrieve GetDrawData() and call the render function themselves. 4153 4317 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS 4154 if (g.DrawData.CmdListsCount > 0 && g.IO.RenderDrawListsFn != NULL)4155 g.IO.RenderDrawListsFn(&g.DrawData);4318 if (g.DrawData.CmdListsCount > 0 && g.IO.RenderDrawListsFn != NULL) 4319 g.IO.RenderDrawListsFn(&g.DrawData); 4156 4320 #endif 4157 4321 } 4158 4322 4159 const char* ImGui::FindRenderedTextEnd(const char* text, const char* text_end) 4160 { 4161 const char* text_display_end = text; 4162 if (!text_end) 4163 text_end = (const char*)-1; 4164 4165 while (text_display_end < text_end && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#')) 4166 text_display_end++; 4167 return text_display_end; 4168 } 4169 4170 // Pass text data straight to log (without being displayed) 4171 void ImGui::LogText(const char* fmt, ...) 4172 { 4173 ImGuiContext& g = *GImGui; 4174 if (!g.LogEnabled) 4175 return; 4176 4177 va_list args; 4178 va_start(args, fmt); 4179 if (g.LogFile) 4180 vfprintf(g.LogFile, fmt, args); 4181 else 4182 g.LogClipboard->appendfv(fmt, args); 4183 va_end(args); 4184 } 4185 4186 // Internal version that takes a position to decide on newline placement and pad items according to their depth. 4187 // We split text into individual lines to add current tree level padding 4188 static void LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end = NULL) 4189 { 4190 ImGuiContext& g = *GImGui; 4191 ImGuiWindow* window = g.CurrentWindow; 4192 4193 if (!text_end) 4194 text_end = ImGui::FindRenderedTextEnd(text, text_end); 4195 4196 const bool log_new_line = ref_pos && (ref_pos->y > window->DC.LogLinePosY + 1); 4197 if (ref_pos) 4198 window->DC.LogLinePosY = ref_pos->y; 4199 4200 const char* text_remaining = text; 4201 if (g.LogStartDepth > window->DC.TreeDepth) // Re-adjust padding if we have popped out of our starting depth 4202 g.LogStartDepth = window->DC.TreeDepth; 4203 const int tree_depth = (window->DC.TreeDepth - g.LogStartDepth); 4204 for (;;) 4205 { 4206 // Split the string. Each new line (after a '\n') is followed by spacing corresponding to the current depth of our log entry. 4207 const char* line_end = text_remaining; 4208 while (line_end < text_end) 4209 if (*line_end == '\n') 4323 // Calculate text size. Text can be multi-line. Optionally ignore text after a ## marker. 4324 // CalcTextSize("") should return ImVec2(0.0f, g.FontSize) 4325 ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_text_after_double_hash, float wrap_width) 4326 { 4327 ImGuiContext& g = *GImGui; 4328 4329 const char* text_display_end; 4330 if (hide_text_after_double_hash) 4331 text_display_end = FindRenderedTextEnd(text, text_end); // Hide anything after a '##' string 4332 else 4333 text_display_end = text_end; 4334 4335 ImFont* font = g.Font; 4336 const float font_size = g.FontSize; 4337 if (text == text_display_end) 4338 return ImVec2(0.0f, font_size); 4339 ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL); 4340 4341 // Round 4342 text_size.x = IM_FLOOR(text_size.x + 0.95f); 4343 4344 return text_size; 4345 } 4346 4347 // Find window given position, search front-to-back 4348 // FIXME: Note that we have an inconsequential lag here: OuterRectClipped is updated in Begin(), so windows moved programmatically 4349 // with SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is 4350 // called, aka before the next Begin(). Moving window isn't affected. 4351 static void FindHoveredWindow() 4352 { 4353 ImGuiContext& g = *GImGui; 4354 4355 ImGuiWindow* hovered_window = NULL; 4356 ImGuiWindow* hovered_window_ignoring_moving_window = NULL; 4357 if (g.MovingWindow && !(g.MovingWindow->Flags & ImGuiWindowFlags_NoMouseInputs)) 4358 hovered_window = g.MovingWindow; 4359 4360 ImVec2 padding_regular = g.Style.TouchExtraPadding; 4361 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; 4362 for (int i = g.Windows.Size - 1; i >= 0; i--) 4363 { 4364 ImGuiWindow* window = g.Windows[i]; 4365 if (!window->Active || window->Hidden) 4366 continue; 4367 if (window->Flags & ImGuiWindowFlags_NoMouseInputs) 4368 continue; 4369 4370 // Using the clipped AABB, a child window will typically be clipped by its parent (not always) 4371 ImRect bb(window->OuterRectClipped); 4372 if (window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) 4373 bb.Expand(padding_regular); 4374 else 4375 bb.Expand(padding_for_resize_from_edges); 4376 if (!bb.Contains(g.IO.MousePos)) 4377 continue; 4378 4379 // Support for one rectangular hole in any given window 4380 // FIXME: Consider generalizing hit-testing override (with more generic data, callback, etc.) (#1512) 4381 if (window->HitTestHoleSize.x != 0) 4382 { 4383 ImVec2 hole_pos(window->Pos.x + (float)window->HitTestHoleOffset.x, window->Pos.y + (float)window->HitTestHoleOffset.y); 4384 ImVec2 hole_size((float)window->HitTestHoleSize.x, (float)window->HitTestHoleSize.y); 4385 if (ImRect(hole_pos, hole_pos + hole_size).Contains(g.IO.MousePos)) 4386 continue; 4387 } 4388 4389 if (hovered_window == NULL) 4390 hovered_window = window; 4391 if (hovered_window_ignoring_moving_window == NULL && (!g.MovingWindow || window->RootWindow != g.MovingWindow->RootWindow)) 4392 hovered_window_ignoring_moving_window = window; 4393 if (hovered_window && hovered_window_ignoring_moving_window) 4210 4394 break; 4211 else 4212 line_end++; 4213 if (line_end >= text_end) 4214 line_end = NULL; 4215 4216 const bool is_first_line = (text == text_remaining); 4217 bool is_last_line = false; 4218 if (line_end == NULL) 4219 { 4220 is_last_line = true; 4221 line_end = text_end; 4222 } 4223 if (line_end != NULL && !(is_last_line && (line_end - text_remaining) == 0)) 4224 { 4225 const int char_count = (int)(line_end - text_remaining); 4226 if (log_new_line || !is_first_line) 4227 ImGui::LogText(IM_NEWLINE "%*s%.*s", tree_depth * 4, "", char_count, text_remaining); 4228 else 4229 ImGui::LogText(" %.*s", char_count, text_remaining); 4230 } 4231 4232 if (is_last_line) 4233 break; 4234 text_remaining = line_end + 1; 4235 } 4236 } 4237 4238 // Internal ImGui functions to render text 4239 // RenderText***() functions calls ImDrawList::AddText() calls ImBitmapFont::RenderText() 4240 void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool hide_text_after_hash) 4241 { 4242 ImGuiContext& g = *GImGui; 4243 ImGuiWindow* window = g.CurrentWindow; 4244 4245 // Hide anything after a '##' string 4246 const char* text_display_end; 4247 if (hide_text_after_hash) 4248 { 4249 text_display_end = FindRenderedTextEnd(text, text_end); 4250 } 4251 else 4252 { 4253 if (!text_end) 4254 text_end = text + strlen(text); // FIXME-OPT 4255 text_display_end = text_end; 4256 } 4257 4258 if (text != text_display_end) 4259 { 4260 window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end); 4261 if (g.LogEnabled) 4262 LogRenderedText(&pos, text, text_display_end); 4263 } 4264 } 4265 4266 void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width) 4267 { 4268 ImGuiContext& g = *GImGui; 4269 ImGuiWindow* window = g.CurrentWindow; 4270 4271 if (!text_end) 4272 text_end = text + strlen(text); // FIXME-OPT 4273 4274 if (text != text_end) 4275 { 4276 window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_end, wrap_width); 4277 if (g.LogEnabled) 4278 LogRenderedText(&pos, text, text_end); 4279 } 4280 } 4281 4282 // Default clip_rect uses (pos_min,pos_max) 4283 // Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges) 4284 void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect) 4285 { 4286 // Hide anything after a '##' string 4287 const char* text_display_end = FindRenderedTextEnd(text, text_end); 4288 const int text_len = (int)(text_display_end - text); 4289 if (text_len == 0) 4290 return; 4291 4292 ImGuiContext& g = *GImGui; 4293 ImGuiWindow* window = g.CurrentWindow; 4294 4295 // Perform CPU side clipping for single clipped element to avoid using scissor state 4296 ImVec2 pos = pos_min; 4297 const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_display_end, false, 0.0f); 4298 4299 const ImVec2* clip_min = clip_rect ? &clip_rect->Min : &pos_min; 4300 const ImVec2* clip_max = clip_rect ? &clip_rect->Max : &pos_max; 4301 bool need_clipping = (pos.x + text_size.x >= clip_max->x) || (pos.y + text_size.y >= clip_max->y); 4302 if (clip_rect) // If we had no explicit clipping rectangle then pos==clip_min 4303 need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y); 4304 4305 // Align whole block. We should defer that to the better rendering function when we'll have support for individual line alignment. 4306 if (align.x > 0.0f) pos.x = ImMax(pos.x, pos.x + (pos_max.x - pos.x - text_size.x) * align.x); 4307 if (align.y > 0.0f) pos.y = ImMax(pos.y, pos.y + (pos_max.y - pos.y - text_size.y) * align.y); 4308 4309 // Render 4310 if (need_clipping) 4311 { 4312 ImVec4 fine_clip_rect(clip_min->x, clip_min->y, clip_max->x, clip_max->y); 4313 window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, &fine_clip_rect); 4314 } 4315 else 4316 { 4317 window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL); 4318 } 4319 if (g.LogEnabled) 4320 LogRenderedText(&pos, text, text_display_end); 4321 } 4322 4323 // Render a rectangle shaped with optional rounding and borders 4324 void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, float rounding) 4325 { 4326 ImGuiContext& g = *GImGui; 4327 ImGuiWindow* window = g.CurrentWindow; 4328 window->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding); 4329 const float border_size = g.Style.FrameBorderSize; 4330 if (border && border_size > 0.0f) 4331 { 4332 window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size); 4333 window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size); 4334 } 4335 } 4336 4337 void ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding) 4338 { 4339 ImGuiContext& g = *GImGui; 4340 ImGuiWindow* window = g.CurrentWindow; 4341 const float border_size = g.Style.FrameBorderSize; 4342 if (border_size > 0.0f) 4343 { 4344 window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size); 4345 window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size); 4346 } 4347 } 4348 4349 // Render a triangle to denote expanded/collapsed state 4350 void ImGui::RenderArrow(ImVec2 p_min, ImGuiDir dir, float scale) 4351 { 4352 ImGuiContext& g = *GImGui; 4353 ImGuiWindow* window = g.CurrentWindow; 4354 4355 const float h = g.FontSize * 1.00f; 4356 float r = h * 0.40f * scale; 4357 ImVec2 center = p_min + ImVec2(h * 0.50f, h * 0.50f * scale); 4358 4359 ImVec2 a, b, c; 4360 switch (dir) 4361 { 4362 case ImGuiDir_Up: 4363 case ImGuiDir_Down: 4364 if (dir == ImGuiDir_Up) r = -r; 4365 center.y -= r * 0.25f; 4366 a = ImVec2(0, 1) * r; 4367 b = ImVec2(-0.866f, -0.5f) * r; 4368 c = ImVec2(+0.866f, -0.5f) * r; 4369 break; 4370 case ImGuiDir_Left: 4371 case ImGuiDir_Right: 4372 if (dir == ImGuiDir_Left) r = -r; 4373 center.x -= r * 0.25f; 4374 a = ImVec2(1, 0) * r; 4375 b = ImVec2(-0.500f, +0.866f) * r; 4376 c = ImVec2(-0.500f, -0.866f) * r; 4377 break; 4378 case ImGuiDir_None: 4379 case ImGuiDir_COUNT: 4380 IM_ASSERT(0); 4381 break; 4382 } 4383 4384 window->DrawList->AddTriangleFilled(center + a, center + b, center + c, GetColorU32(ImGuiCol_Text)); 4385 } 4386 4387 void ImGui::RenderBullet(ImVec2 pos) 4388 { 4389 ImGuiContext& g = *GImGui; 4390 ImGuiWindow* window = g.CurrentWindow; 4391 window->DrawList->AddCircleFilled(pos, GImGui->FontSize*0.20f, GetColorU32(ImGuiCol_Text), 8); 4392 } 4393 4394 void ImGui::RenderCheckMark(ImVec2 pos, ImU32 col, float sz) 4395 { 4396 ImGuiContext& g = *GImGui; 4397 ImGuiWindow* window = g.CurrentWindow; 4398 4399 float thickness = ImMax(sz / 5.0f, 1.0f); 4400 sz -= thickness * 0.5f; 4401 pos += ImVec2(thickness*0.25f, thickness*0.25f); 4402 4403 float third = sz / 3.0f; 4404 float bx = pos.x + third; 4405 float by = pos.y + sz - third * 0.5f; 4406 window->DrawList->PathLineTo(ImVec2(bx - third, by - third)); 4407 window->DrawList->PathLineTo(ImVec2(bx, by)); 4408 window->DrawList->PathLineTo(ImVec2(bx + third * 2, by - third * 2)); 4409 window->DrawList->PathStroke(col, false, thickness); 4410 } 4411 4412 void ImGui::RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags) 4413 { 4414 ImGuiContext& g = *GImGui; 4415 if (id != g.NavId) 4416 return; 4417 if (g.NavDisableHighlight && !(flags & ImGuiNavHighlightFlags_AlwaysDraw)) 4418 return; 4419 ImGuiWindow* window = ImGui::GetCurrentWindow(); 4420 if (window->DC.NavHideHighlightOneFrame) 4421 return; 4422 4423 float rounding = (flags & ImGuiNavHighlightFlags_NoRounding) ? 0.0f : g.Style.FrameRounding; 4424 ImRect display_rect = bb; 4425 display_rect.ClipWith(window->ClipRect); 4426 if (flags & ImGuiNavHighlightFlags_TypeDefault) 4427 { 4428 const float THICKNESS = 2.0f; 4429 const float DISTANCE = 3.0f + THICKNESS * 0.5f; 4430 display_rect.Expand(ImVec2(DISTANCE, DISTANCE)); 4431 bool fully_visible = window->ClipRect.Contains(display_rect); 4432 if (!fully_visible) 4433 window->DrawList->PushClipRect(display_rect.Min, display_rect.Max); 4434 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); 4435 if (!fully_visible) 4436 window->DrawList->PopClipRect(); 4437 } 4438 if (flags & ImGuiNavHighlightFlags_TypeThin) 4439 { 4440 window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavHighlight), rounding, ~0, 1.0f); 4441 } 4442 } 4443 4444 // Calculate text size. Text can be multi-line. Optionally ignore text after a ## marker. 4445 // CalcTextSize("") should return ImVec2(0.0f, GImGui->FontSize) 4446 ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_text_after_double_hash, float wrap_width) 4447 { 4448 ImGuiContext& g = *GImGui; 4449 4450 const char* text_display_end; 4451 if (hide_text_after_double_hash) 4452 text_display_end = FindRenderedTextEnd(text, text_end); // Hide anything after a '##' string 4453 else 4454 text_display_end = text_end; 4455 4456 ImFont* font = g.Font; 4457 const float font_size = g.FontSize; 4458 if (text == text_display_end) 4459 return ImVec2(0.0f, font_size); 4460 ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL); 4461 4462 // Cancel out character spacing for the last character of a line (it is baked into glyph->AdvanceX field) 4463 const float font_scale = font_size / font->FontSize; 4464 const float character_spacing_x = 1.0f * font_scale; 4465 if (text_size.x > 0.0f) 4466 text_size.x -= character_spacing_x; 4467 text_size.x = (float)(int)(text_size.x + 0.95f); 4468 4469 return text_size; 4470 } 4471 4472 // Helper to calculate coarse clipping of large list of evenly sized items. 4473 // NB: Prefer using the ImGuiListClipper higher-level helper if you can! Read comments and instructions there on how those use this sort of pattern. 4474 // NB: 'items_count' is only used to clamp the result, if you don't know your count you can use INT_MAX 4475 void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end) 4476 { 4477 ImGuiContext& g = *GImGui; 4478 ImGuiWindow* window = g.CurrentWindow; 4479 if (g.LogEnabled) 4480 { 4481 // If logging is active, do not perform any clipping 4482 *out_items_display_start = 0; 4483 *out_items_display_end = items_count; 4484 return; 4485 } 4486 if (window->SkipItems) 4487 { 4488 *out_items_display_start = *out_items_display_end = 0; 4489 return; 4490 } 4491 4492 const ImVec2 pos = window->DC.CursorPos; 4493 int start = (int)((window->ClipRect.Min.y - pos.y) / items_height); 4494 int end = (int)((window->ClipRect.Max.y - pos.y) / items_height); 4495 if (g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Up) // When performing a navigation request, ensure we have one item extra in the direction we are moving to 4496 start--; 4497 if (g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Down) 4498 end++; 4499 4500 start = ImClamp(start, 0, items_count); 4501 end = ImClamp(end + 1, start, items_count); 4502 *out_items_display_start = start; 4503 *out_items_display_end = end; 4504 } 4505 4506 // Find window given position, search front-to-back 4507 // FIXME: Note that we have a lag here because WindowRectClipped is updated in Begin() so windows moved by user via SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is called, aka before the next Begin(). Moving window thankfully isn't affected. 4508 static ImGuiWindow* FindHoveredWindow() 4509 { 4510 ImGuiContext& g = *GImGui; 4511 for (int i = g.Windows.Size - 1; i >= 0; i--) 4512 { 4513 ImGuiWindow* window = g.Windows[i]; 4514 if (!window->Active) 4515 continue; 4516 if (window->Flags & ImGuiWindowFlags_NoInputs) 4517 continue; 4518 4519 // Using the clipped AABB, a child window will typically be clipped by its parent (not always) 4520 ImRect bb(window->WindowRectClipped.Min - g.Style.TouchExtraPadding, window->WindowRectClipped.Max + g.Style.TouchExtraPadding); 4521 if (bb.Contains(g.IO.MousePos)) 4522 return window; 4523 } 4524 return NULL; 4395 } 4396 4397 g.HoveredWindow = hovered_window; 4398 g.HoveredRootWindow = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL; 4399 g.HoveredWindowUnderMovingWindow = hovered_window_ignoring_moving_window; 4525 4400 } 4526 4401 … … 4530 4405 bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip) 4531 4406 { 4532 ImGuiContext& g = *GImGui; 4533 4534 // Clip 4535 ImRect rect_clipped(r_min, r_max); 4536 if (clip) 4537 rect_clipped.ClipWith(g.CurrentWindow->ClipRect); 4538 4539 // Expand for touch input 4540 const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, rect_clipped.Max + g.Style.TouchExtraPadding); 4541 return rect_for_touch.Contains(g.IO.MousePos); 4542 } 4543 4544 static bool IsKeyPressedMap(ImGuiKey key, bool repeat) 4545 { 4546 const int key_index = GImGui->IO.KeyMap[key]; 4547 return (key_index >= 0) ? ImGui::IsKeyPressed(key_index, repeat) : false; 4407 ImGuiContext& g = *GImGui; 4408 4409 // Clip 4410 ImRect rect_clipped(r_min, r_max); 4411 if (clip) 4412 rect_clipped.ClipWith(g.CurrentWindow->ClipRect); 4413 4414 // Expand for touch input 4415 const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, rect_clipped.Max + g.Style.TouchExtraPadding); 4416 if (!rect_for_touch.Contains(g.IO.MousePos)) 4417 return false; 4418 return true; 4548 4419 } 4549 4420 4550 4421 int ImGui::GetKeyIndex(ImGuiKey imgui_key) 4551 4422 { 4552 IM_ASSERT(imgui_key >= 0 && imgui_key < ImGuiKey_COUNT); 4553 return GImGui->IO.KeyMap[imgui_key]; 4554 } 4555 4556 // 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[]! 4423 IM_ASSERT(imgui_key >= 0 && imgui_key < ImGuiKey_COUNT); 4424 ImGuiContext& g = *GImGui; 4425 return g.IO.KeyMap[imgui_key]; 4426 } 4427 4428 // Note that dear imgui doesn't know the semantic of each entry of io.KeysDown[]! 4429 // Use your own indices/enums according to how your back-end/engine stored them into io.KeysDown[]! 4557 4430 bool ImGui::IsKeyDown(int user_key_index) 4558 4431 { 4559 if (user_key_index < 0) return false; 4560 IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(GImGui->IO.KeysDown)); 4561 return GImGui->IO.KeysDown[user_key_index]; 4562 } 4563 4564 int ImGui::CalcTypematicPressedRepeatAmount(float t, float t_prev, float repeat_delay, float repeat_rate) 4565 { 4566 if (t == 0.0f) 4567 return 1; 4568 if (t <= repeat_delay || repeat_rate <= 0.0f) 4569 return 0; 4570 const int count = (int)((t - repeat_delay) / repeat_rate) - (int)((t_prev - repeat_delay) / repeat_rate); 4571 return (count > 0) ? count : 0; 4432 if (user_key_index < 0) 4433 return false; 4434 ImGuiContext& g = *GImGui; 4435 IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown)); 4436 return g.IO.KeysDown[user_key_index]; 4437 } 4438 4439 // t0 = previous time (e.g.: g.Time - g.IO.DeltaTime) 4440 // t1 = current time (e.g.: g.Time) 4441 // An event is triggered at: 4442 // t = 0.0f t = repeat_delay, t = repeat_delay + repeat_rate*N 4443 int ImGui::CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate) 4444 { 4445 if (t1 == 0.0f) 4446 return 1; 4447 if (t0 >= t1) 4448 return 0; 4449 if (repeat_rate <= 0.0f) 4450 return (t0 < repeat_delay) && (t1 >= repeat_delay); 4451 const int count_t0 = (t0 < repeat_delay) ? -1 : (int)((t0 - repeat_delay) / repeat_rate); 4452 const int count_t1 = (t1 < repeat_delay) ? -1 : (int)((t1 - repeat_delay) / repeat_rate); 4453 const int count = count_t1 - count_t0; 4454 return count; 4572 4455 } 4573 4456 4574 4457 int ImGui::GetKeyPressedAmount(int key_index, float repeat_delay, float repeat_rate) 4575 4458 { 4576 ImGuiContext& g = *GImGui; 4577 if (key_index < 0) return false; 4578 IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(g.IO.KeysDown)); 4579 const float t = g.IO.KeysDownDuration[key_index]; 4580 return CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, repeat_delay, repeat_rate); 4459 ImGuiContext& g = *GImGui; 4460 if (key_index < 0) 4461 return 0; 4462 IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(g.IO.KeysDown)); 4463 const float t = g.IO.KeysDownDuration[key_index]; 4464 return CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, repeat_delay, repeat_rate); 4581 4465 } 4582 4466 4583 4467 bool ImGui::IsKeyPressed(int user_key_index, bool repeat) 4584 4468 { 4585 ImGuiContext& g = *GImGui; 4586 if (user_key_index < 0) return false; 4587 IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown)); 4588 const float t = g.IO.KeysDownDuration[user_key_index]; 4589 if (t == 0.0f) 4590 return true; 4591 if (repeat && t > g.IO.KeyRepeatDelay) 4592 return GetKeyPressedAmount(user_key_index, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0; 4593 return false; 4469 ImGuiContext& g = *GImGui; 4470 if (user_key_index < 0) 4471 return false; 4472 IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown)); 4473 const float t = g.IO.KeysDownDuration[user_key_index]; 4474 if (t == 0.0f) 4475 return true; 4476 if (repeat && t > g.IO.KeyRepeatDelay) 4477 return GetKeyPressedAmount(user_key_index, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0; 4478 return false; 4594 4479 } 4595 4480 4596 4481 bool ImGui::IsKeyReleased(int user_key_index) 4597 4482 { 4598 ImGuiContext& g = *GImGui;4599 if (user_key_index < 0) return false;4600 IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown));4601 return g.IO.KeysDownDurationPrev[user_key_index] >= 0.0f && !g.IO.KeysDown[user_key_index];4602 } 4603 4604 bool ImGui::IsMouseDown( intbutton)4605 { 4606 ImGuiContext& g = *GImGui;4607 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));4608 return g.IO.MouseDown[button];4609 } 4610 4611 bool ImGui::Is AnyMouseDown()4612 { 4613 ImGuiContext& g = *GImGui;4614 for (int n = 0; n < IM_ARRAYSIZE(g.IO.MouseDown); n++)4615 if (g.IO.MouseDown[n])4616 return true;4617 return false;4618 } 4619 4620 bool ImGui::IsMouseClicked(int button, bool repeat) 4621 { 4622 ImGuiContext& g = *GImGui;4623 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));4624 const float t = g.IO.MouseDownDuration[button];4625 if (t == 0.0f)4626 return true;4627 4628 if (repeat && t > g.IO.KeyRepeatDelay) 4629 { 4630 float delay = g.IO.KeyRepeatDelay, rate = g.IO.KeyRepeatRate; 4631 if ((fmodf(t - delay, rate) > rate*0.5f) != (fmodf(t - delay - g.IO.DeltaTime, rate) > rate*0.5f))4632 return true;4633 }4634 4635 return false; 4636 } 4637 4638 bool ImGui::IsMouseReleased(int button) 4639 { 4640 ImGuiContext& g = *GImGui;4641 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); 4642 return g.IO.MouseReleased[button]; 4643 } 4644 4645 bool ImGui::IsMouseD oubleClicked(int button)4646 { 4647 ImGuiContext& g = *GImGui;4648 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));4649 return g.IO.MouseDoubleClicked[button];4650 } 4651 4652 bool ImGui::IsMouseDragging(int button, float lock_threshold) 4653 { 4654 ImGuiContext& g = *GImGui; 4655 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); 4656 if (!g.IO.MouseDown[button])4657 return false;4658 if (lock_threshold < 0.0f)4659 lock_threshold = g.IO.MouseDragThreshold;4660 return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold;4483 ImGuiContext& g = *GImGui; 4484 if (user_key_index < 0) return false; 4485 IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown)); 4486 return g.IO.KeysDownDurationPrev[user_key_index] >= 0.0f && !g.IO.KeysDown[user_key_index]; 4487 } 4488 4489 bool ImGui::IsMouseDown(ImGuiMouseButton button) 4490 { 4491 ImGuiContext& g = *GImGui; 4492 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); 4493 return g.IO.MouseDown[button]; 4494 } 4495 4496 bool ImGui::IsMouseClicked(ImGuiMouseButton button, bool repeat) 4497 { 4498 ImGuiContext& g = *GImGui; 4499 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); 4500 const float t = g.IO.MouseDownDuration[button]; 4501 if (t == 0.0f) 4502 return true; 4503 4504 if (repeat && t > g.IO.KeyRepeatDelay) 4505 { 4506 // FIXME: 2019/05/03: Our old repeat code was wrong here and led to doubling the repeat rate, which made it an ok rate for repeat on mouse hold. 4507 int amount = CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate * 0.50f); 4508 if (amount > 0) 4509 return true; 4510 } 4511 return false; 4512 } 4513 4514 bool ImGui::IsMouseReleased(ImGuiMouseButton button) 4515 { 4516 ImGuiContext& g = *GImGui; 4517 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); 4518 return g.IO.MouseReleased[button]; 4519 } 4520 4521 bool ImGui::IsMouseDoubleClicked(ImGuiMouseButton button) 4522 { 4523 ImGuiContext& g = *GImGui; 4524 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); 4525 return g.IO.MouseDoubleClicked[button]; 4526 } 4527 4528 // Return if a mouse click/drag went past the given threshold. Valid to call during the MouseReleased frame. 4529 // [Internal] This doesn't test if the button is pressed 4530 bool ImGui::IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold) 4531 { 4532 ImGuiContext& g = *GImGui; 4533 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); 4534 if (lock_threshold < 0.0f) 4535 lock_threshold = g.IO.MouseDragThreshold; 4536 return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold; 4537 } 4538 4539 bool ImGui::IsMouseDragging(ImGuiMouseButton button, float lock_threshold) 4540 { 4541 ImGuiContext& g = *GImGui; 4542 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); 4543 if (!g.IO.MouseDown[button]) 4544 return false; 4545 return IsMouseDragPastThreshold(button, lock_threshold); 4661 4546 } 4662 4547 4663 4548 ImVec2 ImGui::GetMousePos() 4664 4549 { 4665 return GImGui->IO.MousePos; 4550 ImGuiContext& g = *GImGui; 4551 return g.IO.MousePos; 4666 4552 } 4667 4553 … … 4669 4555 ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup() 4670 4556 { 4671 ImGuiContext& g = *GImGui;4672 if (g.CurrentPopupStack.Size > 0)4673 return g.OpenPopupStack[g.CurrentPopupStack.Size - 1].OpenMousePos;4674 return g.IO.MousePos;4675 } 4676 4677 // We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position 4557 ImGuiContext& g = *GImGui; 4558 if (g.BeginPopupStack.Size > 0) 4559 return g.OpenPopupStack[g.BeginPopupStack.Size - 1].OpenMousePos; 4560 return g.IO.MousePos; 4561 } 4562 4563 // We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position. 4678 4564 bool ImGui::IsMousePosValid(const ImVec2* mouse_pos) 4679 4565 { 4680 if (mouse_pos == NULL) 4681 mouse_pos = &GImGui->IO.MousePos; 4682 const float MOUSE_INVALID = -256000.0f; 4683 return mouse_pos->x >= MOUSE_INVALID && mouse_pos->y >= MOUSE_INVALID; 4684 } 4685 4566 // The assert is only to silence a false-positive in XCode Static Analysis. 4567 // 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). 4568 IM_ASSERT(GImGui != NULL); 4569 const float MOUSE_INVALID = -256000.0f; 4570 ImVec2 p = mouse_pos ? *mouse_pos : GImGui->IO.MousePos; 4571 return p.x >= MOUSE_INVALID && p.y >= MOUSE_INVALID; 4572 } 4573 4574 bool ImGui::IsAnyMouseDown() 4575 { 4576 ImGuiContext& g = *GImGui; 4577 for (int n = 0; n < IM_ARRAYSIZE(g.IO.MouseDown); n++) 4578 if (g.IO.MouseDown[n]) 4579 return true; 4580 return false; 4581 } 4582 4583 // Return the delta from the initial clicking position while the mouse button is clicked or was just released. 4584 // This is locked and return 0.0f until the mouse moves past a distance threshold at least once. 4686 4585 // NB: This is only valid if IsMousePosValid(). Back-ends in theory should always keep mouse position valid when dragging even outside the client window. 4687 ImVec2 ImGui::GetMouseDragDelta(int button, float lock_threshold) 4688 { 4689 ImGuiContext& g = *GImGui; 4690 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); 4691 if (lock_threshold < 0.0f) 4692 lock_threshold = g.IO.MouseDragThreshold; 4693 if (g.IO.MouseDown[button]) 4694 if (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold) 4695 return g.IO.MousePos - g.IO.MouseClickedPos[button]; // Assume we can only get active with left-mouse button (at the moment). 4696 return ImVec2(0.0f, 0.0f); 4697 } 4698 4699 void ImGui::ResetMouseDragDelta(int button) 4700 { 4701 ImGuiContext& g = *GImGui; 4702 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); 4703 // NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr 4704 g.IO.MouseClickedPos[button] = g.IO.MousePos; 4586 ImVec2 ImGui::GetMouseDragDelta(ImGuiMouseButton button, float lock_threshold) 4587 { 4588 ImGuiContext& g = *GImGui; 4589 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); 4590 if (lock_threshold < 0.0f) 4591 lock_threshold = g.IO.MouseDragThreshold; 4592 if (g.IO.MouseDown[button] || g.IO.MouseReleased[button]) 4593 if (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold) 4594 if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MouseClickedPos[button])) 4595 return g.IO.MousePos - g.IO.MouseClickedPos[button]; 4596 return ImVec2(0.0f, 0.0f); 4597 } 4598 4599 void ImGui::ResetMouseDragDelta(ImGuiMouseButton button) 4600 { 4601 ImGuiContext& g = *GImGui; 4602 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); 4603 // NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr 4604 g.IO.MouseClickedPos[button] = g.IO.MousePos; 4705 4605 } 4706 4606 4707 4607 ImGuiMouseCursor ImGui::GetMouseCursor() 4708 4608 { 4709 return GImGui->MouseCursor;4609 return GImGui->MouseCursor; 4710 4610 } 4711 4611 4712 4612 void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type) 4713 4613 { 4714 GImGui->MouseCursor = cursor_type;4614 GImGui->MouseCursor = cursor_type; 4715 4615 } 4716 4616 4717 4617 void ImGui::CaptureKeyboardFromApp(bool capture) 4718 4618 { 4719 GImGui->WantCaptureKeyboardNextFrame = capture ? 1 : 0;4619 GImGui->WantCaptureKeyboardNextFrame = capture ? 1 : 0; 4720 4620 } 4721 4621 4722 4622 void ImGui::CaptureMouseFromApp(bool capture) 4723 4623 { 4724 GImGui->WantCaptureMouseNextFrame = capture ? 1 : 0;4624 GImGui->WantCaptureMouseNextFrame = capture ? 1 : 0; 4725 4625 } 4726 4626 4727 4627 bool ImGui::IsItemActive() 4728 4628 { 4729 ImGuiContext& g = *GImGui; 4730 if (g.ActiveId) 4731 { 4732 ImGuiWindow* window = g.CurrentWindow; 4733 return g.ActiveId == window->DC.LastItemId; 4734 } 4735 return false; 4629 ImGuiContext& g = *GImGui; 4630 if (g.ActiveId) 4631 { 4632 ImGuiWindow* window = g.CurrentWindow; 4633 return g.ActiveId == window->DC.LastItemId; 4634 } 4635 return false; 4636 } 4637 4638 bool ImGui::IsItemActivated() 4639 { 4640 ImGuiContext& g = *GImGui; 4641 if (g.ActiveId) 4642 { 4643 ImGuiWindow* window = g.CurrentWindow; 4644 if (g.ActiveId == window->DC.LastItemId && g.ActiveIdPreviousFrame != window->DC.LastItemId) 4645 return true; 4646 } 4647 return false; 4648 } 4649 4650 bool ImGui::IsItemDeactivated() 4651 { 4652 ImGuiContext& g = *GImGui; 4653 ImGuiWindow* window = g.CurrentWindow; 4654 if (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDeactivated) 4655 return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Deactivated) != 0; 4656 return (g.ActiveIdPreviousFrame == window->DC.LastItemId && g.ActiveIdPreviousFrame != 0 && g.ActiveId != window->DC.LastItemId); 4657 } 4658 4659 bool ImGui::IsItemDeactivatedAfterEdit() 4660 { 4661 ImGuiContext& g = *GImGui; 4662 return IsItemDeactivated() && (g.ActiveIdPreviousFrameHasBeenEditedBefore || (g.ActiveId == 0 && g.ActiveIdHasBeenEditedBefore)); 4736 4663 } 4737 4664 4738 4665 bool ImGui::IsItemFocused() 4739 4666 { 4740 ImGuiContext& g = *GImGui; 4741 return g.NavId && !g.NavDisableHighlight && g.NavId == g.CurrentWindow->DC.LastItemId; 4742 } 4743 4744 bool ImGui::IsItemClicked(int mouse_button) 4745 { 4746 return IsMouseClicked(mouse_button) && IsItemHovered(ImGuiHoveredFlags_Default); 4667 ImGuiContext& g = *GImGui; 4668 ImGuiWindow* window = g.CurrentWindow; 4669 4670 if (g.NavId == 0 || g.NavDisableHighlight || g.NavId != window->DC.LastItemId) 4671 return false; 4672 return true; 4673 } 4674 4675 bool ImGui::IsItemClicked(ImGuiMouseButton mouse_button) 4676 { 4677 return IsMouseClicked(mouse_button) && IsItemHovered(ImGuiHoveredFlags_None); 4678 } 4679 4680 bool ImGui::IsItemToggledOpen() 4681 { 4682 ImGuiContext& g = *GImGui; 4683 return (g.CurrentWindow->DC.LastItemStatusFlags & ImGuiItemStatusFlags_ToggledOpen) ? true : false; 4684 } 4685 4686 bool ImGui::IsItemToggledSelection() 4687 { 4688 ImGuiContext& g = *GImGui; 4689 return (g.CurrentWindow->DC.LastItemStatusFlags & ImGuiItemStatusFlags_ToggledSelection) ? true : false; 4747 4690 } 4748 4691 4749 4692 bool ImGui::IsAnyItemHovered() 4750 4693 { 4751 ImGuiContext& g = *GImGui;4752 return g.HoveredId != 0 || g.HoveredIdPreviousFrame != 0;4694 ImGuiContext& g = *GImGui; 4695 return g.HoveredId != 0 || g.HoveredIdPreviousFrame != 0; 4753 4696 } 4754 4697 4755 4698 bool ImGui::IsAnyItemActive() 4756 4699 { 4757 ImGuiContext& g = *GImGui;4758 return g.ActiveId != 0;4700 ImGuiContext& g = *GImGui; 4701 return g.ActiveId != 0; 4759 4702 } 4760 4703 4761 4704 bool ImGui::IsAnyItemFocused() 4762 4705 { 4763 ImGuiContext& g = *GImGui;4764 return g.NavId != 0 && !g.NavDisableHighlight;4706 ImGuiContext& g = *GImGui; 4707 return g.NavId != 0 && !g.NavDisableHighlight; 4765 4708 } 4766 4709 4767 4710 bool ImGui::IsItemVisible() 4768 4711 { 4769 ImGuiWindow* window = GetCurrentWindowRead(); 4770 return window->ClipRect.Overlaps(window->DC.LastItemRect); 4712 ImGuiWindow* window = GetCurrentWindowRead(); 4713 return window->ClipRect.Overlaps(window->DC.LastItemRect); 4714 } 4715 4716 bool ImGui::IsItemEdited() 4717 { 4718 ImGuiWindow* window = GetCurrentWindowRead(); 4719 return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Edited) != 0; 4771 4720 } 4772 4721 … … 4774 4723 void ImGui::SetItemAllowOverlap() 4775 4724 { 4776 ImGuiContext& g = *GImGui;4777 if (g.HoveredId == g.CurrentWindow->DC.LastItemId)4778 g.HoveredIdAllowOverlap = true;4779 if (g.ActiveId == g.CurrentWindow->DC.LastItemId)4780 g.ActiveIdAllowOverlap = true;4725 ImGuiContext& g = *GImGui; 4726 if (g.HoveredId == g.CurrentWindow->DC.LastItemId) 4727 g.HoveredIdAllowOverlap = true; 4728 if (g.ActiveId == g.CurrentWindow->DC.LastItemId) 4729 g.ActiveIdAllowOverlap = true; 4781 4730 } 4782 4731 4783 4732 ImVec2 ImGui::GetItemRectMin() 4784 4733 { 4785 ImGuiWindow* window = GetCurrentWindowRead();4786 return window->DC.LastItemRect.Min;4734 ImGuiWindow* window = GetCurrentWindowRead(); 4735 return window->DC.LastItemRect.Min; 4787 4736 } 4788 4737 4789 4738 ImVec2 ImGui::GetItemRectMax() 4790 4739 { 4791 ImGuiWindow* window = GetCurrentWindowRead();4792 return window->DC.LastItemRect.Max;4740 ImGuiWindow* window = GetCurrentWindowRead(); 4741 return window->DC.LastItemRect.Max; 4793 4742 } 4794 4743 4795 4744 ImVec2 ImGui::GetItemRectSize() 4796 4745 { 4797 ImGuiWindow* window = GetCurrentWindowRead();4798 return window->DC.LastItemRect.GetSize();4746 ImGuiWindow* window = GetCurrentWindowRead(); 4747 return window->DC.LastItemRect.GetSize(); 4799 4748 } 4800 4749 4801 4750 static ImRect GetViewportRect() 4802 4751 { 4803 ImGuiContext& g = *GImGui; 4804 if (g.IO.DisplayVisibleMin.x != g.IO.DisplayVisibleMax.x && g.IO.DisplayVisibleMin.y != g.IO.DisplayVisibleMax.y) 4805 return ImRect(g.IO.DisplayVisibleMin, g.IO.DisplayVisibleMax); 4806 return ImRect(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y); 4807 } 4808 4809 // Not exposed publicly as BeginTooltip() because bool parameters are evil. Let's see if other needs arise first. 4810 void ImGui::BeginTooltipEx(ImGuiWindowFlags extra_flags, bool override_previous_tooltip) 4811 { 4812 ImGuiContext& g = *GImGui; 4813 char window_name[16]; 4814 ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", g.TooltipOverrideCount); 4815 if (override_previous_tooltip) 4816 if (ImGuiWindow* window = FindWindowByName(window_name)) 4817 if (window->Active) 4818 { 4819 // Hide previous tooltip from being displayed. We can't easily "reset" the content of a window so we create a new one. 4820 window->HiddenFrames = 1; 4821 ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", ++g.TooltipOverrideCount); 4822 } 4823 ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoNav; 4824 Begin(window_name, NULL, flags | extra_flags); 4825 } 4826 4827 void ImGui::SetTooltipV(const char* fmt, va_list args) 4828 { 4829 BeginTooltipEx(0, true); 4830 TextV(fmt, args); 4831 EndTooltip(); 4832 } 4833 4834 void ImGui::SetTooltip(const char* fmt, ...) 4835 { 4836 va_list args; 4837 va_start(args, fmt); 4838 SetTooltipV(fmt, args); 4839 va_end(args); 4840 } 4841 4842 void ImGui::BeginTooltip() 4843 { 4844 BeginTooltipEx(0, false); 4845 } 4846 4847 void ImGui::EndTooltip() 4848 { 4849 IM_ASSERT(GetCurrentWindowRead()->Flags & ImGuiWindowFlags_Tooltip); // Mismatched BeginTooltip()/EndTooltip() calls 4850 End(); 4851 } 4852 4853 // Mark popup as open (toggle toward open state). 4854 // Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. 4855 // Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). 4856 // One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL) 4857 void ImGui::OpenPopupEx(ImGuiID id) 4858 { 4859 ImGuiContext& g = *GImGui; 4860 ImGuiWindow* parent_window = g.CurrentWindow; 4861 int current_stack_size = g.CurrentPopupStack.Size; 4862 ImGuiPopupRef popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack. 4863 popup_ref.PopupId = id; 4864 popup_ref.Window = NULL; 4865 popup_ref.ParentWindow = parent_window; 4866 popup_ref.OpenFrameCount = g.FrameCount; 4867 popup_ref.OpenParentId = parent_window->IDStack.back(); 4868 popup_ref.OpenMousePos = g.IO.MousePos; 4869 popup_ref.OpenPopupPos = NavCalcPreferredRefPos(); 4870 4871 //printf("[%05d] OpenPopupEx(0x%08X)\n", g.FrameCount, id); 4872 if (g.OpenPopupStack.Size < current_stack_size + 1) 4873 { 4874 g.OpenPopupStack.push_back(popup_ref); 4875 } 4876 else 4877 { 4878 // Close child popups if any 4879 g.OpenPopupStack.resize(current_stack_size + 1); 4880 4881 // 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 4882 // 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 4883 // 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. 4884 if (g.OpenPopupStack[current_stack_size].PopupId == id && g.OpenPopupStack[current_stack_size].OpenFrameCount == g.FrameCount - 1) 4885 g.OpenPopupStack[current_stack_size].OpenFrameCount = popup_ref.OpenFrameCount; 4886 else 4887 g.OpenPopupStack[current_stack_size] = popup_ref; 4888 4889 // When reopening a popup we first refocus its parent, otherwise if its parent is itself a popup it would get closed by ClosePopupsOverWindow(). 4890 // This is equivalent to what ClosePopupToLevel() does. 4891 //if (g.OpenPopupStack[current_stack_size].PopupId == id) 4892 // FocusWindow(parent_window); 4893 } 4894 } 4895 4896 void ImGui::OpenPopup(const char* str_id) 4897 { 4898 ImGuiContext& g = *GImGui; 4899 OpenPopupEx(g.CurrentWindow->GetID(str_id)); 4900 } 4901 4902 void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window) 4903 { 4904 ImGuiContext& g = *GImGui; 4905 if (g.OpenPopupStack.empty()) 4906 return; 4907 4908 // When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it. 4909 // Don't close our own child popup windows. 4910 int n = 0; 4911 if (ref_window) 4912 { 4913 for (n = 0; n < g.OpenPopupStack.Size; n++) 4914 { 4915 ImGuiPopupRef& popup = g.OpenPopupStack[n]; 4916 if (!popup.Window) 4917 continue; 4918 IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0); 4919 if (popup.Window->Flags & ImGuiWindowFlags_ChildWindow) 4920 continue; 4921 4922 // Trim the stack if popups are not direct descendant of the reference window (which is often the NavWindow) 4923 bool has_focus = false; 4924 for (int m = n; m < g.OpenPopupStack.Size && !has_focus; m++) 4925 has_focus = (g.OpenPopupStack[m].Window && g.OpenPopupStack[m].Window->RootWindow == ref_window->RootWindow); 4926 if (!has_focus) 4927 break; 4928 } 4929 } 4930 if (n < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the block below 4931 ClosePopupToLevel(n); 4932 } 4933 4934 ImGuiWindow* ImGui::GetFrontMostPopupModal() 4935 { 4936 ImGuiContext& g = *GImGui; 4937 for (int n = g.OpenPopupStack.Size - 1; n >= 0; n--) 4938 if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window) 4939 if (popup->Flags & ImGuiWindowFlags_Modal) 4940 return popup; 4941 return NULL; 4942 } 4943 4944 static void ClosePopupToLevel(int remaining) 4945 { 4946 IM_ASSERT(remaining >= 0); 4947 ImGuiContext& g = *GImGui; 4948 ImGuiWindow* focus_window = (remaining > 0) ? g.OpenPopupStack[remaining - 1].Window : g.OpenPopupStack[0].ParentWindow; 4949 if (g.NavLayer == 0) 4950 focus_window = NavRestoreLastChildNavWindow(focus_window); 4951 ImGui::FocusWindow(focus_window); 4952 focus_window->DC.NavHideHighlightOneFrame = true; 4953 g.OpenPopupStack.resize(remaining); 4954 } 4955 4956 void ImGui::ClosePopup(ImGuiID id) 4957 { 4958 if (!IsPopupOpen(id)) 4959 return; 4960 ImGuiContext& g = *GImGui; 4961 ClosePopupToLevel(g.OpenPopupStack.Size - 1); 4962 } 4963 4964 // Close the popup we have begin-ed into. 4965 void ImGui::CloseCurrentPopup() 4966 { 4967 ImGuiContext& g = *GImGui; 4968 int popup_idx = g.CurrentPopupStack.Size - 1; 4969 if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.CurrentPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId) 4970 return; 4971 while (popup_idx > 0 && g.OpenPopupStack[popup_idx].Window && (g.OpenPopupStack[popup_idx].Window->Flags & ImGuiWindowFlags_ChildMenu)) 4972 popup_idx--; 4973 ClosePopupToLevel(popup_idx); 4974 } 4975 4976 bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags) 4977 { 4978 ImGuiContext& g = *GImGui; 4979 if (!IsPopupOpen(id)) 4980 { 4981 g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values 4982 return false; 4983 } 4984 4985 char name[20]; 4986 if (extra_flags & ImGuiWindowFlags_ChildMenu) 4987 ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.CurrentPopupStack.Size); // Recycle windows based on depth 4988 else 4989 ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame 4990 4991 bool is_open = Begin(name, NULL, extra_flags | ImGuiWindowFlags_Popup); 4992 if (!is_open) // NB: Begin can return false when the popup is completely clipped (e.g. zero size display) 4993 EndPopup(); 4994 4995 return is_open; 4996 } 4997 4998 bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags) 4999 { 5000 ImGuiContext& g = *GImGui; 5001 if (g.OpenPopupStack.Size <= g.CurrentPopupStack.Size) // Early out for performance 5002 { 5003 g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values 5004 return false; 5005 } 5006 return BeginPopupEx(g.CurrentWindow->GetID(str_id), flags | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings); 5007 } 5008 5009 bool ImGui::IsPopupOpen(ImGuiID id) 5010 { 5011 ImGuiContext& g = *GImGui; 5012 return g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].PopupId == id; 5013 } 5014 5015 bool ImGui::IsPopupOpen(const char* str_id) 5016 { 5017 ImGuiContext& g = *GImGui; 5018 return g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].PopupId == g.CurrentWindow->GetID(str_id); 5019 } 5020 5021 bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags) 5022 { 5023 ImGuiContext& g = *GImGui; 5024 ImGuiWindow* window = g.CurrentWindow; 5025 const ImGuiID id = window->GetID(name); 5026 if (!IsPopupOpen(id)) 5027 { 5028 g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values 5029 return false; 5030 } 5031 5032 // Center modal windows by default 5033 // FIXME: Should test for (PosCond & window->SetWindowPosAllowFlags) with the upcoming window. 5034 if (g.NextWindowData.PosCond == 0) 5035 SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); 5036 5037 bool is_open = Begin(name, p_open, flags | ImGuiWindowFlags_Popup | ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings); 5038 if (!is_open || (p_open && !*p_open)) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display) 5039 { 5040 EndPopup(); 5041 if (is_open) 5042 ClosePopup(id); 5043 return false; 5044 } 5045 5046 return is_open; 5047 } 5048 5049 static void NavProcessMoveRequestWrapAround(ImGuiWindow* window) 5050 { 5051 ImGuiContext& g = *GImGui; 5052 if (g.NavWindow == window && NavMoveRequestButNoResultYet()) 5053 if ((g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) && g.NavMoveRequestForward == ImGuiNavForward_None && g.NavLayer == 0) 5054 { 5055 g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued; 5056 ImGui::NavMoveRequestCancel(); 5057 g.NavWindow->NavRectRel[0].Min.y = g.NavWindow->NavRectRel[0].Max.y = ((g.NavMoveDir == ImGuiDir_Up) ? ImMax(window->SizeFull.y, window->SizeContents.y) : 0.0f) - window->Scroll.y; 5058 } 5059 } 5060 5061 void ImGui::EndPopup() 5062 { 5063 ImGuiContext& g = *GImGui; (void)g; 5064 IM_ASSERT(g.CurrentWindow->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls 5065 IM_ASSERT(g.CurrentPopupStack.Size > 0); 5066 5067 // Make all menus and popups wrap around for now, may need to expose that policy. 5068 NavProcessMoveRequestWrapAround(g.CurrentWindow); 5069 5070 End(); 5071 } 5072 5073 bool ImGui::OpenPopupOnItemClick(const char* str_id, int mouse_button) 5074 { 5075 ImGuiWindow* window = GImGui->CurrentWindow; 5076 if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) 5077 { 5078 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! 5079 IM_ASSERT(id != 0); // However, you cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item) 5080 OpenPopupEx(id); 5081 return true; 5082 } 5083 return false; 5084 } 5085 5086 // This is a helper to handle the simplest case of associating one named popup to one given widget. 5087 // You may want to handle this on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters). 5088 // You can pass a NULL str_id to use the identifier of the last item. 5089 bool ImGui::BeginPopupContextItem(const char* str_id, int mouse_button) 5090 { 5091 ImGuiWindow* window = GImGui->CurrentWindow; 5092 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! 5093 IM_ASSERT(id != 0); // However, you cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item) 5094 if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) 5095 OpenPopupEx(id); 5096 return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings); 5097 } 5098 5099 bool ImGui::BeginPopupContextWindow(const char* str_id, int mouse_button, bool also_over_items) 5100 { 5101 if (!str_id) 5102 str_id = "window_context"; 5103 ImGuiID id = GImGui->CurrentWindow->GetID(str_id); 5104 if (IsMouseReleased(mouse_button) && IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) 5105 if (also_over_items || !IsAnyItemHovered()) 5106 OpenPopupEx(id); 5107 return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings); 5108 } 5109 5110 bool ImGui::BeginPopupContextVoid(const char* str_id, int mouse_button) 5111 { 5112 if (!str_id) 5113 str_id = "void_context"; 5114 ImGuiID id = GImGui->CurrentWindow->GetID(str_id); 5115 if (IsMouseReleased(mouse_button) && !IsWindowHovered(ImGuiHoveredFlags_AnyWindow)) 5116 OpenPopupEx(id); 5117 return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings); 5118 } 5119 5120 static bool BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags) 5121 { 5122 ImGuiContext& g = *GImGui; 5123 ImGuiWindow* parent_window = ImGui::GetCurrentWindow(); 5124 ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_ChildWindow; 5125 flags |= (parent_window->Flags & ImGuiWindowFlags_NoMove); // Inherit the NoMove flag 5126 5127 const ImVec2 content_avail = ImGui::GetContentRegionAvail(); 5128 ImVec2 size = ImFloor(size_arg); 5129 const int auto_fit_axises = ((size.x == 0.0f) ? (1 << ImGuiAxis_X) : 0x00) | ((size.y == 0.0f) ? (1 << ImGuiAxis_Y) : 0x00); 5130 if (size.x <= 0.0f) 5131 size.x = ImMax(content_avail.x + size.x, 4.0f); // Arbitrary minimum child size (0.0f causing too much issues) 5132 if (size.y <= 0.0f) 5133 size.y = ImMax(content_avail.y + size.y, 4.0f); 5134 5135 const float backup_border_size = g.Style.ChildBorderSize; 5136 if (!border) 5137 g.Style.ChildBorderSize = 0.0f; 5138 flags |= extra_flags; 5139 5140 char title[256]; 5141 if (name) 5142 ImFormatString(title, IM_ARRAYSIZE(title), "%s/%s", parent_window->Name, name); 5143 else 5144 ImFormatString(title, IM_ARRAYSIZE(title), "%s/%08X", parent_window->Name, id); 5145 5146 ImGui::SetNextWindowSize(size); 5147 bool ret = ImGui::Begin(title, NULL, flags); 5148 ImGuiWindow* child_window = ImGui::GetCurrentWindow(); 5149 child_window->ChildId = id; 5150 child_window->AutoFitChildAxises = auto_fit_axises; 5151 g.Style.ChildBorderSize = backup_border_size; 5152 5153 // Process navigation-in immediately so NavInit can run on first frame 5154 if (!(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayerActiveMask != 0 || child_window->DC.NavHasScroll) && g.NavActivateId == id) 5155 { 5156 ImGui::FocusWindow(child_window); 5157 ImGui::NavInitWindow(child_window, false); 5158 ImGui::SetActiveID(id + 1, child_window); // Steal ActiveId with a dummy id so that key-press won't activate child item 5159 g.ActiveIdSource = ImGuiInputSource_Nav; 5160 } 5161 5162 return ret; 4752 ImGuiContext& g = *GImGui; 4753 return ImRect(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y); 4754 } 4755 4756 bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags) 4757 { 4758 ImGuiContext& g = *GImGui; 4759 ImGuiWindow* parent_window = g.CurrentWindow; 4760 4761 flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_ChildWindow; 4762 flags |= (parent_window->Flags & ImGuiWindowFlags_NoMove); // Inherit the NoMove flag 4763 4764 // Size 4765 const ImVec2 content_avail = GetContentRegionAvail(); 4766 ImVec2 size = ImFloor(size_arg); 4767 const int auto_fit_axises = ((size.x == 0.0f) ? (1 << ImGuiAxis_X) : 0x00) | ((size.y == 0.0f) ? (1 << ImGuiAxis_Y) : 0x00); 4768 if (size.x <= 0.0f) 4769 size.x = ImMax(content_avail.x + size.x, 4.0f); // Arbitrary minimum child size (0.0f causing too much issues) 4770 if (size.y <= 0.0f) 4771 size.y = ImMax(content_avail.y + size.y, 4.0f); 4772 SetNextWindowSize(size); 4773 4774 // 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. 4775 char title[256]; 4776 if (name) 4777 ImFormatString(title, IM_ARRAYSIZE(title), "%s/%s_%08X", parent_window->Name, name, id); 4778 else 4779 ImFormatString(title, IM_ARRAYSIZE(title), "%s/%08X", parent_window->Name, id); 4780 4781 const float backup_border_size = g.Style.ChildBorderSize; 4782 if (!border) 4783 g.Style.ChildBorderSize = 0.0f; 4784 bool ret = Begin(title, NULL, flags); 4785 g.Style.ChildBorderSize = backup_border_size; 4786 4787 ImGuiWindow* child_window = g.CurrentWindow; 4788 child_window->ChildId = id; 4789 child_window->AutoFitChildAxises = (ImS8)auto_fit_axises; 4790 4791 // Set the cursor to handle case where the user called SetNextWindowPos()+BeginChild() manually. 4792 // While this is not really documented/defined, it seems that the expected thing to do. 4793 if (child_window->BeginCount == 1) 4794 parent_window->DC.CursorPos = child_window->Pos; 4795 4796 // Process navigation-in immediately so NavInit can run on first frame 4797 if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayerActiveMask != 0 || child_window->DC.NavHasScroll)) 4798 { 4799 FocusWindow(child_window); 4800 NavInitWindow(child_window, false); 4801 SetActiveID(id + 1, child_window); // Steal ActiveId with another arbitrary id so that key-press won't activate child item 4802 g.ActiveIdSource = ImGuiInputSource_Nav; 4803 } 4804 return ret; 5163 4805 } 5164 4806 5165 4807 bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags) 5166 4808 { 5167 ImGuiWindow* window = GetCurrentWindow();5168 return BeginChildEx(str_id, window->GetID(str_id), size_arg, border, extra_flags);4809 ImGuiWindow* window = GetCurrentWindow(); 4810 return BeginChildEx(str_id, window->GetID(str_id), size_arg, border, extra_flags); 5169 4811 } 5170 4812 5171 4813 bool ImGui::BeginChild(ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags) 5172 4814 { 5173 IM_ASSERT(id != 0);5174 return BeginChildEx(NULL, id, size_arg, border, extra_flags);4815 IM_ASSERT(id != 0); 4816 return BeginChildEx(NULL, id, size_arg, border, extra_flags); 5175 4817 } 5176 4818 5177 4819 void ImGui::EndChild() 5178 4820 { 5179 ImGuiContext& g = *GImGui; 5180 ImGuiWindow* window = g.CurrentWindow; 5181 5182 IM_ASSERT(window->Flags & ImGuiWindowFlags_ChildWindow); // Mismatched BeginChild()/EndChild() callss 5183 if (window->BeginCount > 1) 5184 { 5185 End(); 5186 } 5187 else 5188 { 5189 // When using auto-filling child window, we don't provide full width/height to ItemSize so that it doesn't feed back into automatic size-fitting. 5190 ImVec2 sz = GetWindowSize(); 5191 if (window->AutoFitChildAxises & (1 << ImGuiAxis_X)) // Arbitrary minimum zero-ish child size of 4.0f causes less trouble than a 0.0f 5192 sz.x = ImMax(4.0f, sz.x); 5193 if (window->AutoFitChildAxises & (1 << ImGuiAxis_Y)) 5194 sz.y = ImMax(4.0f, sz.y); 5195 End(); 5196 5197 ImGuiWindow* parent_window = g.CurrentWindow; 5198 ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + sz); 5199 ItemSize(sz); 5200 if ((window->DC.NavLayerActiveMask != 0 || window->DC.NavHasScroll) && !(window->Flags & ImGuiWindowFlags_NavFlattened)) 5201 { 5202 ItemAdd(bb, window->ChildId); 5203 RenderNavHighlight(bb, window->ChildId); 5204 5205 // When browsing a window that has no activable items (scroll only) we keep a highlight on the child 5206 if (window->DC.NavLayerActiveMask == 0 && window == g.NavWindow) 5207 RenderNavHighlight(ImRect(bb.Min - ImVec2(2, 2), bb.Max + ImVec2(2, 2)), g.NavId, ImGuiNavHighlightFlags_TypeThin); 5208 } 5209 else 5210 { 5211 // Not navigable into 5212 ItemAdd(bb, 0); 5213 } 5214 } 4821 ImGuiContext& g = *GImGui; 4822 ImGuiWindow* window = g.CurrentWindow; 4823 4824 IM_ASSERT(g.WithinEndChild == false); 4825 IM_ASSERT(window->Flags & ImGuiWindowFlags_ChildWindow); // Mismatched BeginChild()/EndChild() calls 4826 4827 g.WithinEndChild = true; 4828 if (window->BeginCount > 1) 4829 { 4830 End(); 4831 } 4832 else 4833 { 4834 ImVec2 sz = window->Size; 4835 if (window->AutoFitChildAxises & (1 << ImGuiAxis_X)) // Arbitrary minimum zero-ish child size of 4.0f causes less trouble than a 0.0f 4836 sz.x = ImMax(4.0f, sz.x); 4837 if (window->AutoFitChildAxises & (1 << ImGuiAxis_Y)) 4838 sz.y = ImMax(4.0f, sz.y); 4839 End(); 4840 4841 ImGuiWindow* parent_window = g.CurrentWindow; 4842 ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + sz); 4843 ItemSize(sz); 4844 if ((window->DC.NavLayerActiveMask != 0 || window->DC.NavHasScroll) && !(window->Flags & ImGuiWindowFlags_NavFlattened)) 4845 { 4846 ItemAdd(bb, window->ChildId); 4847 RenderNavHighlight(bb, window->ChildId); 4848 4849 // When browsing a window that has no activable items (scroll only) we keep a highlight on the child 4850 if (window->DC.NavLayerActiveMask == 0 && window == g.NavWindow) 4851 RenderNavHighlight(ImRect(bb.Min - ImVec2(2, 2), bb.Max + ImVec2(2, 2)), g.NavId, ImGuiNavHighlightFlags_TypeThin); 4852 } 4853 else 4854 { 4855 // Not navigable into 4856 ItemAdd(bb, 0); 4857 } 4858 } 4859 g.WithinEndChild = false; 5215 4860 } 5216 4861 … … 5218 4863 bool ImGui::BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags extra_flags) 5219 4864 { 5220 ImGuiContext& g = *GImGui; 5221 const ImGuiStyle& style = g.Style; 5222 PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]); 5223 PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding); 5224 PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize); 5225 PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding); 5226 return BeginChild(id, size, true, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysUseWindowPadding | extra_flags); 4865 ImGuiContext& g = *GImGui; 4866 const ImGuiStyle& style = g.Style; 4867 PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]); 4868 PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding); 4869 PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize); 4870 PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding); 4871 bool ret = BeginChild(id, size, true, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysUseWindowPadding | extra_flags); 4872 PopStyleVar(3); 4873 PopStyleColor(); 4874 return ret; 5227 4875 } 5228 4876 5229 4877 void ImGui::EndChildFrame() 5230 4878 { 5231 EndChild(); 5232 PopStyleVar(3); 5233 PopStyleColor(); 5234 } 5235 5236 // Save and compare stack sizes on Begin()/End() to detect usage errors 5237 static void CheckStacksSize(ImGuiWindow* window, bool write) 5238 { 5239 // 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) 5240 ImGuiContext& g = *GImGui; 5241 int* p_backup = &window->DC.StackSizesBackup[0]; 5242 { int current = window->IDStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "PushID/PopID or TreeNode/TreePop Mismatch!"); p_backup++; } // Too few or too many PopID()/TreePop() 5243 { int current = window->DC.GroupStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "BeginGroup/EndGroup Mismatch!"); p_backup++; } // Too few or too many EndGroup() 5244 { int current = g.CurrentPopupStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch"); p_backup++; }// Too few or too many EndMenu()/EndPopup() 5245 // 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. 5246 { int current = g.ColorModifiers.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup >= current && "PushStyleColor/PopStyleColor Mismatch!"); p_backup++; } // Too few or too many PopStyleColor() 5247 { int current = g.StyleModifiers.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup >= current && "PushStyleVar/PopStyleVar Mismatch!"); p_backup++; } // Too few or too many PopStyleVar() 5248 { int current = g.FontStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup >= current && "PushFont/PopFont Mismatch!"); p_backup++; } // Too few or too many PopFont() 5249 IM_ASSERT(p_backup == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup)); 5250 } 5251 5252 enum ImGuiPopupPositionPolicy 5253 { 5254 ImGuiPopupPositionPolicy_Default, 5255 ImGuiPopupPositionPolicy_ComboBox 4879 EndChild(); 4880 } 4881 4882 static void SetWindowConditionAllowFlags(ImGuiWindow* window, ImGuiCond flags, bool enabled) 4883 { 4884 window->SetWindowPosAllowFlags = enabled ? (window->SetWindowPosAllowFlags | flags) : (window->SetWindowPosAllowFlags & ~flags); 4885 window->SetWindowSizeAllowFlags = enabled ? (window->SetWindowSizeAllowFlags | flags) : (window->SetWindowSizeAllowFlags & ~flags); 4886 window->SetWindowCollapsedAllowFlags = enabled ? (window->SetWindowCollapsedAllowFlags | flags) : (window->SetWindowCollapsedAllowFlags & ~flags); 4887 } 4888 4889 ImGuiWindow* ImGui::FindWindowByID(ImGuiID id) 4890 { 4891 ImGuiContext& g = *GImGui; 4892 return (ImGuiWindow*)g.WindowsById.GetVoidPtr(id); 4893 } 4894 4895 ImGuiWindow* ImGui::FindWindowByName(const char* name) 4896 { 4897 ImGuiID id = ImHashStr(name); 4898 return FindWindowByID(id); 4899 } 4900 4901 static void ApplyWindowSettings(ImGuiWindow* window, ImGuiWindowSettings* settings) 4902 { 4903 window->Pos = ImFloor(ImVec2(settings->Pos.x, settings->Pos.y)); 4904 if (settings->Size.x > 0 && settings->Size.y > 0) 4905 window->Size = window->SizeFull = ImFloor(ImVec2(settings->Size.x, settings->Size.y)); 4906 window->Collapsed = settings->Collapsed; 4907 } 4908 4909 static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags) 4910 { 4911 ImGuiContext& g = *GImGui; 4912 //IMGUI_DEBUG_LOG("CreateNewWindow '%s', flags = 0x%08X\n", name, flags); 4913 4914 // Create window the first time 4915 ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name); 4916 window->Flags = flags; 4917 g.WindowsById.SetVoidPtr(window->ID, window); 4918 4919 // Default/arbitrary window position. Use SetNextWindowPos() with the appropriate condition flag to change the initial position of a window. 4920 window->Pos = ImVec2(60, 60); 4921 4922 // User can disable loading and saving of settings. Tooltip and child windows also don't store settings. 4923 if (!(flags & ImGuiWindowFlags_NoSavedSettings)) 4924 if (ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID)) 4925 { 4926 // Retrieve settings from .ini file 4927 window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings); 4928 SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false); 4929 ApplyWindowSettings(window, settings); 4930 } 4931 window->DC.CursorStartPos = window->DC.CursorMaxPos = window->Pos; // So first call to CalcContentSize() doesn't return crazy values 4932 4933 if ((flags & ImGuiWindowFlags_AlwaysAutoResize) != 0) 4934 { 4935 window->AutoFitFramesX = window->AutoFitFramesY = 2; 4936 window->AutoFitOnlyGrows = false; 4937 } 4938 else 4939 { 4940 if (window->Size.x <= 0.0f) 4941 window->AutoFitFramesX = 2; 4942 if (window->Size.y <= 0.0f) 4943 window->AutoFitFramesY = 2; 4944 window->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0); 4945 } 4946 4947 g.WindowsFocusOrder.push_back(window); 4948 if (flags & ImGuiWindowFlags_NoBringToFrontOnFocus) 4949 g.Windows.push_front(window); // Quite slow but rare and only once 4950 else 4951 g.Windows.push_back(window); 4952 return window; 4953 } 4954 4955 static ImVec2 CalcWindowSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size) 4956 { 4957 ImGuiContext& g = *GImGui; 4958 if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint) 4959 { 4960 // Using -1,-1 on either X/Y axis to preserve the current size. 4961 ImRect cr = g.NextWindowData.SizeConstraintRect; 4962 new_size.x = (cr.Min.x >= 0 && cr.Max.x >= 0) ? ImClamp(new_size.x, cr.Min.x, cr.Max.x) : window->SizeFull.x; 4963 new_size.y = (cr.Min.y >= 0 && cr.Max.y >= 0) ? ImClamp(new_size.y, cr.Min.y, cr.Max.y) : window->SizeFull.y; 4964 if (g.NextWindowData.SizeCallback) 4965 { 4966 ImGuiSizeCallbackData data; 4967 data.UserData = g.NextWindowData.SizeCallbackUserData; 4968 data.Pos = window->Pos; 4969 data.CurrentSize = window->SizeFull; 4970 data.DesiredSize = new_size; 4971 g.NextWindowData.SizeCallback(&data); 4972 new_size = data.DesiredSize; 4973 } 4974 new_size.x = IM_FLOOR(new_size.x); 4975 new_size.y = IM_FLOOR(new_size.y); 4976 } 4977 4978 // Minimum size 4979 if (!(window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysAutoResize))) 4980 { 4981 ImGuiWindow* window_for_height = window; 4982 new_size = ImMax(new_size, g.Style.WindowMinSize); 4983 new_size.y = ImMax(new_size.y, window_for_height->TitleBarHeight() + window_for_height->MenuBarHeight() + ImMax(0.0f, g.Style.WindowRounding - 1.0f)); // Reduce artifacts with very small windows 4984 } 4985 return new_size; 4986 } 4987 4988 static ImVec2 CalcWindowContentSize(ImGuiWindow* window) 4989 { 4990 if (window->Collapsed) 4991 if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) 4992 return window->ContentSize; 4993 if (window->Hidden && window->HiddenFramesCannotSkipItems == 0 && window->HiddenFramesCanSkipItems > 0) 4994 return window->ContentSize; 4995 4996 ImVec2 sz; 4997 sz.x = IM_FLOOR((window->ContentSizeExplicit.x != 0.0f) ? window->ContentSizeExplicit.x : window->DC.CursorMaxPos.x - window->DC.CursorStartPos.x); 4998 sz.y = IM_FLOOR((window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : window->DC.CursorMaxPos.y - window->DC.CursorStartPos.y); 4999 return sz; 5000 } 5001 5002 static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_contents) 5003 { 5004 ImGuiContext& g = *GImGui; 5005 ImGuiStyle& style = g.Style; 5006 ImVec2 size_decorations = ImVec2(0.0f, window->TitleBarHeight() + window->MenuBarHeight()); 5007 ImVec2 size_pad = window->WindowPadding * 2.0f; 5008 ImVec2 size_desired = size_contents + size_pad + size_decorations; 5009 if (window->Flags & ImGuiWindowFlags_Tooltip) 5010 { 5011 // Tooltip always resize 5012 return size_desired; 5013 } 5014 else 5015 { 5016 // Maximum window size is determined by the viewport size or monitor size 5017 const bool is_popup = (window->Flags & ImGuiWindowFlags_Popup) != 0; 5018 const bool is_menu = (window->Flags & ImGuiWindowFlags_ChildMenu) != 0; 5019 ImVec2 size_min = style.WindowMinSize; 5020 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) 5021 size_min = ImMin(size_min, ImVec2(4.0f, 4.0f)); 5022 ImVec2 size_auto_fit = ImClamp(size_desired, size_min, ImMax(size_min, g.IO.DisplaySize - style.DisplaySafeAreaPadding * 2.0f)); 5023 5024 // When the window cannot fit all contents (either because of constraints, either because screen is too small), 5025 // we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than ViewportSize-WindowPadding. 5026 ImVec2 size_auto_fit_after_constraint = CalcWindowSizeAfterConstraint(window, size_auto_fit); 5027 bool will_have_scrollbar_x = (size_auto_fit_after_constraint.x - size_pad.x - size_decorations.x < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar); 5028 bool will_have_scrollbar_y = (size_auto_fit_after_constraint.y - size_pad.y - size_decorations.y < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysVerticalScrollbar); 5029 if (will_have_scrollbar_x) 5030 size_auto_fit.y += style.ScrollbarSize; 5031 if (will_have_scrollbar_y) 5032 size_auto_fit.x += style.ScrollbarSize; 5033 return size_auto_fit; 5034 } 5035 } 5036 5037 ImVec2 ImGui::CalcWindowExpectedSize(ImGuiWindow* window) 5038 { 5039 ImVec2 size_contents = CalcWindowContentSize(window); 5040 ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, size_contents); 5041 ImVec2 size_final = CalcWindowSizeAfterConstraint(window, size_auto_fit); 5042 return size_final; 5043 } 5044 5045 static ImGuiCol GetWindowBgColorIdxFromFlags(ImGuiWindowFlags flags) 5046 { 5047 if (flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) 5048 return ImGuiCol_PopupBg; 5049 if (flags & ImGuiWindowFlags_ChildWindow) 5050 return ImGuiCol_ChildBg; 5051 return ImGuiCol_WindowBg; 5052 } 5053 5054 static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& corner_target, const ImVec2& corner_norm, ImVec2* out_pos, ImVec2* out_size) 5055 { 5056 ImVec2 pos_min = ImLerp(corner_target, window->Pos, corner_norm); // Expected window upper-left 5057 ImVec2 pos_max = ImLerp(window->Pos + window->Size, corner_target, corner_norm); // Expected window lower-right 5058 ImVec2 size_expected = pos_max - pos_min; 5059 ImVec2 size_constrained = CalcWindowSizeAfterConstraint(window, size_expected); 5060 *out_pos = pos_min; 5061 if (corner_norm.x == 0.0f) 5062 out_pos->x -= (size_constrained.x - size_expected.x); 5063 if (corner_norm.y == 0.0f) 5064 out_pos->y -= (size_constrained.y - size_expected.y); 5065 *out_size = size_constrained; 5066 } 5067 5068 struct ImGuiResizeGripDef 5069 { 5070 ImVec2 CornerPosN; 5071 ImVec2 InnerDir; 5072 int AngleMin12, AngleMax12; 5256 5073 }; 5257 5074 5258 static ImRect FindAllowedExtentRectForWindow(ImGuiWindow*) 5259 { 5260 ImVec2 padding = GImGui->Style.DisplaySafeAreaPadding; 5261 ImRect r_screen = GetViewportRect(); 5262 r_screen.Expand(ImVec2((r_screen.GetWidth() > padding.x * 2) ? -padding.x : 0.0f, (r_screen.GetHeight() > padding.y * 2) ? -padding.y : 0.0f)); 5263 return r_screen; 5264 } 5265 5266 // 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.) 5267 // 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. 5268 static ImVec2 FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy = ImGuiPopupPositionPolicy_Default) 5269 { 5270 ImVec2 base_pos_clamped = ImClamp(ref_pos, r_outer.Min, r_outer.Max - size); 5271 //GImGui->OverlayDrawList.AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255,0,0,255)); 5272 //GImGui->OverlayDrawList.AddRect(r_outer.Min, r_outer.Max, IM_COL32(0,255,0,255)); 5273 5274 // Combo Box policy (we want a connecting edge) 5275 if (policy == ImGuiPopupPositionPolicy_ComboBox) 5276 { 5277 const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Down, ImGuiDir_Right, ImGuiDir_Left, ImGuiDir_Up }; 5278 for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++) 5279 { 5280 const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n]; 5281 if (n != -1 && dir == *last_dir) // Already tried this direction? 5282 continue; 5283 ImVec2 pos; 5284 if (dir == ImGuiDir_Down) pos = ImVec2(r_avoid.Min.x, r_avoid.Max.y); // Below, Toward Right (default) 5285 if (dir == ImGuiDir_Right) pos = ImVec2(r_avoid.Min.x, r_avoid.Min.y - size.y); // Above, Toward Right 5286 if (dir == ImGuiDir_Left) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Max.y); // Below, Toward Left 5287 if (dir == ImGuiDir_Up) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Min.y - size.y); // Above, Toward Left 5288 if (!r_outer.Contains(ImRect(pos, pos + size))) 5289 continue; 5290 *last_dir = dir; 5291 return pos; 5292 } 5293 } 5294 5295 // Default popup policy 5296 const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Right, ImGuiDir_Down, ImGuiDir_Up, ImGuiDir_Left }; 5297 for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++) 5298 { 5299 const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n]; 5300 if (n != -1 && dir == *last_dir) // Already tried this direction? 5301 continue; 5302 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); 5303 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); 5304 if (avail_w < size.x || avail_h < size.y) 5305 continue; 5306 ImVec2 pos; 5307 pos.x = (dir == ImGuiDir_Left) ? r_avoid.Min.x - size.x : (dir == ImGuiDir_Right) ? r_avoid.Max.x : base_pos_clamped.x; 5308 pos.y = (dir == ImGuiDir_Up) ? r_avoid.Min.y - size.y : (dir == ImGuiDir_Down) ? r_avoid.Max.y : base_pos_clamped.y; 5309 *last_dir = dir; 5310 return pos; 5311 } 5312 5313 // Fallback, try to keep within display 5314 *last_dir = ImGuiDir_None; 5315 ImVec2 pos = ref_pos; 5316 pos.x = ImMax(ImMin(pos.x + size.x, r_outer.Max.x) - size.x, r_outer.Min.x); 5317 pos.y = ImMax(ImMin(pos.y + size.y, r_outer.Max.y) - size.y, r_outer.Min.y); 5318 return pos; 5319 } 5320 5321 static ImVec2 FindBestWindowPosForPopup(ImGuiWindow* window) 5322 { 5323 ImGuiContext& g = *GImGui; 5324 5325 ImRect r_outer = FindAllowedExtentRectForWindow(window); 5326 if (window->Flags & ImGuiWindowFlags_ChildMenu) 5327 { 5328 // Child menus typically request _any_ position within the parent menu item, and then our FindBestWindowPosForPopup() function will move the new menu outside the parent bounds. 5329 // This is how we end up with child menus appearing (most-commonly) on the right of the parent menu. 5330 IM_ASSERT(g.CurrentWindow == window); 5331 ImGuiWindow* parent_window = g.CurrentWindowStack[g.CurrentWindowStack.Size - 2]; 5332 float horizontal_overlap = g.Style.ItemSpacing.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). 5333 ImRect r_avoid; 5334 if (parent_window->DC.MenuBarAppending) 5335 r_avoid = ImRect(-FLT_MAX, parent_window->Pos.y + parent_window->TitleBarHeight(), FLT_MAX, parent_window->Pos.y + parent_window->TitleBarHeight() + parent_window->MenuBarHeight()); 5336 else 5337 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); 5338 return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid); 5339 } 5340 if (window->Flags & ImGuiWindowFlags_Popup) 5341 { 5342 ImRect r_avoid = ImRect(window->Pos.x - 1, window->Pos.y - 1, window->Pos.x + 1, window->Pos.y + 1); 5343 return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid); 5344 } 5345 if (window->Flags & ImGuiWindowFlags_Tooltip) 5346 { 5347 // Position tooltip (always follows mouse) 5348 float sc = g.Style.MouseCursorScale; 5349 ImVec2 ref_pos = NavCalcPreferredRefPos(); 5350 ImRect r_avoid; 5351 if (!g.NavDisableHighlight && g.NavDisableMouseHover && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos)) 5352 r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8); 5353 else 5354 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. 5355 ImVec2 pos = FindBestWindowPosForPopupEx(ref_pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid); 5356 if (window->AutoPosLastDirection == ImGuiDir_None) 5357 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. 5358 return pos; 5359 } 5360 IM_ASSERT(0); 5361 return window->Pos; 5362 } 5363 5364 static void SetWindowConditionAllowFlags(ImGuiWindow* window, ImGuiCond flags, bool enabled) 5365 { 5366 window->SetWindowPosAllowFlags = enabled ? (window->SetWindowPosAllowFlags | flags) : (window->SetWindowPosAllowFlags & ~flags); 5367 window->SetWindowSizeAllowFlags = enabled ? (window->SetWindowSizeAllowFlags | flags) : (window->SetWindowSizeAllowFlags & ~flags); 5368 window->SetWindowCollapsedAllowFlags = enabled ? (window->SetWindowCollapsedAllowFlags | flags) : (window->SetWindowCollapsedAllowFlags & ~flags); 5369 } 5370 5371 ImGuiWindow* ImGui::FindWindowByName(const char* name) 5372 { 5373 ImGuiContext& g = *GImGui; 5374 ImGuiID id = ImHash(name, 0); 5375 return (ImGuiWindow*)g.WindowsById.GetVoidPtr(id); 5376 } 5377 5378 static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFlags flags) 5379 { 5380 ImGuiContext& g = *GImGui; 5381 5382 // Create window the first time 5383 ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name); 5384 window->Flags = flags; 5385 g.WindowsById.SetVoidPtr(window->ID, window); 5386 5387 // Default/arbitrary window position. Use SetNextWindowPos() with the appropriate condition flag to change the initial position of a window. 5388 window->Pos = ImVec2(60, 60); 5389 5390 // User can disable loading and saving of settings. Tooltip and child windows also don't store settings. 5391 if (!(flags & ImGuiWindowFlags_NoSavedSettings)) 5392 { 5393 // Retrieve settings from .ini file 5394 if (ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID)) 5395 { 5396 SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false); 5397 window->Pos = ImFloor(settings->Pos); 5398 window->Collapsed = settings->Collapsed; 5399 if (ImLengthSqr(settings->Size) > 0.00001f) 5400 size = ImFloor(settings->Size); 5401 } 5402 } 5403 window->Size = window->SizeFull = window->SizeFullAtLastBegin = size; 5404 5405 if ((flags & ImGuiWindowFlags_AlwaysAutoResize) != 0) 5406 { 5407 window->AutoFitFramesX = window->AutoFitFramesY = 2; 5408 window->AutoFitOnlyGrows = false; 5409 } 5410 else 5411 { 5412 if (window->Size.x <= 0.0f) 5413 window->AutoFitFramesX = 2; 5414 if (window->Size.y <= 0.0f) 5415 window->AutoFitFramesY = 2; 5416 window->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0); 5417 } 5418 5419 if (flags & ImGuiWindowFlags_NoBringToFrontOnFocus) 5420 g.Windows.insert(g.Windows.begin(), window); // Quite slow but rare and only once 5421 else 5422 g.Windows.push_back(window); 5423 return window; 5424 } 5425 5426 static ImVec2 CalcSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size) 5427 { 5428 ImGuiContext& g = *GImGui; 5429 if (g.NextWindowData.SizeConstraintCond != 0) 5430 { 5431 // Using -1,-1 on either X/Y axis to preserve the current size. 5432 ImRect cr = g.NextWindowData.SizeConstraintRect; 5433 new_size.x = (cr.Min.x >= 0 && cr.Max.x >= 0) ? ImClamp(new_size.x, cr.Min.x, cr.Max.x) : window->SizeFull.x; 5434 new_size.y = (cr.Min.y >= 0 && cr.Max.y >= 0) ? ImClamp(new_size.y, cr.Min.y, cr.Max.y) : window->SizeFull.y; 5435 if (g.NextWindowData.SizeCallback) 5436 { 5437 ImGuiSizeCallbackData data; 5438 data.UserData = g.NextWindowData.SizeCallbackUserData; 5439 data.Pos = window->Pos; 5440 data.CurrentSize = window->SizeFull; 5441 data.DesiredSize = new_size; 5442 g.NextWindowData.SizeCallback(&data); 5443 new_size = data.DesiredSize; 5444 } 5445 } 5446 5447 // Minimum size 5448 if (!(window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysAutoResize))) 5449 { 5450 new_size = ImMax(new_size, g.Style.WindowMinSize); 5451 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 5452 } 5453 return new_size; 5454 } 5455 5456 static ImVec2 CalcSizeContents(ImGuiWindow* window) 5457 { 5458 ImVec2 sz; 5459 sz.x = (float)(int)((window->SizeContentsExplicit.x != 0.0f) ? window->SizeContentsExplicit.x : (window->DC.CursorMaxPos.x - window->Pos.x + window->Scroll.x)); 5460 sz.y = (float)(int)((window->SizeContentsExplicit.y != 0.0f) ? window->SizeContentsExplicit.y : (window->DC.CursorMaxPos.y - window->Pos.y + window->Scroll.y)); 5461 return sz + window->WindowPadding; 5462 } 5463 5464 static ImVec2 CalcSizeAutoFit(ImGuiWindow* window, const ImVec2& size_contents) 5465 { 5466 ImGuiContext& g = *GImGui; 5467 ImGuiStyle& style = g.Style; 5468 if (window->Flags & ImGuiWindowFlags_Tooltip) 5469 { 5470 // Tooltip always resize 5471 return size_contents; 5472 } 5473 else 5474 { 5475 // When the window cannot fit all contents (either because of constraints, either because screen is too small): we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than DisplaySize-WindowPadding. 5476 ImVec2 size_auto_fit = ImClamp(size_contents, style.WindowMinSize, ImMax(style.WindowMinSize, g.IO.DisplaySize - g.Style.DisplaySafeAreaPadding * 2.0f)); 5477 ImVec2 size_auto_fit_after_constraint = CalcSizeAfterConstraint(window, size_auto_fit); 5478 if (size_auto_fit_after_constraint.x < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) 5479 size_auto_fit.y += style.ScrollbarSize; 5480 if (size_auto_fit_after_constraint.y < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) 5481 size_auto_fit.x += style.ScrollbarSize; 5482 return size_auto_fit; 5483 } 5484 } 5485 5486 static float GetScrollMaxX(ImGuiWindow* window) 5487 { 5488 return ImMax(0.0f, window->SizeContents.x - (window->SizeFull.x - window->ScrollbarSizes.x)); 5489 } 5490 5491 static float GetScrollMaxY(ImGuiWindow* window) 5492 { 5493 return ImMax(0.0f, window->SizeContents.y - (window->SizeFull.y - window->ScrollbarSizes.y)); 5494 } 5495 5496 static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window) 5497 { 5498 ImVec2 scroll = window->Scroll; 5499 float cr_x = window->ScrollTargetCenterRatio.x; 5500 float cr_y = window->ScrollTargetCenterRatio.y; 5501 if (window->ScrollTarget.x < FLT_MAX) 5502 scroll.x = window->ScrollTarget.x - cr_x * (window->SizeFull.x - window->ScrollbarSizes.x); 5503 if (window->ScrollTarget.y < FLT_MAX) 5504 scroll.y = window->ScrollTarget.y - (1.0f - cr_y) * (window->TitleBarHeight() + window->MenuBarHeight()) - cr_y * (window->SizeFull.y - window->ScrollbarSizes.y); 5505 scroll = ImMax(scroll, ImVec2(0.0f, 0.0f)); 5506 if (!window->Collapsed && !window->SkipItems) 5507 { 5508 scroll.x = ImMin(scroll.x, GetScrollMaxX(window)); 5509 scroll.y = ImMin(scroll.y, GetScrollMaxY(window)); 5510 } 5511 return scroll; 5512 } 5513 5514 static ImGuiCol GetWindowBgColorIdxFromFlags(ImGuiWindowFlags flags) 5515 { 5516 if (flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) 5517 return ImGuiCol_PopupBg; 5518 if (flags & ImGuiWindowFlags_ChildWindow) 5519 return ImGuiCol_ChildBg; 5520 return ImGuiCol_WindowBg; 5521 } 5522 5523 static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& corner_target, const ImVec2& corner_norm, ImVec2* out_pos, ImVec2* out_size) 5524 { 5525 ImVec2 pos_min = ImLerp(corner_target, window->Pos, corner_norm); // Expected window upper-left 5526 ImVec2 pos_max = ImLerp(window->Pos + window->Size, corner_target, corner_norm); // Expected window lower-right 5527 ImVec2 size_expected = pos_max - pos_min; 5528 ImVec2 size_constrained = CalcSizeAfterConstraint(window, size_expected); 5529 *out_pos = pos_min; 5530 if (corner_norm.x == 0.0f) 5531 out_pos->x -= (size_constrained.x - size_expected.x); 5532 if (corner_norm.y == 0.0f) 5533 out_pos->y -= (size_constrained.y - size_expected.y); 5534 *out_size = size_constrained; 5535 } 5536 5537 struct ImGuiResizeGripDef 5538 { 5539 ImVec2 CornerPos; 5540 ImVec2 InnerDir; 5541 int AngleMin12, AngleMax12; 5075 static const ImGuiResizeGripDef resize_grip_def[4] = 5076 { 5077 { ImVec2(1, 1), ImVec2(-1, -1), 0, 3 }, // Lower-right 5078 { ImVec2(0, 1), ImVec2(+1, -1), 3, 6 }, // Lower-left 5079 { ImVec2(0, 0), ImVec2(+1, +1), 6, 9 }, // Upper-left (Unused) 5080 { ImVec2(1, 0), ImVec2(-1, +1), 9, 12 }, // Upper-right (Unused) 5542 5081 }; 5543 5082 5544 const ImGuiResizeGripDef resize_grip_def[4] = 5545 { 5546 { ImVec2(1,1), ImVec2(-1,-1), 0, 3 }, // Lower right 5547 { ImVec2(0,1), ImVec2(+1,-1), 3, 6 }, // Lower left 5548 { ImVec2(0,0), ImVec2(+1,+1), 6, 9 }, // Upper left 5549 { ImVec2(1,0), ImVec2(-1,+1), 9,12 }, // Upper right 5083 struct ImGuiResizeBorderDef 5084 { 5085 ImVec2 InnerDir; 5086 ImVec2 CornerPosN1, CornerPosN2; 5087 float OuterAngle; 5550 5088 }; 5551 5089 5552 static ImRect GetBorderRect(ImGuiWindow* window, int border_n, float perp_padding, float thickness) 5553 { 5554 ImRect rect = window->Rect(); 5555 if (thickness == 0.0f) rect.Max -= ImVec2(1, 1); 5556 if (border_n == 0) return ImRect(rect.Min.x + perp_padding, rect.Min.y, rect.Max.x - perp_padding, rect.Min.y + thickness); 5557 if (border_n == 1) return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x, rect.Max.y - perp_padding); 5558 if (border_n == 2) return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y); 5559 if (border_n == 3) return ImRect(rect.Min.x, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding); 5560 IM_ASSERT(0); 5561 return ImRect(); 5090 static const ImGuiResizeBorderDef resize_border_def[4] = 5091 { 5092 { ImVec2(0, +1), ImVec2(0, 0), ImVec2(1, 0), IM_PI * 1.50f }, // Top 5093 { ImVec2(-1, 0), ImVec2(1, 0), ImVec2(1, 1), IM_PI * 0.00f }, // Right 5094 { ImVec2(0, -1), ImVec2(1, 1), ImVec2(0, 1), IM_PI * 0.50f }, // Bottom 5095 { ImVec2(+1, 0), ImVec2(0, 1), ImVec2(0, 0), IM_PI * 1.00f } // Left 5096 }; 5097 5098 static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_padding, float thickness) 5099 { 5100 ImRect rect = window->Rect(); 5101 if (thickness == 0.0f) rect.Max -= ImVec2(1, 1); 5102 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 5103 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 5104 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 5105 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 5106 IM_ASSERT(0); 5107 return ImRect(); 5108 } 5109 5110 // 0..3: corners (Lower-right, Lower-left, Unused, Unused) 5111 // 4..7: borders (Top, Right, Bottom, Left) 5112 ImGuiID ImGui::GetWindowResizeID(ImGuiWindow* window, int n) 5113 { 5114 IM_ASSERT(n >= 0 && n <= 7); 5115 ImGuiID id = window->ID; 5116 id = ImHashStr("#RESIZE", 0, id); 5117 id = ImHashData(&n, sizeof(int), id); 5118 return id; 5562 5119 } 5563 5120 5564 5121 // Handle resize for: Resize Grips, Borders, Gamepad 5565 static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]) 5566 { 5567 ImGuiContext& g = *GImGui; 5568 ImGuiWindowFlags flags = window->Flags; 5569 if ((flags & ImGuiWindowFlags_NoResize) || (flags & ImGuiWindowFlags_AlwaysAutoResize) || window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0) 5570 return; 5571 5572 const int resize_border_count = (flags & ImGuiWindowFlags_ResizeFromAnySide) ? 4 : 0; 5573 const float grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f); 5574 const float grip_hover_size = (float)(int)(grip_draw_size * 0.75f); 5575 5576 ImVec2 pos_target(FLT_MAX, FLT_MAX); 5577 ImVec2 size_target(FLT_MAX, FLT_MAX); 5578 5579 // Manual resize grips 5580 PushID("#RESIZE"); 5581 for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++) 5582 { 5583 const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n]; 5584 const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPos); 5585 5586 // Using the FlattenChilds button flag we make the resize button accessible even if we are hovering over a child window 5587 ImRect resize_rect(corner, corner + grip.InnerDir * grip_hover_size); 5588 if (resize_rect.Min.x > resize_rect.Max.x) ImSwap(resize_rect.Min.x, resize_rect.Max.x); 5589 if (resize_rect.Min.y > resize_rect.Max.y) ImSwap(resize_rect.Min.y, resize_rect.Max.y); 5590 bool hovered, held; 5591 ButtonBehavior(resize_rect, window->GetID((void*)(intptr_t)resize_grip_n), &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus); 5592 if (hovered || held) 5593 g.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE; 5594 5595 if (g.HoveredWindow == window && held && g.IO.MouseDoubleClicked[0] && resize_grip_n == 0) 5596 { 5597 // Manual auto-fit when double-clicking 5598 size_target = CalcSizeAfterConstraint(window, size_auto_fit); 5599 ClearActiveID(); 5600 } 5601 else if (held) 5602 { 5603 // Resize from any of the four corners 5604 // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position 5605 ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + resize_rect.GetSize() * grip.CornerPos; // Corner of the window corresponding to our corner grip 5606 CalcResizePosSizeFromAnyCorner(window, corner_target, grip.CornerPos, &pos_target, &size_target); 5607 } 5608 if (resize_grip_n == 0 || held || hovered) 5609 resize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip); 5610 } 5611 for (int border_n = 0; border_n < resize_border_count; border_n++) 5612 { 5613 const float BORDER_SIZE = 5.0f; // FIXME: Only works _inside_ window because of HoveredWindow check. 5614 const float BORDER_APPEAR_TIMER = 0.05f; // Reduce visual noise 5615 bool hovered, held; 5616 ImRect border_rect = GetBorderRect(window, border_n, grip_hover_size, BORDER_SIZE); 5617 ButtonBehavior(border_rect, window->GetID((void*)(intptr_t)(border_n + 4)), &hovered, &held, ImGuiButtonFlags_FlattenChildren); 5618 if ((hovered && g.HoveredIdTimer > BORDER_APPEAR_TIMER) || held) 5619 { 5620 g.MouseCursor = (border_n & 1) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS; 5621 if (held) *border_held = border_n; 5622 } 5623 if (held) 5624 { 5625 ImVec2 border_target = window->Pos; 5626 ImVec2 border_posn; 5627 if (border_n == 0) { border_posn = ImVec2(0, 0); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y); } 5628 if (border_n == 1) { border_posn = ImVec2(1, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + BORDER_SIZE); } 5629 if (border_n == 2) { border_posn = ImVec2(0, 1); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + BORDER_SIZE); } 5630 if (border_n == 3) { border_posn = ImVec2(0, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x); } 5631 CalcResizePosSizeFromAnyCorner(window, border_target, border_posn, &pos_target, &size_target); 5632 } 5633 } 5634 PopID(); 5635 5636 // Navigation resize (keyboard/gamepad) 5637 if (g.NavWindowingTarget == window) 5638 { 5639 ImVec2 nav_resize_delta; 5640 if (g.NavInputSource == ImGuiInputSource_NavKeyboard && g.IO.KeyShift) 5641 nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down); 5642 if (g.NavInputSource == ImGuiInputSource_NavGamepad) 5643 nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_Down); 5644 if (nav_resize_delta.x != 0.0f || nav_resize_delta.y != 0.0f) 5645 { 5646 const float NAV_RESIZE_SPEED = 600.0f; 5647 nav_resize_delta *= ImFloor(NAV_RESIZE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y)); 5648 g.NavWindowingToggleLayer = false; 5649 g.NavDisableMouseHover = true; 5650 resize_grip_col[0] = GetColorU32(ImGuiCol_ResizeGripActive); 5651 // FIXME-NAV: Should store and accumulate into a separate size buffer to handle sizing constraints properly, right now a constraint will make us stuck. 5652 size_target = CalcSizeAfterConstraint(window, window->SizeFull + nav_resize_delta); 5653 } 5654 } 5655 5656 // Apply back modified position/size to window 5657 if (size_target.x != FLT_MAX) 5658 { 5659 window->SizeFull = size_target; 5660 MarkIniSettingsDirty(window); 5661 } 5662 if (pos_target.x != FLT_MAX) 5663 { 5664 window->Pos = ImFloor(pos_target); 5665 MarkIniSettingsDirty(window); 5666 } 5667 5668 window->Size = window->SizeFull; 5669 } 5670 5671 // Push a new ImGui window to add widgets to. 5122 // Return true when using auto-fit (double click on resize grip) 5123 static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect) 5124 { 5125 ImGuiContext& g = *GImGui; 5126 ImGuiWindowFlags flags = window->Flags; 5127 5128 if ((flags & ImGuiWindowFlags_NoResize) || (flags & ImGuiWindowFlags_AlwaysAutoResize) || window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0) 5129 return false; 5130 if (window->WasActive == false) // Early out to avoid running this code for e.g. an hidden implicit/fallback Debug window. 5131 return false; 5132 5133 bool ret_auto_fit = false; 5134 const int resize_border_count = g.IO.ConfigWindowsResizeFromEdges ? 4 : 0; 5135 const float grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f)); 5136 const float grip_hover_inner_size = IM_FLOOR(grip_draw_size * 0.75f); 5137 const float grip_hover_outer_size = g.IO.ConfigWindowsResizeFromEdges ? WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS : 0.0f; 5138 5139 ImVec2 pos_target(FLT_MAX, FLT_MAX); 5140 ImVec2 size_target(FLT_MAX, FLT_MAX); 5141 5142 // Resize grips and borders are on layer 1 5143 window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; 5144 5145 // Manual resize grips 5146 PushID("#RESIZE"); 5147 for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++) 5148 { 5149 const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n]; 5150 const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN); 5151 5152 // Using the FlattenChilds button flag we make the resize button accessible even if we are hovering over a child window 5153 ImRect resize_rect(corner - grip.InnerDir * grip_hover_outer_size, corner + grip.InnerDir * grip_hover_inner_size); 5154 if (resize_rect.Min.x > resize_rect.Max.x) ImSwap(resize_rect.Min.x, resize_rect.Max.x); 5155 if (resize_rect.Min.y > resize_rect.Max.y) ImSwap(resize_rect.Min.y, resize_rect.Max.y); 5156 bool hovered, held; 5157 ButtonBehavior(resize_rect, window->GetID(resize_grip_n), &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus); 5158 //GetForegroundDrawList(window)->AddRect(resize_rect.Min, resize_rect.Max, IM_COL32(255, 255, 0, 255)); 5159 if (hovered || held) 5160 g.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE; 5161 5162 if (held && g.IO.MouseDoubleClicked[0] && resize_grip_n == 0) 5163 { 5164 // Manual auto-fit when double-clicking 5165 size_target = CalcWindowSizeAfterConstraint(window, size_auto_fit); 5166 ret_auto_fit = true; 5167 ClearActiveID(); 5168 } 5169 else if (held) 5170 { 5171 // Resize from any of the four corners 5172 // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position 5173 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 5174 ImVec2 clamp_min = ImVec2(grip.CornerPosN.x == 1.0f ? visibility_rect.Min.x : -FLT_MAX, grip.CornerPosN.y == 1.0f ? visibility_rect.Min.y : -FLT_MAX); 5175 ImVec2 clamp_max = ImVec2(grip.CornerPosN.x == 0.0f ? visibility_rect.Max.x : +FLT_MAX, grip.CornerPosN.y == 0.0f ? visibility_rect.Max.y : +FLT_MAX); 5176 corner_target = ImClamp(corner_target, clamp_min, clamp_max); 5177 CalcResizePosSizeFromAnyCorner(window, corner_target, grip.CornerPosN, &pos_target, &size_target); 5178 } 5179 if (resize_grip_n == 0 || held || hovered) 5180 resize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip); 5181 } 5182 for (int border_n = 0; border_n < resize_border_count; border_n++) 5183 { 5184 bool hovered, held; 5185 ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); 5186 ButtonBehavior(border_rect, window->GetID(border_n + 4), &hovered, &held, ImGuiButtonFlags_FlattenChildren); 5187 //GetForegroundDrawLists(window)->AddRect(border_rect.Min, border_rect.Max, IM_COL32(255, 255, 0, 255)); 5188 if ((hovered && g.HoveredIdTimer > WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) || held) 5189 { 5190 g.MouseCursor = (border_n & 1) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS; 5191 if (held) 5192 *border_held = border_n; 5193 } 5194 if (held) 5195 { 5196 ImVec2 border_target = window->Pos; 5197 ImVec2 border_posn; 5198 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 5199 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 5200 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 5201 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 5202 ImVec2 clamp_min = ImVec2(border_n == 1 ? visibility_rect.Min.x : -FLT_MAX, border_n == 2 ? visibility_rect.Min.y : -FLT_MAX); 5203 ImVec2 clamp_max = ImVec2(border_n == 3 ? visibility_rect.Max.x : +FLT_MAX, border_n == 0 ? visibility_rect.Max.y : +FLT_MAX); 5204 border_target = ImClamp(border_target, clamp_min, clamp_max); 5205 CalcResizePosSizeFromAnyCorner(window, border_target, border_posn, &pos_target, &size_target); 5206 } 5207 } 5208 PopID(); 5209 5210 // Restore nav layer 5211 window->DC.NavLayerCurrent = ImGuiNavLayer_Main; 5212 5213 // Navigation resize (keyboard/gamepad) 5214 if (g.NavWindowingTarget && g.NavWindowingTarget->RootWindow == window) 5215 { 5216 ImVec2 nav_resize_delta; 5217 if (g.NavInputSource == ImGuiInputSource_NavKeyboard && g.IO.KeyShift) 5218 nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down); 5219 if (g.NavInputSource == ImGuiInputSource_NavGamepad) 5220 nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_Down); 5221 if (nav_resize_delta.x != 0.0f || nav_resize_delta.y != 0.0f) 5222 { 5223 const float NAV_RESIZE_SPEED = 600.0f; 5224 nav_resize_delta *= ImFloor(NAV_RESIZE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y)); 5225 nav_resize_delta = ImMax(nav_resize_delta, visibility_rect.Min - window->Pos - window->Size); 5226 g.NavWindowingToggleLayer = false; 5227 g.NavDisableMouseHover = true; 5228 resize_grip_col[0] = GetColorU32(ImGuiCol_ResizeGripActive); 5229 // FIXME-NAV: Should store and accumulate into a separate size buffer to handle sizing constraints properly, right now a constraint will make us stuck. 5230 size_target = CalcWindowSizeAfterConstraint(window, window->SizeFull + nav_resize_delta); 5231 } 5232 } 5233 5234 // Apply back modified position/size to window 5235 if (size_target.x != FLT_MAX) 5236 { 5237 window->SizeFull = size_target; 5238 MarkIniSettingsDirty(window); 5239 } 5240 if (pos_target.x != FLT_MAX) 5241 { 5242 window->Pos = ImFloor(pos_target); 5243 MarkIniSettingsDirty(window); 5244 } 5245 5246 window->Size = window->SizeFull; 5247 return ret_auto_fit; 5248 } 5249 5250 static inline void ClampWindowRect(ImGuiWindow* window, const ImRect& visibility_rect) 5251 { 5252 ImGuiContext& g = *GImGui; 5253 ImVec2 size_for_clamping = window->Size; 5254 if (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(window->Flags & ImGuiWindowFlags_NoTitleBar)) 5255 size_for_clamping.y = window->TitleBarHeight(); 5256 window->Pos = ImClamp(window->Pos, visibility_rect.Min - size_for_clamping, visibility_rect.Max); 5257 } 5258 5259 static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window) 5260 { 5261 ImGuiContext& g = *GImGui; 5262 float rounding = window->WindowRounding; 5263 float border_size = window->WindowBorderSize; 5264 if (border_size > 0.0f && !(window->Flags & ImGuiWindowFlags_NoBackground)) 5265 window->DrawList->AddRect(window->Pos, window->Pos + window->Size, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size); 5266 5267 int border_held = window->ResizeBorderHeld; 5268 if (border_held != -1) 5269 { 5270 const ImGuiResizeBorderDef& def = resize_border_def[border_held]; 5271 ImRect border_r = GetResizeBorderRect(window, border_held, rounding, 0.0f); 5272 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); 5273 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); 5274 window->DrawList->PathStroke(GetColorU32(ImGuiCol_SeparatorActive), false, ImMax(2.0f, border_size)); // Thicker than usual 5275 } 5276 if (g.Style.FrameBorderSize > 0 && !(window->Flags & ImGuiWindowFlags_NoTitleBar)) 5277 { 5278 float y = window->Pos.y + window->TitleBarHeight() - 1; 5279 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); 5280 } 5281 } 5282 5283 // Draw background and borders 5284 // Draw and handle scrollbars 5285 void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size) 5286 { 5287 ImGuiContext& g = *GImGui; 5288 ImGuiStyle& style = g.Style; 5289 ImGuiWindowFlags flags = window->Flags; 5290 5291 // Ensure that ScrollBar doesn't read last frame's SkipItems 5292 IM_ASSERT(window->BeginCount == 0); 5293 window->SkipItems = false; 5294 5295 // Draw window + handle manual resize 5296 // 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. 5297 const float window_rounding = window->WindowRounding; 5298 const float window_border_size = window->WindowBorderSize; 5299 if (window->Collapsed) 5300 { 5301 // Title bar only 5302 float backup_border_size = style.FrameBorderSize; 5303 g.Style.FrameBorderSize = window->WindowBorderSize; 5304 ImU32 title_bar_col = GetColorU32((title_bar_is_highlight && !g.NavDisableHighlight) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed); 5305 RenderFrame(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, true, window_rounding); 5306 g.Style.FrameBorderSize = backup_border_size; 5307 } 5308 else 5309 { 5310 // Window background 5311 if (!(flags & ImGuiWindowFlags_NoBackground)) 5312 { 5313 ImU32 bg_col = GetColorU32(GetWindowBgColorIdxFromFlags(flags)); 5314 bool override_alpha = false; 5315 float alpha = 1.0f; 5316 if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasBgAlpha) 5317 { 5318 alpha = g.NextWindowData.BgAlphaVal; 5319 override_alpha = true; 5320 } 5321 if (override_alpha) 5322 bg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(alpha) << IM_COL32_A_SHIFT); 5323 window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Bot); 5324 } 5325 5326 // Title bar 5327 if (!(flags & ImGuiWindowFlags_NoTitleBar)) 5328 { 5329 ImU32 title_bar_col = GetColorU32(title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg); 5330 window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawCornerFlags_Top); 5331 } 5332 5333 // Menu bar 5334 if (flags & ImGuiWindowFlags_MenuBar) 5335 { 5336 ImRect menu_bar_rect = window->MenuBarRect(); 5337 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. 5338 window->DrawList->AddRectFilled(menu_bar_rect.Min + ImVec2(window_border_size, 0), menu_bar_rect.Max - ImVec2(window_border_size, 0), GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawCornerFlags_Top); 5339 if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y) 5340 window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize); 5341 } 5342 5343 // Scrollbars 5344 if (window->ScrollbarX) 5345 Scrollbar(ImGuiAxis_X); 5346 if (window->ScrollbarY) 5347 Scrollbar(ImGuiAxis_Y); 5348 5349 // Render resize grips (after their input handling so we don't have a frame of latency) 5350 if (!(flags & ImGuiWindowFlags_NoResize)) 5351 { 5352 for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++) 5353 { 5354 const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n]; 5355 const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN); 5356 window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, resize_grip_draw_size) : ImVec2(resize_grip_draw_size, window_border_size))); 5357 window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(resize_grip_draw_size, window_border_size) : ImVec2(window_border_size, resize_grip_draw_size))); 5358 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); 5359 window->DrawList->PathFillConvex(resize_grip_col[resize_grip_n]); 5360 } 5361 } 5362 5363 // Borders 5364 RenderWindowOuterBorders(window); 5365 } 5366 } 5367 5368 // Render title text, collapse button, close button 5369 void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open) 5370 { 5371 ImGuiContext& g = *GImGui; 5372 ImGuiStyle& style = g.Style; 5373 ImGuiWindowFlags flags = window->Flags; 5374 5375 const bool has_close_button = (p_open != NULL); 5376 const bool has_collapse_button = !(flags & ImGuiWindowFlags_NoCollapse) && (style.WindowMenuButtonPosition != ImGuiDir_None); 5377 5378 // Close & Collapse button are on the Menu NavLayer and don't default focus (unless there's nothing else on that layer) 5379 const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags; 5380 window->DC.ItemFlags |= ImGuiItemFlags_NoNavDefaultFocus; 5381 window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; 5382 5383 // Layout buttons 5384 // FIXME: Would be nice to generalize the subtleties expressed here into reusable code. 5385 float pad_l = style.FramePadding.x; 5386 float pad_r = style.FramePadding.x; 5387 float button_sz = g.FontSize; 5388 ImVec2 close_button_pos; 5389 ImVec2 collapse_button_pos; 5390 if (has_close_button) 5391 { 5392 pad_r += button_sz; 5393 close_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y); 5394 } 5395 if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Right) 5396 { 5397 pad_r += button_sz; 5398 collapse_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y); 5399 } 5400 if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Left) 5401 { 5402 collapse_button_pos = ImVec2(title_bar_rect.Min.x + pad_l - style.FramePadding.x, title_bar_rect.Min.y); 5403 pad_l += button_sz; 5404 } 5405 5406 // Collapse button (submitting first so it gets priority when choosing a navigation init fallback) 5407 if (has_collapse_button) 5408 if (CollapseButton(window->GetID("#COLLAPSE"), collapse_button_pos)) 5409 window->WantCollapseToggle = true; // Defer actual collapsing to next frame as we are too far in the Begin() function 5410 5411 // Close button 5412 if (has_close_button) 5413 if (CloseButton(window->GetID("#CLOSE"), close_button_pos)) 5414 *p_open = false; 5415 5416 window->DC.NavLayerCurrent = ImGuiNavLayer_Main; 5417 window->DC.ItemFlags = item_flags_backup; 5418 5419 // Title bar text (with: horizontal alignment, avoiding collapse/close button, optional "unsaved document" marker) 5420 // FIXME: Refactor text alignment facilities along with RenderText helpers, this is WAY too much messy code.. 5421 const char* UNSAVED_DOCUMENT_MARKER = "*"; 5422 const float marker_size_x = (flags & ImGuiWindowFlags_UnsavedDocument) ? CalcTextSize(UNSAVED_DOCUMENT_MARKER, NULL, false).x : 0.0f; 5423 const ImVec2 text_size = CalcTextSize(name, NULL, true) + ImVec2(marker_size_x, 0.0f); 5424 5425 // As a nice touch we try to ensure that centered title text doesn't get affected by visibility of Close/Collapse button, 5426 // while uncentered title text will still reach edges correct. 5427 if (pad_l > style.FramePadding.x) 5428 pad_l += g.Style.ItemInnerSpacing.x; 5429 if (pad_r > style.FramePadding.x) 5430 pad_r += g.Style.ItemInnerSpacing.x; 5431 if (style.WindowTitleAlign.x > 0.0f && style.WindowTitleAlign.x < 1.0f) 5432 { 5433 float centerness = ImSaturate(1.0f - ImFabs(style.WindowTitleAlign.x - 0.5f) * 2.0f); // 0.0f on either edges, 1.0f on center 5434 float pad_extend = ImMin(ImMax(pad_l, pad_r), title_bar_rect.GetWidth() - pad_l - pad_r - text_size.x); 5435 pad_l = ImMax(pad_l, pad_extend * centerness); 5436 pad_r = ImMax(pad_r, pad_extend * centerness); 5437 } 5438 5439 ImRect layout_r(title_bar_rect.Min.x + pad_l, title_bar_rect.Min.y, title_bar_rect.Max.x - pad_r, title_bar_rect.Max.y); 5440 ImRect clip_r(layout_r.Min.x, layout_r.Min.y, layout_r.Max.x + g.Style.ItemInnerSpacing.x, layout_r.Max.y); 5441 //if (g.IO.KeyCtrl) window->DrawList->AddRect(layout_r.Min, layout_r.Max, IM_COL32(255, 128, 0, 255)); // [DEBUG] 5442 RenderTextClipped(layout_r.Min, layout_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_r); 5443 if (flags & ImGuiWindowFlags_UnsavedDocument) 5444 { 5445 ImVec2 marker_pos = ImVec2(ImMax(layout_r.Min.x, layout_r.Min.x + (layout_r.GetWidth() - text_size.x) * style.WindowTitleAlign.x) + text_size.x, layout_r.Min.y) + ImVec2(2 - marker_size_x, 0.0f); 5446 ImVec2 off = ImVec2(0.0f, IM_FLOOR(-g.FontSize * 0.25f)); 5447 RenderTextClipped(marker_pos + off, layout_r.Max + off, UNSAVED_DOCUMENT_MARKER, NULL, NULL, ImVec2(0, style.WindowTitleAlign.y), &clip_r); 5448 } 5449 } 5450 5451 void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window) 5452 { 5453 window->ParentWindow = parent_window; 5454 window->RootWindow = window->RootWindowForTitleBarHighlight = window->RootWindowForNav = window; 5455 if (parent_window && (flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip)) 5456 window->RootWindow = parent_window->RootWindow; 5457 if (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup))) 5458 window->RootWindowForTitleBarHighlight = parent_window->RootWindowForTitleBarHighlight; 5459 while (window->RootWindowForNav->Flags & ImGuiWindowFlags_NavFlattened) 5460 { 5461 IM_ASSERT(window->RootWindowForNav->ParentWindow != NULL); 5462 window->RootWindowForNav = window->RootWindowForNav->ParentWindow; 5463 } 5464 } 5465 5466 // Push a new Dear ImGui window to add widgets to. 5672 5467 // - 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. 5673 5468 // - Begin/End can be called multiple times during the frame with the same window name to append content. … … 5678 5473 bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) 5679 5474 { 5680 ImGuiContext& g = *GImGui; 5681 const ImGuiStyle& style = g.Style; 5682 IM_ASSERT(name != NULL); // Window name required 5683 IM_ASSERT(g.Initialized); // Forgot to call ImGui::NewFrame() 5684 IM_ASSERT(g.FrameCountEnded != g.FrameCount); // Called ImGui::Render() or ImGui::EndFrame() and haven't called ImGui::NewFrame() again yet 5685 5686 // Find or create 5687 ImGuiWindow* window = FindWindowByName(name); 5688 const bool window_just_created = (window == NULL); 5689 if (window_just_created) 5690 { 5691 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. 5692 window = CreateNewWindow(name, size_on_first_use, flags); 5693 } 5694 5695 // Automatically disable manual moving/resizing when NoInputs is set 5696 if (flags & ImGuiWindowFlags_NoInputs) 5697 flags |= ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize; 5698 5699 if (flags & ImGuiWindowFlags_NavFlattened) 5700 IM_ASSERT(flags & ImGuiWindowFlags_ChildWindow); 5701 5702 const int current_frame = g.FrameCount; 5703 const bool first_begin_of_the_frame = (window->LastFrameActive != current_frame); 5704 if (first_begin_of_the_frame) 5705 window->Flags = (ImGuiWindowFlags)flags; 5706 else 5707 flags = window->Flags; 5708 5709 // Update the Appearing flag 5710 bool window_just_activated_by_user = (window->LastFrameActive < current_frame - 1); // Not using !WasActive because the implicit "Debug" window would always toggle off->on 5711 const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFrames > 0); 5712 if (flags & ImGuiWindowFlags_Popup) 5713 { 5714 ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.CurrentPopupStack.Size]; 5715 window_just_activated_by_user |= (window->PopupId != popup_ref.PopupId); // We recycle popups so treat window as activated if popup id changed 5716 window_just_activated_by_user |= (window != popup_ref.Window); 5717 } 5718 window->Appearing = (window_just_activated_by_user || window_just_appearing_after_hidden_for_resize); 5719 window->CloseButton = (p_open != NULL); 5720 if (window->Appearing) 5721 SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, true); 5722 5723 // 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 5724 ImGuiWindow* parent_window_in_stack = g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back(); 5725 ImGuiWindow* parent_window = first_begin_of_the_frame ? ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)) ? parent_window_in_stack : NULL) : window->ParentWindow; 5726 IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow)); 5727 5728 // Add to stack 5729 g.CurrentWindowStack.push_back(window); 5730 SetCurrentWindow(window); 5731 CheckStacksSize(window, true); 5732 if (flags & ImGuiWindowFlags_Popup) 5733 { 5734 ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.CurrentPopupStack.Size]; 5735 popup_ref.Window = window; 5736 g.CurrentPopupStack.push_back(popup_ref); 5737 window->PopupId = popup_ref.PopupId; 5738 } 5739 5740 if (window_just_appearing_after_hidden_for_resize && !(flags & ImGuiWindowFlags_ChildWindow)) 5741 window->NavLastIds[0] = 0; 5742 5743 // Process SetNextWindow***() calls 5744 bool window_pos_set_by_api = false; 5745 bool window_size_x_set_by_api = false, window_size_y_set_by_api = false; 5746 if (g.NextWindowData.PosCond) 5747 { 5748 window_pos_set_by_api = (window->SetWindowPosAllowFlags & g.NextWindowData.PosCond) != 0; 5749 if (window_pos_set_by_api && ImLengthSqr(g.NextWindowData.PosPivotVal) > 0.00001f) 5750 { 5751 // May be processed on the next frame if this is our first frame and we are measuring size 5752 // FIXME: Look into removing the branch so everything can go through this same code path for consistency. 5753 window->SetWindowPosVal = g.NextWindowData.PosVal; 5754 window->SetWindowPosPivot = g.NextWindowData.PosPivotVal; 5755 window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); 5756 } 5757 else 5758 { 5759 SetWindowPos(window, g.NextWindowData.PosVal, g.NextWindowData.PosCond); 5760 } 5761 } 5762 if (g.NextWindowData.SizeCond) 5763 { 5764 window_size_x_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.x > 0.0f); 5765 window_size_y_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.y > 0.0f); 5766 SetWindowSize(window, g.NextWindowData.SizeVal, g.NextWindowData.SizeCond); 5767 } 5768 if (g.NextWindowData.ContentSizeCond) 5769 { 5770 // Adjust passed "client size" to become a "window size" 5771 window->SizeContentsExplicit = g.NextWindowData.ContentSizeVal; 5772 if (window->SizeContentsExplicit.y != 0.0f) 5773 window->SizeContentsExplicit.y += window->TitleBarHeight() + window->MenuBarHeight(); 5774 } 5775 else if (first_begin_of_the_frame) 5776 { 5777 window->SizeContentsExplicit = ImVec2(0.0f, 0.0f); 5778 } 5779 if (g.NextWindowData.CollapsedCond) 5780 SetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond); 5781 if (g.NextWindowData.FocusCond) 5782 FocusWindow(window); 5783 if (window->Appearing) 5784 SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, false); 5785 5786 // When reusing window again multiple times a frame, just append content (don't need to setup again) 5787 if (first_begin_of_the_frame) 5788 { 5789 const bool window_is_child_tooltip = (flags & ImGuiWindowFlags_ChildWindow) && (flags & ImGuiWindowFlags_Tooltip); // FIXME-WIP: Undocumented behavior of Child+Tooltip for pinned tooltip (#1345) 5790 5791 // Initialize 5792 window->ParentWindow = parent_window; 5793 window->RootWindow = window->RootWindowForTitleBarHighlight = window->RootWindowForTabbing = window->RootWindowForNav = window; 5794 if (parent_window && (flags & ImGuiWindowFlags_ChildWindow) && !window_is_child_tooltip) 5795 window->RootWindow = parent_window->RootWindow; 5796 if (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup))) 5797 window->RootWindowForTitleBarHighlight = window->RootWindowForTabbing = parent_window->RootWindowForTitleBarHighlight; // Same value in master branch, will differ for docking 5798 while (window->RootWindowForNav->Flags & ImGuiWindowFlags_NavFlattened) 5799 window->RootWindowForNav = window->RootWindowForNav->ParentWindow; 5800 5801 window->Active = true; 5802 window->BeginOrderWithinParent = 0; 5803 window->BeginOrderWithinContext = g.WindowsActiveCount++; 5804 window->BeginCount = 0; 5805 window->ClipRect = ImVec4(-FLT_MAX, -FLT_MAX, +FLT_MAX, +FLT_MAX); 5806 window->LastFrameActive = current_frame; 5807 window->IDStack.resize(1); 5808 5809 // UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS 5810 5811 // Update contents size from last frame for auto-fitting (or use explicit size) 5812 window->SizeContents = CalcSizeContents(window); 5813 if (window->HiddenFrames > 0) 5814 window->HiddenFrames--; 5815 5816 // Hide new windows for one frame until they calculate their size 5817 if (window_just_created && (!window_size_x_set_by_api || !window_size_y_set_by_api)) 5818 window->HiddenFrames = 1; 5819 5820 // Hide popup/tooltip window when re-opening while we measure size (because we recycle the windows) 5821 // We reset Size/SizeContents for reappearing popups/tooltips early in this function, so further code won't be tempted to use the old size. 5822 if (window_just_activated_by_user && (flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0) 5823 { 5824 window->HiddenFrames = 1; 5825 if (flags & ImGuiWindowFlags_AlwaysAutoResize) 5826 { 5475 ImGuiContext& g = *GImGui; 5476 const ImGuiStyle& style = g.Style; 5477 IM_ASSERT(name != NULL && name[0] != '\0'); // Window name required 5478 IM_ASSERT(g.WithinFrameScope); // Forgot to call ImGui::NewFrame() 5479 IM_ASSERT(g.FrameCountEnded != g.FrameCount); // Called ImGui::Render() or ImGui::EndFrame() and haven't called ImGui::NewFrame() again yet 5480 5481 // Find or create 5482 ImGuiWindow* window = FindWindowByName(name); 5483 const bool window_just_created = (window == NULL); 5484 if (window_just_created) 5485 window = CreateNewWindow(name, flags); 5486 5487 // Automatically disable manual moving/resizing when NoInputs is set 5488 if ((flags & ImGuiWindowFlags_NoInputs) == ImGuiWindowFlags_NoInputs) 5489 flags |= ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize; 5490 5491 if (flags & ImGuiWindowFlags_NavFlattened) 5492 IM_ASSERT(flags & ImGuiWindowFlags_ChildWindow); 5493 5494 const int current_frame = g.FrameCount; 5495 const bool first_begin_of_the_frame = (window->LastFrameActive != current_frame); 5496 window->IsFallbackWindow = (g.CurrentWindowStack.Size == 0 && g.WithinFrameScopeWithImplicitWindow); 5497 5498 // Update the Appearing flag 5499 bool window_just_activated_by_user = (window->LastFrameActive < current_frame - 1); // Not using !WasActive because the implicit "Debug" window would always toggle off->on 5500 const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesCannotSkipItems > 0); 5501 if (flags & ImGuiWindowFlags_Popup) 5502 { 5503 ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size]; 5504 window_just_activated_by_user |= (window->PopupId != popup_ref.PopupId); // We recycle popups so treat window as activated if popup id changed 5505 window_just_activated_by_user |= (window != popup_ref.Window); 5506 } 5507 window->Appearing = (window_just_activated_by_user || window_just_appearing_after_hidden_for_resize); 5508 if (window->Appearing) 5509 SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, true); 5510 5511 // Update Flags, LastFrameActive, BeginOrderXXX fields 5512 if (first_begin_of_the_frame) 5513 { 5514 window->Flags = (ImGuiWindowFlags)flags; 5515 window->LastFrameActive = current_frame; 5516 window->LastTimeActive = (float)g.Time; 5517 window->BeginOrderWithinParent = 0; 5518 window->BeginOrderWithinContext = (short)(g.WindowsActiveCount++); 5519 } 5520 else 5521 { 5522 flags = window->Flags; 5523 } 5524 5525 // 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 5526 ImGuiWindow* parent_window_in_stack = g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back(); 5527 ImGuiWindow* parent_window = first_begin_of_the_frame ? ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)) ? parent_window_in_stack : NULL) : window->ParentWindow; 5528 IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow)); 5529 5530 // We allow window memory to be compacted so recreate the base stack when needed. 5531 if (window->IDStack.Size == 0) 5532 window->IDStack.push_back(window->ID); 5533 5534 // Add to stack 5535 // We intentionally set g.CurrentWindow to NULL to prevent usage until when the viewport is set, then will call SetCurrentWindow() 5536 g.CurrentWindowStack.push_back(window); 5537 g.CurrentWindow = NULL; 5538 ErrorCheckBeginEndCompareStacksSize(window, true); 5539 if (flags & ImGuiWindowFlags_Popup) 5540 { 5541 ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size]; 5542 popup_ref.Window = window; 5543 g.BeginPopupStack.push_back(popup_ref); 5544 window->PopupId = popup_ref.PopupId; 5545 } 5546 5547 if (window_just_appearing_after_hidden_for_resize && !(flags & ImGuiWindowFlags_ChildWindow)) 5548 window->NavLastIds[0] = 0; 5549 5550 // Update ->RootWindow and others pointers (before any possible call to FocusWindow) 5551 if (first_begin_of_the_frame) 5552 UpdateWindowParentAndRootLinks(window, flags, parent_window); 5553 5554 // Process SetNextWindow***() calls 5555 // (FIXME: Consider splitting the HasXXX flags into X/Y components 5556 bool window_pos_set_by_api = false; 5557 bool window_size_x_set_by_api = false, window_size_y_set_by_api = false; 5558 if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) 5559 { 5560 window_pos_set_by_api = (window->SetWindowPosAllowFlags & g.NextWindowData.PosCond) != 0; 5561 if (window_pos_set_by_api && ImLengthSqr(g.NextWindowData.PosPivotVal) > 0.00001f) 5562 { 5563 // May be processed on the next frame if this is our first frame and we are measuring size 5564 // FIXME: Look into removing the branch so everything can go through this same code path for consistency. 5565 window->SetWindowPosVal = g.NextWindowData.PosVal; 5566 window->SetWindowPosPivot = g.NextWindowData.PosPivotVal; 5567 window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); 5568 } 5569 else 5570 { 5571 SetWindowPos(window, g.NextWindowData.PosVal, g.NextWindowData.PosCond); 5572 } 5573 } 5574 if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) 5575 { 5576 window_size_x_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.x > 0.0f); 5577 window_size_y_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.y > 0.0f); 5578 SetWindowSize(window, g.NextWindowData.SizeVal, g.NextWindowData.SizeCond); 5579 } 5580 if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasScroll) 5581 { 5582 if (g.NextWindowData.ScrollVal.x >= 0.0f) 5583 { 5584 window->ScrollTarget.x = g.NextWindowData.ScrollVal.x; 5585 window->ScrollTargetCenterRatio.x = 0.0f; 5586 } 5587 if (g.NextWindowData.ScrollVal.y >= 0.0f) 5588 { 5589 window->ScrollTarget.y = g.NextWindowData.ScrollVal.y; 5590 window->ScrollTargetCenterRatio.y = 0.0f; 5591 } 5592 } 5593 if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasContentSize) 5594 window->ContentSizeExplicit = g.NextWindowData.ContentSizeVal; 5595 else if (first_begin_of_the_frame) 5596 window->ContentSizeExplicit = ImVec2(0.0f, 0.0f); 5597 if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasCollapsed) 5598 SetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond); 5599 if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasFocus) 5600 FocusWindow(window); 5601 if (window->Appearing) 5602 SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, false); 5603 5604 // When reusing window again multiple times a frame, just append content (don't need to setup again) 5605 if (first_begin_of_the_frame) 5606 { 5607 // Initialize 5608 const bool window_is_child_tooltip = (flags & ImGuiWindowFlags_ChildWindow) && (flags & ImGuiWindowFlags_Tooltip); // FIXME-WIP: Undocumented behavior of Child+Tooltip for pinned tooltip (#1345) 5609 window->Active = true; 5610 window->HasCloseButton = (p_open != NULL); 5611 window->ClipRect = ImVec4(-FLT_MAX, -FLT_MAX, +FLT_MAX, +FLT_MAX); 5612 window->IDStack.resize(1); 5613 window->DrawList->_ResetForNewFrame(); 5614 5615 // Restore buffer capacity when woken from a compacted state, to avoid 5616 if (window->MemoryCompacted) 5617 GcAwakeTransientWindowBuffers(window); 5618 5619 // Update stored window name when it changes (which can _only_ happen with the "###" operator, so the ID would stay unchanged). 5620 // 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. 5621 bool window_title_visible_elsewhere = false; 5622 if (g.NavWindowingListWindow != NULL && (window->Flags & ImGuiWindowFlags_NoNavFocus) == 0) // Window titles visible when using CTRL+TAB 5623 window_title_visible_elsewhere = true; 5624 if (window_title_visible_elsewhere && !window_just_created && strcmp(name, window->Name) != 0) 5625 { 5626 size_t buf_len = (size_t)window->NameBufLen; 5627 window->Name = ImStrdupcpy(window->Name, &buf_len, name); 5628 window->NameBufLen = (int)buf_len; 5629 } 5630 5631 // UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS 5632 5633 // Update contents size from last frame for auto-fitting (or use explicit size) 5634 window->ContentSize = CalcWindowContentSize(window); 5635 if (window->HiddenFramesCanSkipItems > 0) 5636 window->HiddenFramesCanSkipItems--; 5637 if (window->HiddenFramesCannotSkipItems > 0) 5638 window->HiddenFramesCannotSkipItems--; 5639 5640 // Hide new windows for one frame until they calculate their size 5641 if (window_just_created && (!window_size_x_set_by_api || !window_size_y_set_by_api)) 5642 window->HiddenFramesCannotSkipItems = 1; 5643 5644 // Hide popup/tooltip window when re-opening while we measure size (because we recycle the windows) 5645 // We reset Size/ContentSize for reappearing popups/tooltips early in this function, so further code won't be tempted to use the old size. 5646 if (window_just_activated_by_user && (flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0) 5647 { 5648 window->HiddenFramesCannotSkipItems = 1; 5649 if (flags & ImGuiWindowFlags_AlwaysAutoResize) 5650 { 5651 if (!window_size_x_set_by_api) 5652 window->Size.x = window->SizeFull.x = 0.f; 5653 if (!window_size_y_set_by_api) 5654 window->Size.y = window->SizeFull.y = 0.f; 5655 window->ContentSize = ImVec2(0.f, 0.f); 5656 } 5657 } 5658 5659 // SELECT VIEWPORT 5660 // FIXME-VIEWPORT: In the docking/viewport branch, this is the point where we select the current viewport (which may affect the style) 5661 SetCurrentWindow(window); 5662 5663 // LOCK BORDER SIZE AND PADDING FOR THE FRAME (so that altering them doesn't cause inconsistencies) 5664 5665 if (flags & ImGuiWindowFlags_ChildWindow) 5666 window->WindowBorderSize = style.ChildBorderSize; 5667 else 5668 window->WindowBorderSize = ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupBorderSize : style.WindowBorderSize; 5669 window->WindowPadding = style.WindowPadding; 5670 if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_Popup)) && window->WindowBorderSize == 0.0f) 5671 window->WindowPadding = ImVec2(0.0f, (flags & ImGuiWindowFlags_MenuBar) ? style.WindowPadding.y : 0.0f); 5672 5673 // Lock menu offset so size calculation can use it as menu-bar windows need a minimum size. 5674 window->DC.MenuBarOffset.x = ImMax(ImMax(window->WindowPadding.x, style.ItemSpacing.x), g.NextWindowData.MenuBarOffsetMinVal.x); 5675 window->DC.MenuBarOffset.y = g.NextWindowData.MenuBarOffsetMinVal.y; 5676 5677 // Collapse window by double-clicking on title bar 5678 // 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 5679 if (!(flags & ImGuiWindowFlags_NoTitleBar) && !(flags & ImGuiWindowFlags_NoCollapse)) 5680 { 5681 // 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. 5682 ImRect title_bar_rect = window->TitleBarRect(); 5683 if (g.HoveredWindow == window && g.HoveredId == 0 && g.HoveredIdPreviousFrame == 0 && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max) && g.IO.MouseDoubleClicked[0]) 5684 window->WantCollapseToggle = true; 5685 if (window->WantCollapseToggle) 5686 { 5687 window->Collapsed = !window->Collapsed; 5688 MarkIniSettingsDirty(window); 5689 FocusWindow(window); 5690 } 5691 } 5692 else 5693 { 5694 window->Collapsed = false; 5695 } 5696 window->WantCollapseToggle = false; 5697 5698 // SIZE 5699 5700 // Calculate auto-fit size, handle automatic resize 5701 const ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, window->ContentSize); 5702 bool use_current_size_for_scrollbar_x = window_just_created; 5703 bool use_current_size_for_scrollbar_y = window_just_created; 5704 if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed) 5705 { 5706 // Using SetNextWindowSize() overrides ImGuiWindowFlags_AlwaysAutoResize, so it can be used on tooltips/popups, etc. 5827 5707 if (!window_size_x_set_by_api) 5828 window->Size.x = window->SizeFull.x = 0.f; 5708 { 5709 window->SizeFull.x = size_auto_fit.x; 5710 use_current_size_for_scrollbar_x = true; 5711 } 5829 5712 if (!window_size_y_set_by_api) 5830 window->Size.y = window->SizeFull.y = 0.f; 5831 window->SizeContents = ImVec2(0.f, 0.f); 5832 } 5833 } 5834 5835 SetCurrentWindow(window); 5836 5837 // Lock border size and padding for the frame (so that altering them doesn't cause inconsistencies) 5838 window->WindowBorderSize = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildBorderSize : ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupBorderSize : style.WindowBorderSize; 5839 window->WindowPadding = style.WindowPadding; 5840 if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_Popup)) && window->WindowBorderSize == 0.0f) 5841 window->WindowPadding = ImVec2(0.0f, (flags & ImGuiWindowFlags_MenuBar) ? style.WindowPadding.y : 0.0f); 5842 window->DC.MenuBarOffset.x = ImMax(ImMax(window->WindowPadding.x, style.ItemSpacing.x), g.NextWindowData.MenuBarOffsetMinVal.x); 5843 window->DC.MenuBarOffset.y = g.NextWindowData.MenuBarOffsetMinVal.y; 5844 5845 // Collapse window by double-clicking on title bar 5846 // 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 5847 if (!(flags & ImGuiWindowFlags_NoTitleBar) && !(flags & ImGuiWindowFlags_NoCollapse)) 5848 { 5849 ImRect title_bar_rect = window->TitleBarRect(); 5850 if (window->CollapseToggleWanted || (g.HoveredWindow == window && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max) && g.IO.MouseDoubleClicked[0])) 5851 { 5852 window->Collapsed = !window->Collapsed; 5853 MarkIniSettingsDirty(window); 5713 { 5714 window->SizeFull.y = size_auto_fit.y; 5715 use_current_size_for_scrollbar_y = true; 5716 } 5717 } 5718 else if (window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0) 5719 { 5720 // Auto-fit may only grow window during the first few frames 5721 // We still process initial auto-fit on collapsed windows to get a window width, but otherwise don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed. 5722 if (!window_size_x_set_by_api && window->AutoFitFramesX > 0) 5723 { 5724 window->SizeFull.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x; 5725 use_current_size_for_scrollbar_x = true; 5726 } 5727 if (!window_size_y_set_by_api && window->AutoFitFramesY > 0) 5728 { 5729 window->SizeFull.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y; 5730 use_current_size_for_scrollbar_y = true; 5731 } 5732 if (!window->Collapsed) 5733 MarkIniSettingsDirty(window); 5734 } 5735 5736 // Apply minimum/maximum window size constraints and final size 5737 window->SizeFull = CalcWindowSizeAfterConstraint(window, window->SizeFull); 5738 window->Size = window->Collapsed && !(flags & ImGuiWindowFlags_ChildWindow) ? window->TitleBarRect().GetSize() : window->SizeFull; 5739 5740 // Decoration size 5741 const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight(); 5742 5743 // POSITION 5744 5745 // Popup latch its initial position, will position itself when it appears next frame 5746 if (window_just_activated_by_user) 5747 { 5748 window->AutoPosLastDirection = ImGuiDir_None; 5749 if ((flags & ImGuiWindowFlags_Popup) != 0 && !(flags & ImGuiWindowFlags_Modal) && !window_pos_set_by_api) // FIXME: BeginPopup() could use SetNextWindowPos() 5750 window->Pos = g.BeginPopupStack.back().OpenPopupPos; 5751 } 5752 5753 // Position child window 5754 if (flags & ImGuiWindowFlags_ChildWindow) 5755 { 5756 IM_ASSERT(parent_window && parent_window->Active); 5757 window->BeginOrderWithinParent = (short)parent_window->DC.ChildWindows.Size; 5758 parent_window->DC.ChildWindows.push_back(window); 5759 if (!(flags & ImGuiWindowFlags_Popup) && !window_pos_set_by_api && !window_is_child_tooltip) 5760 window->Pos = parent_window->DC.CursorPos; 5761 } 5762 5763 const bool window_pos_with_pivot = (window->SetWindowPosVal.x != FLT_MAX && window->HiddenFramesCannotSkipItems == 0); 5764 if (window_pos_with_pivot) 5765 SetWindowPos(window, window->SetWindowPosVal - window->Size * window->SetWindowPosPivot, 0); // Position given a pivot (e.g. for centering) 5766 else if ((flags & ImGuiWindowFlags_ChildMenu) != 0) 5767 window->Pos = FindBestWindowPosForPopup(window); 5768 else if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api && window_just_appearing_after_hidden_for_resize) 5769 window->Pos = FindBestWindowPosForPopup(window); 5770 else if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api && !window_is_child_tooltip) 5771 window->Pos = FindBestWindowPosForPopup(window); 5772 5773 // Calculate the range of allowed position for that window (to be movable and visible past safe area padding) 5774 // When clamping to stay visible, we will enforce that window->Pos stays inside of visibility_rect. 5775 ImRect viewport_rect(GetViewportRect()); 5776 ImVec2 visibility_padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding); 5777 ImRect visibility_rect(viewport_rect.Min + visibility_padding, viewport_rect.Max - visibility_padding); 5778 5779 // Clamp position/size so window stays visible within its viewport or monitor 5780 // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing. 5781 if (!window_pos_set_by_api && !(flags & ImGuiWindowFlags_ChildWindow) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) 5782 if (viewport_rect.GetWidth() > 0.0f && viewport_rect.GetHeight() > 0.0f) 5783 ClampWindowRect(window, visibility_rect); 5784 window->Pos = ImFloor(window->Pos); 5785 5786 // Lock window rounding for the frame (so that altering them doesn't cause inconsistencies) 5787 // Large values tend to lead to variety of artifacts and are not recommended. 5788 window->WindowRounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildRounding : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupRounding : style.WindowRounding; 5789 5790 // For windows with title bar or menu bar, we clamp to FrameHeight(FontSize + FramePadding.y * 2.0f) to completely hide artifacts. 5791 //if ((window->Flags & ImGuiWindowFlags_MenuBar) || !(window->Flags & ImGuiWindowFlags_NoTitleBar)) 5792 // window->WindowRounding = ImMin(window->WindowRounding, g.FontSize + style.FramePadding.y * 2.0f); 5793 5794 // Apply window focus (new and reactivated windows are moved to front) 5795 bool want_focus = false; 5796 if (window_just_activated_by_user && !(flags & ImGuiWindowFlags_NoFocusOnAppearing)) 5797 { 5798 if (flags & ImGuiWindowFlags_Popup) 5799 want_focus = true; 5800 else if ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip)) == 0) 5801 want_focus = true; 5802 } 5803 5804 // Handle manual resize: Resize Grips, Borders, Gamepad 5805 int border_held = -1; 5806 ImU32 resize_grip_col[4] = {}; 5807 const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // Allow resize from lower-left if we have the mouse cursor feedback for it. 5808 const float resize_grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f)); 5809 if (!window->Collapsed) 5810 if (UpdateWindowManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0], visibility_rect)) 5811 use_current_size_for_scrollbar_x = use_current_size_for_scrollbar_y = true; 5812 window->ResizeBorderHeld = (signed char)border_held; 5813 5814 // SCROLLBAR VISIBILITY 5815 5816 // Update scrollbar visibility (based on the Size that was effective during last frame or the auto-resized Size). 5817 if (!window->Collapsed) 5818 { 5819 // When reading the current size we need to read it after size constraints have been applied. 5820 // When we use InnerRect here we are intentionally reading last frame size, same for ScrollbarSizes values before we set them again. 5821 ImVec2 avail_size_from_current_frame = ImVec2(window->SizeFull.x, window->SizeFull.y - decoration_up_height); 5822 ImVec2 avail_size_from_last_frame = window->InnerRect.GetSize() + window->ScrollbarSizes; 5823 ImVec2 needed_size_from_last_frame = window_just_created ? ImVec2(0, 0) : window->ContentSize + window->WindowPadding * 2.0f; 5824 float size_x_for_scrollbars = use_current_size_for_scrollbar_x ? avail_size_from_current_frame.x : avail_size_from_last_frame.x; 5825 float size_y_for_scrollbars = use_current_size_for_scrollbar_y ? avail_size_from_current_frame.y : avail_size_from_last_frame.y; 5826 //bool scrollbar_y_from_last_frame = window->ScrollbarY; // FIXME: May want to use that in the ScrollbarX expression? How many pros vs cons? 5827 window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar)); 5828 window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((needed_size_from_last_frame.x > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar)); 5829 if (window->ScrollbarX && !window->ScrollbarY) 5830 window->ScrollbarY = (needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar); 5831 window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f); 5832 } 5833 5834 // UPDATE RECTANGLES (1- THOSE NOT AFFECTED BY SCROLLING) 5835 // Update various regions. Variables they depends on should be set above in this function. 5836 // We set this up after processing the resize grip so that our rectangles doesn't lag by a frame. 5837 5838 // Outer rectangle 5839 // Not affected by window border size. Used by: 5840 // - FindHoveredWindow() (w/ extra padding when border resize is enabled) 5841 // - Begin() initial clipping rect for drawing window background and borders. 5842 // - Begin() clipping whole child 5843 const ImRect host_rect = ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) ? parent_window->ClipRect : viewport_rect; 5844 const ImRect outer_rect = window->Rect(); 5845 const ImRect title_bar_rect = window->TitleBarRect(); 5846 window->OuterRectClipped = outer_rect; 5847 window->OuterRectClipped.ClipWith(host_rect); 5848 5849 // Inner rectangle 5850 // Not affected by window border size. Used by: 5851 // - InnerClipRect 5852 // - ScrollToBringRectIntoView() 5853 // - NavUpdatePageUpPageDown() 5854 // - Scrollbar() 5855 window->InnerRect.Min.x = window->Pos.x; 5856 window->InnerRect.Min.y = window->Pos.y + decoration_up_height; 5857 window->InnerRect.Max.x = window->Pos.x + window->Size.x - window->ScrollbarSizes.x; 5858 window->InnerRect.Max.y = window->Pos.y + window->Size.y - window->ScrollbarSizes.y; 5859 5860 // Inner clipping rectangle. 5861 // Will extend a little bit outside the normal work region. 5862 // This is to allow e.g. Selectable or CollapsingHeader or some separators to cover that space. 5863 // Force round operator last to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result. 5864 // Note that if our window is collapsed we will end up with an inverted (~null) clipping rectangle which is the correct behavior. 5865 // Affected by window/frame border size. Used by: 5866 // - Begin() initial clip rect 5867 float top_border_size = (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize); 5868 window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerRect.Min.x + ImMax(ImFloor(window->WindowPadding.x * 0.5f), window->WindowBorderSize)); 5869 window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerRect.Min.y + top_border_size); 5870 window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerRect.Max.x - ImMax(ImFloor(window->WindowPadding.x * 0.5f), window->WindowBorderSize)); 5871 window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerRect.Max.y - window->WindowBorderSize); 5872 window->InnerClipRect.ClipWithFull(host_rect); 5873 5874 // Default item width. Make it proportional to window size if window manually resizes 5875 if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize)) 5876 window->ItemWidthDefault = ImFloor(window->Size.x * 0.65f); 5877 else 5878 window->ItemWidthDefault = ImFloor(g.FontSize * 16.0f); 5879 5880 // SCROLLING 5881 5882 // Lock down maximum scrolling 5883 // The value of ScrollMax are ahead from ScrollbarX/ScrollbarY which is intentionally using InnerRect from previous rect in order to accommodate 5884 // for right/bottom aligned items without creating a scrollbar. 5885 window->ScrollMax.x = ImMax(0.0f, window->ContentSize.x + window->WindowPadding.x * 2.0f - window->InnerRect.GetWidth()); 5886 window->ScrollMax.y = ImMax(0.0f, window->ContentSize.y + window->WindowPadding.y * 2.0f - window->InnerRect.GetHeight()); 5887 5888 // Apply scrolling 5889 window->Scroll = CalcNextScrollFromScrollTargetAndClamp(window); 5890 window->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX); 5891 5892 // DRAWING 5893 5894 // Setup draw list and outer clipping rectangle 5895 IM_ASSERT(window->DrawList->CmdBuffer.Size == 1 && window->DrawList->CmdBuffer[0].ElemCount == 0); 5896 window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID); 5897 PushClipRect(host_rect.Min, host_rect.Max, false); 5898 5899 // Draw modal window background (darkens what is behind them, all viewports) 5900 const bool dim_bg_for_modal = (flags & ImGuiWindowFlags_Modal) && window == GetTopMostPopupModal() && window->HiddenFramesCannotSkipItems <= 0; 5901 const bool dim_bg_for_window_list = g.NavWindowingTargetAnim && (window == g.NavWindowingTargetAnim->RootWindow); 5902 if (dim_bg_for_modal || dim_bg_for_window_list) 5903 { 5904 const ImU32 dim_bg_col = GetColorU32(dim_bg_for_modal ? ImGuiCol_ModalWindowDimBg : ImGuiCol_NavWindowingDimBg, g.DimBgRatio); 5905 window->DrawList->AddRectFilled(viewport_rect.Min, viewport_rect.Max, dim_bg_col); 5906 } 5907 5908 // Draw navigation selection/windowing rectangle background 5909 if (dim_bg_for_window_list && window == g.NavWindowingTargetAnim) 5910 { 5911 ImRect bb = window->Rect(); 5912 bb.Expand(g.FontSize); 5913 if (!bb.Contains(viewport_rect)) // Avoid drawing if the window covers all the viewport anyway 5914 window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha * 0.25f), g.Style.WindowRounding); 5915 } 5916 5917 // Since 1.71, child window can render their decoration (bg color, border, scrollbars, etc.) within their parent to save a draw call. 5918 // When using overlapping child windows, this will break the assumption that child z-order is mapped to submission order. 5919 // We disable this when the parent window has zero vertices, which is a common pattern leading to laying out multiple overlapping child. 5920 // We also disabled this when we have dimming overlay behind this specific one child. 5921 // FIXME: More code may rely on explicit sorting of overlapping child window and would need to disable this somehow. Please get in contact if you are affected. 5922 { 5923 bool render_decorations_in_parent = false; 5924 if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) 5925 if (window->DrawList->CmdBuffer.back().ElemCount == 0 && parent_window->DrawList->VtxBuffer.Size > 0) 5926 render_decorations_in_parent = true; 5927 if (render_decorations_in_parent) 5928 window->DrawList = parent_window->DrawList; 5929 5930 // Handle title bar, scrollbar, resize grips and resize borders 5931 const ImGuiWindow* window_to_highlight = g.NavWindowingTarget ? g.NavWindowingTarget : g.NavWindow; 5932 const bool title_bar_is_highlight = want_focus || (window_to_highlight && window->RootWindowForTitleBarHighlight == window_to_highlight->RootWindowForTitleBarHighlight); 5933 RenderWindowDecorations(window, title_bar_rect, title_bar_is_highlight, resize_grip_count, resize_grip_col, resize_grip_draw_size); 5934 5935 if (render_decorations_in_parent) 5936 window->DrawList = &window->DrawListInst; 5937 } 5938 5939 // Draw navigation selection/windowing rectangle border 5940 if (g.NavWindowingTargetAnim == window) 5941 { 5942 float rounding = ImMax(window->WindowRounding, g.Style.WindowRounding); 5943 ImRect bb = window->Rect(); 5944 bb.Expand(g.FontSize); 5945 if (bb.Contains(viewport_rect)) // If a window fits the entire viewport, adjust its highlight inward 5946 { 5947 bb.Expand(-g.FontSize - 1.0f); 5948 rounding = window->WindowRounding; 5949 } 5950 window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), rounding, ~0, 3.0f); 5951 } 5952 5953 // UPDATE RECTANGLES (2- THOSE AFFECTED BY SCROLLING) 5954 5955 // Work rectangle. 5956 // Affected by window padding and border size. Used by: 5957 // - Columns() for right-most edge 5958 // - TreeNode(), CollapsingHeader() for right-most edge 5959 // - BeginTabBar() for right-most edge 5960 const bool allow_scrollbar_x = !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar); 5961 const bool allow_scrollbar_y = !(flags & ImGuiWindowFlags_NoScrollbar); 5962 const float work_rect_size_x = (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : ImMax(allow_scrollbar_x ? window->ContentSize.x : 0.0f, window->Size.x - window->WindowPadding.x * 2.0f - window->ScrollbarSizes.x)); 5963 const float work_rect_size_y = (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : ImMax(allow_scrollbar_y ? window->ContentSize.y : 0.0f, window->Size.y - window->WindowPadding.y * 2.0f - decoration_up_height - window->ScrollbarSizes.y)); 5964 window->WorkRect.Min.x = ImFloor(window->InnerRect.Min.x - window->Scroll.x + ImMax(window->WindowPadding.x, window->WindowBorderSize)); 5965 window->WorkRect.Min.y = ImFloor(window->InnerRect.Min.y - window->Scroll.y + ImMax(window->WindowPadding.y, window->WindowBorderSize)); 5966 window->WorkRect.Max.x = window->WorkRect.Min.x + work_rect_size_x; 5967 window->WorkRect.Max.y = window->WorkRect.Min.y + work_rect_size_y; 5968 window->ParentWorkRect = window->WorkRect; 5969 5970 // [LEGACY] Content Region 5971 // FIXME-OBSOLETE: window->ContentRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it. 5972 // Used by: 5973 // - Mouse wheel scrolling + many other things 5974 window->ContentRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x; 5975 window->ContentRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + decoration_up_height; 5976 window->ContentRegionRect.Max.x = window->ContentRegionRect.Min.x + (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : (window->Size.x - window->WindowPadding.x * 2.0f - window->ScrollbarSizes.x)); 5977 window->ContentRegionRect.Max.y = window->ContentRegionRect.Min.y + (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : (window->Size.y - window->WindowPadding.y * 2.0f - decoration_up_height - window->ScrollbarSizes.y)); 5978 5979 // Setup drawing context 5980 // (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.) 5981 window->DC.Indent.x = 0.0f + window->WindowPadding.x - window->Scroll.x; 5982 window->DC.GroupOffset.x = 0.0f; 5983 window->DC.ColumnsOffset.x = 0.0f; 5984 window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.Indent.x + window->DC.ColumnsOffset.x, decoration_up_height + window->WindowPadding.y - window->Scroll.y); 5985 window->DC.CursorPos = window->DC.CursorStartPos; 5986 window->DC.CursorPosPrevLine = window->DC.CursorPos; 5987 window->DC.CursorMaxPos = window->DC.CursorStartPos; 5988 window->DC.CurrLineSize = window->DC.PrevLineSize = ImVec2(0.0f, 0.0f); 5989 window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f; 5990 5991 window->DC.NavLayerCurrent = ImGuiNavLayer_Main; 5992 window->DC.NavLayerActiveMask = window->DC.NavLayerActiveMaskNext; 5993 window->DC.NavLayerActiveMaskNext = 0x00; 5994 window->DC.NavFocusScopeIdCurrent = (flags & ImGuiWindowFlags_ChildWindow) ? parent_window->DC.NavFocusScopeIdCurrent : 0; // -V595 5995 window->DC.NavHideHighlightOneFrame = false; 5996 window->DC.NavHasScroll = (window->ScrollMax.y > 0.0f); 5997 5998 window->DC.MenuBarAppending = false; 5999 window->DC.MenuColumns.Update(3, style.ItemSpacing.x, window_just_activated_by_user); 6000 window->DC.TreeDepth = 0; 6001 window->DC.TreeJumpToParentOnPopMask = 0x00; 6002 window->DC.ChildWindows.resize(0); 6003 window->DC.StateStorage = &window->StateStorage; 6004 window->DC.CurrentColumns = NULL; 6005 window->DC.LayoutType = ImGuiLayoutType_Vertical; 6006 window->DC.ParentLayoutType = parent_window ? parent_window->DC.LayoutType : ImGuiLayoutType_Vertical; 6007 window->DC.FocusCounterRegular = window->DC.FocusCounterTabStop = -1; 6008 6009 window->DC.ItemWidth = window->ItemWidthDefault; 6010 window->DC.TextWrapPos = -1.0f; // disabled 6011 window->DC.ItemFlagsStack.resize(0); 6012 window->DC.ItemWidthStack.resize(0); 6013 window->DC.TextWrapPosStack.resize(0); 6014 window->DC.GroupStack.resize(0); 6015 window->DC.ItemFlags = parent_window ? parent_window->DC.ItemFlags : ImGuiItemFlags_Default_; 6016 if (parent_window) 6017 window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags); 6018 6019 if (window->AutoFitFramesX > 0) 6020 window->AutoFitFramesX--; 6021 if (window->AutoFitFramesY > 0) 6022 window->AutoFitFramesY--; 6023 6024 // Apply focus (we need to call FocusWindow() AFTER setting DC.CursorStartPos so our initial navigation reference rectangle can start around there) 6025 if (want_focus) 6026 { 5854 6027 FocusWindow(window); 5855 } 5856 } 5857 else 5858 { 5859 window->Collapsed = false; 5860 } 5861 window->CollapseToggleWanted = false; 5862 5863 // SIZE 5864 5865 // Calculate auto-fit size, handle automatic resize 5866 const ImVec2 size_auto_fit = CalcSizeAutoFit(window, window->SizeContents); 5867 ImVec2 size_full_modified(FLT_MAX, FLT_MAX); 5868 if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed) 5869 { 5870 // Using SetNextWindowSize() overrides ImGuiWindowFlags_AlwaysAutoResize, so it can be used on tooltips/popups, etc. 5871 if (!window_size_x_set_by_api) 5872 window->SizeFull.x = size_full_modified.x = size_auto_fit.x; 5873 if (!window_size_y_set_by_api) 5874 window->SizeFull.y = size_full_modified.y = size_auto_fit.y; 5875 } 5876 else if (window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0) 5877 { 5878 // Auto-fit may only grow window during the first few frames 5879 // We still process initial auto-fit on collapsed windows to get a window width, but otherwise don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed. 5880 if (!window_size_x_set_by_api && window->AutoFitFramesX > 0) 5881 window->SizeFull.x = size_full_modified.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x; 5882 if (!window_size_y_set_by_api && window->AutoFitFramesY > 0) 5883 window->SizeFull.y = size_full_modified.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y; 5884 if (!window->Collapsed) 5885 MarkIniSettingsDirty(window); 5886 } 5887 5888 // Apply minimum/maximum window size constraints and final size 5889 window->SizeFull = CalcSizeAfterConstraint(window, window->SizeFull); 5890 window->Size = window->Collapsed && !(flags & ImGuiWindowFlags_ChildWindow) ? window->TitleBarRect().GetSize() : window->SizeFull; 5891 5892 // SCROLLBAR STATUS 5893 5894 // Update scrollbar status (based on the Size that was effective during last frame or the auto-resized Size). 5895 if (!window->Collapsed) 5896 { 5897 // When reading the current size we need to read it after size constraints have been applied 5898 float size_x_for_scrollbars = size_full_modified.x != FLT_MAX ? window->SizeFull.x : window->SizeFullAtLastBegin.x; 5899 float size_y_for_scrollbars = size_full_modified.y != FLT_MAX ? window->SizeFull.y : window->SizeFullAtLastBegin.y; 5900 window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((window->SizeContents.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar)); 5901 window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((window->SizeContents.x > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar)); 5902 if (window->ScrollbarX && !window->ScrollbarY) 5903 window->ScrollbarY = (window->SizeContents.y > size_y_for_scrollbars - style.ScrollbarSize) && !(flags & ImGuiWindowFlags_NoScrollbar); 5904 window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f); 5905 } 5906 5907 // POSITION 5908 5909 // Popup latch its initial position, will position itself when it appears next frame 5910 if (window_just_activated_by_user) 5911 { 5912 window->AutoPosLastDirection = ImGuiDir_None; 5913 if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api) 5914 window->Pos = g.CurrentPopupStack.back().OpenPopupPos; 5915 } 5916 5917 // Position child window 5918 if (flags & ImGuiWindowFlags_ChildWindow) 5919 { 5920 window->BeginOrderWithinParent = parent_window->DC.ChildWindows.Size; 5921 parent_window->DC.ChildWindows.push_back(window); 5922 if (!(flags & ImGuiWindowFlags_Popup) && !window_pos_set_by_api && !window_is_child_tooltip) 5923 window->Pos = parent_window->DC.CursorPos; 5924 } 5925 5926 const bool window_pos_with_pivot = (window->SetWindowPosVal.x != FLT_MAX && window->HiddenFrames == 0); 5927 if (window_pos_with_pivot) 5928 SetWindowPos(window, ImMax(style.DisplaySafeAreaPadding, window->SetWindowPosVal - window->SizeFull * window->SetWindowPosPivot), 0); // Position given a pivot (e.g. for centering) 5929 else if ((flags & ImGuiWindowFlags_ChildMenu) != 0) 5930 window->Pos = FindBestWindowPosForPopup(window); 5931 else if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api && window_just_appearing_after_hidden_for_resize) 5932 window->Pos = FindBestWindowPosForPopup(window); 5933 else if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api && !window_is_child_tooltip) 5934 window->Pos = FindBestWindowPosForPopup(window); 5935 5936 // Clamp position so it stays visible 5937 if (!(flags & ImGuiWindowFlags_ChildWindow)) 5938 { 5939 if (!window_pos_set_by_api && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && g.IO.DisplaySize.x > 0.0f && g.IO.DisplaySize.y > 0.0f) // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing. 5940 { 5941 ImVec2 padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding); 5942 window->Pos = ImMax(window->Pos + window->Size, padding) - window->Size; 5943 window->Pos = ImMin(window->Pos, g.IO.DisplaySize - padding); 5944 } 5945 } 5946 window->Pos = ImFloor(window->Pos); 5947 5948 // Lock window rounding for the frame (so that altering them doesn't cause inconsistencies) 5949 window->WindowRounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildRounding : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupRounding : style.WindowRounding; 5950 5951 // Prepare for focus requests 5952 window->FocusIdxAllRequestCurrent = (window->FocusIdxAllRequestNext == INT_MAX || window->FocusIdxAllCounter == -1) ? INT_MAX : (window->FocusIdxAllRequestNext + (window->FocusIdxAllCounter + 1)) % (window->FocusIdxAllCounter + 1); 5953 window->FocusIdxTabRequestCurrent = (window->FocusIdxTabRequestNext == INT_MAX || window->FocusIdxTabCounter == -1) ? INT_MAX : (window->FocusIdxTabRequestNext + (window->FocusIdxTabCounter + 1)) % (window->FocusIdxTabCounter + 1); 5954 window->FocusIdxAllCounter = window->FocusIdxTabCounter = -1; 5955 window->FocusIdxAllRequestNext = window->FocusIdxTabRequestNext = INT_MAX; 5956 5957 // Apply scrolling 5958 window->Scroll = CalcNextScrollFromScrollTargetAndClamp(window); 5959 window->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX); 5960 5961 // Apply focus, new windows appears in front 5962 bool want_focus = false; 5963 if (window_just_activated_by_user && !(flags & ImGuiWindowFlags_NoFocusOnAppearing)) 5964 if (!(flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip)) || (flags & ImGuiWindowFlags_Popup)) 5965 want_focus = true; 5966 5967 // Handle manual resize: Resize Grips, Borders, Gamepad 5968 int border_held = -1; 5969 ImU32 resize_grip_col[4] = { 0 }; 5970 const int resize_grip_count = (flags & ImGuiWindowFlags_ResizeFromAnySide) ? 2 : 1; // 4 5971 const float grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f); 5972 if (!window->Collapsed) 5973 UpdateManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0]); 5974 5975 // Default item width. Make it proportional to window size if window manually resizes 5976 if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize)) 5977 window->ItemWidthDefault = (float)(int)(window->Size.x * 0.65f); 5978 else 5979 window->ItemWidthDefault = (float)(int)(g.FontSize * 16.0f); 5980 5981 // DRAWING 5982 5983 // Setup draw list and outer clipping rectangle 5984 window->DrawList->Clear(); 5985 window->DrawList->Flags = (g.Style.AntiAliasedLines ? ImDrawListFlags_AntiAliasedLines : 0) | (g.Style.AntiAliasedFill ? ImDrawListFlags_AntiAliasedFill : 0); 5986 window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID); 5987 ImRect viewport_rect(GetViewportRect()); 5988 if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) 5989 PushClipRect(parent_window->ClipRect.Min, parent_window->ClipRect.Max, true); 5990 else 5991 PushClipRect(viewport_rect.Min, viewport_rect.Max, true); 5992 5993 // Draw modal window background (darkens what is behind them) 5994 if ((flags & ImGuiWindowFlags_Modal) != 0 && window == GetFrontMostPopupModal()) 5995 window->DrawList->AddRectFilled(viewport_rect.Min, viewport_rect.Max, GetColorU32(ImGuiCol_ModalWindowDarkening, g.ModalWindowDarkeningRatio)); 5996 5997 // Draw navigation selection/windowing rectangle background 5998 if (g.NavWindowingTarget == window) 5999 { 6000 ImRect bb = window->Rect(); 6001 bb.Expand(g.FontSize); 6002 if (!bb.Contains(viewport_rect)) // Avoid drawing if the window covers all the viewport anyway 6003 window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha * 0.25f), g.Style.WindowRounding); 6004 } 6005 6006 // Draw window + handle manual resize 6007 const float window_rounding = window->WindowRounding; 6008 const float window_border_size = window->WindowBorderSize; 6009 const bool title_bar_is_highlight = want_focus || (g.NavWindow && window->RootWindowForTitleBarHighlight == g.NavWindow->RootWindowForTitleBarHighlight); 6010 const ImRect title_bar_rect = window->TitleBarRect(); 6011 if (window->Collapsed) 6012 { 6013 // Title bar only 6014 float backup_border_size = style.FrameBorderSize; 6015 g.Style.FrameBorderSize = window->WindowBorderSize; 6016 ImU32 title_bar_col = GetColorU32((title_bar_is_highlight && !g.NavDisableHighlight) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed); 6017 RenderFrame(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, true, window_rounding); 6018 g.Style.FrameBorderSize = backup_border_size; 6019 } 6020 else 6021 { 6022 // Window background 6023 ImU32 bg_col = GetColorU32(GetWindowBgColorIdxFromFlags(flags)); 6024 if (g.NextWindowData.BgAlphaCond != 0) 6025 { 6026 bg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(g.NextWindowData.BgAlphaVal) << IM_COL32_A_SHIFT); 6027 g.NextWindowData.BgAlphaCond = 0; 6028 } 6029 window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Bot); 6030 6031 // Title bar 6032 ImU32 title_bar_col = GetColorU32(window->Collapsed ? ImGuiCol_TitleBgCollapsed : title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg); 6033 if (!(flags & ImGuiWindowFlags_NoTitleBar)) 6034 window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawCornerFlags_Top); 6035 6036 // Menu bar 6037 if (flags & ImGuiWindowFlags_MenuBar) 6038 { 6039 ImRect menu_bar_rect = window->MenuBarRect(); 6040 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. 6041 window->DrawList->AddRectFilled(menu_bar_rect.Min, menu_bar_rect.Max, GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawCornerFlags_Top); 6042 if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y) 6043 window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize); 6044 } 6045 6046 // Scrollbars 6047 if (window->ScrollbarX) 6048 Scrollbar(ImGuiLayoutType_Horizontal); 6049 if (window->ScrollbarY) 6050 Scrollbar(ImGuiLayoutType_Vertical); 6051 6052 // Render resize grips (after their input handling so we don't have a frame of latency) 6053 if (!(flags & ImGuiWindowFlags_NoResize)) 6054 { 6055 for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++) 6056 { 6057 const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n]; 6058 const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPos); 6059 window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, grip_draw_size) : ImVec2(grip_draw_size, window_border_size))); 6060 window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(grip_draw_size, window_border_size) : ImVec2(window_border_size, grip_draw_size))); 6061 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); 6062 window->DrawList->PathFillConvex(resize_grip_col[resize_grip_n]); 6063 } 6064 } 6065 6066 // Borders 6067 if (window_border_size > 0.0f) 6068 window->DrawList->AddRect(window->Pos, window->Pos + window->Size, GetColorU32(ImGuiCol_Border), window_rounding, ImDrawCornerFlags_All, window_border_size); 6069 if (border_held != -1) 6070 { 6071 ImRect border = GetBorderRect(window, border_held, grip_draw_size, 0.0f); 6072 window->DrawList->AddLine(border.Min, border.Max, GetColorU32(ImGuiCol_SeparatorActive), ImMax(1.0f, window_border_size)); 6073 } 6074 if (style.FrameBorderSize > 0 && !(flags & ImGuiWindowFlags_NoTitleBar)) 6075 window->DrawList->AddLine(title_bar_rect.GetBL() + ImVec2(style.WindowBorderSize, -1), title_bar_rect.GetBR() + ImVec2(-style.WindowBorderSize, -1), GetColorU32(ImGuiCol_Border), style.FrameBorderSize); 6076 } 6077 6078 // Draw navigation selection/windowing rectangle border 6079 if (g.NavWindowingTarget == window) 6080 { 6081 float rounding = ImMax(window->WindowRounding, g.Style.WindowRounding); 6082 ImRect bb = window->Rect(); 6083 bb.Expand(g.FontSize); 6084 if (bb.Contains(viewport_rect)) // If a window fits the entire viewport, adjust its highlight inward 6085 { 6086 bb.Expand(-g.FontSize - 1.0f); 6087 rounding = window->WindowRounding; 6088 } 6089 window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), rounding, ~0, 3.0f); 6090 } 6091 6092 // Store a backup of SizeFull which we will use next frame to decide if we need scrollbars. 6093 window->SizeFullAtLastBegin = window->SizeFull; 6094 6095 // Update ContentsRegionMax. All the variable it depends on are set above in this function. 6096 window->ContentsRegionRect.Min.x = -window->Scroll.x + window->WindowPadding.x; 6097 window->ContentsRegionRect.Min.y = -window->Scroll.y + window->WindowPadding.y + window->TitleBarHeight() + window->MenuBarHeight(); 6098 window->ContentsRegionRect.Max.x = -window->Scroll.x - window->WindowPadding.x + (window->SizeContentsExplicit.x != 0.0f ? window->SizeContentsExplicit.x : (window->Size.x - window->ScrollbarSizes.x)); 6099 window->ContentsRegionRect.Max.y = -window->Scroll.y - window->WindowPadding.y + (window->SizeContentsExplicit.y != 0.0f ? window->SizeContentsExplicit.y : (window->Size.y - window->ScrollbarSizes.y)); 6100 6101 // Setup drawing context 6102 // (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.) 6103 window->DC.IndentX = 0.0f + window->WindowPadding.x - window->Scroll.x; 6104 window->DC.GroupOffsetX = 0.0f; 6105 window->DC.ColumnsOffsetX = 0.0f; 6106 window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.IndentX + window->DC.ColumnsOffsetX, window->TitleBarHeight() + window->MenuBarHeight() + window->WindowPadding.y - window->Scroll.y); 6107 window->DC.CursorPos = window->DC.CursorStartPos; 6108 window->DC.CursorPosPrevLine = window->DC.CursorPos; 6109 window->DC.CursorMaxPos = window->DC.CursorStartPos; 6110 window->DC.CurrentLineHeight = window->DC.PrevLineHeight = 0.0f; 6111 window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f; 6112 window->DC.NavHideHighlightOneFrame = false; 6113 window->DC.NavHasScroll = (GetScrollMaxY() > 0.0f); 6114 window->DC.NavLayerActiveMask = window->DC.NavLayerActiveMaskNext; 6115 window->DC.NavLayerActiveMaskNext = 0x00; 6116 window->DC.MenuBarAppending = false; 6117 window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; 6118 window->DC.ChildWindows.resize(0); 6119 window->DC.LayoutType = ImGuiLayoutType_Vertical; 6120 window->DC.ParentLayoutType = parent_window ? parent_window->DC.LayoutType : ImGuiLayoutType_Vertical; 6121 window->DC.ItemFlags = ImGuiItemFlags_Default_; 6122 window->DC.ItemWidth = window->ItemWidthDefault; 6123 window->DC.TextWrapPos = -1.0f; // disabled 6124 window->DC.ItemFlagsStack.resize(0); 6125 window->DC.ItemWidthStack.resize(0); 6126 window->DC.TextWrapPosStack.resize(0); 6127 window->DC.ColumnsSet = NULL; 6128 window->DC.TreeDepth = 0; 6129 window->DC.TreeDepthMayJumpToParentOnPop = 0x00; 6130 window->DC.StateStorage = &window->StateStorage; 6131 window->DC.GroupStack.resize(0); 6132 window->MenuColumns.Update(3, style.ItemSpacing.x, window_just_activated_by_user); 6133 6134 if ((flags & ImGuiWindowFlags_ChildWindow) && (window->DC.ItemFlags != parent_window->DC.ItemFlags)) 6135 { 6136 window->DC.ItemFlags = parent_window->DC.ItemFlags; 6137 window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags); 6138 } 6139 6140 if (window->AutoFitFramesX > 0) 6141 window->AutoFitFramesX--; 6142 if (window->AutoFitFramesY > 0) 6143 window->AutoFitFramesY--; 6144 6145 // Apply focus (we need to call FocusWindow() AFTER setting DC.CursorStartPos so our initial navigation reference rectangle can start around there) 6146 if (want_focus) 6147 { 6148 FocusWindow(window); 6149 NavInitWindow(window, false); 6150 } 6151 6152 // Title bar 6153 if (!(flags & ImGuiWindowFlags_NoTitleBar)) 6154 { 6155 // Close & collapse button are on layer 1 (same as menus) and don't default focus 6156 const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags; 6157 window->DC.ItemFlags |= ImGuiItemFlags_NoNavDefaultFocus; 6158 window->DC.NavLayerCurrent++; 6159 window->DC.NavLayerCurrentMask <<= 1; 6160 6161 // Collapse button 6162 if (!(flags & ImGuiWindowFlags_NoCollapse)) 6163 { 6164 ImGuiID id = window->GetID("#COLLAPSE"); 6165 ImRect bb(window->Pos + style.FramePadding + ImVec2(1, 1), window->Pos + style.FramePadding + ImVec2(g.FontSize, g.FontSize) - ImVec2(1, 1)); 6166 ItemAdd(bb, id); 6167 if (ButtonBehavior(bb, id, NULL, NULL)) 6168 window->CollapseToggleWanted = true; // Defer collapsing to next frame as we are too far in the Begin() function 6169 RenderNavHighlight(bb, id); 6170 RenderArrow(window->Pos + style.FramePadding, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f); 6171 } 6172 6173 // Close button 6174 if (p_open != NULL) 6175 { 6176 const float pad = style.FramePadding.y; 6177 const float rad = g.FontSize * 0.5f; 6178 if (CloseButton(window->GetID("#CLOSE"), window->Rect().GetTR() + ImVec2(-pad - rad, pad + rad), rad + 1)) 6179 *p_open = false; 6180 } 6181 6182 window->DC.NavLayerCurrent--; 6183 window->DC.NavLayerCurrentMask >>= 1; 6184 window->DC.ItemFlags = item_flags_backup; 6185 6186 // Title text (FIXME: refactor text alignment facilities along with RenderText helpers, this is too much code for what it does.) 6187 ImVec2 text_size = CalcTextSize(name, NULL, true); 6188 ImRect text_r = title_bar_rect; 6189 float pad_left = (flags & ImGuiWindowFlags_NoCollapse) ? style.FramePadding.x : (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x); 6190 float pad_right = (p_open == NULL) ? style.FramePadding.x : (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x); 6191 if (style.WindowTitleAlign.x > 0.0f) 6192 pad_right = ImLerp(pad_right, pad_left, style.WindowTitleAlign.x); 6193 text_r.Min.x += pad_left; 6194 text_r.Max.x -= pad_right; 6195 ImRect clip_rect = text_r; 6196 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() 6197 RenderTextClipped(text_r.Min, text_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_rect); 6198 } 6199 6200 // Save clipped aabb so we can access it in constant-time in FindHoveredWindow() 6201 window->WindowRectClipped = window->Rect(); 6202 window->WindowRectClipped.ClipWith(window->ClipRect); 6203 6204 // Pressing CTRL+C while holding on a window copy its content to the clipboard 6205 // 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. 6206 // Maybe we can support CTRL+C on every element? 6207 /* 6208 if (g.ActiveId == move_id) 6209 if (g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_C)) 6210 ImGui::LogToClipboard(); 6211 */ 6212 6213 // Inner rectangle 6214 // We set this up after processing the resize grip so that our clip rectangle doesn't lag by a frame 6215 // Note that if our window is collapsed we will end up with an inverted (~null) clipping rectangle which is the correct behavior. 6216 window->InnerRect.Min.x = title_bar_rect.Min.x + window->WindowBorderSize; 6217 window->InnerRect.Min.y = title_bar_rect.Max.y + window->MenuBarHeight() + (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize); 6218 window->InnerRect.Max.x = window->Pos.x + window->Size.x - window->ScrollbarSizes.x - window->WindowBorderSize; 6219 window->InnerRect.Max.y = window->Pos.y + window->Size.y - window->ScrollbarSizes.y - window->WindowBorderSize; 6220 //window->DrawList->AddRect(window->InnerRect.Min, window->InnerRect.Max, IM_COL32_WHITE); 6221 6222 // Inner clipping rectangle 6223 // Force round operator last to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result. 6224 window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerRect.Min.x + ImMax(0.0f, ImFloor(window->WindowPadding.x*0.5f - window->WindowBorderSize))); 6225 window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerRect.Min.y); 6226 window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerRect.Max.x - ImMax(0.0f, ImFloor(window->WindowPadding.x*0.5f - window->WindowBorderSize))); 6227 window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerRect.Max.y); 6228 6229 // After Begin() we fill the last item / hovered data based on title bar data. It is a standard behavior (to allow creation of context menus on title bar only, etc.). 6230 window->DC.LastItemId = window->MoveId; 6231 window->DC.LastItemStatusFlags = IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0; 6232 window->DC.LastItemRect = title_bar_rect; 6233 } 6234 6235 PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true); 6236 6237 // 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) 6238 if (first_begin_of_the_frame) 6239 window->WriteAccessed = false; 6240 6241 window->BeginCount++; 6242 g.NextWindowData.Clear(); 6243 6244 // Child window can be out of sight and have "negative" clip windows. 6245 // Mark them as collapsed so commands are skipped earlier (we can't manually collapse them because they have no title bar). 6246 if (flags & ImGuiWindowFlags_ChildWindow) 6247 { 6248 IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0); 6249 window->Collapsed = parent_window && parent_window->Collapsed; 6250 6251 if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) 6252 window->Collapsed |= (window->WindowRectClipped.Min.x >= window->WindowRectClipped.Max.x || window->WindowRectClipped.Min.y >= window->WindowRectClipped.Max.y); 6253 6254 // We also hide the window from rendering because we've already added its border to the command list. 6255 // (we could perform the check earlier in the function but it is simpler at this point) 6256 if (window->Collapsed) 6257 window->Active = false; 6258 } 6259 if (style.Alpha <= 0.0f) 6260 window->Active = false; 6261 6262 // Return false if we don't intend to display anything to allow user to perform an early out optimization 6263 window->SkipItems = (window->Collapsed || !window->Active) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0; 6264 return !window->SkipItems; 6265 } 6266 6267 // Old Begin() API with 5 parameters, avoid calling this version directly! Use SetNextWindowSize()/SetNextWindowBgAlpha() + Begin() instead. 6268 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS 6269 bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_first_use, float bg_alpha_override, ImGuiWindowFlags flags) 6270 { 6271 // 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. 6272 if (size_first_use.x != 0.0f || size_first_use.y != 0.0f) 6273 ImGui::SetNextWindowSize(size_first_use, ImGuiCond_FirstUseEver); 6274 6275 // Old API feature: override the window background alpha with a parameter. 6276 if (bg_alpha_override >= 0.0f) 6277 ImGui::SetNextWindowBgAlpha(bg_alpha_override); 6278 6279 return ImGui::Begin(name, p_open, flags); 6280 } 6281 #endif // IMGUI_DISABLE_OBSOLETE_FUNCTIONS 6028 NavInitWindow(window, false); 6029 } 6030 6031 // Title bar 6032 if (!(flags & ImGuiWindowFlags_NoTitleBar)) 6033 RenderWindowTitleBarContents(window, title_bar_rect, name, p_open); 6034 6035 // Clear hit test shape every frame 6036 window->HitTestHoleSize.x = window->HitTestHoleSize.y = 0; 6037 6038 // Pressing CTRL+C while holding on a window copy its content to the clipboard 6039 // 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. 6040 // Maybe we can support CTRL+C on every element? 6041 /* 6042 if (g.ActiveId == move_id) 6043 if (g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_C)) 6044 LogToClipboard(); 6045 */ 6046 6047 // We fill last item data based on Title Bar/Tab, in order for IsItemHovered() and IsItemActive() to be usable after Begin(). 6048 // This is useful to allow creating context menus on title bar only, etc. 6049 SetLastItemData(window, window->MoveId, IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0, title_bar_rect); 6050 6051 #ifdef IMGUI_ENABLE_TEST_ENGINE 6052 if (!(window->Flags & ImGuiWindowFlags_NoTitleBar)) 6053 IMGUI_TEST_ENGINE_ITEM_ADD(window->DC.LastItemRect, window->DC.LastItemId); 6054 #endif 6055 } 6056 else 6057 { 6058 // Append 6059 SetCurrentWindow(window); 6060 } 6061 6062 PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true); 6063 6064 // 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) 6065 if (first_begin_of_the_frame) 6066 window->WriteAccessed = false; 6067 6068 window->BeginCount++; 6069 g.NextWindowData.ClearFlags(); 6070 6071 // Update visibility 6072 if (first_begin_of_the_frame) 6073 { 6074 if (flags & ImGuiWindowFlags_ChildWindow) 6075 { 6076 // Child window can be out of sight and have "negative" clip windows. 6077 // Mark them as collapsed so commands are skipped earlier (we can't manually collapse them because they have no title bar). 6078 IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0); 6079 if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) 6080 if (window->OuterRectClipped.Min.x >= window->OuterRectClipped.Max.x || window->OuterRectClipped.Min.y >= window->OuterRectClipped.Max.y) 6081 window->HiddenFramesCanSkipItems = 1; 6082 6083 // Hide along with parent or if parent is collapsed 6084 if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCanSkipItems > 0)) 6085 window->HiddenFramesCanSkipItems = 1; 6086 if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCannotSkipItems > 0)) 6087 window->HiddenFramesCannotSkipItems = 1; 6088 } 6089 6090 // 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) 6091 if (style.Alpha <= 0.0f) 6092 window->HiddenFramesCanSkipItems = 1; 6093 6094 // Update the Hidden flag 6095 window->Hidden = (window->HiddenFramesCanSkipItems > 0) || (window->HiddenFramesCannotSkipItems > 0); 6096 6097 // Update the SkipItems flag, used to early out of all items functions (no layout required) 6098 bool skip_items = false; 6099 if (window->Collapsed || !window->Active || window->Hidden) 6100 if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && window->HiddenFramesCannotSkipItems <= 0) 6101 skip_items = true; 6102 window->SkipItems = skip_items; 6103 } 6104 6105 return !window->SkipItems; 6106 } 6282 6107 6283 6108 void ImGui::End() 6284 6109 { 6285 ImGuiContext& g = *GImGui; 6286 ImGuiWindow* window = g.CurrentWindow; 6287 6288 if (window->DC.ColumnsSet != NULL) 6289 EndColumns(); 6290 PopClipRect(); // Inner window clip rectangle 6291 6292 // Stop logging 6293 if (!(window->Flags & ImGuiWindowFlags_ChildWindow)) // FIXME: add more options for scope of logging 6294 LogFinish(); 6295 6296 // Pop from window stack 6297 g.CurrentWindowStack.pop_back(); 6298 if (window->Flags & ImGuiWindowFlags_Popup) 6299 g.CurrentPopupStack.pop_back(); 6300 CheckStacksSize(window, false); 6301 SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back()); 6302 } 6303 6304 // Vertical scrollbar 6305 // The entire piece of code below is rather confusing because: 6306 // - We handle absolute seeking (when first clicking outside the grab) and relative manipulation (afterward or when clicking inside the grab) 6307 // - We store values as normalized ratio and in a form that allows the window content to change while we are holding on a scrollbar 6308 // - We handle both horizontal and vertical scrollbars, which makes the terminology not ideal. 6309 void ImGui::Scrollbar(ImGuiLayoutType direction) 6310 { 6311 ImGuiContext& g = *GImGui; 6312 ImGuiWindow* window = g.CurrentWindow; 6313 6314 const bool horizontal = (direction == ImGuiLayoutType_Horizontal); 6315 const ImGuiStyle& style = g.Style; 6316 const ImGuiID id = window->GetID(horizontal ? "#SCROLLX" : "#SCROLLY"); 6317 6318 // Render background 6319 bool other_scrollbar = (horizontal ? window->ScrollbarY : window->ScrollbarX); 6320 float other_scrollbar_size_w = other_scrollbar ? style.ScrollbarSize : 0.0f; 6321 const ImRect window_rect = window->Rect(); 6322 const float border_size = window->WindowBorderSize; 6323 ImRect bb = horizontal 6324 ? ImRect(window->Pos.x + border_size, window_rect.Max.y - style.ScrollbarSize, window_rect.Max.x - other_scrollbar_size_w - border_size, window_rect.Max.y - border_size) 6325 : ImRect(window_rect.Max.x - style.ScrollbarSize, window->Pos.y + border_size, window_rect.Max.x - border_size, window_rect.Max.y - other_scrollbar_size_w - border_size); 6326 if (!horizontal) 6327 bb.Min.y += window->TitleBarHeight() + ((window->Flags & ImGuiWindowFlags_MenuBar) ? window->MenuBarHeight() : 0.0f); 6328 if (bb.GetWidth() <= 0.0f || bb.GetHeight() <= 0.0f) 6329 return; 6330 6331 int window_rounding_corners; 6332 if (horizontal) 6333 window_rounding_corners = ImDrawCornerFlags_BotLeft | (other_scrollbar ? 0 : ImDrawCornerFlags_BotRight); 6334 else 6335 window_rounding_corners = (((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar)) ? ImDrawCornerFlags_TopRight : 0) | (other_scrollbar ? 0 : ImDrawCornerFlags_BotRight); 6336 window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_ScrollbarBg), window->WindowRounding, window_rounding_corners); 6337 bb.Expand(ImVec2(-ImClamp((float)(int)((bb.Max.x - bb.Min.x - 2.0f) * 0.5f), 0.0f, 3.0f), -ImClamp((float)(int)((bb.Max.y - bb.Min.y - 2.0f) * 0.5f), 0.0f, 3.0f))); 6338 6339 // V denote the main, longer axis of the scrollbar (= height for a vertical scrollbar) 6340 float scrollbar_size_v = horizontal ? bb.GetWidth() : bb.GetHeight(); 6341 float scroll_v = horizontal ? window->Scroll.x : window->Scroll.y; 6342 float win_size_avail_v = (horizontal ? window->SizeFull.x : window->SizeFull.y) - other_scrollbar_size_w; 6343 float win_size_contents_v = horizontal ? window->SizeContents.x : window->SizeContents.y; 6344 6345 // Calculate the height of our grabbable box. It generally represent the amount visible (vs the total scrollable amount) 6346 // But we maintain a minimum size in pixel to allow for the user to still aim inside. 6347 IM_ASSERT(ImMax(win_size_contents_v, win_size_avail_v) > 0.0f); // Adding this assert to check if the ImMax(XXX,1.0f) is still needed. PLEASE CONTACT ME if this triggers. 6348 const float win_size_v = ImMax(ImMax(win_size_contents_v, win_size_avail_v), 1.0f); 6349 const float grab_h_pixels = ImClamp(scrollbar_size_v * (win_size_avail_v / win_size_v), style.GrabMinSize, scrollbar_size_v); 6350 const float grab_h_norm = grab_h_pixels / scrollbar_size_v; 6351 6352 // Handle input right away. None of the code of Begin() is relying on scrolling position before calling Scrollbar(). 6353 bool held = false; 6354 bool hovered = false; 6355 const bool previously_held = (g.ActiveId == id); 6356 ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_NoNavFocus); 6357 6358 float scroll_max = ImMax(1.0f, win_size_contents_v - win_size_avail_v); 6359 float scroll_ratio = ImSaturate(scroll_v / scroll_max); 6360 float grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v; 6361 if (held && grab_h_norm < 1.0f) 6362 { 6363 float scrollbar_pos_v = horizontal ? bb.Min.x : bb.Min.y; 6364 float mouse_pos_v = horizontal ? g.IO.MousePos.x : g.IO.MousePos.y; 6365 float* click_delta_to_grab_center_v = horizontal ? &g.ScrollbarClickDeltaToGrabCenter.x : &g.ScrollbarClickDeltaToGrabCenter.y; 6366 6367 // Click position in scrollbar normalized space (0.0f->1.0f) 6368 const float clicked_v_norm = ImSaturate((mouse_pos_v - scrollbar_pos_v) / scrollbar_size_v); 6369 SetHoveredID(id); 6370 6371 bool seek_absolute = false; 6372 if (!previously_held) 6373 { 6374 // On initial click calculate the distance between mouse and the center of the grab 6375 if (clicked_v_norm >= grab_v_norm && clicked_v_norm <= grab_v_norm + grab_h_norm) 6376 { 6377 *click_delta_to_grab_center_v = clicked_v_norm - grab_v_norm - grab_h_norm * 0.5f; 6378 } 6379 else 6380 { 6381 seek_absolute = true; 6382 *click_delta_to_grab_center_v = 0.0f; 6383 } 6384 } 6385 6386 // Apply scroll 6387 // It is ok to modify Scroll here because we are being called in Begin() after the calculation of SizeContents and before setting up our starting position 6388 const float scroll_v_norm = ImSaturate((clicked_v_norm - *click_delta_to_grab_center_v - grab_h_norm * 0.5f) / (1.0f - grab_h_norm)); 6389 scroll_v = (float)(int)(0.5f + scroll_v_norm * scroll_max);//(win_size_contents_v - win_size_v)); 6390 if (horizontal) 6391 window->Scroll.x = scroll_v; 6392 else 6393 window->Scroll.y = scroll_v; 6394 6395 // Update values for rendering 6396 scroll_ratio = ImSaturate(scroll_v / scroll_max); 6397 grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v; 6398 6399 // Update distance to grab now that we have seeked and saturated 6400 if (seek_absolute) 6401 *click_delta_to_grab_center_v = clicked_v_norm - grab_v_norm - grab_h_norm * 0.5f; 6402 } 6403 6404 // Render 6405 const ImU32 grab_col = GetColorU32(held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab); 6406 ImRect grab_rect; 6407 if (horizontal) 6408 grab_rect = ImRect(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm), bb.Min.y, ImMin(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm) + grab_h_pixels, window_rect.Max.x), bb.Max.y); 6409 else 6410 grab_rect = ImRect(bb.Min.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm), bb.Max.x, ImMin(ImLerp(bb.Min.y, bb.Max.y, grab_v_norm) + grab_h_pixels, window_rect.Max.y)); 6411 window->DrawList->AddRectFilled(grab_rect.Min, grab_rect.Max, grab_col, style.ScrollbarRounding); 6412 } 6413 6414 void ImGui::BringWindowToFront(ImGuiWindow* window) 6415 { 6416 ImGuiContext& g = *GImGui; 6417 ImGuiWindow* current_front_window = g.Windows.back(); 6418 if (current_front_window == window || current_front_window->RootWindow == window) 6419 return; 6420 for (int i = g.Windows.Size - 2; i >= 0; i--) // We can ignore the front most window 6421 if (g.Windows[i] == window) 6422 { 6423 g.Windows.erase(g.Windows.Data + i); 6424 g.Windows.push_back(window); 6425 break; 6426 } 6427 } 6428 6429 void ImGui::BringWindowToBack(ImGuiWindow* window) 6430 { 6431 ImGuiContext& g = *GImGui; 6432 if (g.Windows[0] == window) 6433 return; 6434 for (int i = 0; i < g.Windows.Size; i++) 6435 if (g.Windows[i] == window) 6436 { 6437 memmove(&g.Windows[1], &g.Windows[0], (size_t)i * sizeof(ImGuiWindow*)); 6438 g.Windows[0] = window; 6439 break; 6440 } 6110 ImGuiContext& g = *GImGui; 6111 ImGuiWindow* window = g.CurrentWindow; 6112 6113 // Error checking: verify that user hasn't called End() too many times! 6114 if (g.CurrentWindowStack.Size <= 1 && g.WithinFrameScopeWithImplicitWindow) 6115 { 6116 IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size > 1, "Calling End() too many times!"); 6117 return; 6118 } 6119 IM_ASSERT(g.CurrentWindowStack.Size > 0); 6120 6121 // Error checking: verify that user doesn't directly call End() on a child window. 6122 if (window->Flags & ImGuiWindowFlags_ChildWindow) 6123 IM_ASSERT_USER_ERROR(g.WithinEndChild, "Must call EndChild() and not End()!"); 6124 6125 // Close anything that is open 6126 if (window->DC.CurrentColumns) 6127 EndColumns(); 6128 PopClipRect(); // Inner window clip rectangle 6129 6130 // Stop logging 6131 if (!(window->Flags & ImGuiWindowFlags_ChildWindow)) // FIXME: add more options for scope of logging 6132 LogFinish(); 6133 6134 // Pop from window stack 6135 g.CurrentWindowStack.pop_back(); 6136 if (window->Flags & ImGuiWindowFlags_Popup) 6137 g.BeginPopupStack.pop_back(); 6138 ErrorCheckBeginEndCompareStacksSize(window, false); 6139 SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back()); 6140 } 6141 6142 void ImGui::BringWindowToFocusFront(ImGuiWindow* window) 6143 { 6144 ImGuiContext& g = *GImGui; 6145 if (g.WindowsFocusOrder.back() == window) 6146 return; 6147 for (int i = g.WindowsFocusOrder.Size - 2; i >= 0; i--) // We can ignore the top-most window 6148 if (g.WindowsFocusOrder[i] == window) 6149 { 6150 memmove(&g.WindowsFocusOrder[i], &g.WindowsFocusOrder[i + 1], (size_t)(g.WindowsFocusOrder.Size - i - 1) * sizeof(ImGuiWindow*)); 6151 g.WindowsFocusOrder[g.WindowsFocusOrder.Size - 1] = window; 6152 break; 6153 } 6154 } 6155 6156 void ImGui::BringWindowToDisplayFront(ImGuiWindow* window) 6157 { 6158 ImGuiContext& g = *GImGui; 6159 ImGuiWindow* current_front_window = g.Windows.back(); 6160 if (current_front_window == window || current_front_window->RootWindow == window) // Cheap early out (could be better) 6161 return; 6162 for (int i = g.Windows.Size - 2; i >= 0; i--) // We can ignore the top-most window 6163 if (g.Windows[i] == window) 6164 { 6165 memmove(&g.Windows[i], &g.Windows[i + 1], (size_t)(g.Windows.Size - i - 1) * sizeof(ImGuiWindow*)); 6166 g.Windows[g.Windows.Size - 1] = window; 6167 break; 6168 } 6169 } 6170 6171 void ImGui::BringWindowToDisplayBack(ImGuiWindow* window) 6172 { 6173 ImGuiContext& g = *GImGui; 6174 if (g.Windows[0] == window) 6175 return; 6176 for (int i = 0; i < g.Windows.Size; i++) 6177 if (g.Windows[i] == window) 6178 { 6179 memmove(&g.Windows[1], &g.Windows[0], (size_t)i * sizeof(ImGuiWindow*)); 6180 g.Windows[0] = window; 6181 break; 6182 } 6441 6183 } 6442 6184 … … 6444 6186 void ImGui::FocusWindow(ImGuiWindow* window) 6445 6187 { 6446 ImGuiContext& g = *GImGui; 6447 6448 if (g.NavWindow != window) 6449 { 6450 g.NavWindow = window; 6451 if (window && g.NavDisableMouseHover) 6452 g.NavMousePosDirty = true; 6453 g.NavInitRequest = false; 6454 g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId 6455 g.NavIdIsAlive = false; 6456 g.NavLayer = 0; 6457 //printf("[%05d] FocusWindow(\"%s\")\n", g.FrameCount, window ? window->Name : NULL); 6458 } 6459 6460 // Passing NULL allow to disable keyboard focus 6461 if (!window) 6462 return; 6463 6464 // Move the root window to the top of the pile 6465 if (window->RootWindow) 6466 window = window->RootWindow; 6467 6468 // Steal focus on active widgets 6469 if (window->Flags & ImGuiWindowFlags_Popup) // FIXME: This statement should be unnecessary. Need further testing before removing it.. 6470 if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != window) 6471 ClearActiveID(); 6472 6473 // Bring to front 6474 if (!(window->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) 6475 BringWindowToFront(window); 6476 } 6477 6478 void ImGui::FocusFrontMostActiveWindow(ImGuiWindow* ignore_window) 6479 { 6480 ImGuiContext& g = *GImGui; 6481 for (int i = g.Windows.Size - 1; i >= 0; i--) 6482 if (g.Windows[i] != ignore_window && g.Windows[i]->WasActive && !(g.Windows[i]->Flags & ImGuiWindowFlags_ChildWindow)) 6483 { 6484 ImGuiWindow* focus_window = NavRestoreLastChildNavWindow(g.Windows[i]); 6485 FocusWindow(focus_window); 6486 return; 6487 } 6488 } 6489 6490 void ImGui::PushItemWidth(float item_width) 6491 { 6492 ImGuiWindow* window = GetCurrentWindow(); 6493 window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width); 6494 window->DC.ItemWidthStack.push_back(window->DC.ItemWidth); 6495 } 6496 6497 void ImGui::PushMultiItemsWidths(int components, float w_full) 6498 { 6499 ImGuiWindow* window = GetCurrentWindow(); 6500 const ImGuiStyle& style = GImGui->Style; 6501 if (w_full <= 0.0f) 6502 w_full = CalcItemWidth(); 6503 const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.ItemInnerSpacing.x) * (components - 1)) / (float)components)); 6504 const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components - 1))); 6505 window->DC.ItemWidthStack.push_back(w_item_last); 6506 for (int i = 0; i < components - 1; i++) 6507 window->DC.ItemWidthStack.push_back(w_item_one); 6508 window->DC.ItemWidth = window->DC.ItemWidthStack.back(); 6509 } 6510 6511 void ImGui::PopItemWidth() 6512 { 6513 ImGuiWindow* window = GetCurrentWindow(); 6514 window->DC.ItemWidthStack.pop_back(); 6515 window->DC.ItemWidth = window->DC.ItemWidthStack.empty() ? window->ItemWidthDefault : window->DC.ItemWidthStack.back(); 6516 } 6517 6518 float ImGui::CalcItemWidth() 6519 { 6520 ImGuiWindow* window = GetCurrentWindowRead(); 6521 float w = window->DC.ItemWidth; 6522 if (w < 0.0f) 6523 { 6524 // 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. 6525 float width_to_right_edge = GetContentRegionAvail().x; 6526 w = ImMax(1.0f, width_to_right_edge + w); 6527 } 6528 w = (float)(int)w; 6529 return w; 6530 } 6531 6532 static ImFont* GetDefaultFont() 6533 { 6534 ImGuiContext& g = *GImGui; 6535 return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; 6188 ImGuiContext& g = *GImGui; 6189 6190 if (g.NavWindow != window) 6191 { 6192 g.NavWindow = window; 6193 if (window && g.NavDisableMouseHover) 6194 g.NavMousePosDirty = true; 6195 g.NavInitRequest = false; 6196 g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId 6197 g.NavFocusScopeId = 0; 6198 g.NavIdIsAlive = false; 6199 g.NavLayer = ImGuiNavLayer_Main; 6200 //IMGUI_DEBUG_LOG("FocusWindow(\"%s\")\n", window ? window->Name : NULL); 6201 } 6202 6203 // Close popups if any 6204 ClosePopupsOverWindow(window, false); 6205 6206 // Move the root window to the top of the pile 6207 IM_ASSERT(window == NULL || window->RootWindow != NULL); 6208 ImGuiWindow* focus_front_window = window ? window->RootWindow : NULL; // NB: In docking branch this is window->RootWindowDockStop 6209 ImGuiWindow* display_front_window = window ? window->RootWindow : NULL; 6210 6211 // Steal active widgets. Some of the cases it triggers includes: 6212 // - Focus a window while an InputText in another window is active, if focus happens before the old InputText can run. 6213 // - When using Nav to activate menu items (due to timing of activating on press->new window appears->losing ActiveId) 6214 if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != focus_front_window) 6215 if (!g.ActiveIdNoClearOnFocusLoss) 6216 ClearActiveID(); 6217 6218 // Passing NULL allow to disable keyboard focus 6219 if (!window) 6220 return; 6221 6222 // Bring to front 6223 BringWindowToFocusFront(focus_front_window); 6224 if (((window->Flags | display_front_window->Flags) & ImGuiWindowFlags_NoBringToFrontOnFocus) == 0) 6225 BringWindowToDisplayFront(display_front_window); 6226 } 6227 6228 void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window) 6229 { 6230 ImGuiContext& g = *GImGui; 6231 6232 int start_idx = g.WindowsFocusOrder.Size - 1; 6233 if (under_this_window != NULL) 6234 { 6235 int under_this_window_idx = FindWindowFocusIndex(under_this_window); 6236 if (under_this_window_idx != -1) 6237 start_idx = under_this_window_idx - 1; 6238 } 6239 for (int i = start_idx; i >= 0; i--) 6240 { 6241 // 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. 6242 ImGuiWindow* window = g.WindowsFocusOrder[i]; 6243 if (window != ignore_window && window->WasActive && !(window->Flags & ImGuiWindowFlags_ChildWindow)) 6244 if ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) 6245 { 6246 ImGuiWindow* focus_window = NavRestoreLastChildNavWindow(window); 6247 FocusWindow(focus_window); 6248 return; 6249 } 6250 } 6251 FocusWindow(NULL); 6536 6252 } 6537 6253 6538 6254 void ImGui::SetCurrentFont(ImFont* font) 6539 6255 { 6540 ImGuiContext& g = *GImGui; 6541 IM_ASSERT(font && font->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ? 6542 IM_ASSERT(font->Scale > 0.0f); 6543 g.Font = font; 6544 g.FontBaseSize = g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale; 6545 g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f; 6546 6547 ImFontAtlas* atlas = g.Font->ContainerAtlas; 6548 g.DrawListSharedData.TexUvWhitePixel = atlas->TexUvWhitePixel; 6549 g.DrawListSharedData.Font = g.Font; 6550 g.DrawListSharedData.FontSize = g.FontSize; 6256 ImGuiContext& g = *GImGui; 6257 IM_ASSERT(font && font->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ? 6258 IM_ASSERT(font->Scale > 0.0f); 6259 g.Font = font; 6260 g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale); 6261 g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f; 6262 6263 ImFontAtlas* atlas = g.Font->ContainerAtlas; 6264 g.DrawListSharedData.TexUvWhitePixel = atlas->TexUvWhitePixel; 6265 g.DrawListSharedData.TexUvLines = atlas->TexUvLines; 6266 g.DrawListSharedData.Font = g.Font; 6267 g.DrawListSharedData.FontSize = g.FontSize; 6551 6268 } 6552 6269 6553 6270 void ImGui::PushFont(ImFont* font) 6554 6271 { 6555 ImGuiContext& g = *GImGui;6556 if (!font)6557 font = GetDefaultFont();6558 SetCurrentFont(font);6559 g.FontStack.push_back(font);6560 g.CurrentWindow->DrawList->PushTextureID(font->ContainerAtlas->TexID);6272 ImGuiContext& g = *GImGui; 6273 if (!font) 6274 font = GetDefaultFont(); 6275 SetCurrentFont(font); 6276 g.FontStack.push_back(font); 6277 g.CurrentWindow->DrawList->PushTextureID(font->ContainerAtlas->TexID); 6561 6278 } 6562 6279 6563 6280 void ImGui::PopFont() 6564 6281 { 6565 ImGuiContext& g = *GImGui;6566 g.CurrentWindow->DrawList->PopTextureID();6567 g.FontStack.pop_back();6568 SetCurrentFont(g.FontStack.empty() ? GetDefaultFont() : g.FontStack.back());6282 ImGuiContext& g = *GImGui; 6283 g.CurrentWindow->DrawList->PopTextureID(); 6284 g.FontStack.pop_back(); 6285 SetCurrentFont(g.FontStack.empty() ? GetDefaultFont() : g.FontStack.back()); 6569 6286 } 6570 6287 6571 6288 void ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled) 6572 6289 { 6573 ImGuiWindow* window = GetCurrentWindow();6574 if (enabled)6575 window->DC.ItemFlags |= option;6576 else6577 window->DC.ItemFlags &= ~option;6578 window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags);6290 ImGuiWindow* window = GetCurrentWindow(); 6291 if (enabled) 6292 window->DC.ItemFlags |= option; 6293 else 6294 window->DC.ItemFlags &= ~option; 6295 window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags); 6579 6296 } 6580 6297 6581 6298 void ImGui::PopItemFlag() 6582 6299 { 6583 ImGuiWindow* window = GetCurrentWindow(); 6584 window->DC.ItemFlagsStack.pop_back(); 6585 window->DC.ItemFlags = window->DC.ItemFlagsStack.empty() ? ImGuiItemFlags_Default_ : window->DC.ItemFlagsStack.back(); 6586 } 6587 6300 ImGuiWindow* window = GetCurrentWindow(); 6301 window->DC.ItemFlagsStack.pop_back(); 6302 window->DC.ItemFlags = window->DC.ItemFlagsStack.empty() ? ImGuiItemFlags_Default_ : window->DC.ItemFlagsStack.back(); 6303 } 6304 6305 // FIXME: Look into renaming this once we have settled the new Focus/Activation/TabStop system. 6588 6306 void ImGui::PushAllowKeyboardFocus(bool allow_keyboard_focus) 6589 6307 { 6590 PushItemFlag(ImGuiItemFlags_AllowKeyboardFocus,allow_keyboard_focus);6308 PushItemFlag(ImGuiItemFlags_NoTabStop, !allow_keyboard_focus); 6591 6309 } 6592 6310 6593 6311 void ImGui::PopAllowKeyboardFocus() 6594 6312 { 6595 PopItemFlag();6313 PopItemFlag(); 6596 6314 } 6597 6315 6598 6316 void ImGui::PushButtonRepeat(bool repeat) 6599 6317 { 6600 PushItemFlag(ImGuiItemFlags_ButtonRepeat, repeat);6318 PushItemFlag(ImGuiItemFlags_ButtonRepeat, repeat); 6601 6319 } 6602 6320 6603 6321 void ImGui::PopButtonRepeat() 6604 6322 { 6605 PopItemFlag();6323 PopItemFlag(); 6606 6324 } 6607 6325 6608 6326 void ImGui::PushTextWrapPos(float wrap_pos_x) 6609 6327 { 6610 ImGuiWindow* window = GetCurrentWindow();6611 window->DC.TextWrapPos = wrap_pos_x;6612 window->DC.TextWrapPosStack.push_back(wrap_pos_x);6328 ImGuiWindow* window = GetCurrentWindow(); 6329 window->DC.TextWrapPos = wrap_pos_x; 6330 window->DC.TextWrapPosStack.push_back(wrap_pos_x); 6613 6331 } 6614 6332 6615 6333 void ImGui::PopTextWrapPos() 6616 6334 { 6617 ImGuiWindow* window = GetCurrentWindow(); 6618 window->DC.TextWrapPosStack.pop_back(); 6619 window->DC.TextWrapPos = window->DC.TextWrapPosStack.empty() ? -1.0f : window->DC.TextWrapPosStack.back(); 6620 } 6621 6622 // 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 6623 void ImGui::PushStyleColor(ImGuiCol idx, ImU32 col) 6624 { 6625 ImGuiContext& g = *GImGui; 6626 ImGuiColMod backup; 6627 backup.Col = idx; 6628 backup.BackupValue = g.Style.Colors[idx]; 6629 g.ColorModifiers.push_back(backup); 6630 g.Style.Colors[idx] = ColorConvertU32ToFloat4(col); 6631 } 6632 6633 void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col) 6634 { 6635 ImGuiContext& g = *GImGui; 6636 ImGuiColMod backup; 6637 backup.Col = idx; 6638 backup.BackupValue = g.Style.Colors[idx]; 6639 g.ColorModifiers.push_back(backup); 6640 g.Style.Colors[idx] = col; 6641 } 6642 6643 void ImGui::PopStyleColor(int count) 6644 { 6645 ImGuiContext& g = *GImGui; 6646 while (count > 0) 6647 { 6648 ImGuiColMod& backup = g.ColorModifiers.back(); 6649 g.Style.Colors[backup.Col] = backup.BackupValue; 6650 g.ColorModifiers.pop_back(); 6651 count--; 6652 } 6653 } 6654 6655 struct ImGuiStyleVarInfo 6656 { 6657 ImGuiDataType Type; 6658 ImU32 Count; 6659 ImU32 Offset; 6660 void* GetVarPtr(ImGuiStyle* style) const { return (void*)((unsigned char*)style + Offset); } 6661 }; 6662 6663 static const ImGuiStyleVarInfo GStyleVarInfo[] = 6664 { 6665 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, Alpha) }, // ImGuiStyleVar_Alpha 6666 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowPadding) }, // ImGuiStyleVar_WindowPadding 6667 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowRounding) }, // ImGuiStyleVar_WindowRounding 6668 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowBorderSize) }, // ImGuiStyleVar_WindowBorderSize 6669 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowMinSize) }, // ImGuiStyleVar_WindowMinSize 6670 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowTitleAlign) }, // ImGuiStyleVar_WindowTitleAlign 6671 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildRounding) }, // ImGuiStyleVar_ChildRounding 6672 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildBorderSize) }, // ImGuiStyleVar_ChildBorderSize 6673 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupRounding) }, // ImGuiStyleVar_PopupRounding 6674 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupBorderSize) }, // ImGuiStyleVar_PopupBorderSize 6675 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, FramePadding) }, // ImGuiStyleVar_FramePadding 6676 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameRounding) }, // ImGuiStyleVar_FrameRounding 6677 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameBorderSize) }, // ImGuiStyleVar_FrameBorderSize 6678 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemSpacing) }, // ImGuiStyleVar_ItemSpacing 6679 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemInnerSpacing) }, // ImGuiStyleVar_ItemInnerSpacing 6680 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, IndentSpacing) }, // ImGuiStyleVar_IndentSpacing 6681 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarSize) }, // ImGuiStyleVar_ScrollbarSize 6682 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarRounding) }, // ImGuiStyleVar_ScrollbarRounding 6683 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) }, // ImGuiStyleVar_GrabMinSize 6684 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabRounding) }, // ImGuiStyleVar_GrabRounding 6685 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign 6686 }; 6687 6688 static const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx) 6689 { 6690 IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_COUNT); 6691 IM_ASSERT(IM_ARRAYSIZE(GStyleVarInfo) == ImGuiStyleVar_COUNT); 6692 return &GStyleVarInfo[idx]; 6693 } 6694 6695 void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) 6696 { 6697 const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); 6698 if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1) 6699 { 6700 ImGuiContext& g = *GImGui; 6701 float* pvar = (float*)var_info->GetVarPtr(&g.Style); 6702 g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); 6703 *pvar = val; 6704 return; 6705 } 6706 IM_ASSERT(0); // Called function with wrong-type? Variable is not a float. 6707 } 6708 6709 void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val) 6710 { 6711 const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); 6712 if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2) 6713 { 6714 ImGuiContext& g = *GImGui; 6715 ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style); 6716 g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); 6717 *pvar = val; 6718 return; 6719 } 6720 IM_ASSERT(0); // Called function with wrong-type? Variable is not a ImVec2. 6721 } 6722 6723 void ImGui::PopStyleVar(int count) 6724 { 6725 ImGuiContext& g = *GImGui; 6726 while (count > 0) 6727 { 6728 // We avoid a generic memcpy(data, &backup.Backup.., GDataTypeSize[info->Type] * info->Count), the overhead in Debug is not worth it. 6729 ImGuiStyleMod& backup = g.StyleModifiers.back(); 6730 const ImGuiStyleVarInfo* info = GetStyleVarInfo(backup.VarIdx); 6731 void* data = info->GetVarPtr(&g.Style); 6732 if (info->Type == ImGuiDataType_Float && info->Count == 1) { ((float*)data)[0] = backup.BackupFloat[0]; } 6733 else if (info->Type == ImGuiDataType_Float && info->Count == 2) { ((float*)data)[0] = backup.BackupFloat[0]; ((float*)data)[1] = backup.BackupFloat[1]; } 6734 g.StyleModifiers.pop_back(); 6735 count--; 6736 } 6737 } 6738 6739 const char* ImGui::GetStyleColorName(ImGuiCol idx) 6740 { 6741 // Create switch-case from enum with regexp: ImGuiCol_{.*}, --> case ImGuiCol_\1: return "\1"; 6742 switch (idx) 6743 { 6744 case ImGuiCol_Text: return "Text"; 6745 case ImGuiCol_TextDisabled: return "TextDisabled"; 6746 case ImGuiCol_WindowBg: return "WindowBg"; 6747 case ImGuiCol_ChildBg: return "ChildBg"; 6748 case ImGuiCol_PopupBg: return "PopupBg"; 6749 case ImGuiCol_Border: return "Border"; 6750 case ImGuiCol_BorderShadow: return "BorderShadow"; 6751 case ImGuiCol_FrameBg: return "FrameBg"; 6752 case ImGuiCol_FrameBgHovered: return "FrameBgHovered"; 6753 case ImGuiCol_FrameBgActive: return "FrameBgActive"; 6754 case ImGuiCol_TitleBg: return "TitleBg"; 6755 case ImGuiCol_TitleBgActive: return "TitleBgActive"; 6756 case ImGuiCol_TitleBgCollapsed: return "TitleBgCollapsed"; 6757 case ImGuiCol_MenuBarBg: return "MenuBarBg"; 6758 case ImGuiCol_ScrollbarBg: return "ScrollbarBg"; 6759 case ImGuiCol_ScrollbarGrab: return "ScrollbarGrab"; 6760 case ImGuiCol_ScrollbarGrabHovered: return "ScrollbarGrabHovered"; 6761 case ImGuiCol_ScrollbarGrabActive: return "ScrollbarGrabActive"; 6762 case ImGuiCol_CheckMark: return "CheckMark"; 6763 case ImGuiCol_SliderGrab: return "SliderGrab"; 6764 case ImGuiCol_SliderGrabActive: return "SliderGrabActive"; 6765 case ImGuiCol_Button: return "Button"; 6766 case ImGuiCol_ButtonHovered: return "ButtonHovered"; 6767 case ImGuiCol_ButtonActive: return "ButtonActive"; 6768 case ImGuiCol_Header: return "Header"; 6769 case ImGuiCol_HeaderHovered: return "HeaderHovered"; 6770 case ImGuiCol_HeaderActive: return "HeaderActive"; 6771 case ImGuiCol_Separator: return "Separator"; 6772 case ImGuiCol_SeparatorHovered: return "SeparatorHovered"; 6773 case ImGuiCol_SeparatorActive: return "SeparatorActive"; 6774 case ImGuiCol_ResizeGrip: return "ResizeGrip"; 6775 case ImGuiCol_ResizeGripHovered: return "ResizeGripHovered"; 6776 case ImGuiCol_ResizeGripActive: return "ResizeGripActive"; 6777 case ImGuiCol_PlotLines: return "PlotLines"; 6778 case ImGuiCol_PlotLinesHovered: return "PlotLinesHovered"; 6779 case ImGuiCol_PlotHistogram: return "PlotHistogram"; 6780 case ImGuiCol_PlotHistogramHovered: return "PlotHistogramHovered"; 6781 case ImGuiCol_TextSelectedBg: return "TextSelectedBg"; 6782 case ImGuiCol_ModalWindowDarkening: return "ModalWindowDarkening"; 6783 case ImGuiCol_DragDropTarget: return "DragDropTarget"; 6784 case ImGuiCol_NavHighlight: return "NavHighlight"; 6785 case ImGuiCol_NavWindowingHighlight: return "NavWindowingHighlight"; 6786 } 6787 IM_ASSERT(0); 6788 return "Unknown"; 6335 ImGuiWindow* window = GetCurrentWindow(); 6336 window->DC.TextWrapPosStack.pop_back(); 6337 window->DC.TextWrapPos = window->DC.TextWrapPosStack.empty() ? -1.0f : window->DC.TextWrapPosStack.back(); 6789 6338 } 6790 6339 6791 6340 bool ImGui::IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent) 6792 6341 { 6793 if (window->RootWindow == potential_parent)6794 return true;6795 while (window != NULL)6796 {6797 if (window == potential_parent)6798 return true;6799 window = window->ParentWindow;6800 }6801 return false;6342 if (window->RootWindow == potential_parent) 6343 return true; 6344 while (window != NULL) 6345 { 6346 if (window == potential_parent) 6347 return true; 6348 window = window->ParentWindow; 6349 } 6350 return false; 6802 6351 } 6803 6352 6804 6353 bool ImGui::IsWindowHovered(ImGuiHoveredFlags flags) 6805 6354 { 6806 IM_ASSERT((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0); // Flags not supported by this function 6807 ImGuiContext& g = *GImGui; 6808 6809 if (flags & ImGuiHoveredFlags_AnyWindow) 6810 { 6811 if (g.HoveredWindow == NULL) 6812 return false; 6813 } 6814 else 6815 { 6816 switch (flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) 6817 { 6818 case ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows: 6819 if (g.HoveredRootWindow != g.CurrentWindow->RootWindow) 6355 IM_ASSERT((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0); // Flags not supported by this function 6356 ImGuiContext& g = *GImGui; 6357 6358 if (flags & ImGuiHoveredFlags_AnyWindow) 6359 { 6360 if (g.HoveredWindow == NULL) 6820 6361 return false; 6821 break; 6822 case ImGuiHoveredFlags_RootWindow: 6823 if (g.HoveredWindow != g.CurrentWindow->RootWindow) 6362 } 6363 else 6364 { 6365 switch (flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) 6366 { 6367 case ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows: 6368 if (g.HoveredRootWindow != g.CurrentWindow->RootWindow) 6369 return false; 6370 break; 6371 case ImGuiHoveredFlags_RootWindow: 6372 if (g.HoveredWindow != g.CurrentWindow->RootWindow) 6373 return false; 6374 break; 6375 case ImGuiHoveredFlags_ChildWindows: 6376 if (g.HoveredWindow == NULL || !IsWindowChildOf(g.HoveredWindow, g.CurrentWindow)) 6377 return false; 6378 break; 6379 default: 6380 if (g.HoveredWindow != g.CurrentWindow) 6381 return false; 6382 break; 6383 } 6384 } 6385 6386 if (!IsWindowContentHoverable(g.HoveredWindow, flags)) 6387 return false; 6388 if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) 6389 if (g.ActiveId != 0 && !g.ActiveIdAllowOverlap && g.ActiveId != g.HoveredWindow->MoveId) 6824 6390 return false; 6825 break; 6826 case ImGuiHoveredFlags_ChildWindows: 6827 if (g.HoveredWindow == NULL || !IsWindowChildOf(g.HoveredWindow, g.CurrentWindow)) 6828 return false; 6829 break; 6830 default: 6831 if (g.HoveredWindow != g.CurrentWindow) 6832 return false; 6833 break; 6834 } 6835 } 6836 6837 if (!IsWindowContentHoverable(g.HoveredRootWindow, flags)) 6838 return false; 6839 if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) 6840 if (g.ActiveId != 0 && !g.ActiveIdAllowOverlap && g.ActiveId != g.HoveredWindow->MoveId) 6841 return false; 6842 return true; 6391 return true; 6843 6392 } 6844 6393 6845 6394 bool ImGui::IsWindowFocused(ImGuiFocusedFlags flags) 6846 6395 { 6847 ImGuiContext& g = *GImGui;6848 IM_ASSERT(g.CurrentWindow); // Not inside a Begin()/End() 6849 6850 if (flags & ImGuiFocusedFlags_AnyWindow)6851 return g.NavWindow != NULL; 6852 6853 switch (flags & (ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows))6854 {6855 case ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows:6856 return g.NavWindow && g.NavWindow->RootWindow == g.CurrentWindow->RootWindow;6857 case ImGuiFocusedFlags_RootWindow:6858 return g.NavWindow == g.CurrentWindow->RootWindow;6859 case ImGuiFocusedFlags_ChildWindows:6860 return g.NavWindow && IsWindowChildOf(g.NavWindow, g.CurrentWindow);6861 default:6862 return g.NavWindow == g.CurrentWindow;6863 }6396 ImGuiContext& g = *GImGui; 6397 6398 if (flags & ImGuiFocusedFlags_AnyWindow) 6399 return g.NavWindow != NULL; 6400 6401 IM_ASSERT(g.CurrentWindow); // Not inside a Begin()/End() 6402 switch (flags & (ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows)) 6403 { 6404 case ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows: 6405 return g.NavWindow && g.NavWindow->RootWindow == g.CurrentWindow->RootWindow; 6406 case ImGuiFocusedFlags_RootWindow: 6407 return g.NavWindow == g.CurrentWindow->RootWindow; 6408 case ImGuiFocusedFlags_ChildWindows: 6409 return g.NavWindow && IsWindowChildOf(g.NavWindow, g.CurrentWindow); 6410 default: 6411 return g.NavWindow == g.CurrentWindow; 6412 } 6864 6413 } 6865 6414 6866 6415 // Can we focus this window with CTRL+TAB (or PadMenu + PadFocusPrev/PadFocusNext) 6416 // Note that NoNavFocus makes the window not reachable with CTRL+TAB but it can still be focused with mouse or programmatically. 6417 // If you want a window to never be focused, you may use the e.g. NoInputs flag. 6867 6418 bool ImGui::IsWindowNavFocusable(ImGuiWindow* window) 6868 6419 { 6869 ImGuiContext& g = *GImGui; 6870 return window->Active && window == window->RootWindowForTabbing && (!(window->Flags & ImGuiWindowFlags_NoNavFocus) || window == g.NavWindow); 6420 return window->Active && window == window->RootWindow && !(window->Flags & ImGuiWindowFlags_NoNavFocus); 6871 6421 } 6872 6422 6873 6423 float ImGui::GetWindowWidth() 6874 6424 { 6875 ImGuiWindow* window = GImGui->CurrentWindow;6876 return window->Size.x;6425 ImGuiWindow* window = GImGui->CurrentWindow; 6426 return window->Size.x; 6877 6427 } 6878 6428 6879 6429 float ImGui::GetWindowHeight() 6880 6430 { 6881 ImGuiWindow* window = GImGui->CurrentWindow;6882 return window->Size.y;6431 ImGuiWindow* window = GImGui->CurrentWindow; 6432 return window->Size.y; 6883 6433 } 6884 6434 6885 6435 ImVec2 ImGui::GetWindowPos() 6886 6436 { 6887 ImGuiContext& g = *GImGui; 6888 ImGuiWindow* window = g.CurrentWindow; 6889 return window->Pos; 6890 } 6891 6892 static void SetWindowScrollX(ImGuiWindow* window, float new_scroll_x) 6893 { 6894 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. 6895 window->Scroll.x = new_scroll_x; 6896 window->DC.CursorMaxPos.x -= window->Scroll.x; 6897 } 6898 6899 static void SetWindowScrollY(ImGuiWindow* window, float new_scroll_y) 6900 { 6901 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. 6902 window->Scroll.y = new_scroll_y; 6903 window->DC.CursorMaxPos.y -= window->Scroll.y; 6904 } 6905 6906 static void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond) 6907 { 6908 // Test condition (NB: bit 0 is always true) and clear flags for next time 6909 if (cond && (window->SetWindowPosAllowFlags & cond) == 0) 6910 return; 6911 6912 IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. 6913 window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); 6914 window->SetWindowPosVal = ImVec2(FLT_MAX, FLT_MAX); 6915 6916 // Set 6917 const ImVec2 old_pos = window->Pos; 6918 window->Pos = ImFloor(pos); 6919 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 6920 window->DC.CursorMaxPos += (window->Pos - old_pos); // And more importantly we need to adjust this so size calculation doesn't get affected. 6437 ImGuiContext& g = *GImGui; 6438 ImGuiWindow* window = g.CurrentWindow; 6439 return window->Pos; 6440 } 6441 6442 void ImGui::SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond) 6443 { 6444 // Test condition (NB: bit 0 is always true) and clear flags for next time 6445 if (cond && (window->SetWindowPosAllowFlags & cond) == 0) 6446 return; 6447 6448 IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. 6449 window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); 6450 window->SetWindowPosVal = ImVec2(FLT_MAX, FLT_MAX); 6451 6452 // Set 6453 const ImVec2 old_pos = window->Pos; 6454 window->Pos = ImFloor(pos); 6455 ImVec2 offset = window->Pos - old_pos; 6456 window->DC.CursorPos += offset; // 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 6457 window->DC.CursorMaxPos += offset; // And more importantly we need to offset CursorMaxPos/CursorStartPos this so ContentSize calculation doesn't get affected. 6458 window->DC.CursorStartPos += offset; 6921 6459 } 6922 6460 6923 6461 void ImGui::SetWindowPos(const ImVec2& pos, ImGuiCond cond) 6924 6462 { 6925 ImGuiWindow* window = GetCurrentWindowRead();6926 SetWindowPos(window, pos, cond);6463 ImGuiWindow* window = GetCurrentWindowRead(); 6464 SetWindowPos(window, pos, cond); 6927 6465 } 6928 6466 6929 6467 void ImGui::SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond) 6930 6468 { 6931 if (ImGuiWindow* window = FindWindowByName(name))6932 SetWindowPos(window, pos, cond);6469 if (ImGuiWindow* window = FindWindowByName(name)) 6470 SetWindowPos(window, pos, cond); 6933 6471 } 6934 6472 6935 6473 ImVec2 ImGui::GetWindowSize() 6936 6474 { 6937 ImGuiWindow* window = GetCurrentWindowRead();6938 return window->Size;6939 } 6940 6941 static voidSetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond)6942 { 6943 // Test condition (NB: bit 0 is always true) and clear flags for next time6944 if (cond && (window->SetWindowSizeAllowFlags & cond) == 0)6945 return;6946 6947 IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.6948 window->SetWindowSizeAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);6949 6950 // Set6951 if (size.x > 0.0f)6952 {6953 window->AutoFitFramesX = 0;6954 window->SizeFull.x = size.x;6955 }6956 else6957 {6958 window->AutoFitFramesX = 2;6959 window->AutoFitOnlyGrows = false;6960 }6961 if (size.y > 0.0f)6962 {6963 window->AutoFitFramesY = 0;6964 window->SizeFull.y = size.y;6965 }6966 else6967 {6968 window->AutoFitFramesY = 2;6969 window->AutoFitOnlyGrows = false;6970 }6475 ImGuiWindow* window = GetCurrentWindowRead(); 6476 return window->Size; 6477 } 6478 6479 void ImGui::SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond) 6480 { 6481 // Test condition (NB: bit 0 is always true) and clear flags for next time 6482 if (cond && (window->SetWindowSizeAllowFlags & cond) == 0) 6483 return; 6484 6485 IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. 6486 window->SetWindowSizeAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); 6487 6488 // Set 6489 if (size.x > 0.0f) 6490 { 6491 window->AutoFitFramesX = 0; 6492 window->SizeFull.x = IM_FLOOR(size.x); 6493 } 6494 else 6495 { 6496 window->AutoFitFramesX = 2; 6497 window->AutoFitOnlyGrows = false; 6498 } 6499 if (size.y > 0.0f) 6500 { 6501 window->AutoFitFramesY = 0; 6502 window->SizeFull.y = IM_FLOOR(size.y); 6503 } 6504 else 6505 { 6506 window->AutoFitFramesY = 2; 6507 window->AutoFitOnlyGrows = false; 6508 } 6971 6509 } 6972 6510 6973 6511 void ImGui::SetWindowSize(const ImVec2& size, ImGuiCond cond) 6974 6512 { 6975 SetWindowSize(GImGui->CurrentWindow, size, cond);6513 SetWindowSize(GImGui->CurrentWindow, size, cond); 6976 6514 } 6977 6515 6978 6516 void ImGui::SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond) 6979 6517 { 6980 if (ImGuiWindow* window = FindWindowByName(name)) 6981 SetWindowSize(window, size, cond); 6982 } 6983 6984 static void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond) 6985 { 6986 // Test condition (NB: bit 0 is always true) and clear flags for next time 6987 if (cond && (window->SetWindowCollapsedAllowFlags & cond) == 0) 6988 return; 6989 window->SetWindowCollapsedAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); 6990 6991 // Set 6992 window->Collapsed = collapsed; 6518 if (ImGuiWindow* window = FindWindowByName(name)) 6519 SetWindowSize(window, size, cond); 6520 } 6521 6522 void ImGui::SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond) 6523 { 6524 // Test condition (NB: bit 0 is always true) and clear flags for next time 6525 if (cond && (window->SetWindowCollapsedAllowFlags & cond) == 0) 6526 return; 6527 window->SetWindowCollapsedAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); 6528 6529 // Set 6530 window->Collapsed = collapsed; 6531 } 6532 6533 void ImGui::SetWindowHitTestHole(ImGuiWindow* window, const ImVec2& pos, const ImVec2& size) 6534 { 6535 IM_ASSERT(window->HitTestHoleSize.x == 0); // We don't support multiple holes/hit test filters 6536 window->HitTestHoleSize = ImVec2ih(size); 6537 window->HitTestHoleOffset = ImVec2ih(pos - window->Pos); 6993 6538 } 6994 6539 6995 6540 void ImGui::SetWindowCollapsed(bool collapsed, ImGuiCond cond) 6996 6541 { 6997 SetWindowCollapsed(GImGui->CurrentWindow, collapsed, cond);6542 SetWindowCollapsed(GImGui->CurrentWindow, collapsed, cond); 6998 6543 } 6999 6544 7000 6545 bool ImGui::IsWindowCollapsed() 7001 6546 { 7002 ImGuiWindow* window = GetCurrentWindowRead();7003 return window->Collapsed;6547 ImGuiWindow* window = GetCurrentWindowRead(); 6548 return window->Collapsed; 7004 6549 } 7005 6550 7006 6551 bool ImGui::IsWindowAppearing() 7007 6552 { 7008 ImGuiWindow* window = GetCurrentWindowRead();7009 return window->Appearing;6553 ImGuiWindow* window = GetCurrentWindowRead(); 6554 return window->Appearing; 7010 6555 } 7011 6556 7012 6557 void ImGui::SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond) 7013 6558 { 7014 if (ImGuiWindow* window = FindWindowByName(name))7015 SetWindowCollapsed(window, collapsed, cond);6559 if (ImGuiWindow* window = FindWindowByName(name)) 6560 SetWindowCollapsed(window, collapsed, cond); 7016 6561 } 7017 6562 7018 6563 void ImGui::SetWindowFocus() 7019 6564 { 7020 FocusWindow(GImGui->CurrentWindow);6565 FocusWindow(GImGui->CurrentWindow); 7021 6566 } 7022 6567 7023 6568 void ImGui::SetWindowFocus(const char* name) 7024 6569 { 7025 if (name)7026 {7027 if (ImGuiWindow* window = FindWindowByName(name))7028 FocusWindow(window);7029 }7030 else7031 {7032 FocusWindow(NULL);7033 }6570 if (name) 6571 { 6572 if (ImGuiWindow* window = FindWindowByName(name)) 6573 FocusWindow(window); 6574 } 6575 else 6576 { 6577 FocusWindow(NULL); 6578 } 7034 6579 } 7035 6580 7036 6581 void ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiCond cond, const ImVec2& pivot) 7037 6582 { 7038 ImGuiContext& g = *GImGui; 7039 IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. 7040 g.NextWindowData.PosVal = pos; 7041 g.NextWindowData.PosPivotVal = pivot; 7042 g.NextWindowData.PosCond = cond ? cond : ImGuiCond_Always; 6583 ImGuiContext& g = *GImGui; 6584 IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. 6585 g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasPos; 6586 g.NextWindowData.PosVal = pos; 6587 g.NextWindowData.PosPivotVal = pivot; 6588 g.NextWindowData.PosCond = cond ? cond : ImGuiCond_Always; 7043 6589 } 7044 6590 7045 6591 void ImGui::SetNextWindowSize(const ImVec2& size, ImGuiCond cond) 7046 6592 { 7047 ImGuiContext& g = *GImGui; 7048 IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. 7049 g.NextWindowData.SizeVal = size; 7050 g.NextWindowData.SizeCond = cond ? cond : ImGuiCond_Always; 6593 ImGuiContext& g = *GImGui; 6594 IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. 6595 g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSize; 6596 g.NextWindowData.SizeVal = size; 6597 g.NextWindowData.SizeCond = cond ? cond : ImGuiCond_Always; 7051 6598 } 7052 6599 7053 6600 void ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback, void* custom_callback_user_data) 7054 6601 { 7055 ImGuiContext& g = *GImGui; 7056 g.NextWindowData.SizeConstraintCond = ImGuiCond_Always; 7057 g.NextWindowData.SizeConstraintRect = ImRect(size_min, size_max); 7058 g.NextWindowData.SizeCallback = custom_callback; 7059 g.NextWindowData.SizeCallbackUserData = custom_callback_user_data; 7060 } 7061 6602 ImGuiContext& g = *GImGui; 6603 g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSizeConstraint; 6604 g.NextWindowData.SizeConstraintRect = ImRect(size_min, size_max); 6605 g.NextWindowData.SizeCallback = custom_callback; 6606 g.NextWindowData.SizeCallbackUserData = custom_callback_user_data; 6607 } 6608 6609 // Content size = inner scrollable rectangle, padded with WindowPadding. 6610 // SetNextWindowContentSize(ImVec2(100,100) + ImGuiWindowFlags_AlwaysAutoResize will always allow submitting a 100x100 item. 7062 6611 void ImGui::SetNextWindowContentSize(const ImVec2& size) 7063 6612 { 7064 ImGuiContext& g = *GImGui; 7065 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. 7066 g.NextWindowData.ContentSizeCond = ImGuiCond_Always; 6613 ImGuiContext& g = *GImGui; 6614 g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasContentSize; 6615 g.NextWindowData.ContentSizeVal = size; 6616 } 6617 6618 void ImGui::SetNextWindowScroll(const ImVec2& scroll) 6619 { 6620 ImGuiContext& g = *GImGui; 6621 g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasScroll; 6622 g.NextWindowData.ScrollVal = scroll; 7067 6623 } 7068 6624 7069 6625 void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond) 7070 6626 { 7071 ImGuiContext& g = *GImGui; 7072 IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. 7073 g.NextWindowData.CollapsedVal = collapsed; 7074 g.NextWindowData.CollapsedCond = cond ? cond : ImGuiCond_Always; 6627 ImGuiContext& g = *GImGui; 6628 IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. 6629 g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasCollapsed; 6630 g.NextWindowData.CollapsedVal = collapsed; 6631 g.NextWindowData.CollapsedCond = cond ? cond : ImGuiCond_Always; 7075 6632 } 7076 6633 7077 6634 void ImGui::SetNextWindowFocus() 7078 6635 { 7079 ImGuiContext& g = *GImGui;7080 g.NextWindowData.FocusCond = ImGuiCond_Always; // Using a Cond member for consistency (may transition all of them to single flag set for fast Clear() op)6636 ImGuiContext& g = *GImGui; 6637 g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasFocus; 7081 6638 } 7082 6639 7083 6640 void ImGui::SetNextWindowBgAlpha(float alpha) 7084 6641 { 7085 ImGuiContext& g = *GImGui; 7086 g.NextWindowData.BgAlphaVal = alpha; 7087 g.NextWindowData.BgAlphaCond = ImGuiCond_Always; // Using a Cond member for consistency (may transition all of them to single flag set for fast Clear() op) 7088 } 7089 7090 // In window space (not screen space!) 7091 ImVec2 ImGui::GetContentRegionMax() 7092 { 7093 ImGuiWindow* window = GetCurrentWindowRead(); 7094 ImVec2 mx = window->ContentsRegionRect.Max; 7095 if (window->DC.ColumnsSet) 7096 mx.x = GetColumnOffset(window->DC.ColumnsSet->Current + 1) - window->WindowPadding.x; 7097 return mx; 7098 } 7099 7100 ImVec2 ImGui::GetContentRegionAvail() 7101 { 7102 ImGuiWindow* window = GetCurrentWindowRead(); 7103 return GetContentRegionMax() - (window->DC.CursorPos - window->Pos); 7104 } 7105 7106 float ImGui::GetContentRegionAvailWidth() 7107 { 7108 return GetContentRegionAvail().x; 7109 } 7110 7111 // In window space (not screen space!) 7112 ImVec2 ImGui::GetWindowContentRegionMin() 7113 { 7114 ImGuiWindow* window = GetCurrentWindowRead(); 7115 return window->ContentsRegionRect.Min; 7116 } 7117 7118 ImVec2 ImGui::GetWindowContentRegionMax() 7119 { 7120 ImGuiWindow* window = GetCurrentWindowRead(); 7121 return window->ContentsRegionRect.Max; 7122 } 7123 7124 float ImGui::GetWindowContentRegionWidth() 7125 { 7126 ImGuiWindow* window = GetCurrentWindowRead(); 7127 return window->ContentsRegionRect.Max.x - window->ContentsRegionRect.Min.x; 7128 } 7129 7130 float ImGui::GetTextLineHeight() 7131 { 7132 ImGuiContext& g = *GImGui; 7133 return g.FontSize; 7134 } 7135 7136 float ImGui::GetTextLineHeightWithSpacing() 7137 { 7138 ImGuiContext& g = *GImGui; 7139 return g.FontSize + g.Style.ItemSpacing.y; 7140 } 7141 7142 float ImGui::GetFrameHeight() 7143 { 7144 ImGuiContext& g = *GImGui; 7145 return g.FontSize + g.Style.FramePadding.y * 2.0f; 7146 } 7147 7148 float ImGui::GetFrameHeightWithSpacing() 7149 { 7150 ImGuiContext& g = *GImGui; 7151 return g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y; 6642 ImGuiContext& g = *GImGui; 6643 g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasBgAlpha; 6644 g.NextWindowData.BgAlphaVal = alpha; 7152 6645 } 7153 6646 7154 6647 ImDrawList* ImGui::GetWindowDrawList() 7155 6648 { 7156 ImGuiWindow* window = GetCurrentWindow();7157 return window->DrawList;6649 ImGuiWindow* window = GetCurrentWindow(); 6650 return window->DrawList; 7158 6651 } 7159 6652 7160 6653 ImFont* ImGui::GetFont() 7161 6654 { 7162 return GImGui->Font;6655 return GImGui->Font; 7163 6656 } 7164 6657 7165 6658 float ImGui::GetFontSize() 7166 6659 { 7167 return GImGui->FontSize;6660 return GImGui->FontSize; 7168 6661 } 7169 6662 7170 6663 ImVec2 ImGui::GetFontTexUvWhitePixel() 7171 6664 { 7172 return GImGui->DrawListSharedData.TexUvWhitePixel;6665 return GImGui->DrawListSharedData.TexUvWhitePixel; 7173 6666 } 7174 6667 7175 6668 void ImGui::SetWindowFontScale(float scale) 7176 6669 { 7177 ImGuiContext& g = *GImGui; 7178 ImGuiWindow* window = GetCurrentWindow(); 7179 window->FontWindowScale = scale; 7180 g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize(); 6670 IM_ASSERT(scale > 0.0f); 6671 ImGuiContext& g = *GImGui; 6672 ImGuiWindow* window = GetCurrentWindow(); 6673 window->FontWindowScale = scale; 6674 g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize(); 6675 } 6676 6677 void ImGui::ActivateItem(ImGuiID id) 6678 { 6679 ImGuiContext& g = *GImGui; 6680 g.NavNextActivateId = id; 6681 } 6682 6683 // Note: this is storing in same stack as IDStack, so Push/Pop mismatch will be reported there. 6684 void ImGui::PushFocusScope(ImGuiID id) 6685 { 6686 ImGuiContext& g = *GImGui; 6687 ImGuiWindow* window = g.CurrentWindow; 6688 window->IDStack.push_back(window->DC.NavFocusScopeIdCurrent); 6689 window->DC.NavFocusScopeIdCurrent = id; 6690 } 6691 6692 void ImGui::PopFocusScope() 6693 { 6694 ImGuiContext& g = *GImGui; 6695 ImGuiWindow* window = g.CurrentWindow; 6696 window->DC.NavFocusScopeIdCurrent = window->IDStack.back(); 6697 window->IDStack.pop_back(); 6698 } 6699 6700 void ImGui::SetKeyboardFocusHere(int offset) 6701 { 6702 IM_ASSERT(offset >= -1); // -1 is allowed but not below 6703 ImGuiContext& g = *GImGui; 6704 ImGuiWindow* window = g.CurrentWindow; 6705 g.FocusRequestNextWindow = window; 6706 g.FocusRequestNextCounterRegular = window->DC.FocusCounterRegular + 1 + offset; 6707 g.FocusRequestNextCounterTabStop = INT_MAX; 6708 } 6709 6710 void ImGui::SetItemDefaultFocus() 6711 { 6712 ImGuiContext& g = *GImGui; 6713 ImGuiWindow* window = g.CurrentWindow; 6714 if (!window->Appearing) 6715 return; 6716 if (g.NavWindow == window->RootWindowForNav && (g.NavInitRequest || g.NavInitResultId != 0) && g.NavLayer == g.NavWindow->DC.NavLayerCurrent) 6717 { 6718 g.NavInitRequest = false; 6719 g.NavInitResultId = g.NavWindow->DC.LastItemId; 6720 g.NavInitResultRectRel = ImRect(g.NavWindow->DC.LastItemRect.Min - g.NavWindow->Pos, g.NavWindow->DC.LastItemRect.Max - g.NavWindow->Pos); 6721 NavUpdateAnyRequestFlag(); 6722 if (!IsItemVisible()) 6723 SetScrollHereY(); 6724 } 6725 } 6726 6727 void ImGui::SetStateStorage(ImGuiStorage* tree) 6728 { 6729 ImGuiWindow* window = GImGui->CurrentWindow; 6730 window->DC.StateStorage = tree ? tree : &window->StateStorage; 6731 } 6732 6733 ImGuiStorage* ImGui::GetStateStorage() 6734 { 6735 ImGuiWindow* window = GImGui->CurrentWindow; 6736 return window->DC.StateStorage; 6737 } 6738 6739 void ImGui::PushID(const char* str_id) 6740 { 6741 ImGuiContext& g = *GImGui; 6742 ImGuiWindow* window = g.CurrentWindow; 6743 ImGuiID id = window->GetIDNoKeepAlive(str_id); 6744 window->IDStack.push_back(id); 6745 } 6746 6747 void ImGui::PushID(const char* str_id_begin, const char* str_id_end) 6748 { 6749 ImGuiContext& g = *GImGui; 6750 ImGuiWindow* window = g.CurrentWindow; 6751 ImGuiID id = window->GetIDNoKeepAlive(str_id_begin, str_id_end); 6752 window->IDStack.push_back(id); 6753 } 6754 6755 void ImGui::PushID(const void* ptr_id) 6756 { 6757 ImGuiContext& g = *GImGui; 6758 ImGuiWindow* window = g.CurrentWindow; 6759 ImGuiID id = window->GetIDNoKeepAlive(ptr_id); 6760 window->IDStack.push_back(id); 6761 } 6762 6763 void ImGui::PushID(int int_id) 6764 { 6765 ImGuiContext& g = *GImGui; 6766 ImGuiWindow* window = g.CurrentWindow; 6767 ImGuiID id = window->GetIDNoKeepAlive(int_id); 6768 window->IDStack.push_back(id); 6769 } 6770 6771 // Push a given id value ignoring the ID stack as a seed. 6772 void ImGui::PushOverrideID(ImGuiID id) 6773 { 6774 ImGuiContext& g = *GImGui; 6775 ImGuiWindow* window = g.CurrentWindow; 6776 window->IDStack.push_back(id); 6777 } 6778 6779 // Helper to avoid a common series of PushOverrideID -> GetID() -> PopID() call 6780 // (note that when using this pattern, TestEngine's "Stack Tool" will tend to not display the intermediate stack level. 6781 // for that to work we would need to do PushOverrideID() -> ItemAdd() -> PopID() which would alter widget code a little more) 6782 ImGuiID ImGui::GetIDWithSeed(const char* str, const char* str_end, ImGuiID seed) 6783 { 6784 ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed); 6785 ImGui::KeepAliveID(id); 6786 #ifdef IMGUI_ENABLE_TEST_ENGINE 6787 ImGuiContext& g = *GImGui; 6788 IMGUI_TEST_ENGINE_ID_INFO2(id, ImGuiDataType_String, str, str_end); 6789 #endif 6790 return id; 6791 } 6792 6793 void ImGui::PopID() 6794 { 6795 ImGuiWindow* window = GImGui->CurrentWindow; 6796 window->IDStack.pop_back(); 6797 } 6798 6799 ImGuiID ImGui::GetID(const char* str_id) 6800 { 6801 ImGuiWindow* window = GImGui->CurrentWindow; 6802 return window->GetID(str_id); 6803 } 6804 6805 ImGuiID ImGui::GetID(const char* str_id_begin, const char* str_id_end) 6806 { 6807 ImGuiWindow* window = GImGui->CurrentWindow; 6808 return window->GetID(str_id_begin, str_id_end); 6809 } 6810 6811 ImGuiID ImGui::GetID(const void* ptr_id) 6812 { 6813 ImGuiWindow* window = GImGui->CurrentWindow; 6814 return window->GetID(ptr_id); 6815 } 6816 6817 bool ImGui::IsRectVisible(const ImVec2& size) 6818 { 6819 ImGuiWindow* window = GImGui->CurrentWindow; 6820 return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size)); 6821 } 6822 6823 bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max) 6824 { 6825 ImGuiWindow* window = GImGui->CurrentWindow; 6826 return window->ClipRect.Overlaps(ImRect(rect_min, rect_max)); 6827 } 6828 6829 6830 //----------------------------------------------------------------------------- 6831 // [SECTION] ERROR CHECKING 6832 //----------------------------------------------------------------------------- 6833 6834 // Helper function to verify ABI compatibility between caller code and compiled version of Dear ImGui. 6835 // Verify that the type sizes are matching between the calling file's compilation unit and imgui.cpp's compilation unit 6836 // If the user has inconsistent compilation settings, imgui configuration #define, packing pragma, etc. your user code 6837 // may see different structures than what imgui.cpp sees, which is problematic. 6838 // We usually require settings to be in imconfig.h to make sure that they are accessible to all compilation units involved with Dear ImGui. 6839 bool 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, size_t sz_idx) 6840 { 6841 bool error = false; 6842 if (strcmp(version, IMGUI_VERSION) != 0) { error = true; IM_ASSERT(strcmp(version, IMGUI_VERSION) == 0 && "Mismatched version string!"); } 6843 if (sz_io != sizeof(ImGuiIO)) { error = true; IM_ASSERT(sz_io == sizeof(ImGuiIO) && "Mismatched struct layout!"); } 6844 if (sz_style != sizeof(ImGuiStyle)) { error = true; IM_ASSERT(sz_style == sizeof(ImGuiStyle) && "Mismatched struct layout!"); } 6845 if (sz_vec2 != sizeof(ImVec2)) { error = true; IM_ASSERT(sz_vec2 == sizeof(ImVec2) && "Mismatched struct layout!"); } 6846 if (sz_vec4 != sizeof(ImVec4)) { error = true; IM_ASSERT(sz_vec4 == sizeof(ImVec4) && "Mismatched struct layout!"); } 6847 if (sz_vert != sizeof(ImDrawVert)) { error = true; IM_ASSERT(sz_vert == sizeof(ImDrawVert) && "Mismatched struct layout!"); } 6848 if (sz_idx != sizeof(ImDrawIdx)) { error = true; IM_ASSERT(sz_idx == sizeof(ImDrawIdx) && "Mismatched struct layout!"); } 6849 return !error; 6850 } 6851 6852 static void ImGui::ErrorCheckNewFrameSanityChecks() 6853 { 6854 ImGuiContext& g = *GImGui; 6855 6856 // Check user IM_ASSERT macro 6857 // (IF YOU GET A WARNING OR COMPILE ERROR HERE: it means you assert macro is incorrectly defined! 6858 // If your macro uses multiple statements, it NEEDS to be surrounded by a 'do { ... } while (0)' block. 6859 // This is a common C/C++ idiom to allow multiple statements macros to be used in control flow blocks.) 6860 // #define IM_ASSERT(EXPR) SomeCode(EXPR); SomeMoreCode(); // Wrong! 6861 // #define IM_ASSERT(EXPR) do { SomeCode(EXPR); SomeMoreCode(); } while (0) // Correct! 6862 if (true) IM_ASSERT(1); else IM_ASSERT(0); 6863 6864 // Check user data 6865 // (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) 6866 IM_ASSERT(g.Initialized); 6867 IM_ASSERT((g.IO.DeltaTime > 0.0f || g.FrameCount == 0) && "Need a positive DeltaTime!"); 6868 IM_ASSERT((g.FrameCount == 0 || g.FrameCountEnded == g.FrameCount) && "Forgot to call Render() or EndFrame() at the end of the previous frame?"); 6869 IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f && "Invalid DisplaySize value!"); 6870 IM_ASSERT(g.IO.Fonts->Fonts.Size > 0 && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8() ?"); 6871 IM_ASSERT(g.IO.Fonts->Fonts[0]->IsLoaded() && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8() ?"); 6872 IM_ASSERT(g.Style.CurveTessellationTol > 0.0f && "Invalid style setting!"); 6873 IM_ASSERT(g.Style.CircleSegmentMaxError > 0.0f && "Invalid style setting!"); 6874 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)!"); 6875 IM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && "Invalid style setting."); 6876 IM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_None || g.Style.WindowMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGuiDir_Right); 6877 for (int n = 0; n < ImGuiKey_COUNT; n++) 6878 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)"); 6879 6880 // 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) 6881 if (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) 6882 IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation."); 6883 6884 // Perform simple check: the beta io.ConfigWindowsResizeFromEdges option requires back-end to honor mouse cursor changes and set the ImGuiBackendFlags_HasMouseCursors flag accordingly. 6885 if (g.IO.ConfigWindowsResizeFromEdges && !(g.IO.BackendFlags & ImGuiBackendFlags_HasMouseCursors)) 6886 g.IO.ConfigWindowsResizeFromEdges = false; 6887 } 6888 6889 static void ImGui::ErrorCheckEndFrameSanityChecks() 6890 { 6891 ImGuiContext& g = *GImGui; 6892 6893 // Verify that io.KeyXXX fields haven't been tampered with. Key mods should not be modified between NewFrame() and EndFrame() 6894 // One possible reason leading to this assert is that your back-ends update inputs _AFTER_ NewFrame(). 6895 const ImGuiKeyModFlags expected_key_mod_flags = GetMergedKeyModFlags(); 6896 IM_ASSERT(g.IO.KeyMods == expected_key_mod_flags && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods"); 6897 IM_UNUSED(expected_key_mod_flags); 6898 6899 // Report when there is a mismatch of Begin/BeginChild vs End/EndChild calls. Important: Remember that the Begin/BeginChild API requires you 6900 // to always call End/EndChild even if Begin/BeginChild returns false! (this is unfortunately inconsistent with most other Begin* API). 6901 if (g.CurrentWindowStack.Size != 1) 6902 { 6903 if (g.CurrentWindowStack.Size > 1) 6904 { 6905 IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?"); 6906 while (g.CurrentWindowStack.Size > 1) 6907 End(); 6908 } 6909 else 6910 { 6911 IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?"); 6912 } 6913 } 6914 } 6915 6916 // Save and compare stack sizes on Begin()/End() to detect usage errors 6917 // Begin() calls this with write=true 6918 // End() calls this with write=false 6919 static void ImGui::ErrorCheckBeginEndCompareStacksSize(ImGuiWindow* window, bool write) 6920 { 6921 ImGuiContext& g = *GImGui; 6922 short* p = &window->DC.StackSizesBackup[0]; 6923 6924 // Window stacks 6925 // 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) 6926 { int n = window->IDStack.Size; if (write) *p = (short)n; else IM_ASSERT(*p == n && "PushID/PopID or TreeNode/TreePop Mismatch!"); p++; } // Too few or too many PopID()/TreePop() 6927 { int n = window->DC.GroupStack.Size; if (write) *p = (short)n; else IM_ASSERT(*p == n && "BeginGroup/EndGroup Mismatch!"); p++; } // Too few or too many EndGroup() 6928 6929 // Global stacks 6930 // 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. 6931 { int n = g.BeginPopupStack.Size; if (write) *p = (short)n; else IM_ASSERT(*p == n && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch!"); p++; }// Too few or too many EndMenu()/EndPopup() 6932 { int n = g.ColorModifiers.Size; if (write) *p = (short)n; else IM_ASSERT(*p >= n && "PushStyleColor/PopStyleColor Mismatch!"); p++; } // Too few or too many PopStyleColor() 6933 { int n = g.StyleModifiers.Size; if (write) *p = (short)n; else IM_ASSERT(*p >= n && "PushStyleVar/PopStyleVar Mismatch!"); p++; } // Too few or too many PopStyleVar() 6934 { int n = g.FontStack.Size; if (write) *p = (short)n; else IM_ASSERT(*p >= n && "PushFont/PopFont Mismatch!"); p++; } // Too few or too many PopFont() 6935 IM_ASSERT(p == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup)); 6936 } 6937 6938 6939 //----------------------------------------------------------------------------- 6940 // [SECTION] LAYOUT 6941 //----------------------------------------------------------------------------- 6942 // - ItemSize() 6943 // - ItemAdd() 6944 // - SameLine() 6945 // - GetCursorScreenPos() 6946 // - SetCursorScreenPos() 6947 // - GetCursorPos(), GetCursorPosX(), GetCursorPosY() 6948 // - SetCursorPos(), SetCursorPosX(), SetCursorPosY() 6949 // - GetCursorStartPos() 6950 // - Indent() 6951 // - Unindent() 6952 // - SetNextItemWidth() 6953 // - PushItemWidth() 6954 // - PushMultiItemsWidths() 6955 // - PopItemWidth() 6956 // - CalcItemWidth() 6957 // - CalcItemSize() 6958 // - GetTextLineHeight() 6959 // - GetTextLineHeightWithSpacing() 6960 // - GetFrameHeight() 6961 // - GetFrameHeightWithSpacing() 6962 // - GetContentRegionMax() 6963 // - GetContentRegionMaxAbs() [Internal] 6964 // - GetContentRegionAvail(), 6965 // - GetWindowContentRegionMin(), GetWindowContentRegionMax() 6966 // - GetWindowContentRegionWidth() 6967 // - BeginGroup() 6968 // - EndGroup() 6969 // Also see in imgui_widgets: tab bars, columns. 6970 //----------------------------------------------------------------------------- 6971 6972 // Advance cursor given item size for layout. 6973 // Register minimum needed size so it can extend the bounding box used for auto-fit calculation. 6974 // See comments in ItemAdd() about how/why the size provided to ItemSize() vs ItemAdd() may often different. 6975 void ImGui::ItemSize(const ImVec2& size, float text_baseline_y) 6976 { 6977 ImGuiContext& g = *GImGui; 6978 ImGuiWindow* window = g.CurrentWindow; 6979 if (window->SkipItems) 6980 return; 6981 6982 // We increase the height in this function to accommodate for baseline offset. 6983 // In theory we should be offsetting the starting position (window->DC.CursorPos), that will be the topic of a larger refactor, 6984 // but since ItemSize() is not yet an API that moves the cursor (to handle e.g. wrapping) enlarging the height has the same effect. 6985 const float offset_to_match_baseline_y = (text_baseline_y >= 0) ? ImMax(0.0f, window->DC.CurrLineTextBaseOffset - text_baseline_y) : 0.0f; 6986 const float line_height = ImMax(window->DC.CurrLineSize.y, size.y + offset_to_match_baseline_y); 6987 6988 // Always align ourselves on pixel boundaries 6989 //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] 6990 window->DC.CursorPosPrevLine.x = window->DC.CursorPos.x + size.x; 6991 window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y; 6992 window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); // Next line 6993 window->DC.CursorPos.y = IM_FLOOR(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y); // Next line 6994 window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x); 6995 window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y); 6996 //if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG] 6997 6998 window->DC.PrevLineSize.y = line_height; 6999 window->DC.CurrLineSize.y = 0.0f; 7000 window->DC.PrevLineTextBaseOffset = ImMax(window->DC.CurrLineTextBaseOffset, text_baseline_y); 7001 window->DC.CurrLineTextBaseOffset = 0.0f; 7002 7003 // Horizontal layout mode 7004 if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) 7005 SameLine(); 7006 } 7007 7008 void ImGui::ItemSize(const ImRect& bb, float text_baseline_y) 7009 { 7010 ItemSize(bb.GetSize(), text_baseline_y); 7011 } 7012 7013 // Declare item bounding box for clipping and interaction. 7014 // Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface 7015 // declare their minimum size requirement to ItemSize() and provide a larger region to ItemAdd() which is used drawing/interaction. 7016 bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg) 7017 { 7018 ImGuiContext& g = *GImGui; 7019 ImGuiWindow* window = g.CurrentWindow; 7020 7021 if (id != 0) 7022 { 7023 // Navigation processing runs prior to clipping early-out 7024 // (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget 7025 // (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests 7026 // unfortunately, but it is still limited to one window. It may not scale very well for windows with ten of 7027 // thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame. 7028 // We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able 7029 // to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick). 7030 // We intentionally don't check if g.NavWindow != NULL because g.NavAnyRequest should only be set when it is non null. 7031 // If we crash on a NULL g.NavWindow we need to fix the bug elsewhere. 7032 window->DC.NavLayerActiveMaskNext |= (1 << window->DC.NavLayerCurrent); 7033 if (g.NavId == id || g.NavAnyRequest) 7034 if (g.NavWindow->RootWindowForNav == window->RootWindowForNav) 7035 if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened)) 7036 NavProcessItem(window, nav_bb_arg ? *nav_bb_arg : bb, id); 7037 7038 // [DEBUG] Item Picker tool, when enabling the "extended" version we perform the check in ItemAdd() 7039 #ifdef IMGUI_DEBUG_TOOL_ITEM_PICKER_EX 7040 if (id == g.DebugItemPickerBreakId) 7041 { 7042 IM_DEBUG_BREAK(); 7043 g.DebugItemPickerBreakId = 0; 7044 } 7045 #endif 7046 } 7047 7048 // Equivalent to calling SetLastItemData() 7049 window->DC.LastItemId = id; 7050 window->DC.LastItemRect = bb; 7051 window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None; 7052 g.NextItemData.Flags = ImGuiNextItemDataFlags_None; 7053 7054 #ifdef IMGUI_ENABLE_TEST_ENGINE 7055 if (id != 0) 7056 IMGUI_TEST_ENGINE_ITEM_ADD(nav_bb_arg ? *nav_bb_arg : bb, id); 7057 #endif 7058 7059 // Clipping test 7060 const bool is_clipped = IsClippedEx(bb, id, false); 7061 if (is_clipped) 7062 return false; 7063 //if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG] 7064 7065 // We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them) 7066 if (IsMouseHoveringRect(bb.Min, bb.Max)) 7067 window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredRect; 7068 return true; 7069 } 7070 7071 // Gets back to previous line and continue with horizontal layout 7072 // offset_from_start_x == 0 : follow right after previous item 7073 // offset_from_start_x != 0 : align to specified x position (relative to window/group left) 7074 // spacing_w < 0 : use default spacing if pos_x == 0, no spacing if pos_x != 0 7075 // spacing_w >= 0 : enforce spacing amount 7076 void ImGui::SameLine(float offset_from_start_x, float spacing_w) 7077 { 7078 ImGuiWindow* window = GetCurrentWindow(); 7079 if (window->SkipItems) 7080 return; 7081 7082 ImGuiContext& g = *GImGui; 7083 if (offset_from_start_x != 0.0f) 7084 { 7085 if (spacing_w < 0.0f) spacing_w = 0.0f; 7086 window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + offset_from_start_x + spacing_w + window->DC.GroupOffset.x + window->DC.ColumnsOffset.x; 7087 window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y; 7088 } 7089 else 7090 { 7091 if (spacing_w < 0.0f) spacing_w = g.Style.ItemSpacing.x; 7092 window->DC.CursorPos.x = window->DC.CursorPosPrevLine.x + spacing_w; 7093 window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y; 7094 } 7095 window->DC.CurrLineSize = window->DC.PrevLineSize; 7096 window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset; 7097 } 7098 7099 ImVec2 ImGui::GetCursorScreenPos() 7100 { 7101 ImGuiWindow* window = GetCurrentWindowRead(); 7102 return window->DC.CursorPos; 7103 } 7104 7105 void ImGui::SetCursorScreenPos(const ImVec2& pos) 7106 { 7107 ImGuiWindow* window = GetCurrentWindow(); 7108 window->DC.CursorPos = pos; 7109 window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos); 7181 7110 } 7182 7111 … … 7185 7114 ImVec2 ImGui::GetCursorPos() 7186 7115 { 7187 ImGuiWindow* window = GetCurrentWindowRead();7188 return window->DC.CursorPos - window->Pos + window->Scroll;7116 ImGuiWindow* window = GetCurrentWindowRead(); 7117 return window->DC.CursorPos - window->Pos + window->Scroll; 7189 7118 } 7190 7119 7191 7120 float ImGui::GetCursorPosX() 7192 7121 { 7193 ImGuiWindow* window = GetCurrentWindowRead();7194 return window->DC.CursorPos.x - window->Pos.x + window->Scroll.x;7122 ImGuiWindow* window = GetCurrentWindowRead(); 7123 return window->DC.CursorPos.x - window->Pos.x + window->Scroll.x; 7195 7124 } 7196 7125 7197 7126 float ImGui::GetCursorPosY() 7198 7127 { 7199 ImGuiWindow* window = GetCurrentWindowRead();7200 return window->DC.CursorPos.y - window->Pos.y + window->Scroll.y;7128 ImGuiWindow* window = GetCurrentWindowRead(); 7129 return window->DC.CursorPos.y - window->Pos.y + window->Scroll.y; 7201 7130 } 7202 7131 7203 7132 void ImGui::SetCursorPos(const ImVec2& local_pos) 7204 7133 { 7205 ImGuiWindow* window = GetCurrentWindow();7206 window->DC.CursorPos = window->Pos - window->Scroll + local_pos;7207 window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);7134 ImGuiWindow* window = GetCurrentWindow(); 7135 window->DC.CursorPos = window->Pos - window->Scroll + local_pos; 7136 window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos); 7208 7137 } 7209 7138 7210 7139 void ImGui::SetCursorPosX(float x) 7211 7140 { 7212 ImGuiWindow* window = GetCurrentWindow();7213 window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + x;7214 window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPos.x);7141 ImGuiWindow* window = GetCurrentWindow(); 7142 window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + x; 7143 window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPos.x); 7215 7144 } 7216 7145 7217 7146 void ImGui::SetCursorPosY(float y) 7218 7147 { 7219 ImGuiWindow* window = GetCurrentWindow();7220 window->DC.CursorPos.y = window->Pos.y - window->Scroll.y + y;7221 window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y);7148 ImGuiWindow* window = GetCurrentWindow(); 7149 window->DC.CursorPos.y = window->Pos.y - window->Scroll.y + y; 7150 window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y); 7222 7151 } 7223 7152 7224 7153 ImVec2 ImGui::GetCursorStartPos() 7225 7154 { 7226 ImGuiWindow* window = GetCurrentWindowRead(); 7227 return window->DC.CursorStartPos - window->Pos; 7228 } 7229 7230 ImVec2 ImGui::GetCursorScreenPos() 7231 { 7232 ImGuiWindow* window = GetCurrentWindowRead(); 7233 return window->DC.CursorPos; 7234 } 7235 7236 void ImGui::SetCursorScreenPos(const ImVec2& screen_pos) 7237 { 7238 ImGuiWindow* window = GetCurrentWindow(); 7239 window->DC.CursorPos = screen_pos; 7240 window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos); 7155 ImGuiWindow* window = GetCurrentWindowRead(); 7156 return window->DC.CursorStartPos - window->Pos; 7157 } 7158 7159 void ImGui::Indent(float indent_w) 7160 { 7161 ImGuiContext& g = *GImGui; 7162 ImGuiWindow* window = GetCurrentWindow(); 7163 window->DC.Indent.x += (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing; 7164 window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x; 7165 } 7166 7167 void ImGui::Unindent(float indent_w) 7168 { 7169 ImGuiContext& g = *GImGui; 7170 ImGuiWindow* window = GetCurrentWindow(); 7171 window->DC.Indent.x -= (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing; 7172 window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x; 7173 } 7174 7175 // Affect large frame+labels widgets only. 7176 void ImGui::SetNextItemWidth(float item_width) 7177 { 7178 ImGuiContext& g = *GImGui; 7179 g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasWidth; 7180 g.NextItemData.Width = item_width; 7181 } 7182 7183 void ImGui::PushItemWidth(float item_width) 7184 { 7185 ImGuiContext& g = *GImGui; 7186 ImGuiWindow* window = g.CurrentWindow; 7187 window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width); 7188 window->DC.ItemWidthStack.push_back(window->DC.ItemWidth); 7189 g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth; 7190 } 7191 7192 void ImGui::PushMultiItemsWidths(int components, float w_full) 7193 { 7194 ImGuiContext& g = *GImGui; 7195 ImGuiWindow* window = g.CurrentWindow; 7196 const ImGuiStyle& style = g.Style; 7197 const float w_item_one = ImMax(1.0f, IM_FLOOR((w_full - (style.ItemInnerSpacing.x) * (components - 1)) / (float)components)); 7198 const float w_item_last = ImMax(1.0f, IM_FLOOR(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components - 1))); 7199 window->DC.ItemWidthStack.push_back(w_item_last); 7200 for (int i = 0; i < components - 1; i++) 7201 window->DC.ItemWidthStack.push_back(w_item_one); 7202 window->DC.ItemWidth = window->DC.ItemWidthStack.back(); 7203 g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth; 7204 } 7205 7206 void ImGui::PopItemWidth() 7207 { 7208 ImGuiWindow* window = GetCurrentWindow(); 7209 window->DC.ItemWidthStack.pop_back(); 7210 window->DC.ItemWidth = window->DC.ItemWidthStack.empty() ? window->ItemWidthDefault : window->DC.ItemWidthStack.back(); 7211 } 7212 7213 // Calculate default item width given value passed to PushItemWidth() or SetNextItemWidth(). 7214 // The SetNextItemWidth() data is generally cleared/consumed by ItemAdd() or NextItemData.ClearFlags() 7215 float ImGui::CalcItemWidth() 7216 { 7217 ImGuiContext& g = *GImGui; 7218 ImGuiWindow* window = g.CurrentWindow; 7219 float w; 7220 if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth) 7221 w = g.NextItemData.Width; 7222 else 7223 w = window->DC.ItemWidth; 7224 if (w < 0.0f) 7225 { 7226 float region_max_x = GetContentRegionMaxAbs().x; 7227 w = ImMax(1.0f, region_max_x - window->DC.CursorPos.x + w); 7228 } 7229 w = IM_FLOOR(w); 7230 return w; 7231 } 7232 7233 // [Internal] Calculate full item size given user provided 'size' parameter and default width/height. Default width is often == CalcItemWidth(). 7234 // Those two functions CalcItemWidth vs CalcItemSize are awkwardly named because they are not fully symmetrical. 7235 // Note that only CalcItemWidth() is publicly exposed. 7236 // The 4.0f here may be changed to match CalcItemWidth() and/or BeginChild() (right now we have a mismatch which is harmless but undesirable) 7237 ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h) 7238 { 7239 ImGuiWindow* window = GImGui->CurrentWindow; 7240 7241 ImVec2 region_max; 7242 if (size.x < 0.0f || size.y < 0.0f) 7243 region_max = GetContentRegionMaxAbs(); 7244 7245 if (size.x == 0.0f) 7246 size.x = default_w; 7247 else if (size.x < 0.0f) 7248 size.x = ImMax(4.0f, region_max.x - window->DC.CursorPos.x + size.x); 7249 7250 if (size.y == 0.0f) 7251 size.y = default_h; 7252 else if (size.y < 0.0f) 7253 size.y = ImMax(4.0f, region_max.y - window->DC.CursorPos.y + size.y); 7254 7255 return size; 7256 } 7257 7258 float ImGui::GetTextLineHeight() 7259 { 7260 ImGuiContext& g = *GImGui; 7261 return g.FontSize; 7262 } 7263 7264 float ImGui::GetTextLineHeightWithSpacing() 7265 { 7266 ImGuiContext& g = *GImGui; 7267 return g.FontSize + g.Style.ItemSpacing.y; 7268 } 7269 7270 float ImGui::GetFrameHeight() 7271 { 7272 ImGuiContext& g = *GImGui; 7273 return g.FontSize + g.Style.FramePadding.y * 2.0f; 7274 } 7275 7276 float ImGui::GetFrameHeightWithSpacing() 7277 { 7278 ImGuiContext& g = *GImGui; 7279 return g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y; 7280 } 7281 7282 // FIXME: All the Contents Region function are messy or misleading. WE WILL AIM TO OBSOLETE ALL OF THEM WITH A NEW "WORK RECT" API. Thanks for your patience! 7283 7284 // FIXME: This is in window space (not screen space!). 7285 ImVec2 ImGui::GetContentRegionMax() 7286 { 7287 ImGuiContext& g = *GImGui; 7288 ImGuiWindow* window = g.CurrentWindow; 7289 ImVec2 mx = window->ContentRegionRect.Max - window->Pos; 7290 if (window->DC.CurrentColumns) 7291 mx.x = window->WorkRect.Max.x - window->Pos.x; 7292 return mx; 7293 } 7294 7295 // [Internal] Absolute coordinate. Saner. This is not exposed until we finishing refactoring work rect features. 7296 ImVec2 ImGui::GetContentRegionMaxAbs() 7297 { 7298 ImGuiContext& g = *GImGui; 7299 ImGuiWindow* window = g.CurrentWindow; 7300 ImVec2 mx = window->ContentRegionRect.Max; 7301 if (window->DC.CurrentColumns) 7302 mx.x = window->WorkRect.Max.x; 7303 return mx; 7304 } 7305 7306 ImVec2 ImGui::GetContentRegionAvail() 7307 { 7308 ImGuiWindow* window = GImGui->CurrentWindow; 7309 return GetContentRegionMaxAbs() - window->DC.CursorPos; 7310 } 7311 7312 // In window space (not screen space!) 7313 ImVec2 ImGui::GetWindowContentRegionMin() 7314 { 7315 ImGuiWindow* window = GImGui->CurrentWindow; 7316 return window->ContentRegionRect.Min - window->Pos; 7317 } 7318 7319 ImVec2 ImGui::GetWindowContentRegionMax() 7320 { 7321 ImGuiWindow* window = GImGui->CurrentWindow; 7322 return window->ContentRegionRect.Max - window->Pos; 7323 } 7324 7325 float ImGui::GetWindowContentRegionWidth() 7326 { 7327 ImGuiWindow* window = GImGui->CurrentWindow; 7328 return window->ContentRegionRect.GetWidth(); 7329 } 7330 7331 // 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.) 7332 // Groups are currently a mishmash of functionalities which should perhaps be clarified and separated. 7333 void ImGui::BeginGroup() 7334 { 7335 ImGuiContext& g = *GImGui; 7336 ImGuiWindow* window = g.CurrentWindow; 7337 7338 window->DC.GroupStack.resize(window->DC.GroupStack.Size + 1); 7339 ImGuiGroupData& group_data = window->DC.GroupStack.back(); 7340 group_data.BackupCursorPos = window->DC.CursorPos; 7341 group_data.BackupCursorMaxPos = window->DC.CursorMaxPos; 7342 group_data.BackupIndent = window->DC.Indent; 7343 group_data.BackupGroupOffset = window->DC.GroupOffset; 7344 group_data.BackupCurrLineSize = window->DC.CurrLineSize; 7345 group_data.BackupCurrLineTextBaseOffset = window->DC.CurrLineTextBaseOffset; 7346 group_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive; 7347 group_data.BackupActiveIdPreviousFrameIsAlive = g.ActiveIdPreviousFrameIsAlive; 7348 group_data.EmitItem = true; 7349 7350 window->DC.GroupOffset.x = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffset.x; 7351 window->DC.Indent = window->DC.GroupOffset; 7352 window->DC.CursorMaxPos = window->DC.CursorPos; 7353 window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); 7354 if (g.LogEnabled) 7355 g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return 7356 } 7357 7358 void ImGui::EndGroup() 7359 { 7360 ImGuiContext& g = *GImGui; 7361 ImGuiWindow* window = g.CurrentWindow; 7362 IM_ASSERT(window->DC.GroupStack.Size > 0); // Mismatched BeginGroup()/EndGroup() calls 7363 7364 ImGuiGroupData& group_data = window->DC.GroupStack.back(); 7365 7366 ImRect group_bb(group_data.BackupCursorPos, ImMax(window->DC.CursorMaxPos, group_data.BackupCursorPos)); 7367 7368 window->DC.CursorPos = group_data.BackupCursorPos; 7369 window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos); 7370 window->DC.Indent = group_data.BackupIndent; 7371 window->DC.GroupOffset = group_data.BackupGroupOffset; 7372 window->DC.CurrLineSize = group_data.BackupCurrLineSize; 7373 window->DC.CurrLineTextBaseOffset = group_data.BackupCurrLineTextBaseOffset; 7374 if (g.LogEnabled) 7375 g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return 7376 7377 if (!group_data.EmitItem) 7378 { 7379 window->DC.GroupStack.pop_back(); 7380 return; 7381 } 7382 7383 window->DC.CurrLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now. 7384 ItemSize(group_bb.GetSize()); 7385 ItemAdd(group_bb, 0); 7386 7387 // 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. 7388 // 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. 7389 // Also if you grep for LastItemId you'll notice it is only used in that context. 7390 // (The two tests not the same because ActiveIdIsAlive is an ID itself, in order to be able to handle ActiveId being overwritten during the frame.) 7391 const bool group_contains_curr_active_id = (group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId; 7392 const bool group_contains_prev_active_id = (group_data.BackupActiveIdPreviousFrameIsAlive == false) && (g.ActiveIdPreviousFrameIsAlive == true); 7393 if (group_contains_curr_active_id) 7394 window->DC.LastItemId = g.ActiveId; 7395 else if (group_contains_prev_active_id) 7396 window->DC.LastItemId = g.ActiveIdPreviousFrame; 7397 window->DC.LastItemRect = group_bb; 7398 7399 // Forward Edited flag 7400 if (group_contains_curr_active_id && g.ActiveIdHasBeenEditedThisFrame) 7401 window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited; 7402 7403 // Forward Deactivated flag 7404 window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HasDeactivated; 7405 if (group_contains_prev_active_id && g.ActiveId != g.ActiveIdPreviousFrame) 7406 window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Deactivated; 7407 7408 window->DC.GroupStack.pop_back(); 7409 //window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // [Debug] 7410 } 7411 7412 7413 //----------------------------------------------------------------------------- 7414 // [SECTION] SCROLLING 7415 //----------------------------------------------------------------------------- 7416 7417 // Helper to snap on edges when aiming at an item very close to the edge, 7418 // So the difference between WindowPadding and ItemSpacing will be in the visible area after scrolling. 7419 // When we refactor the scrolling API this may be configurable with a flag? 7420 // Note that the effect for this won't be visible on X axis with default Style settings as WindowPadding.x == ItemSpacing.x by default. 7421 static float CalcScrollEdgeSnap(float target, float snap_min, float snap_max, float snap_threshold, float center_ratio) 7422 { 7423 if (target <= snap_min + snap_threshold) 7424 return ImLerp(snap_min, target, center_ratio); 7425 if (target >= snap_max - snap_threshold) 7426 return ImLerp(target, snap_max, center_ratio); 7427 return target; 7428 } 7429 7430 static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window) 7431 { 7432 ImVec2 scroll = window->Scroll; 7433 if (window->ScrollTarget.x < FLT_MAX) 7434 { 7435 float center_x_ratio = window->ScrollTargetCenterRatio.x; 7436 float scroll_target_x = window->ScrollTarget.x; 7437 float snap_x_min = 0.0f; 7438 float snap_x_max = window->ScrollMax.x + window->Size.x; 7439 if (window->ScrollTargetEdgeSnapDist.x > 0.0f) 7440 scroll_target_x = CalcScrollEdgeSnap(scroll_target_x, snap_x_min, snap_x_max, window->ScrollTargetEdgeSnapDist.x, center_x_ratio); 7441 scroll.x = scroll_target_x - center_x_ratio * (window->SizeFull.x - window->ScrollbarSizes.x); 7442 } 7443 if (window->ScrollTarget.y < FLT_MAX) 7444 { 7445 float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight(); 7446 float center_y_ratio = window->ScrollTargetCenterRatio.y; 7447 float scroll_target_y = window->ScrollTarget.y; 7448 float snap_y_min = 0.0f; 7449 float snap_y_max = window->ScrollMax.y + window->Size.y - decoration_up_height; 7450 if (window->ScrollTargetEdgeSnapDist.y > 0.0f) 7451 scroll_target_y = CalcScrollEdgeSnap(scroll_target_y, snap_y_min, snap_y_max, window->ScrollTargetEdgeSnapDist.y, center_y_ratio); 7452 scroll.y = scroll_target_y - center_y_ratio * (window->SizeFull.y - window->ScrollbarSizes.y - decoration_up_height); 7453 } 7454 scroll.x = IM_FLOOR(ImMax(scroll.x, 0.0f)); 7455 scroll.y = IM_FLOOR(ImMax(scroll.y, 0.0f)); 7456 if (!window->Collapsed && !window->SkipItems) 7457 { 7458 scroll.x = ImMin(scroll.x, window->ScrollMax.x); 7459 scroll.y = ImMin(scroll.y, window->ScrollMax.y); 7460 } 7461 return scroll; 7462 } 7463 7464 // Scroll to keep newly navigated item fully into view 7465 ImVec2 ImGui::ScrollToBringRectIntoView(ImGuiWindow* window, const ImRect& item_rect) 7466 { 7467 ImGuiContext& g = *GImGui; 7468 ImRect window_rect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1)); 7469 //GetForegroundDrawList(window)->AddRect(window_rect.Min, window_rect.Max, IM_COL32_WHITE); // [DEBUG] 7470 7471 ImVec2 delta_scroll; 7472 if (!window_rect.Contains(item_rect)) 7473 { 7474 if (window->ScrollbarX && item_rect.Min.x < window_rect.Min.x) 7475 SetScrollFromPosX(window, item_rect.Min.x - window->Pos.x - g.Style.ItemSpacing.x, 0.0f); 7476 else if (window->ScrollbarX && item_rect.Max.x >= window_rect.Max.x) 7477 SetScrollFromPosX(window, item_rect.Max.x - window->Pos.x + g.Style.ItemSpacing.x, 1.0f); 7478 if (item_rect.Min.y < window_rect.Min.y) 7479 SetScrollFromPosY(window, item_rect.Min.y - window->Pos.y - g.Style.ItemSpacing.y, 0.0f); 7480 else if (item_rect.Max.y >= window_rect.Max.y) 7481 SetScrollFromPosY(window, item_rect.Max.y - window->Pos.y + g.Style.ItemSpacing.y, 1.0f); 7482 7483 ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window); 7484 delta_scroll = next_scroll - window->Scroll; 7485 } 7486 7487 // Also scroll parent window to keep us into view if necessary 7488 if (window->Flags & ImGuiWindowFlags_ChildWindow) 7489 delta_scroll += ScrollToBringRectIntoView(window->ParentWindow, ImRect(item_rect.Min - delta_scroll, item_rect.Max - delta_scroll)); 7490 7491 return delta_scroll; 7241 7492 } 7242 7493 7243 7494 float ImGui::GetScrollX() 7244 7495 { 7245 return GImGui->CurrentWindow->Scroll.x; 7496 ImGuiWindow* window = GImGui->CurrentWindow; 7497 return window->Scroll.x; 7246 7498 } 7247 7499 7248 7500 float ImGui::GetScrollY() 7249 7501 { 7250 return GImGui->CurrentWindow->Scroll.y; 7502 ImGuiWindow* window = GImGui->CurrentWindow; 7503 return window->Scroll.y; 7251 7504 } 7252 7505 7253 7506 float ImGui::GetScrollMaxX() 7254 7507 { 7255 return GetScrollMaxX(GImGui->CurrentWindow); 7508 ImGuiWindow* window = GImGui->CurrentWindow; 7509 return window->ScrollMax.x; 7256 7510 } 7257 7511 7258 7512 float ImGui::GetScrollMaxY() 7259 7513 { 7260 return GetScrollMaxY(GImGui->CurrentWindow); 7514 ImGuiWindow* window = GImGui->CurrentWindow; 7515 return window->ScrollMax.y; 7516 } 7517 7518 void ImGui::SetScrollX(ImGuiWindow* window, float scroll_x) 7519 { 7520 window->ScrollTarget.x = scroll_x; 7521 window->ScrollTargetCenterRatio.x = 0.0f; 7522 window->ScrollTargetEdgeSnapDist.x = 0.0f; 7523 } 7524 7525 void ImGui::SetScrollY(ImGuiWindow* window, float scroll_y) 7526 { 7527 window->ScrollTarget.y = scroll_y; 7528 window->ScrollTargetCenterRatio.y = 0.0f; 7529 window->ScrollTargetEdgeSnapDist.y = 0.0f; 7261 7530 } 7262 7531 7263 7532 void ImGui::SetScrollX(float scroll_x) 7264 7533 { 7265 ImGuiWindow* window = GetCurrentWindow(); 7266 window->ScrollTarget.x = scroll_x; 7267 window->ScrollTargetCenterRatio.x = 0.0f; 7534 ImGuiContext& g = *GImGui; 7535 SetScrollX(g.CurrentWindow, scroll_x); 7268 7536 } 7269 7537 7270 7538 void ImGui::SetScrollY(float scroll_y) 7271 7539 { 7272 ImGuiWindow* window = GetCurrentWindow(); 7273 window->ScrollTarget.y = scroll_y + window->TitleBarHeight() + window->MenuBarHeight(); // title bar height canceled out when using ScrollTargetRelY 7274 window->ScrollTargetCenterRatio.y = 0.0f; 7275 } 7276 7277 void ImGui::SetScrollFromPosY(float pos_y, float center_y_ratio) 7278 { 7279 // We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size 7280 ImGuiWindow* window = GetCurrentWindow(); 7281 IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f); 7282 window->ScrollTarget.y = (float)(int)(pos_y + window->Scroll.y); 7283 window->ScrollTargetCenterRatio.y = center_y_ratio; 7284 7285 // Minor hack to to make scrolling to top/bottom of window take account of WindowPadding, it looks more right to the user this way 7286 if (center_y_ratio <= 0.0f && window->ScrollTarget.y <= window->WindowPadding.y) 7287 window->ScrollTarget.y = 0.0f; 7288 else if (center_y_ratio >= 1.0f && window->ScrollTarget.y >= window->SizeContents.y - window->WindowPadding.y + GImGui->Style.ItemSpacing.y) 7289 window->ScrollTarget.y = window->SizeContents.y; 7540 ImGuiContext& g = *GImGui; 7541 SetScrollY(g.CurrentWindow, scroll_y); 7542 } 7543 7544 // Note that a local position will vary depending on initial scroll value, 7545 // This is a little bit confusing so bear with us: 7546 // - local_pos = (absolution_pos - window->Pos) 7547 // - So local_x/local_y are 0.0f for a position at the upper-left corner of a window, 7548 // and generally local_x/local_y are >(padding+decoration) && <(size-padding-decoration) when in the visible area. 7549 // - They mostly exists because of legacy API. 7550 // Following the rules above, when trying to work with scrolling code, consider that: 7551 // - SetScrollFromPosY(0.0f) == SetScrollY(0.0f + scroll.y) == has no effect! 7552 // - SetScrollFromPosY(-scroll.y) == SetScrollY(-scroll.y + scroll.y) == SetScrollY(0.0f) == reset scroll. Of course writing SetScrollY(0.0f) directly then makes more sense 7553 // We store a target position so centering and clamping can occur on the next frame when we are guaranteed to have a known window size 7554 void ImGui::SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio) 7555 { 7556 IM_ASSERT(center_x_ratio >= 0.0f && center_x_ratio <= 1.0f); 7557 window->ScrollTarget.x = IM_FLOOR(local_x + window->Scroll.x); // Convert local position to scroll offset 7558 window->ScrollTargetCenterRatio.x = center_x_ratio; 7559 window->ScrollTargetEdgeSnapDist.x = 0.0f; 7560 } 7561 7562 void ImGui::SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio) 7563 { 7564 IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f); 7565 local_y -= window->TitleBarHeight() + window->MenuBarHeight(); // FIXME: Would be nice to have a more standardized access to our scrollable/client rect 7566 window->ScrollTarget.y = IM_FLOOR(local_y + window->Scroll.y); // Convert local position to scroll offset 7567 window->ScrollTargetCenterRatio.y = center_y_ratio; 7568 window->ScrollTargetEdgeSnapDist.y = 0.0f; 7569 } 7570 7571 void ImGui::SetScrollFromPosX(float local_x, float center_x_ratio) 7572 { 7573 ImGuiContext& g = *GImGui; 7574 SetScrollFromPosX(g.CurrentWindow, local_x, center_x_ratio); 7575 } 7576 7577 void ImGui::SetScrollFromPosY(float local_y, float center_y_ratio) 7578 { 7579 ImGuiContext& g = *GImGui; 7580 SetScrollFromPosY(g.CurrentWindow, local_y, center_y_ratio); 7581 } 7582 7583 // center_x_ratio: 0.0f left of last item, 0.5f horizontal center of last item, 1.0f right of last item. 7584 void ImGui::SetScrollHereX(float center_x_ratio) 7585 { 7586 ImGuiContext& g = *GImGui; 7587 ImGuiWindow* window = g.CurrentWindow; 7588 float spacing_x = g.Style.ItemSpacing.x; 7589 float target_pos_x = ImLerp(window->DC.LastItemRect.Min.x - spacing_x, window->DC.LastItemRect.Max.x + spacing_x, center_x_ratio); 7590 SetScrollFromPosX(window, target_pos_x - window->Pos.x, center_x_ratio); // Convert from absolute to local pos 7591 7592 // Tweak: snap on edges when aiming at an item very close to the edge 7593 window->ScrollTargetEdgeSnapDist.x = ImMax(0.0f, window->WindowPadding.x - spacing_x); 7290 7594 } 7291 7595 7292 7596 // center_y_ratio: 0.0f top of last item, 0.5f vertical center of last item, 1.0f bottom of last item. 7293 void ImGui::SetScrollHere(float center_y_ratio) 7294 { 7295 ImGuiWindow* window = GetCurrentWindow(); 7296 float target_y = window->DC.CursorPosPrevLine.y - window->Pos.y; // Top of last item, in window space 7297 target_y += (window->DC.PrevLineHeight * center_y_ratio) + (GImGui->Style.ItemSpacing.y * (center_y_ratio - 0.5f) * 2.0f); // Precisely aim above, in the middle or below the last line. 7298 SetScrollFromPosY(target_y, center_y_ratio); 7299 } 7300 7301 void ImGui::ActivateItem(ImGuiID id) 7302 { 7303 ImGuiContext& g = *GImGui; 7304 g.NavNextActivateId = id; 7305 } 7306 7307 void ImGui::SetKeyboardFocusHere(int offset) 7308 { 7309 IM_ASSERT(offset >= -1); // -1 is allowed but not below 7310 ImGuiWindow* window = GetCurrentWindow(); 7311 window->FocusIdxAllRequestNext = window->FocusIdxAllCounter + 1 + offset; 7312 window->FocusIdxTabRequestNext = INT_MAX; 7313 } 7314 7315 void ImGui::SetItemDefaultFocus() 7316 { 7317 ImGuiContext& g = *GImGui; 7318 ImGuiWindow* window = g.CurrentWindow; 7319 if (!window->Appearing) 7320 return; 7321 if (g.NavWindow == window->RootWindowForNav && (g.NavInitRequest || g.NavInitResultId != 0) && g.NavLayer == g.NavWindow->DC.NavLayerCurrent) 7322 { 7323 g.NavInitRequest = false; 7324 g.NavInitResultId = g.NavWindow->DC.LastItemId; 7325 g.NavInitResultRectRel = ImRect(g.NavWindow->DC.LastItemRect.Min - g.NavWindow->Pos, g.NavWindow->DC.LastItemRect.Max - g.NavWindow->Pos); 7326 NavUpdateAnyRequestFlag(); 7327 if (!IsItemVisible()) 7328 SetScrollHere(); 7329 } 7330 } 7331 7332 void ImGui::SetStateStorage(ImGuiStorage* tree) 7333 { 7334 ImGuiWindow* window = GetCurrentWindow(); 7335 window->DC.StateStorage = tree ? tree : &window->StateStorage; 7336 } 7337 7338 ImGuiStorage* ImGui::GetStateStorage() 7339 { 7340 ImGuiWindow* window = GetCurrentWindowRead(); 7341 return window->DC.StateStorage; 7342 } 7343 7344 void ImGui::TextV(const char* fmt, va_list args) 7345 { 7346 ImGuiWindow* window = GetCurrentWindow(); 7347 if (window->SkipItems) 7348 return; 7349 7350 ImGuiContext& g = *GImGui; 7351 const char* text_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); 7352 TextUnformatted(g.TempBuffer, text_end); 7353 } 7354 7355 void ImGui::Text(const char* fmt, ...) 7356 { 7357 va_list args; 7358 va_start(args, fmt); 7359 TextV(fmt, args); 7360 va_end(args); 7361 } 7362 7363 void ImGui::TextColoredV(const ImVec4& col, const char* fmt, va_list args) 7364 { 7365 PushStyleColor(ImGuiCol_Text, col); 7366 TextV(fmt, args); 7367 PopStyleColor(); 7368 } 7369 7370 void ImGui::TextColored(const ImVec4& col, const char* fmt, ...) 7371 { 7372 va_list args; 7373 va_start(args, fmt); 7374 TextColoredV(col, fmt, args); 7375 va_end(args); 7376 } 7377 7378 void ImGui::TextDisabledV(const char* fmt, va_list args) 7379 { 7380 PushStyleColor(ImGuiCol_Text, GImGui->Style.Colors[ImGuiCol_TextDisabled]); 7381 TextV(fmt, args); 7382 PopStyleColor(); 7383 } 7384 7385 void ImGui::TextDisabled(const char* fmt, ...) 7386 { 7387 va_list args; 7388 va_start(args, fmt); 7389 TextDisabledV(fmt, args); 7390 va_end(args); 7391 } 7392 7393 void ImGui::TextWrappedV(const char* fmt, va_list args) 7394 { 7395 bool need_wrap = (GImGui->CurrentWindow->DC.TextWrapPos < 0.0f); // Keep existing wrap position is one ia already set 7396 if (need_wrap) PushTextWrapPos(0.0f); 7397 TextV(fmt, args); 7398 if (need_wrap) PopTextWrapPos(); 7399 } 7400 7401 void ImGui::TextWrapped(const char* fmt, ...) 7402 { 7403 va_list args; 7404 va_start(args, fmt); 7405 TextWrappedV(fmt, args); 7406 va_end(args); 7407 } 7408 7409 void ImGui::TextUnformatted(const char* text, const char* text_end) 7410 { 7411 ImGuiWindow* window = GetCurrentWindow(); 7412 if (window->SkipItems) 7413 return; 7414 7415 ImGuiContext& g = *GImGui; 7416 IM_ASSERT(text != NULL); 7417 const char* text_begin = text; 7418 if (text_end == NULL) 7419 text_end = text + strlen(text); // FIXME-OPT 7420 7421 const ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrentLineTextBaseOffset); 7422 const float wrap_pos_x = window->DC.TextWrapPos; 7423 const bool wrap_enabled = wrap_pos_x >= 0.0f; 7424 if (text_end - text > 2000 && !wrap_enabled) 7425 { 7426 // Long text! 7427 // Perform manual coarse clipping to optimize for long multi-line text 7428 // From this point we will only compute the width of lines that are visible. Optimization only available when word-wrapping is disabled. 7429 // We also don't vertically center the text within the line full height, which is unlikely to matter because we are likely the biggest and only item on the line. 7430 const char* line = text; 7431 const float line_height = GetTextLineHeight(); 7432 const ImRect clip_rect = window->ClipRect; 7433 ImVec2 text_size(0, 0); 7434 7435 if (text_pos.y <= clip_rect.Max.y) 7436 { 7437 ImVec2 pos = text_pos; 7438 7439 // Lines to skip (can't skip when logging text) 7440 if (!g.LogEnabled) 7441 { 7442 int lines_skippable = (int)((clip_rect.Min.y - text_pos.y) / line_height); 7443 if (lines_skippable > 0) 7597 void ImGui::SetScrollHereY(float center_y_ratio) 7598 { 7599 ImGuiContext& g = *GImGui; 7600 ImGuiWindow* window = g.CurrentWindow; 7601 float spacing_y = g.Style.ItemSpacing.y; 7602 float target_pos_y = ImLerp(window->DC.CursorPosPrevLine.y - spacing_y, window->DC.CursorPosPrevLine.y + window->DC.PrevLineSize.y + spacing_y, center_y_ratio); 7603 SetScrollFromPosY(window, target_pos_y - window->Pos.y, center_y_ratio); // Convert from absolute to local pos 7604 7605 // Tweak: snap on edges when aiming at an item very close to the edge 7606 window->ScrollTargetEdgeSnapDist.y = ImMax(0.0f, window->WindowPadding.y - spacing_y); 7607 } 7608 7609 //----------------------------------------------------------------------------- 7610 // [SECTION] TOOLTIPS 7611 //----------------------------------------------------------------------------- 7612 7613 void ImGui::BeginTooltip() 7614 { 7615 BeginTooltipEx(ImGuiWindowFlags_None, ImGuiTooltipFlags_None); 7616 } 7617 7618 void ImGui::BeginTooltipEx(ImGuiWindowFlags extra_flags, ImGuiTooltipFlags tooltip_flags) 7619 { 7620 ImGuiContext& g = *GImGui; 7621 7622 if (g.DragDropWithinSource || g.DragDropWithinTarget) 7623 { 7624 // 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) 7625 // In the context of a dragging tooltip we try to reduce that offset and we enforce following the cursor. 7626 // 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. 7627 //ImVec2 tooltip_pos = g.IO.MousePos - g.ActiveIdClickOffset - g.Style.WindowPadding; 7628 ImVec2 tooltip_pos = g.IO.MousePos + ImVec2(16 * g.Style.MouseCursorScale, 8 * g.Style.MouseCursorScale); 7629 SetNextWindowPos(tooltip_pos); 7630 SetNextWindowBgAlpha(g.Style.Colors[ImGuiCol_PopupBg].w * 0.60f); 7631 //PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * 0.60f); // This would be nice but e.g ColorButton with checkboard has issue with transparent colors :( 7632 tooltip_flags |= ImGuiTooltipFlags_OverridePreviousTooltip; 7633 } 7634 7635 char window_name[16]; 7636 ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", g.TooltipOverrideCount); 7637 if (tooltip_flags & ImGuiTooltipFlags_OverridePreviousTooltip) 7638 if (ImGuiWindow* window = FindWindowByName(window_name)) 7639 if (window->Active) 7444 7640 { 7445 int lines_skipped = 0; 7446 while (line < text_end && lines_skipped < lines_skippable) 7447 { 7448 const char* line_end = strchr(line, '\n'); 7449 if (!line_end) 7450 line_end = text_end; 7451 line = line_end + 1; 7452 lines_skipped++; 7453 } 7454 pos.y += lines_skipped * line_height; 7641 // Hide previous tooltip from being displayed. We can't easily "reset" the content of a window so we create a new one. 7642 window->Hidden = true; 7643 window->HiddenFramesCanSkipItems = 1; 7644 ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", ++g.TooltipOverrideCount); 7455 7645 } 7456 } 7457 7458 // Lines to render 7459 if (line < text_end) 7460 { 7461 ImRect line_rect(pos, pos + ImVec2(FLT_MAX, line_height)); 7462 while (line < text_end) 7646 ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize; 7647 Begin(window_name, NULL, flags | extra_flags); 7648 } 7649 7650 void ImGui::EndTooltip() 7651 { 7652 IM_ASSERT(GetCurrentWindowRead()->Flags & ImGuiWindowFlags_Tooltip); // Mismatched BeginTooltip()/EndTooltip() calls 7653 End(); 7654 } 7655 7656 void ImGui::SetTooltipV(const char* fmt, va_list args) 7657 { 7658 BeginTooltipEx(0, ImGuiTooltipFlags_OverridePreviousTooltip); 7659 TextV(fmt, args); 7660 EndTooltip(); 7661 } 7662 7663 void ImGui::SetTooltip(const char* fmt, ...) 7664 { 7665 va_list args; 7666 va_start(args, fmt); 7667 SetTooltipV(fmt, args); 7668 va_end(args); 7669 } 7670 7671 //----------------------------------------------------------------------------- 7672 // [SECTION] POPUPS 7673 //----------------------------------------------------------------------------- 7674 7675 // Supported flags: ImGuiPopupFlags_AnyPopupId, ImGuiPopupFlags_AnyPopupLevel 7676 bool ImGui::IsPopupOpen(ImGuiID id, ImGuiPopupFlags popup_flags) 7677 { 7678 ImGuiContext& g = *GImGui; 7679 if (popup_flags & ImGuiPopupFlags_AnyPopupId) 7680 { 7681 // Return true if any popup is open at the current BeginPopup() level of the popup stack 7682 // This may be used to e.g. test for another popups already opened to handle popups priorities at the same level. 7683 IM_ASSERT(id == 0); 7684 if (popup_flags & ImGuiPopupFlags_AnyPopupLevel) 7685 return g.OpenPopupStack.Size > 0; 7686 else 7687 return g.OpenPopupStack.Size > g.BeginPopupStack.Size; 7688 } 7689 else 7690 { 7691 if (popup_flags & ImGuiPopupFlags_AnyPopupLevel) 7692 { 7693 // Return true if the popup is open anywhere in the popup stack 7694 for (int n = 0; n < g.OpenPopupStack.Size; n++) 7695 if (g.OpenPopupStack[n].PopupId == id) 7696 return true; 7697 return false; 7698 } 7699 else 7700 { 7701 // Return true if the popup is open at the current BeginPopup() level of the popup stack (this is the most-common query) 7702 return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == id; 7703 } 7704 } 7705 } 7706 7707 bool ImGui::IsPopupOpen(const char* str_id, ImGuiPopupFlags popup_flags) 7708 { 7709 ImGuiContext& g = *GImGui; 7710 ImGuiID id = (popup_flags & ImGuiPopupFlags_AnyPopupId) ? 0 : g.CurrentWindow->GetID(str_id); 7711 if ((popup_flags & ImGuiPopupFlags_AnyPopupLevel) && id != 0) 7712 IM_ASSERT(0 && "Cannot use IsPopupOpen() with a string id and ImGuiPopupFlags_AnyPopupLevel."); // But non-string version is legal and used internally 7713 return IsPopupOpen(id, popup_flags); 7714 } 7715 7716 ImGuiWindow* ImGui::GetTopMostPopupModal() 7717 { 7718 ImGuiContext& g = *GImGui; 7719 for (int n = g.OpenPopupStack.Size - 1; n >= 0; n--) 7720 if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window) 7721 if (popup->Flags & ImGuiWindowFlags_Modal) 7722 return popup; 7723 return NULL; 7724 } 7725 7726 void ImGui::OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags) 7727 { 7728 ImGuiContext& g = *GImGui; 7729 OpenPopupEx(g.CurrentWindow->GetID(str_id), popup_flags); 7730 } 7731 7732 // Mark popup as open (toggle toward open state). 7733 // Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. 7734 // Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). 7735 // One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL) 7736 void ImGui::OpenPopupEx(ImGuiID id, ImGuiPopupFlags popup_flags) 7737 { 7738 ImGuiContext& g = *GImGui; 7739 ImGuiWindow* parent_window = g.CurrentWindow; 7740 const int current_stack_size = g.BeginPopupStack.Size; 7741 7742 if (popup_flags & ImGuiPopupFlags_NoOpenOverExistingPopup) 7743 if (IsPopupOpen(0u, ImGuiPopupFlags_AnyPopupId)) 7744 return; 7745 7746 ImGuiPopupData popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack. 7747 popup_ref.PopupId = id; 7748 popup_ref.Window = NULL; 7749 popup_ref.SourceWindow = g.NavWindow; 7750 popup_ref.OpenFrameCount = g.FrameCount; 7751 popup_ref.OpenParentId = parent_window->IDStack.back(); 7752 popup_ref.OpenPopupPos = NavCalcPreferredRefPos(); 7753 popup_ref.OpenMousePos = IsMousePosValid(&g.IO.MousePos) ? g.IO.MousePos : popup_ref.OpenPopupPos; 7754 7755 IMGUI_DEBUG_LOG_POPUP("OpenPopupEx(0x%08X)\n", id); 7756 if (g.OpenPopupStack.Size < current_stack_size + 1) 7757 { 7758 g.OpenPopupStack.push_back(popup_ref); 7759 } 7760 else 7761 { 7762 // 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 7763 // 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 7764 // 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. 7765 if (g.OpenPopupStack[current_stack_size].PopupId == id && g.OpenPopupStack[current_stack_size].OpenFrameCount == g.FrameCount - 1) 7766 { 7767 g.OpenPopupStack[current_stack_size].OpenFrameCount = popup_ref.OpenFrameCount; 7768 } 7769 else 7770 { 7771 // Close child popups if any, then flag popup for open/reopen 7772 ClosePopupToLevel(current_stack_size, false); 7773 g.OpenPopupStack.push_back(popup_ref); 7774 } 7775 7776 // When reopening a popup we first refocus its parent, otherwise if its parent is itself a popup it would get closed by ClosePopupsOverWindow(). 7777 // This is equivalent to what ClosePopupToLevel() does. 7778 //if (g.OpenPopupStack[current_stack_size].PopupId == id) 7779 // FocusWindow(parent_window); 7780 } 7781 } 7782 7783 // When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it. 7784 // This function closes any popups that are over 'ref_window'. 7785 void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup) 7786 { 7787 ImGuiContext& g = *GImGui; 7788 if (g.OpenPopupStack.Size == 0) 7789 return; 7790 7791 // Don't close our own child popup windows. 7792 int popup_count_to_keep = 0; 7793 if (ref_window) 7794 { 7795 // Find the highest popup which is a descendant of the reference window (generally reference window = NavWindow) 7796 for (; popup_count_to_keep < g.OpenPopupStack.Size; popup_count_to_keep++) 7797 { 7798 ImGuiPopupData& popup = g.OpenPopupStack[popup_count_to_keep]; 7799 if (!popup.Window) 7800 continue; 7801 IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0); 7802 if (popup.Window->Flags & ImGuiWindowFlags_ChildWindow) 7803 continue; 7804 7805 // Trim the stack unless the popup is a direct parent of the reference window (the reference window is often the NavWindow) 7806 // - With this stack of window, clicking/focusing Popup1 will close Popup2 and Popup3: 7807 // Window -> Popup1 -> Popup2 -> Popup3 7808 // - Each popups may contain child windows, which is why we compare ->RootWindow! 7809 // Window -> Popup1 -> Popup1_Child -> Popup2 -> Popup2_Child 7810 bool ref_window_is_descendent_of_popup = false; 7811 for (int n = popup_count_to_keep; n < g.OpenPopupStack.Size; n++) 7812 if (ImGuiWindow* popup_window = g.OpenPopupStack[n].Window) 7813 if (popup_window->RootWindow == ref_window->RootWindow) 7814 { 7815 ref_window_is_descendent_of_popup = true; 7816 break; 7817 } 7818 if (!ref_window_is_descendent_of_popup) 7819 break; 7820 } 7821 } 7822 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 7823 { 7824 IMGUI_DEBUG_LOG_POPUP("ClosePopupsOverWindow(\"%s\") -> ClosePopupToLevel(%d)\n", ref_window->Name, popup_count_to_keep); 7825 ClosePopupToLevel(popup_count_to_keep, restore_focus_to_window_under_popup); 7826 } 7827 } 7828 7829 void ImGui::ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup) 7830 { 7831 ImGuiContext& g = *GImGui; 7832 IMGUI_DEBUG_LOG_POPUP("ClosePopupToLevel(%d), restore_focus_to_window_under_popup=%d\n", remaining, restore_focus_to_window_under_popup); 7833 IM_ASSERT(remaining >= 0 && remaining < g.OpenPopupStack.Size); 7834 7835 // Trim open popup stack 7836 ImGuiWindow* focus_window = g.OpenPopupStack[remaining].SourceWindow; 7837 ImGuiWindow* popup_window = g.OpenPopupStack[remaining].Window; 7838 g.OpenPopupStack.resize(remaining); 7839 7840 if (restore_focus_to_window_under_popup) 7841 { 7842 if (focus_window && !focus_window->WasActive && popup_window) 7843 { 7844 // Fallback 7845 FocusTopMostWindowUnderOne(popup_window, NULL); 7846 } 7847 else 7848 { 7849 if (g.NavLayer == ImGuiNavLayer_Main && focus_window) 7850 focus_window = NavRestoreLastChildNavWindow(focus_window); 7851 FocusWindow(focus_window); 7852 } 7853 } 7854 } 7855 7856 // Close the popup we have begin-ed into. 7857 void ImGui::CloseCurrentPopup() 7858 { 7859 ImGuiContext& g = *GImGui; 7860 int popup_idx = g.BeginPopupStack.Size - 1; 7861 if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.BeginPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId) 7862 return; 7863 7864 // Closing a menu closes its top-most parent popup (unless a modal) 7865 while (popup_idx > 0) 7866 { 7867 ImGuiWindow* popup_window = g.OpenPopupStack[popup_idx].Window; 7868 ImGuiWindow* parent_popup_window = g.OpenPopupStack[popup_idx - 1].Window; 7869 bool close_parent = false; 7870 if (popup_window && (popup_window->Flags & ImGuiWindowFlags_ChildMenu)) 7871 if (parent_popup_window == NULL || !(parent_popup_window->Flags & ImGuiWindowFlags_Modal)) 7872 close_parent = true; 7873 if (!close_parent) 7874 break; 7875 popup_idx--; 7876 } 7877 IMGUI_DEBUG_LOG_POPUP("CloseCurrentPopup %d -> %d\n", g.BeginPopupStack.Size - 1, popup_idx); 7878 ClosePopupToLevel(popup_idx, true); 7879 7880 // A common pattern is to close a popup when selecting a menu item/selectable that will open another window. 7881 // To improve this usage pattern, we avoid nav highlight for a single frame in the parent window. 7882 // Similarly, we could avoid mouse hover highlight in this window but it is less visually problematic. 7883 if (ImGuiWindow* window = g.NavWindow) 7884 window->DC.NavHideHighlightOneFrame = true; 7885 } 7886 7887 // Attention! BeginPopup() adds default flags which BeginPopupEx()! 7888 bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags flags) 7889 { 7890 ImGuiContext& g = *GImGui; 7891 if (!IsPopupOpen(id, ImGuiPopupFlags_None)) 7892 { 7893 g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values 7894 return false; 7895 } 7896 7897 char name[20]; 7898 if (flags & ImGuiWindowFlags_ChildMenu) 7899 ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.BeginPopupStack.Size); // Recycle windows based on depth 7900 else 7901 ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame 7902 7903 flags |= ImGuiWindowFlags_Popup; 7904 bool is_open = Begin(name, NULL, flags); 7905 if (!is_open) // NB: Begin can return false when the popup is completely clipped (e.g. zero size display) 7906 EndPopup(); 7907 7908 return is_open; 7909 } 7910 7911 bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags) 7912 { 7913 ImGuiContext& g = *GImGui; 7914 if (g.OpenPopupStack.Size <= g.BeginPopupStack.Size) // Early out for performance 7915 { 7916 g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values 7917 return false; 7918 } 7919 flags |= ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings; 7920 return BeginPopupEx(g.CurrentWindow->GetID(str_id), flags); 7921 } 7922 7923 // If 'p_open' is specified for a modal popup window, the popup will have a regular close button which will close the popup. 7924 // Note that popup visibility status is owned by Dear ImGui (and manipulated with e.g. OpenPopup) so the actual value of *p_open is meaningless here. 7925 bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags) 7926 { 7927 ImGuiContext& g = *GImGui; 7928 ImGuiWindow* window = g.CurrentWindow; 7929 const ImGuiID id = window->GetID(name); 7930 if (!IsPopupOpen(id, ImGuiPopupFlags_None)) 7931 { 7932 g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values 7933 return false; 7934 } 7935 7936 // Center modal windows by default for increased visibility 7937 // (this won't really last as settings will kick in, and is mostly for backward compatibility. user may do the same themselves) 7938 // FIXME: Should test for (PosCond & window->SetWindowPosAllowFlags) with the upcoming window. 7939 if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) == 0) 7940 SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_FirstUseEver, ImVec2(0.5f, 0.5f)); 7941 7942 flags |= ImGuiWindowFlags_Popup | ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoCollapse; 7943 const bool is_open = Begin(name, p_open, flags); 7944 if (!is_open || (p_open && !*p_open)) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display) 7945 { 7946 EndPopup(); 7947 if (is_open) 7948 ClosePopupToLevel(g.BeginPopupStack.Size, true); 7949 return false; 7950 } 7951 return is_open; 7952 } 7953 7954 void ImGui::EndPopup() 7955 { 7956 ImGuiContext& g = *GImGui; 7957 ImGuiWindow* window = g.CurrentWindow; 7958 IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls 7959 IM_ASSERT(g.BeginPopupStack.Size > 0); 7960 7961 // Make all menus and popups wrap around for now, may need to expose that policy. 7962 if (g.NavWindow == window) 7963 NavMoveRequestTryWrapping(window, ImGuiNavMoveFlags_LoopY); 7964 7965 // Child-popups don't need to be laid out 7966 IM_ASSERT(g.WithinEndChild == false); 7967 if (window->Flags & ImGuiWindowFlags_ChildWindow) 7968 g.WithinEndChild = true; 7969 End(); 7970 g.WithinEndChild = false; 7971 } 7972 7973 // Helper to open a popup if mouse button is released over the item 7974 // - This is essentially the same as BeginPopupContextItem() but without the trailing BeginPopup() 7975 void ImGui::OpenPopupOnItemClick(const char* str_id, ImGuiPopupFlags popup_flags) 7976 { 7977 ImGuiWindow* window = GImGui->CurrentWindow; 7978 int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_); 7979 if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) 7980 { 7981 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! 7982 IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item) 7983 OpenPopupEx(id, popup_flags); 7984 } 7985 } 7986 7987 // This is a helper to handle the simplest case of associating one named popup to one given widget. 7988 // - You can pass a NULL str_id to use the identifier of the last item. 7989 // - You may want to handle this on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters). 7990 // - This is essentially the same as calling OpenPopupOnItemClick() + BeginPopup() but written to avoid 7991 // computing the ID twice because BeginPopupContextXXX functions may be called very frequently. 7992 bool ImGui::BeginPopupContextItem(const char* str_id, ImGuiPopupFlags popup_flags) 7993 { 7994 ImGuiWindow* window = GImGui->CurrentWindow; 7995 if (window->SkipItems) 7996 return false; 7997 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! 7998 IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item) 7999 int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_); 8000 if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) 8001 OpenPopupEx(id, popup_flags); 8002 return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings); 8003 } 8004 8005 bool ImGui::BeginPopupContextWindow(const char* str_id, ImGuiPopupFlags popup_flags) 8006 { 8007 ImGuiWindow* window = GImGui->CurrentWindow; 8008 if (!str_id) 8009 str_id = "window_context"; 8010 ImGuiID id = window->GetID(str_id); 8011 int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_); 8012 if (IsMouseReleased(mouse_button) && IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) 8013 if (!(popup_flags & ImGuiPopupFlags_NoOpenOverItems) || !IsAnyItemHovered()) 8014 OpenPopupEx(id, popup_flags); 8015 return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings); 8016 } 8017 8018 bool ImGui::BeginPopupContextVoid(const char* str_id, ImGuiPopupFlags popup_flags) 8019 { 8020 ImGuiWindow* window = GImGui->CurrentWindow; 8021 if (!str_id) 8022 str_id = "void_context"; 8023 ImGuiID id = window->GetID(str_id); 8024 int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_); 8025 if (IsMouseReleased(mouse_button) && !IsWindowHovered(ImGuiHoveredFlags_AnyWindow)) 8026 if (GetTopMostPopupModal() == NULL) 8027 OpenPopupEx(id, popup_flags); 8028 return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings); 8029 } 8030 8031 // 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.) 8032 // 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. 8033 ImVec2 ImGui::FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy) 8034 { 8035 ImVec2 base_pos_clamped = ImClamp(ref_pos, r_outer.Min, r_outer.Max - size); 8036 //GetForegroundDrawList()->AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255,0,0,255)); 8037 //GetForegroundDrawList()->AddRect(r_outer.Min, r_outer.Max, IM_COL32(0,255,0,255)); 8038 8039 // Combo Box policy (we want a connecting edge) 8040 if (policy == ImGuiPopupPositionPolicy_ComboBox) 8041 { 8042 const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Down, ImGuiDir_Right, ImGuiDir_Left, ImGuiDir_Up }; 8043 for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++) 8044 { 8045 const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n]; 8046 if (n != -1 && dir == *last_dir) // Already tried this direction? 8047 continue; 8048 ImVec2 pos; 8049 if (dir == ImGuiDir_Down) pos = ImVec2(r_avoid.Min.x, r_avoid.Max.y); // Below, Toward Right (default) 8050 if (dir == ImGuiDir_Right) pos = ImVec2(r_avoid.Min.x, r_avoid.Min.y - size.y); // Above, Toward Right 8051 if (dir == ImGuiDir_Left) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Max.y); // Below, Toward Left 8052 if (dir == ImGuiDir_Up) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Min.y - size.y); // Above, Toward Left 8053 if (!r_outer.Contains(ImRect(pos, pos + size))) 8054 continue; 8055 *last_dir = dir; 8056 return pos; 8057 } 8058 } 8059 8060 // Tooltip and Default popup policy 8061 // (Always first try the direction we used on the last frame, if any) 8062 if (policy == ImGuiPopupPositionPolicy_Tooltip || policy == ImGuiPopupPositionPolicy_Default) 8063 { 8064 const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Right, ImGuiDir_Down, ImGuiDir_Up, ImGuiDir_Left }; 8065 for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++) 8066 { 8067 const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n]; 8068 if (n != -1 && dir == *last_dir) // Already tried this direction? 8069 continue; 8070 8071 const 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); 8072 const 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); 8073 8074 // If there not enough room on one axis, there's no point in positioning on a side on this axis (e.g. when not enough width, use a top/bottom position to maximize available width) 8075 if (avail_w < size.x && (dir == ImGuiDir_Left || dir == ImGuiDir_Right)) 8076 continue; 8077 if (avail_h < size.y && (dir == ImGuiDir_Up || dir == ImGuiDir_Down)) 8078 continue; 8079 8080 ImVec2 pos; 8081 pos.x = (dir == ImGuiDir_Left) ? r_avoid.Min.x - size.x : (dir == ImGuiDir_Right) ? r_avoid.Max.x : base_pos_clamped.x; 8082 pos.y = (dir == ImGuiDir_Up) ? r_avoid.Min.y - size.y : (dir == ImGuiDir_Down) ? r_avoid.Max.y : base_pos_clamped.y; 8083 8084 // Clamp top-left corner of popup 8085 pos.x = ImMax(pos.x, r_outer.Min.x); 8086 pos.y = ImMax(pos.y, r_outer.Min.y); 8087 8088 *last_dir = dir; 8089 return pos; 8090 } 8091 } 8092 8093 // Fallback when not enough room: 8094 *last_dir = ImGuiDir_None; 8095 8096 // For tooltip we prefer avoiding the cursor at all cost even if it means that part of the tooltip won't be visible. 8097 if (policy == ImGuiPopupPositionPolicy_Tooltip) 8098 return ref_pos + ImVec2(2, 2); 8099 8100 // Otherwise try to keep within display 8101 ImVec2 pos = ref_pos; 8102 pos.x = ImMax(ImMin(pos.x + size.x, r_outer.Max.x) - size.x, r_outer.Min.x); 8103 pos.y = ImMax(ImMin(pos.y + size.y, r_outer.Max.y) - size.y, r_outer.Min.y); 8104 return pos; 8105 } 8106 8107 ImRect ImGui::GetWindowAllowedExtentRect(ImGuiWindow* window) 8108 { 8109 IM_UNUSED(window); 8110 ImVec2 padding = GImGui->Style.DisplaySafeAreaPadding; 8111 ImRect r_screen = GetViewportRect(); 8112 r_screen.Expand(ImVec2((r_screen.GetWidth() > padding.x * 2) ? -padding.x : 0.0f, (r_screen.GetHeight() > padding.y * 2) ? -padding.y : 0.0f)); 8113 return r_screen; 8114 } 8115 8116 ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window) 8117 { 8118 ImGuiContext& g = *GImGui; 8119 8120 ImRect r_outer = GetWindowAllowedExtentRect(window); 8121 if (window->Flags & ImGuiWindowFlags_ChildMenu) 8122 { 8123 // Child menus typically request _any_ position within the parent menu item, and then we move the new menu outside the parent bounds. 8124 // This is how we end up with child menus appearing (most-commonly) on the right of the parent menu. 8125 IM_ASSERT(g.CurrentWindow == window); 8126 ImGuiWindow* parent_window = g.CurrentWindowStack[g.CurrentWindowStack.Size - 2]; 8127 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). 8128 ImRect r_avoid; 8129 if (parent_window->DC.MenuBarAppending) 8130 r_avoid = ImRect(-FLT_MAX, parent_window->ClipRect.Min.y, FLT_MAX, parent_window->ClipRect.Max.y); // Avoid parent menu-bar. If we wanted multi-line menu-bar, we may instead want to have the calling window setup e.g. a NextWindowData.PosConstraintAvoidRect field 8131 else 8132 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); 8133 return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Default); 8134 } 8135 if (window->Flags & ImGuiWindowFlags_Popup) 8136 { 8137 ImRect r_avoid = ImRect(window->Pos.x - 1, window->Pos.y - 1, window->Pos.x + 1, window->Pos.y + 1); 8138 return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Default); 8139 } 8140 if (window->Flags & ImGuiWindowFlags_Tooltip) 8141 { 8142 // Position tooltip (always follows mouse) 8143 float sc = g.Style.MouseCursorScale; 8144 ImVec2 ref_pos = NavCalcPreferredRefPos(); 8145 ImRect r_avoid; 8146 if (!g.NavDisableHighlight && g.NavDisableMouseHover && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos)) 8147 r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8); 8148 else 8149 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. 8150 return FindBestWindowPosForPopupEx(ref_pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Tooltip); 8151 } 8152 IM_ASSERT(0); 8153 return window->Pos; 8154 } 8155 8156 //----------------------------------------------------------------------------- 8157 // [SECTION] KEYBOARD/GAMEPAD NAVIGATION 8158 //----------------------------------------------------------------------------- 8159 8160 // FIXME-NAV: The existence of SetNavID vs SetNavIDWithRectRel vs SetFocusID is incredibly messy and confusing, 8161 // and needs some explanation or serious refactoring. 8162 void ImGui::SetNavID(ImGuiID id, int nav_layer, ImGuiID focus_scope_id) 8163 { 8164 ImGuiContext& g = *GImGui; 8165 IM_ASSERT(g.NavWindow); 8166 IM_ASSERT(nav_layer == 0 || nav_layer == 1); 8167 g.NavId = id; 8168 g.NavFocusScopeId = focus_scope_id; 8169 g.NavWindow->NavLastIds[nav_layer] = id; 8170 } 8171 8172 void ImGui::SetNavIDWithRectRel(ImGuiID id, int nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel) 8173 { 8174 ImGuiContext& g = *GImGui; 8175 SetNavID(id, nav_layer, focus_scope_id); 8176 g.NavWindow->NavRectRel[nav_layer] = rect_rel; 8177 g.NavMousePosDirty = true; 8178 g.NavDisableHighlight = false; 8179 g.NavDisableMouseHover = true; 8180 } 8181 8182 void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window) 8183 { 8184 ImGuiContext& g = *GImGui; 8185 IM_ASSERT(id != 0); 8186 8187 // Assume that SetFocusID() is called in the context where its window->DC.NavLayerCurrent and window->DC.NavFocusScopeIdCurrent are valid. 8188 // Note that window may be != g.CurrentWindow (e.g. SetFocusID call in InputTextEx for multi-line text) 8189 const ImGuiNavLayer nav_layer = window->DC.NavLayerCurrent; 8190 if (g.NavWindow != window) 8191 g.NavInitRequest = false; 8192 g.NavWindow = window; 8193 g.NavId = id; 8194 g.NavLayer = nav_layer; 8195 g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent; 8196 window->NavLastIds[nav_layer] = id; 8197 if (window->DC.LastItemId == id) 8198 window->NavRectRel[nav_layer] = ImRect(window->DC.LastItemRect.Min - window->Pos, window->DC.LastItemRect.Max - window->Pos); 8199 8200 if (g.ActiveIdSource == ImGuiInputSource_Nav) 8201 g.NavDisableMouseHover = true; 8202 else 8203 g.NavDisableHighlight = true; 8204 } 8205 8206 ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy) 8207 { 8208 if (ImFabs(dx) > ImFabs(dy)) 8209 return (dx > 0.0f) ? ImGuiDir_Right : ImGuiDir_Left; 8210 return (dy > 0.0f) ? ImGuiDir_Down : ImGuiDir_Up; 8211 } 8212 8213 static float inline NavScoreItemDistInterval(float a0, float a1, float b0, float b1) 8214 { 8215 if (a1 < b0) 8216 return a1 - b0; 8217 if (b1 < a0) 8218 return a0 - b1; 8219 return 0.0f; 8220 } 8221 8222 static void inline NavClampRectToVisibleAreaForMoveDir(ImGuiDir move_dir, ImRect& r, const ImRect& clip_rect) 8223 { 8224 if (move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right) 8225 { 8226 r.Min.y = ImClamp(r.Min.y, clip_rect.Min.y, clip_rect.Max.y); 8227 r.Max.y = ImClamp(r.Max.y, clip_rect.Min.y, clip_rect.Max.y); 8228 } 8229 else 8230 { 8231 r.Min.x = ImClamp(r.Min.x, clip_rect.Min.x, clip_rect.Max.x); 8232 r.Max.x = ImClamp(r.Max.x, clip_rect.Min.x, clip_rect.Max.x); 8233 } 8234 } 8235 8236 // Scoring function for gamepad/keyboard directional navigation. Based on https://gist.github.com/rygorous/6981057 8237 static bool ImGui::NavScoreItem(ImGuiNavMoveResult* result, ImRect cand) 8238 { 8239 ImGuiContext& g = *GImGui; 8240 ImGuiWindow* window = g.CurrentWindow; 8241 if (g.NavLayer != window->DC.NavLayerCurrent) 8242 return false; 8243 8244 const ImRect& curr = g.NavScoringRect; // Current modified source rect (NB: we've applied Max.x = Min.x in NavUpdate() to inhibit the effect of having varied item width) 8245 g.NavScoringCount++; 8246 8247 // When entering through a NavFlattened border, we consider child window items as fully clipped for scoring 8248 if (window->ParentWindow == g.NavWindow) 8249 { 8250 IM_ASSERT((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened); 8251 if (!window->ClipRect.Overlaps(cand)) 8252 return false; 8253 cand.ClipWithFull(window->ClipRect); // This allows the scored item to not overlap other candidates in the parent window 8254 } 8255 8256 // 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) 8257 // For example, this ensure that items in one column are not reached when moving vertically from items in another column. 8258 NavClampRectToVisibleAreaForMoveDir(g.NavMoveClipDir, cand, window->ClipRect); 8259 8260 // Compute distance between boxes 8261 // FIXME-NAV: Introducing biases for vertical navigation, needs to be removed. 8262 float dbx = NavScoreItemDistInterval(cand.Min.x, cand.Max.x, curr.Min.x, curr.Max.x); 8263 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 8264 if (dby != 0.0f && dbx != 0.0f) 8265 dbx = (dbx / 1000.0f) + ((dbx > 0.0f) ? +1.0f : -1.0f); 8266 float dist_box = ImFabs(dbx) + ImFabs(dby); 8267 8268 // 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) 8269 float dcx = (cand.Min.x + cand.Max.x) - (curr.Min.x + curr.Max.x); 8270 float dcy = (cand.Min.y + cand.Max.y) - (curr.Min.y + curr.Max.y); 8271 float dist_center = ImFabs(dcx) + ImFabs(dcy); // L1 metric (need this for our connectedness guarantee) 8272 8273 // Determine which quadrant of 'curr' our candidate item 'cand' lies in based on distance 8274 ImGuiDir quadrant; 8275 float dax = 0.0f, day = 0.0f, dist_axial = 0.0f; 8276 if (dbx != 0.0f || dby != 0.0f) 8277 { 8278 // For non-overlapping boxes, use distance between boxes 8279 dax = dbx; 8280 day = dby; 8281 dist_axial = dist_box; 8282 quadrant = ImGetDirQuadrantFromDelta(dbx, dby); 8283 } 8284 else if (dcx != 0.0f || dcy != 0.0f) 8285 { 8286 // For overlapping boxes with different centers, use distance between centers 8287 dax = dcx; 8288 day = dcy; 8289 dist_axial = dist_center; 8290 quadrant = ImGetDirQuadrantFromDelta(dcx, dcy); 8291 } 8292 else 8293 { 8294 // 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) 8295 quadrant = (window->DC.LastItemId < g.NavId) ? ImGuiDir_Left : ImGuiDir_Right; 8296 } 8297 8298 #if IMGUI_DEBUG_NAV_SCORING 8299 char buf[128]; 8300 if (IsMouseHoveringRect(cand.Min, cand.Max)) 8301 { 8302 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]); 8303 ImDrawList* draw_list = GetForegroundDrawList(window); 8304 draw_list->AddRect(curr.Min, curr.Max, IM_COL32(255,200,0,100)); 8305 draw_list->AddRect(cand.Min, cand.Max, IM_COL32(255,255,0,200)); 8306 draw_list->AddRectFilled(cand.Max - ImVec2(4, 4), cand.Max + CalcTextSize(buf) + ImVec2(4, 4), IM_COL32(40,0,0,150)); 8307 draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Max, ~0U, buf); 8308 } 8309 else if (g.IO.KeyCtrl) // Hold to preview score in matching quadrant. Press C to rotate. 8310 { 8311 if (IsKeyPressedMap(ImGuiKey_C)) { g.NavMoveDirLast = (ImGuiDir)((g.NavMoveDirLast + 1) & 3); g.IO.KeysDownDuration[g.IO.KeyMap[ImGuiKey_C]] = 0.01f; } 8312 if (quadrant == g.NavMoveDir) 8313 { 8314 ImFormatString(buf, IM_ARRAYSIZE(buf), "%.0f/%.0f", dist_box, dist_center); 8315 ImDrawList* draw_list = GetForegroundDrawList(window); 8316 draw_list->AddRectFilled(cand.Min, cand.Max, IM_COL32(255, 0, 0, 200)); 8317 draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Min, IM_COL32(255, 255, 255, 255), buf); 8318 } 8319 } 8320 #endif 8321 8322 // Is it in the quadrant we're interesting in moving to? 8323 bool new_best = false; 8324 if (quadrant == g.NavMoveDir) 8325 { 8326 // Does it beat the current best candidate? 8327 if (dist_box < result->DistBox) 8328 { 8329 result->DistBox = dist_box; 8330 result->DistCenter = dist_center; 8331 return true; 8332 } 8333 if (dist_box == result->DistBox) 8334 { 8335 // Try using distance between center points to break ties 8336 if (dist_center < result->DistCenter) 7463 8337 { 7464 const char* line_end = strchr(line, '\n'); 7465 if (IsClippedEx(line_rect, 0, false)) 7466 break; 7467 7468 const ImVec2 line_size = CalcTextSize(line, line_end, false); 7469 text_size.x = ImMax(text_size.x, line_size.x); 7470 RenderText(pos, line, line_end, false); 7471 if (!line_end) 7472 line_end = text_end; 7473 line = line_end + 1; 7474 line_rect.Min.y += line_height; 7475 line_rect.Max.y += line_height; 7476 pos.y += line_height; 8338 result->DistCenter = dist_center; 8339 new_best = true; 7477 8340 } 7478 7479 // Count remaining lines 7480 int lines_skipped = 0; 7481 while (line < text_end) 8341 else if (dist_center == result->DistCenter) 7482 8342 { 7483 const char* line_end = strchr(line, '\n');7484 if (!line_end)7485 line_end = text_end;7486 line = line_end + 1;7487 lines_skipped++;8343 // Still tied! we need to be extra-careful to make sure everything gets linked properly. We consistently break ties by symbolically moving "later" items 8344 // (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), 8345 // 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. 8346 if (((g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? dby : dbx) < 0.0f) // moving bj to the right/down decreases distance 8347 new_best = true; 7488 8348 } 7489 pos.y += lines_skipped * line_height; 7490 } 7491 7492 text_size.y += (pos - text_pos).y; 7493 } 7494 7495 ImRect bb(text_pos, text_pos + text_size); 7496 ItemSize(bb); 7497 ItemAdd(bb, 0); 7498 } 7499 else 7500 { 7501 const float wrap_width = wrap_enabled ? CalcWrapWidthForPos(window->DC.CursorPos, wrap_pos_x) : 0.0f; 7502 const ImVec2 text_size = CalcTextSize(text_begin, text_end, false, wrap_width); 7503 7504 // Account of baseline offset 7505 ImRect bb(text_pos, text_pos + text_size); 7506 ItemSize(text_size); 7507 if (!ItemAdd(bb, 0)) 7508 return; 7509 7510 // Render (we don't hide text after ## in this end-user function) 7511 RenderTextWrapped(bb.Min, text_begin, text_end, wrap_width); 7512 } 7513 } 7514 7515 void ImGui::AlignTextToFramePadding() 7516 { 7517 ImGuiWindow* window = GetCurrentWindow(); 7518 if (window->SkipItems) 7519 return; 7520 7521 ImGuiContext& g = *GImGui; 7522 window->DC.CurrentLineHeight = ImMax(window->DC.CurrentLineHeight, g.FontSize + g.Style.FramePadding.y * 2); 7523 window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.CurrentLineTextBaseOffset, g.Style.FramePadding.y); 7524 } 7525 7526 // Add a label+text combo aligned to other label+value widgets 7527 void ImGui::LabelTextV(const char* label, const char* fmt, va_list args) 7528 { 7529 ImGuiWindow* window = GetCurrentWindow(); 7530 if (window->SkipItems) 7531 return; 7532 7533 ImGuiContext& g = *GImGui; 7534 const ImGuiStyle& style = g.Style; 7535 const float w = CalcItemWidth(); 7536 7537 const ImVec2 label_size = CalcTextSize(label, NULL, true); 7538 const ImRect value_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2)); 7539 const ImRect total_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w + (label_size.x > 0.0f ? style.ItemInnerSpacing.x : 0.0f), style.FramePadding.y * 2) + label_size); 7540 ItemSize(total_bb, style.FramePadding.y); 7541 if (!ItemAdd(total_bb, 0)) 7542 return; 7543 7544 // Render 7545 const char* value_text_begin = &g.TempBuffer[0]; 7546 const char* value_text_end = value_text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); 7547 RenderTextClipped(value_bb.Min, value_bb.Max, value_text_begin, value_text_end, NULL, ImVec2(0.0f, 0.5f)); 7548 if (label_size.x > 0.0f) 7549 RenderText(ImVec2(value_bb.Max.x + style.ItemInnerSpacing.x, value_bb.Min.y + style.FramePadding.y), label); 7550 } 7551 7552 void ImGui::LabelText(const char* label, const char* fmt, ...) 7553 { 7554 va_list args; 7555 va_start(args, fmt); 7556 LabelTextV(label, fmt, args); 7557 va_end(args); 7558 } 7559 7560 bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags) 7561 { 7562 ImGuiContext& g = *GImGui; 7563 ImGuiWindow* window = GetCurrentWindow(); 7564 7565 if (flags & ImGuiButtonFlags_Disabled) 7566 { 7567 if (out_hovered) *out_hovered = false; 7568 if (out_held) *out_held = false; 7569 if (g.ActiveId == id) ClearActiveID(); 7570 return false; 7571 } 7572 7573 // Default behavior requires click+release on same spot 7574 if ((flags & (ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnRelease | ImGuiButtonFlags_PressedOnDoubleClick)) == 0) 7575 flags |= ImGuiButtonFlags_PressedOnClickRelease; 7576 7577 ImGuiWindow* backup_hovered_window = g.HoveredWindow; 7578 if ((flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredRootWindow == window) 7579 g.HoveredWindow = window; 7580 7581 bool pressed = false; 7582 bool hovered = ItemHoverable(bb, id); 7583 7584 // Special mode for Drag and Drop where holding button pressed for a long time while dragging another item triggers the button 7585 if ((flags & ImGuiButtonFlags_PressedOnDragDropHold) && g.DragDropActive && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoHoldToOpenOthers)) 7586 if (IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) 7587 { 7588 hovered = true; 7589 SetHoveredID(id); 7590 if (CalcTypematicPressedRepeatAmount(g.HoveredIdTimer + 0.0001f, g.HoveredIdTimer + 0.0001f - g.IO.DeltaTime, 0.01f, 0.70f)) // FIXME: Our formula for CalcTypematicPressedRepeatAmount() is fishy 7591 { 7592 pressed = true; 7593 FocusWindow(window); 7594 } 7595 } 7596 7597 if ((flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredRootWindow == window) 7598 g.HoveredWindow = backup_hovered_window; 7599 7600 // AllowOverlap mode (rarely used) requires previous frame HoveredId to be null or to match. This allows using patterns where a later submitted widget overlaps a previous one. 7601 if (hovered && (flags & ImGuiButtonFlags_AllowItemOverlap) && (g.HoveredIdPreviousFrame != id && g.HoveredIdPreviousFrame != 0)) 7602 hovered = false; 7603 7604 // Mouse 7605 if (hovered) 7606 { 7607 if (!(flags & ImGuiButtonFlags_NoKeyModifiers) || (!g.IO.KeyCtrl && !g.IO.KeyShift && !g.IO.KeyAlt)) 7608 { 7609 // | CLICKING | HOLDING with ImGuiButtonFlags_Repeat 7610 // PressedOnClickRelease | <on release>* | <on repeat> <on repeat> .. (NOT on release) <-- MOST COMMON! (*) only if both click/release were over bounds 7611 // PressedOnClick | <on click> | <on click> <on repeat> <on repeat> .. 7612 // PressedOnRelease | <on release> | <on repeat> <on repeat> .. (NOT on release) 7613 // PressedOnDoubleClick | <on dclick> | <on dclick> <on repeat> <on repeat> .. 7614 // FIXME-NAV: We don't honor those different behaviors. 7615 if ((flags & ImGuiButtonFlags_PressedOnClickRelease) && g.IO.MouseClicked[0]) 7616 { 7617 SetActiveID(id, window); 7618 if (!(flags & ImGuiButtonFlags_NoNavFocus)) 7619 SetFocusID(id, window); 7620 FocusWindow(window); 7621 } 7622 if (((flags & ImGuiButtonFlags_PressedOnClick) && g.IO.MouseClicked[0]) || ((flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseDoubleClicked[0])) 7623 { 7624 pressed = true; 7625 if (flags & ImGuiButtonFlags_NoHoldingActiveID) 7626 ClearActiveID(); 7627 else 7628 SetActiveID(id, window); // Hold on ID 7629 FocusWindow(window); 7630 } 7631 if ((flags & ImGuiButtonFlags_PressedOnRelease) && g.IO.MouseReleased[0]) 7632 { 7633 if (!((flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[0] >= g.IO.KeyRepeatDelay)) // Repeat mode trumps <on release> 7634 pressed = true; 7635 ClearActiveID(); 7636 } 7637 7638 // 'Repeat' mode acts when held regardless of _PressedOn flags (see table above). 7639 // Relies on repeat logic of IsMouseClicked() but we may as well do it ourselves if we end up exposing finer RepeatDelay/RepeatRate settings. 7640 if ((flags & ImGuiButtonFlags_Repeat) && g.ActiveId == id && g.IO.MouseDownDuration[0] > 0.0f && IsMouseClicked(0, true)) 7641 pressed = true; 7642 } 7643 7644 if (pressed) 7645 g.NavDisableHighlight = true; 7646 } 7647 7648 // Gamepad/Keyboard navigation 7649 // We report navigated item as hovered but we don't set g.HoveredId to not interfere with mouse. 7650 if (g.NavId == id && !g.NavDisableHighlight && g.NavDisableMouseHover && (g.ActiveId == 0 || g.ActiveId == id || g.ActiveId == window->MoveId)) 7651 hovered = true; 7652 7653 if (g.NavActivateDownId == id) 7654 { 7655 bool nav_activated_by_code = (g.NavActivateId == id); 7656 bool nav_activated_by_inputs = IsNavInputPressed(ImGuiNavInput_Activate, (flags & ImGuiButtonFlags_Repeat) ? ImGuiInputReadMode_Repeat : ImGuiInputReadMode_Pressed); 7657 if (nav_activated_by_code || nav_activated_by_inputs) 7658 pressed = true; 7659 if (nav_activated_by_code || nav_activated_by_inputs || g.ActiveId == id) 7660 { 7661 // Set active id so it can be queried by user via IsItemActive(), equivalent of holding the mouse button. 7662 g.NavActivateId = id; // This is so SetActiveId assign a Nav source 7663 SetActiveID(id, window); 7664 if (!(flags & ImGuiButtonFlags_NoNavFocus)) 7665 SetFocusID(id, window); 7666 g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right) | (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); 7667 } 7668 } 7669 7670 bool held = false; 7671 if (g.ActiveId == id) 7672 { 7673 if (g.ActiveIdSource == ImGuiInputSource_Mouse) 7674 { 7675 if (g.ActiveIdIsJustActivated) 7676 g.ActiveIdClickOffset = g.IO.MousePos - bb.Min; 7677 if (g.IO.MouseDown[0]) 7678 { 7679 held = true; 7680 } 7681 else 7682 { 7683 if (hovered && (flags & ImGuiButtonFlags_PressedOnClickRelease)) 7684 if (!((flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[0] >= g.IO.KeyRepeatDelay)) // Repeat mode trumps <on release> 7685 if (!g.DragDropActive) 7686 pressed = true; 7687 ClearActiveID(); 7688 } 7689 if (!(flags & ImGuiButtonFlags_NoNavFocus)) 7690 g.NavDisableHighlight = true; 7691 } 7692 else if (g.ActiveIdSource == ImGuiInputSource_Nav) 7693 { 7694 if (g.NavActivateDownId != id) 7695 ClearActiveID(); 7696 } 7697 } 7698 7699 if (out_hovered) *out_hovered = hovered; 7700 if (out_held) *out_held = held; 7701 7702 return pressed; 7703 } 7704 7705 bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags flags) 7706 { 7707 ImGuiWindow* window = GetCurrentWindow(); 7708 if (window->SkipItems) 7709 return false; 7710 7711 ImGuiContext& g = *GImGui; 7712 const ImGuiStyle& style = g.Style; 7713 const ImGuiID id = window->GetID(label); 7714 const ImVec2 label_size = CalcTextSize(label, NULL, true); 7715 7716 ImVec2 pos = window->DC.CursorPos; 7717 if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrentLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag) 7718 pos.y += window->DC.CurrentLineTextBaseOffset - style.FramePadding.y; 7719 ImVec2 size = CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f); 7720 7721 const ImRect bb(pos, pos + size); 7722 ItemSize(bb, style.FramePadding.y); 7723 if (!ItemAdd(bb, id)) 7724 return false; 7725 7726 if (window->DC.ItemFlags & ImGuiItemFlags_ButtonRepeat) 7727 flags |= ImGuiButtonFlags_Repeat; 7728 bool hovered, held; 7729 bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); 7730 7731 // Render 7732 const ImU32 col = GetColorU32((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); 7733 RenderNavHighlight(bb, id); 7734 RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); 7735 RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb); 7736 7737 // Automatically close popups 7738 //if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup)) 7739 // CloseCurrentPopup(); 7740 7741 return pressed; 7742 } 7743 7744 bool ImGui::Button(const char* label, const ImVec2& size_arg) 7745 { 7746 return ButtonEx(label, size_arg, 0); 7747 } 7748 7749 // Small buttons fits within text without additional vertical spacing. 7750 bool ImGui::SmallButton(const char* label) 7751 { 7752 ImGuiContext& g = *GImGui; 7753 float backup_padding_y = g.Style.FramePadding.y; 7754 g.Style.FramePadding.y = 0.0f; 7755 bool pressed = ButtonEx(label, ImVec2(0, 0), ImGuiButtonFlags_AlignTextBaseLine); 7756 g.Style.FramePadding.y = backup_padding_y; 7757 return pressed; 7758 } 7759 7760 bool ImGui::ArrowButton(const char* str_id, ImGuiDir dir) 7761 { 7762 ImGuiWindow* window = GetCurrentWindow(); 7763 if (window->SkipItems) 7764 return false; 7765 7766 ImGuiContext& g = *GImGui; 7767 const ImGuiID id = window->GetID(str_id); 7768 float sz = ImGui::GetFrameHeight(); 7769 const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(sz, sz)); 7770 ItemSize(bb); 7771 if (!ItemAdd(bb, id)) 7772 return false; 7773 7774 bool hovered, held; 7775 bool pressed = ButtonBehavior(bb, id, &hovered, &held); 7776 7777 // Render 7778 const ImU32 col = GetColorU32((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); 7779 RenderNavHighlight(bb, id); 7780 RenderFrame(bb.Min, bb.Max, col, true, g.Style.FrameRounding); 7781 RenderArrow(bb.Min + g.Style.FramePadding, dir); 7782 7783 return pressed; 7784 } 7785 7786 // Tip: use ImGui::PushID()/PopID() to push indices or pointers in the ID stack. 7787 // Then you can keep 'str_id' empty or the same for all your buttons (instead of creating a string based on a non-string id) 7788 bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size_arg) 7789 { 7790 ImGuiWindow* window = GetCurrentWindow(); 7791 if (window->SkipItems) 7792 return false; 7793 7794 const ImGuiID id = window->GetID(str_id); 7795 ImVec2 size = CalcItemSize(size_arg, 0.0f, 0.0f); 7796 const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); 7797 ItemSize(bb); 7798 if (!ItemAdd(bb, id)) 7799 return false; 7800 7801 bool hovered, held; 7802 bool pressed = ButtonBehavior(bb, id, &hovered, &held); 7803 7804 return pressed; 7805 } 7806 7807 // Button to close a window 7808 bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos, float radius) 7809 { 7810 ImGuiContext& g = *GImGui; 7811 ImGuiWindow* window = g.CurrentWindow; 7812 7813 // We intentionally allow interaction when clipped so that a mechanical Alt,Right,Validate sequence close a window. 7814 // (this isn't the regular behavior of buttons, but it doesn't affect the user much because navigation tends to keep items visible). 7815 const ImRect bb(pos - ImVec2(radius, radius), pos + ImVec2(radius, radius)); 7816 bool is_clipped = !ItemAdd(bb, id); 7817 7818 bool hovered, held; 7819 bool pressed = ButtonBehavior(bb, id, &hovered, &held); 7820 if (is_clipped) 7821 return pressed; 7822 7823 // Render 7824 ImVec2 center = bb.GetCenter(); 7825 if (hovered) 7826 window->DrawList->AddCircleFilled(center, ImMax(2.0f, radius), GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered), 9); 7827 7828 float cross_extent = (radius * 0.7071f) - 1.0f; 7829 ImU32 cross_col = GetColorU32(ImGuiCol_Text); 7830 center -= ImVec2(0.5f, 0.5f); 7831 window->DrawList->AddLine(center + ImVec2(+cross_extent, +cross_extent), center + ImVec2(-cross_extent, -cross_extent), cross_col, 1.0f); 7832 window->DrawList->AddLine(center + ImVec2(+cross_extent, -cross_extent), center + ImVec2(-cross_extent, +cross_extent), cross_col, 1.0f); 7833 7834 return pressed; 7835 } 7836 7837 void ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col) 7838 { 7839 ImGuiWindow* window = GetCurrentWindow(); 7840 if (window->SkipItems) 7841 return; 7842 7843 ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); 7844 if (border_col.w > 0.0f) 7845 bb.Max += ImVec2(2, 2); 7846 ItemSize(bb); 7847 if (!ItemAdd(bb, 0)) 7848 return; 7849 7850 if (border_col.w > 0.0f) 7851 { 7852 window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(border_col), 0.0f); 7853 window->DrawList->AddImage(user_texture_id, bb.Min + ImVec2(1, 1), bb.Max - ImVec2(1, 1), uv0, uv1, GetColorU32(tint_col)); 7854 } 7855 else 7856 { 7857 window->DrawList->AddImage(user_texture_id, bb.Min, bb.Max, uv0, uv1, GetColorU32(tint_col)); 7858 } 7859 } 7860 7861 // frame_padding < 0: uses FramePadding from style (default) 7862 // frame_padding = 0: no framing 7863 // frame_padding > 0: set framing size 7864 // The color used are the button colors. 7865 bool ImGui::ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col) 7866 { 7867 ImGuiWindow* window = GetCurrentWindow(); 7868 if (window->SkipItems) 7869 return false; 7870 7871 ImGuiContext& g = *GImGui; 7872 const ImGuiStyle& style = g.Style; 7873 7874 // Default to using texture ID as ID. User can still push string/integer prefixes. 7875 // We could hash the size/uv to create a unique ID but that would prevent the user from animating UV. 7876 PushID((void *)user_texture_id); 7877 const ImGuiID id = window->GetID("#image"); 7878 PopID(); 7879 7880 const ImVec2 padding = (frame_padding >= 0) ? ImVec2((float)frame_padding, (float)frame_padding) : style.FramePadding; 7881 const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size + padding * 2); 7882 const ImRect image_bb(window->DC.CursorPos + padding, window->DC.CursorPos + padding + size); 7883 ItemSize(bb); 7884 if (!ItemAdd(bb, id)) 7885 return false; 7886 7887 bool hovered, held; 7888 bool pressed = ButtonBehavior(bb, id, &hovered, &held); 7889 7890 // Render 7891 const ImU32 col = GetColorU32((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); 7892 RenderNavHighlight(bb, id); 7893 RenderFrame(bb.Min, bb.Max, col, true, ImClamp((float)ImMin(padding.x, padding.y), 0.0f, style.FrameRounding)); 7894 if (bg_col.w > 0.0f) 7895 window->DrawList->AddRectFilled(image_bb.Min, image_bb.Max, GetColorU32(bg_col)); 7896 window->DrawList->AddImage(user_texture_id, image_bb.Min, image_bb.Max, uv0, uv1, GetColorU32(tint_col)); 7897 7898 return pressed; 7899 } 7900 7901 // Start logging ImGui output to TTY 7902 void ImGui::LogToTTY(int max_depth) 7903 { 7904 ImGuiContext& g = *GImGui; 7905 if (g.LogEnabled) 7906 return; 7907 ImGuiWindow* window = g.CurrentWindow; 7908 7909 IM_ASSERT(g.LogFile == NULL); 7910 g.LogFile = stdout; 7911 g.LogEnabled = true; 7912 g.LogStartDepth = window->DC.TreeDepth; 7913 if (max_depth >= 0) 7914 g.LogAutoExpandMaxDepth = max_depth; 7915 } 7916 7917 // Start logging ImGui output to given file 7918 void ImGui::LogToFile(int max_depth, const char* filename) 7919 { 7920 ImGuiContext& g = *GImGui; 7921 if (g.LogEnabled) 7922 return; 7923 ImGuiWindow* window = g.CurrentWindow; 7924 7925 if (!filename) 7926 { 7927 filename = g.IO.LogFilename; 7928 if (!filename) 7929 return; 7930 } 7931 7932 IM_ASSERT(g.LogFile == NULL); 7933 g.LogFile = ImFileOpen(filename, "ab"); 7934 if (!g.LogFile) 7935 { 7936 IM_ASSERT(g.LogFile != NULL); // Consider this an error 7937 return; 7938 } 7939 g.LogEnabled = true; 7940 g.LogStartDepth = window->DC.TreeDepth; 7941 if (max_depth >= 0) 7942 g.LogAutoExpandMaxDepth = max_depth; 7943 } 7944 7945 // Start logging ImGui output to clipboard 7946 void ImGui::LogToClipboard(int max_depth) 7947 { 7948 ImGuiContext& g = *GImGui; 7949 if (g.LogEnabled) 7950 return; 7951 ImGuiWindow* window = g.CurrentWindow; 7952 7953 IM_ASSERT(g.LogFile == NULL); 7954 g.LogFile = NULL; 7955 g.LogEnabled = true; 7956 g.LogStartDepth = window->DC.TreeDepth; 7957 if (max_depth >= 0) 7958 g.LogAutoExpandMaxDepth = max_depth; 7959 } 7960 7961 void ImGui::LogFinish() 7962 { 7963 ImGuiContext& g = *GImGui; 7964 if (!g.LogEnabled) 7965 return; 7966 7967 LogText(IM_NEWLINE); 7968 if (g.LogFile != NULL) 7969 { 7970 if (g.LogFile == stdout) 7971 fflush(g.LogFile); 7972 else 7973 fclose(g.LogFile); 7974 g.LogFile = NULL; 7975 } 7976 if (g.LogClipboard->size() > 1) 7977 { 7978 SetClipboardText(g.LogClipboard->begin()); 7979 g.LogClipboard->clear(); 7980 } 7981 g.LogEnabled = false; 7982 } 7983 7984 // Helper to display logging buttons 7985 void ImGui::LogButtons() 7986 { 7987 ImGuiContext& g = *GImGui; 7988 7989 PushID("LogButtons"); 7990 const bool log_to_tty = Button("Log To TTY"); SameLine(); 7991 const bool log_to_file = Button("Log To File"); SameLine(); 7992 const bool log_to_clipboard = Button("Log To Clipboard"); SameLine(); 7993 PushItemWidth(80.0f); 7994 PushAllowKeyboardFocus(false); 7995 SliderInt("Depth", &g.LogAutoExpandMaxDepth, 0, 9, NULL); 7996 PopAllowKeyboardFocus(); 7997 PopItemWidth(); 7998 PopID(); 7999 8000 // Start logging at the end of the function so that the buttons don't appear in the log 8001 if (log_to_tty) 8002 LogToTTY(g.LogAutoExpandMaxDepth); 8003 if (log_to_file) 8004 LogToFile(g.LogAutoExpandMaxDepth, g.IO.LogFilename); 8005 if (log_to_clipboard) 8006 LogToClipboard(g.LogAutoExpandMaxDepth); 8007 } 8008 8009 bool ImGui::TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags) 8010 { 8011 if (flags & ImGuiTreeNodeFlags_Leaf) 8012 return true; 8013 8014 // We only write to the tree storage if the user clicks (or explicitly use SetNextTreeNode*** functions) 8015 ImGuiContext& g = *GImGui; 8016 ImGuiWindow* window = g.CurrentWindow; 8017 ImGuiStorage* storage = window->DC.StateStorage; 8018 8019 bool is_open; 8020 if (g.NextTreeNodeOpenCond != 0) 8021 { 8022 if (g.NextTreeNodeOpenCond & ImGuiCond_Always) 8023 { 8024 is_open = g.NextTreeNodeOpenVal; 8025 storage->SetInt(id, is_open); 8026 } 8027 else 8028 { 8029 // We treat ImGuiCond_Once and ImGuiCond_FirstUseEver the same because tree node state are not saved persistently. 8030 const int stored_value = storage->GetInt(id, -1); 8031 if (stored_value == -1) 8032 { 8033 is_open = g.NextTreeNodeOpenVal; 8034 storage->SetInt(id, is_open); 8035 } 8036 else 8037 { 8038 is_open = stored_value != 0; 8039 } 8040 } 8041 g.NextTreeNodeOpenCond = 0; 8042 } 8043 else 8044 { 8045 is_open = storage->GetInt(id, (flags & ImGuiTreeNodeFlags_DefaultOpen) ? 1 : 0) != 0; 8046 } 8047 8048 // When logging is enabled, we automatically expand tree nodes (but *NOT* collapsing headers.. seems like sensible behavior). 8049 // NB- If we are above max depth we still allow manually opened nodes to be logged. 8050 if (g.LogEnabled && !(flags & ImGuiTreeNodeFlags_NoAutoOpenOnLog) && window->DC.TreeDepth < g.LogAutoExpandMaxDepth) 8051 is_open = true; 8052 8053 return is_open; 8054 } 8055 8056 bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end) 8057 { 8058 ImGuiWindow* window = GetCurrentWindow(); 8059 if (window->SkipItems) 8060 return false; 8061 8062 ImGuiContext& g = *GImGui; 8063 const ImGuiStyle& style = g.Style; 8064 const bool display_frame = (flags & ImGuiTreeNodeFlags_Framed) != 0; 8065 const ImVec2 padding = (display_frame || (flags & ImGuiTreeNodeFlags_FramePadding)) ? style.FramePadding : ImVec2(style.FramePadding.x, 0.0f); 8066 8067 if (!label_end) 8068 label_end = FindRenderedTextEnd(label); 8069 const ImVec2 label_size = CalcTextSize(label, label_end, false); 8070 8071 // We vertically grow up to current line height up the typical widget height. 8072 const float text_base_offset_y = ImMax(padding.y, window->DC.CurrentLineTextBaseOffset); // Latch before ItemSize changes it 8073 const float frame_height = ImMax(ImMin(window->DC.CurrentLineHeight, g.FontSize + style.FramePadding.y * 2), label_size.y + padding.y * 2); 8074 ImRect frame_bb = ImRect(window->DC.CursorPos, ImVec2(window->Pos.x + GetContentRegionMax().x, window->DC.CursorPos.y + frame_height)); 8075 if (display_frame) 8076 { 8077 // Framed header expand a little outside the default padding 8078 frame_bb.Min.x -= (float)(int)(window->WindowPadding.x*0.5f) - 1; 8079 frame_bb.Max.x += (float)(int)(window->WindowPadding.x*0.5f) - 1; 8080 } 8081 8082 const float text_offset_x = (g.FontSize + (display_frame ? padding.x * 3 : padding.x * 2)); // Collapser arrow width + Spacing 8083 const float text_width = g.FontSize + (label_size.x > 0.0f ? label_size.x + padding.x * 2 : 0.0f); // Include collapser 8084 ItemSize(ImVec2(text_width, frame_height), text_base_offset_y); 8085 8086 // For regular tree nodes, we arbitrary allow to click past 2 worth of ItemSpacing 8087 // (Ideally we'd want to add a flag for the user to specify if we want the hit test to be done up to the right side of the content or not) 8088 const ImRect interact_bb = display_frame ? frame_bb : ImRect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + text_width + style.ItemSpacing.x * 2, frame_bb.Max.y); 8089 bool is_open = TreeNodeBehaviorIsOpen(id, flags); 8090 8091 // Store a flag for the current depth to tell if we will allow closing this node when navigating one of its child. 8092 // For this purpose we essentially compare if g.NavIdIsAlive went from 0 to 1 between TreeNode() and TreePop(). 8093 // This is currently only support 32 level deep and we are fine with (1 << Depth) overflowing into a zero. 8094 if (is_open && !g.NavIdIsAlive && (flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) 8095 window->DC.TreeDepthMayJumpToParentOnPop |= (1 << window->DC.TreeDepth); 8096 8097 bool item_add = ItemAdd(interact_bb, id); 8098 window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HasDisplayRect; 8099 window->DC.LastItemDisplayRect = frame_bb; 8100 8101 if (!item_add) 8102 { 8103 if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) 8104 TreePushRawID(id); 8105 return is_open; 8106 } 8107 8108 // Flags that affects opening behavior: 8109 // - 0(default) ..................... single-click anywhere to open 8110 // - OpenOnDoubleClick .............. double-click anywhere to open 8111 // - OpenOnArrow .................... single-click on arrow to open 8112 // - OpenOnDoubleClick|OpenOnArrow .. single-click on arrow or double-click anywhere to open 8113 ImGuiButtonFlags button_flags = ImGuiButtonFlags_NoKeyModifiers | ((flags & ImGuiTreeNodeFlags_AllowItemOverlap) ? ImGuiButtonFlags_AllowItemOverlap : 0); 8114 if (!(flags & ImGuiTreeNodeFlags_Leaf)) 8115 button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; 8116 if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) 8117 button_flags |= ImGuiButtonFlags_PressedOnDoubleClick | ((flags & ImGuiTreeNodeFlags_OpenOnArrow) ? ImGuiButtonFlags_PressedOnClickRelease : 0); 8118 8119 bool hovered, held, pressed = ButtonBehavior(interact_bb, id, &hovered, &held, button_flags); 8120 if (!(flags & ImGuiTreeNodeFlags_Leaf)) 8121 { 8122 bool toggled = false; 8123 if (pressed) 8124 { 8125 toggled = !(flags & (ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick)) || (g.NavActivateId == id); 8126 if (flags & ImGuiTreeNodeFlags_OpenOnArrow) 8127 toggled |= IsMouseHoveringRect(interact_bb.Min, ImVec2(interact_bb.Min.x + text_offset_x, interact_bb.Max.y)) && (!g.NavDisableMouseHover); 8128 if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) 8129 toggled |= g.IO.MouseDoubleClicked[0]; 8130 if (g.DragDropActive && is_open) // When using Drag and Drop "hold to open" we keep the node highlighted after opening, but never close it again. 8131 toggled = false; 8132 } 8133 8134 if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Left && is_open) 8135 { 8136 toggled = true; 8137 NavMoveRequestCancel(); 8138 } 8139 if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Right && !is_open) // If there's something upcoming on the line we may want to give it the priority? 8140 { 8141 toggled = true; 8142 NavMoveRequestCancel(); 8143 } 8144 8145 if (toggled) 8146 { 8147 is_open = !is_open; 8148 window->DC.StateStorage->SetInt(id, is_open); 8149 } 8150 } 8151 if (flags & ImGuiTreeNodeFlags_AllowItemOverlap) 8152 SetItemAllowOverlap(); 8153 8154 // Render 8155 const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); 8156 const ImVec2 text_pos = frame_bb.Min + ImVec2(text_offset_x, text_base_offset_y); 8157 if (display_frame) 8158 { 8159 // Framed type 8160 RenderFrame(frame_bb.Min, frame_bb.Max, col, true, style.FrameRounding); 8161 RenderNavHighlight(frame_bb, id, ImGuiNavHighlightFlags_TypeThin); 8162 RenderArrow(frame_bb.Min + ImVec2(padding.x, text_base_offset_y), is_open ? ImGuiDir_Down : ImGuiDir_Right, 1.0f); 8163 if (g.LogEnabled) 8164 { 8165 // NB: '##' is normally used to hide text (as a library-wide feature), so we need to specify the text range to make sure the ## aren't stripped out here. 8166 const char log_prefix[] = "\n##"; 8167 const char log_suffix[] = "##"; 8168 LogRenderedText(&text_pos, log_prefix, log_prefix + 3); 8169 RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size); 8170 LogRenderedText(&text_pos, log_suffix + 1, log_suffix + 3); 8171 } 8172 else 8173 { 8174 RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size); 8175 } 8176 } 8177 else 8178 { 8179 // Unframed typed for tree nodes 8180 if (hovered || (flags & ImGuiTreeNodeFlags_Selected)) 8181 { 8182 RenderFrame(frame_bb.Min, frame_bb.Max, col, false); 8183 RenderNavHighlight(frame_bb, id, ImGuiNavHighlightFlags_TypeThin); 8184 } 8185 8186 if (flags & ImGuiTreeNodeFlags_Bullet) 8187 RenderBullet(frame_bb.Min + ImVec2(text_offset_x * 0.5f, g.FontSize*0.50f + text_base_offset_y)); 8188 else if (!(flags & ImGuiTreeNodeFlags_Leaf)) 8189 RenderArrow(frame_bb.Min + ImVec2(padding.x, g.FontSize*0.15f + text_base_offset_y), is_open ? ImGuiDir_Down : ImGuiDir_Right, 0.70f); 8190 if (g.LogEnabled) 8191 LogRenderedText(&text_pos, ">"); 8192 RenderText(text_pos, label, label_end, false); 8193 } 8194 8195 if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) 8196 TreePushRawID(id); 8197 return is_open; 8198 } 8199 8200 // CollapsingHeader returns true when opened but do not indent nor push into the ID stack (because of the ImGuiTreeNodeFlags_NoTreePushOnOpen flag). 8201 // This is basically the same as calling TreeNodeEx(label, ImGuiTreeNodeFlags_CollapsingHeader | ImGuiTreeNodeFlags_NoTreePushOnOpen). You can remove the _NoTreePushOnOpen flag if you want behavior closer to normal TreeNode(). 8202 bool ImGui::CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags) 8203 { 8204 ImGuiWindow* window = GetCurrentWindow(); 8205 if (window->SkipItems) 8206 return false; 8207 8208 return TreeNodeBehavior(window->GetID(label), flags | ImGuiTreeNodeFlags_CollapsingHeader | ImGuiTreeNodeFlags_NoTreePushOnOpen, label); 8209 } 8210 8211 bool ImGui::CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags) 8212 { 8213 ImGuiWindow* window = GetCurrentWindow(); 8214 if (window->SkipItems) 8215 return false; 8216 8217 if (p_open && !*p_open) 8218 return false; 8219 8220 ImGuiID id = window->GetID(label); 8221 bool is_open = TreeNodeBehavior(id, flags | ImGuiTreeNodeFlags_CollapsingHeader | ImGuiTreeNodeFlags_NoTreePushOnOpen | (p_open ? ImGuiTreeNodeFlags_AllowItemOverlap : 0), label); 8222 if (p_open) 8223 { 8224 // Create a small overlapping close button // FIXME: We can evolve this into user accessible helpers to add extra buttons on title bars, headers, etc. 8225 ImGuiContext& g = *GImGui; 8226 float button_sz = g.FontSize * 0.5f; 8227 ImGuiItemHoveredDataBackup last_item_backup; 8228 if (CloseButton(window->GetID((void*)(intptr_t)(id + 1)), ImVec2(ImMin(window->DC.LastItemRect.Max.x, window->ClipRect.Max.x) - g.Style.FramePadding.x - button_sz, window->DC.LastItemRect.Min.y + g.Style.FramePadding.y + button_sz), button_sz)) 8229 *p_open = false; 8230 last_item_backup.Restore(); 8231 } 8232 8233 return is_open; 8234 } 8235 8236 bool ImGui::TreeNodeEx(const char* label, ImGuiTreeNodeFlags flags) 8237 { 8238 ImGuiWindow* window = GetCurrentWindow(); 8239 if (window->SkipItems) 8240 return false; 8241 8242 return TreeNodeBehavior(window->GetID(label), flags, label, NULL); 8243 } 8244 8245 bool ImGui::TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) 8246 { 8247 ImGuiWindow* window = GetCurrentWindow(); 8248 if (window->SkipItems) 8249 return false; 8250 8251 ImGuiContext& g = *GImGui; 8252 const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); 8253 return TreeNodeBehavior(window->GetID(str_id), flags, g.TempBuffer, label_end); 8254 } 8255 8256 bool ImGui::TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) 8257 { 8258 ImGuiWindow* window = GetCurrentWindow(); 8259 if (window->SkipItems) 8260 return false; 8261 8262 ImGuiContext& g = *GImGui; 8263 const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); 8264 return TreeNodeBehavior(window->GetID(ptr_id), flags, g.TempBuffer, label_end); 8265 } 8266 8267 bool ImGui::TreeNodeV(const char* str_id, const char* fmt, va_list args) 8268 { 8269 return TreeNodeExV(str_id, 0, fmt, args); 8270 } 8271 8272 bool ImGui::TreeNodeV(const void* ptr_id, const char* fmt, va_list args) 8273 { 8274 return TreeNodeExV(ptr_id, 0, fmt, args); 8275 } 8276 8277 bool ImGui::TreeNodeEx(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) 8278 { 8279 va_list args; 8280 va_start(args, fmt); 8281 bool is_open = TreeNodeExV(str_id, flags, fmt, args); 8282 va_end(args); 8283 return is_open; 8284 } 8285 8286 bool ImGui::TreeNodeEx(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) 8287 { 8288 va_list args; 8289 va_start(args, fmt); 8290 bool is_open = TreeNodeExV(ptr_id, flags, fmt, args); 8291 va_end(args); 8292 return is_open; 8293 } 8294 8295 bool ImGui::TreeNode(const char* str_id, const char* fmt, ...) 8296 { 8297 va_list args; 8298 va_start(args, fmt); 8299 bool is_open = TreeNodeExV(str_id, 0, fmt, args); 8300 va_end(args); 8301 return is_open; 8302 } 8303 8304 bool ImGui::TreeNode(const void* ptr_id, const char* fmt, ...) 8305 { 8306 va_list args; 8307 va_start(args, fmt); 8308 bool is_open = TreeNodeExV(ptr_id, 0, fmt, args); 8309 va_end(args); 8310 return is_open; 8311 } 8312 8313 bool ImGui::TreeNode(const char* label) 8314 { 8315 ImGuiWindow* window = GetCurrentWindow(); 8316 if (window->SkipItems) 8317 return false; 8318 return TreeNodeBehavior(window->GetID(label), 0, label, NULL); 8319 } 8320 8321 void ImGui::TreeAdvanceToLabelPos() 8322 { 8323 ImGuiContext& g = *GImGui; 8324 g.CurrentWindow->DC.CursorPos.x += GetTreeNodeToLabelSpacing(); 8325 } 8326 8327 // Horizontal distance preceding label when using TreeNode() or Bullet() 8328 float ImGui::GetTreeNodeToLabelSpacing() 8329 { 8330 ImGuiContext& g = *GImGui; 8331 return g.FontSize + (g.Style.FramePadding.x * 2.0f); 8332 } 8333 8334 void ImGui::SetNextTreeNodeOpen(bool is_open, ImGuiCond cond) 8335 { 8336 ImGuiContext& g = *GImGui; 8337 if (g.CurrentWindow->SkipItems) 8338 return; 8339 g.NextTreeNodeOpenVal = is_open; 8340 g.NextTreeNodeOpenCond = cond ? cond : ImGuiCond_Always; 8341 } 8342 8343 void ImGui::PushID(const char* str_id) 8344 { 8345 ImGuiWindow* window = GetCurrentWindowRead(); 8346 window->IDStack.push_back(window->GetID(str_id)); 8347 } 8348 8349 void ImGui::PushID(const char* str_id_begin, const char* str_id_end) 8350 { 8351 ImGuiWindow* window = GetCurrentWindowRead(); 8352 window->IDStack.push_back(window->GetID(str_id_begin, str_id_end)); 8353 } 8354 8355 void ImGui::PushID(const void* ptr_id) 8356 { 8357 ImGuiWindow* window = GetCurrentWindowRead(); 8358 window->IDStack.push_back(window->GetID(ptr_id)); 8359 } 8360 8361 void ImGui::PushID(int int_id) 8362 { 8363 const void* ptr_id = (void*)(intptr_t)int_id; 8364 ImGuiWindow* window = GetCurrentWindowRead(); 8365 window->IDStack.push_back(window->GetID(ptr_id)); 8366 } 8367 8368 void ImGui::PopID() 8369 { 8370 ImGuiWindow* window = GetCurrentWindowRead(); 8371 window->IDStack.pop_back(); 8372 } 8373 8374 ImGuiID ImGui::GetID(const char* str_id) 8375 { 8376 return GImGui->CurrentWindow->GetID(str_id); 8377 } 8378 8379 ImGuiID ImGui::GetID(const char* str_id_begin, const char* str_id_end) 8380 { 8381 return GImGui->CurrentWindow->GetID(str_id_begin, str_id_end); 8382 } 8383 8384 ImGuiID ImGui::GetID(const void* ptr_id) 8385 { 8386 return GImGui->CurrentWindow->GetID(ptr_id); 8387 } 8388 8389 void ImGui::Bullet() 8390 { 8391 ImGuiWindow* window = GetCurrentWindow(); 8392 if (window->SkipItems) 8393 return; 8394 8395 ImGuiContext& g = *GImGui; 8396 const ImGuiStyle& style = g.Style; 8397 const float line_height = ImMax(ImMin(window->DC.CurrentLineHeight, g.FontSize + g.Style.FramePadding.y * 2), g.FontSize); 8398 const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize, line_height)); 8399 ItemSize(bb); 8400 if (!ItemAdd(bb, 0)) 8401 { 8402 SameLine(0, style.FramePadding.x * 2); 8403 return; 8404 } 8405 8406 // Render and stay on same line 8407 RenderBullet(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f)); 8408 SameLine(0, style.FramePadding.x * 2); 8409 } 8410 8411 // Text with a little bullet aligned to the typical tree node. 8412 void ImGui::BulletTextV(const char* fmt, va_list args) 8413 { 8414 ImGuiWindow* window = GetCurrentWindow(); 8415 if (window->SkipItems) 8416 return; 8417 8418 ImGuiContext& g = *GImGui; 8419 const ImGuiStyle& style = g.Style; 8420 8421 const char* text_begin = g.TempBuffer; 8422 const char* text_end = text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); 8423 const ImVec2 label_size = CalcTextSize(text_begin, text_end, false); 8424 const float text_base_offset_y = ImMax(0.0f, window->DC.CurrentLineTextBaseOffset); // Latch before ItemSize changes it 8425 const float line_height = ImMax(ImMin(window->DC.CurrentLineHeight, g.FontSize + g.Style.FramePadding.y * 2), g.FontSize); 8426 const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize + (label_size.x > 0.0f ? (label_size.x + style.FramePadding.x * 2) : 0.0f), ImMax(line_height, label_size.y))); // Empty text doesn't add padding 8427 ItemSize(bb); 8428 if (!ItemAdd(bb, 0)) 8429 return; 8430 8431 // Render 8432 RenderBullet(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f)); 8433 RenderText(bb.Min + ImVec2(g.FontSize + style.FramePadding.x * 2, text_base_offset_y), text_begin, text_end, false); 8434 } 8435 8436 void ImGui::BulletText(const char* fmt, ...) 8437 { 8438 va_list args; 8439 va_start(args, fmt); 8440 BulletTextV(fmt, args); 8441 va_end(args); 8442 } 8443 8444 static inline int DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* data_ptr, const char* format) 8445 { 8446 if (data_type == ImGuiDataType_Int32 || data_type == ImGuiDataType_Uint32) 8447 return ImFormatString(buf, buf_size, format, *(const int*)data_ptr); 8448 if (data_type == ImGuiDataType_Float) 8449 return ImFormatString(buf, buf_size, format, *(const float*)data_ptr); 8450 if (data_type == ImGuiDataType_Double) 8451 return ImFormatString(buf, buf_size, format, *(const double*)data_ptr); 8452 IM_ASSERT(0); 8453 return 0; 8454 } 8455 8456 static void DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, void* arg1, const void* arg2) 8457 { 8458 IM_ASSERT(op == '+' || op == '-'); 8459 if (data_type == ImGuiDataType_Int32) 8460 { 8461 if (op == '+') *(int*)output = *(const int*)arg1 + *(const int*)arg2; 8462 else if (op == '-') *(int*)output = *(const int*)arg1 - *(const int*)arg2; 8463 } 8464 else if (data_type == ImGuiDataType_Uint32) 8465 { 8466 if (op == '+') *(unsigned int*)output = *(const unsigned int*)arg1 + *(const unsigned int*)arg2; 8467 else if (op == '-') *(unsigned int*)output = *(const unsigned int*)arg1 - *(const unsigned int*)arg2; 8468 } 8469 else if (data_type == ImGuiDataType_Float) 8470 { 8471 if (op == '+') *(float*)output = *(const float*)arg1 + *(const float*)arg2; 8472 else if (op == '-') *(float*)output = *(const float*)arg1 - *(const float*)arg2; 8473 } 8474 else if (data_type == ImGuiDataType_Double) 8475 { 8476 if (op == '+') *(double*)output = *(const double*)arg1 + *(const double*)arg2; 8477 else if (op == '-') *(double*)output = *(const double*)arg1 - *(const double*)arg2; 8478 } 8479 } 8480 8481 static size_t GDataTypeSize[ImGuiDataType_COUNT] = 8482 { 8483 sizeof(int), 8484 sizeof(unsigned int), 8485 sizeof(float), 8486 sizeof(double) 8487 }; 8488 8489 // User can input math operators (e.g. +100) to edit a numerical values. 8490 // NB: This is _not_ a full expression evaluator. We should probably add one and replace this dumb mess.. 8491 static bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* data_ptr, const char* scalar_format) 8492 { 8493 while (ImCharIsSpace((unsigned int)*buf)) 8494 buf++; 8495 8496 // We don't support '-' op because it would conflict with inputing negative value. 8497 // Instead you can use +-100 to subtract from an existing value 8498 char op = buf[0]; 8499 if (op == '+' || op == '*' || op == '/') 8500 { 8501 buf++; 8502 while (ImCharIsSpace((unsigned int)*buf)) 8503 buf++; 8504 } 8505 else 8506 { 8507 op = 0; 8508 } 8509 if (!buf[0]) 8510 return false; 8511 8512 IM_ASSERT(data_type < ImGuiDataType_COUNT); 8513 int data_backup[2]; 8514 IM_ASSERT(GDataTypeSize[data_type] <= sizeof(data_backup)); 8515 memcpy(data_backup, data_ptr, GDataTypeSize[data_type]); 8516 8517 int arg1i = 0; 8518 float arg1f = 0.0f; 8519 if (data_type == ImGuiDataType_Int32) 8520 { 8521 if (!scalar_format) 8522 scalar_format = "%d"; 8523 int* v = (int*)data_ptr; 8524 int arg0i = *v; 8525 if (op && sscanf(initial_value_buf, scalar_format, &arg0i) < 1) 8526 return false; 8527 // Store operand in a float so we can use fractional value for multipliers (*1.1), but constant always parsed as integer so we can fit big integers (e.g. 2000000003) past float precision 8528 if (op == '+') { if (sscanf(buf, "%d", &arg1i)) *v = (int)(arg0i + arg1i); } // Add (use "+-" to subtract) 8529 else if (op == '*') { if (sscanf(buf, "%f", &arg1f)) *v = (int)(arg0i * arg1f); } // Multiply 8530 else if (op == '/') { if (sscanf(buf, "%f", &arg1f) && arg1f != 0.0f) *v = (int)(arg0i / arg1f); } // Divide 8531 else { if (sscanf(buf, scalar_format, &arg0i) == 1) *v = arg0i; } // Assign integer constant 8532 } 8533 else if (data_type == ImGuiDataType_Uint32) 8534 { 8535 if (!scalar_format) 8536 scalar_format = "%u"; 8537 ImU32* v = (unsigned int*)data_ptr; 8538 ImU32 arg0i = *v; 8539 if (op && sscanf(initial_value_buf, scalar_format, &arg0i) < 1) 8540 return false; 8541 // Store operand in a float so we can use fractional value for multipliers (*1.1), but constant always parsed as integer so we can fit big integers (e.g. 2000000003) past float precision 8542 if (op == '+') { if (sscanf(buf, "%d", &arg1i)) *v = (ImU32)(arg0i + arg1f); } // Add (use "+-" to subtract) 8543 else if (op == '*') { if (sscanf(buf, "%f", &arg1f)) *v = (ImU32)(arg0i * arg1f); } // Multiply 8544 else if (op == '/') { if (sscanf(buf, "%f", &arg1f) && arg1f != 0.0f) *v = (ImU32)(arg0i / arg1f); }// Divide 8545 else { if (sscanf(buf, scalar_format, &arg0i) == 1) *v = arg0i; } // Assign integer constant 8546 } 8547 else if (data_type == ImGuiDataType_Float) 8548 { 8549 // For floats we have to ignore format with precision (e.g. "%.2f") because sscanf doesn't take them in 8550 scalar_format = "%f"; 8551 float* v = (float*)data_ptr; 8552 float arg0f = *v; 8553 if (op && sscanf(initial_value_buf, scalar_format, &arg0f) < 1) 8554 return false; 8555 if (sscanf(buf, scalar_format, &arg1f) < 1) 8556 return false; 8557 if (op == '+') { *v = arg0f + arg1f; } // Add (use "+-" to subtract) 8558 else if (op == '*') { *v = arg0f * arg1f; } // Multiply 8559 else if (op == '/') { if (arg1f != 0.0f) *v = arg0f / arg1f; } // Divide 8560 else { *v = arg1f; } // Assign constant 8561 } 8562 else if (data_type == ImGuiDataType_Double) 8563 { 8564 scalar_format = "%lf"; // scanf differentiate float/double unlike printf which forces everything to double because of ellipsis 8565 double* v = (double*)data_ptr; 8566 double arg0f = *v; 8567 if (op && sscanf(initial_value_buf, scalar_format, &arg0f) < 1) 8568 return false; 8569 if (sscanf(buf, scalar_format, &arg1f) < 1) 8570 return false; 8571 if (op == '+') { *v = arg0f + arg1f; } // Add (use "+-" to subtract) 8572 else if (op == '*') { *v = arg0f * arg1f; } // Multiply 8573 else if (op == '/') { if (arg1f != 0.0f) *v = arg0f / arg1f; } // Divide 8574 else { *v = arg1f; } // Assign constant 8575 } 8576 return memcmp(data_backup, data_ptr, GDataTypeSize[data_type]) != 0; 8577 } 8578 8579 // Create text input in place of a slider (when CTRL+Clicking on slider) 8580 // FIXME: Logic is messy and confusing. 8581 bool ImGui::InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* data_ptr, const char* format) 8582 { 8583 ImGuiContext& g = *GImGui; 8584 ImGuiWindow* window = GetCurrentWindow(); 8585 8586 // Our replacement widget will override the focus ID (registered previously to allow for a TAB focus to happen) 8587 // On the first frame, g.ScalarAsInputTextId == 0, then on subsequent frames it becomes == id 8588 SetActiveID(g.ScalarAsInputTextId, window); 8589 g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); 8590 SetHoveredID(0); 8591 FocusableItemUnregister(window); 8592 8593 char fmt_buf[32]; 8594 char data_buf[32]; 8595 format = ParseFormatTrimDecorations(format, fmt_buf, IM_ARRAYSIZE(fmt_buf)); 8596 DataTypeFormatString(data_buf, IM_ARRAYSIZE(data_buf), data_type, data_ptr, format); 8597 ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ((data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) ? ImGuiInputTextFlags_CharsScientific : ImGuiInputTextFlags_CharsDecimal); 8598 bool value_changed = InputTextEx(label, data_buf, IM_ARRAYSIZE(data_buf), bb.GetSize(), flags); 8599 if (g.ScalarAsInputTextId == 0) // First frame we started displaying the InputText widget 8600 { 8601 IM_ASSERT(g.ActiveId == id); // InputText ID expected to match the Slider ID 8602 g.ScalarAsInputTextId = g.ActiveId; 8603 SetHoveredID(id); 8604 } 8605 if (value_changed) 8606 return DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialText.begin(), data_type, data_ptr, NULL); 8607 return false; 8608 } 8609 8610 const char* ImGui::ParseFormatTrimDecorationsLeading(const char* fmt) 8611 { 8612 while (char c = fmt[0]) 8613 { 8614 if (c == '%' && fmt[1] != '%') 8615 return fmt; 8616 else if (c == '%') 8617 fmt++; 8618 fmt++; 8619 } 8620 return fmt; 8621 } 8622 8623 // Extract the format out of a format string with leading or trailing decorations 8624 // fmt = "blah blah" -> return fmt 8625 // fmt = "%.3f" -> return fmt 8626 // fmt = "hello %.3f" -> return fmt + 6 8627 // fmt = "%.3f hello" -> return buf written with "%.3f" 8628 const char* ImGui::ParseFormatTrimDecorations(const char* fmt, char* buf, int buf_size) 8629 { 8630 // We don't use strchr() because our strings are usually very short and often start with '%' 8631 const char* fmt_start = ParseFormatTrimDecorationsLeading(fmt); 8632 if (fmt_start[0] != '%') 8633 return fmt; 8634 fmt = fmt_start; 8635 while (char c = *fmt++) 8636 { 8637 if (c >= 'A' && c <= 'Z' && (c != 'L')) // L is a type modifier, other letters qualify as types aka end of the format 8638 break; 8639 if (c >= 'a' && c <= 'z' && (c != 'h' && c != 'j' && c != 'l' && c != 't' && c != 'w' && c != 'z')) // h/j/l/t/w/z are type modifiers, other letters qualify as types aka end of the format 8640 break; 8641 } 8642 if (fmt[0] == 0) // If we only have leading decoration, we don't need to copy the data. 8643 return fmt_start; 8644 ImStrncpy(buf, fmt_start, ImMin((int)(fmt + 1 - fmt_start), buf_size)); 8645 return buf; 8646 } 8647 8648 // Parse display precision back from the display format string 8649 // FIXME: This is still used by some navigation code path to infer a minimum tweak step, but we should aim to rework widgets so it isn't needed. 8650 int ImGui::ParseFormatPrecision(const char* fmt, int default_precision) 8651 { 8652 fmt = ParseFormatTrimDecorationsLeading(fmt); 8653 if (fmt[0] != '%') 8654 return default_precision; 8655 fmt++; 8656 while (*fmt >= '0' && *fmt <= '9') 8657 fmt++; 8658 int precision = INT_MAX; 8659 if (*fmt == '.') 8660 { 8661 fmt = ImAtoi(fmt + 1, &precision); 8662 if (precision < 0 || precision > 99) 8663 precision = default_precision; 8664 } 8665 if (*fmt == 'e' || *fmt == 'E') // Maximum precision with scientific notation 8666 precision = -1; 8667 if ((*fmt == 'g' || *fmt == 'G') && precision == INT_MAX) 8668 precision = -1; 8669 return (precision == INT_MAX) ? default_precision : precision; 8670 } 8671 8672 static float GetMinimumStepAtDecimalPrecision(int decimal_precision) 8673 { 8674 static const float min_steps[10] = { 1.0f, 0.1f, 0.01f, 0.001f, 0.0001f, 0.00001f, 0.000001f, 0.0000001f, 0.00000001f, 0.000000001f }; 8675 return (decimal_precision >= 0 && decimal_precision < 10) ? min_steps[decimal_precision] : powf(10.0f, (float)-decimal_precision); 8676 } 8677 8678 float ImGui::RoundScalarWithFormat(const char* format, float value) 8679 { 8680 char buf[64]; 8681 ImFormatString(buf, IM_ARRAYSIZE(buf), ParseFormatTrimDecorationsLeading(format), value); 8682 return (float)atof(buf); 8683 } 8684 8685 static inline float SliderBehaviorCalcRatioFromValue(float v, float v_min, float v_max, float power, float linear_zero_pos) 8686 { 8687 if (v_min == v_max) 8688 return 0.0f; 8689 8690 const bool is_non_linear = (power < 1.0f - 0.00001f) || (power > 1.0f + 0.00001f); 8691 const float v_clamped = (v_min < v_max) ? ImClamp(v, v_min, v_max) : ImClamp(v, v_max, v_min); 8692 if (is_non_linear) 8693 { 8694 if (v_clamped < 0.0f) 8695 { 8696 const float f = 1.0f - (v_clamped - v_min) / (ImMin(0.0f, v_max) - v_min); 8697 return (1.0f - powf(f, 1.0f / power)) * linear_zero_pos; 8698 } 8699 else 8700 { 8701 const float f = (v_clamped - ImMax(0.0f, v_min)) / (v_max - ImMax(0.0f, v_min)); 8702 return linear_zero_pos + powf(f, 1.0f / power) * (1.0f - linear_zero_pos); 8703 } 8704 } 8705 8706 // Linear slider 8707 return (v_clamped - v_min) / (v_max - v_min); 8708 } 8709 8710 bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_min, float v_max, const char* format, float power, ImGuiSliderFlags flags) 8711 { 8712 ImGuiContext& g = *GImGui; 8713 ImGuiWindow* window = GetCurrentWindow(); 8714 const ImGuiStyle& style = g.Style; 8715 8716 // Draw frame 8717 const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); 8718 RenderNavHighlight(frame_bb, id); 8719 RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding); 8720 8721 const bool is_non_linear = (power < 1.0f - 0.00001f) || (power > 1.0f + 0.00001f); 8722 const bool is_horizontal = (flags & ImGuiSliderFlags_Vertical) == 0; 8723 const bool is_decimal = ParseFormatPrecision(format, 3) > 0; 8724 8725 const float grab_padding = 2.0f; 8726 const float slider_sz = is_horizontal ? (frame_bb.GetWidth() - grab_padding * 2.0f) : (frame_bb.GetHeight() - grab_padding * 2.0f); 8727 float grab_sz; 8728 if (is_decimal) 8729 grab_sz = ImMin(style.GrabMinSize, slider_sz); 8730 else 8731 grab_sz = ImMin(ImMax(1.0f * (slider_sz / ((v_min < v_max ? v_max - v_min : v_min - v_max) + 1.0f)), style.GrabMinSize), slider_sz); // Integer sliders, if possible have the grab size represent 1 unit 8732 const float slider_usable_sz = slider_sz - grab_sz; 8733 const float slider_usable_pos_min = (is_horizontal ? frame_bb.Min.x : frame_bb.Min.y) + grab_padding + grab_sz * 0.5f; 8734 const float slider_usable_pos_max = (is_horizontal ? frame_bb.Max.x : frame_bb.Max.y) - grab_padding - grab_sz * 0.5f; 8735 8736 // For logarithmic sliders that cross over sign boundary we want the exponential increase to be symmetric around 0.0f 8737 float linear_zero_pos = 0.0f; // 0.0->1.0f 8738 if (v_min * v_max < 0.0f) 8739 { 8740 // Different sign 8741 const float linear_dist_min_to_0 = powf(fabsf(0.0f - v_min), 1.0f / power); 8742 const float linear_dist_max_to_0 = powf(fabsf(v_max - 0.0f), 1.0f / power); 8743 linear_zero_pos = linear_dist_min_to_0 / (linear_dist_min_to_0 + linear_dist_max_to_0); 8744 } 8745 else 8746 { 8747 // Same sign 8748 linear_zero_pos = v_min < 0.0f ? 1.0f : 0.0f; 8749 } 8750 8751 // Process interacting with the slider 8752 bool value_changed = false; 8753 if (g.ActiveId == id) 8754 { 8755 bool set_new_value = false; 8756 float clicked_t = 0.0f; 8757 if (g.ActiveIdSource == ImGuiInputSource_Mouse) 8758 { 8759 if (!g.IO.MouseDown[0]) 8760 { 8761 ClearActiveID(); 8762 } 8763 else 8764 { 8765 const float mouse_abs_pos = is_horizontal ? g.IO.MousePos.x : g.IO.MousePos.y; 8766 clicked_t = (slider_usable_sz > 0.0f) ? ImClamp((mouse_abs_pos - slider_usable_pos_min) / slider_usable_sz, 0.0f, 1.0f) : 0.0f; 8767 if (!is_horizontal) 8768 clicked_t = 1.0f - clicked_t; 8769 set_new_value = true; 8770 } 8771 } 8772 else if (g.ActiveIdSource == ImGuiInputSource_Nav) 8773 { 8774 const ImVec2 delta2 = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard | ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_RepeatFast, 0.0f, 0.0f); 8775 float delta = is_horizontal ? delta2.x : -delta2.y; 8776 if (g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated) 8777 { 8778 ClearActiveID(); 8779 } 8780 else if (delta != 0.0f) 8781 { 8782 clicked_t = SliderBehaviorCalcRatioFromValue(*v, v_min, v_max, power, linear_zero_pos); 8783 if (!is_decimal && !is_non_linear) 8349 } 8350 } 8351 8352 // 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 8353 // are found, so it only augments the graph produced by the above method using extra links. (important, since it doesn't guarantee strong connectedness) 8354 // 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. 8355 // 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. 8356 // Disabling it may lead to disconnected graphs when nodes are very spaced out on different axis. Perhaps consider offering this as an option? 8357 if (result->DistBox == FLT_MAX && dist_axial < result->DistAxial) // Check axial match 8358 if (g.NavLayer == ImGuiNavLayer_Menu && !(g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu)) 8359 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)) 8784 8360 { 8785 if (fabsf(v_max - v_min) <= 100.0f || IsNavInputDown(ImGuiNavInput_TweakSlow)) 8786 delta = ((delta < 0.0f) ? -1.0f : +1.0f) / (v_max - v_min); // Gamepad/keyboard tweak speeds in integer steps 8787 else 8788 delta /= 100.0f; 8361 result->DistAxial = dist_axial; 8362 new_best = true; 8789 8363 } 8790 else 8364 8365 return new_best; 8366 } 8367 8368 // We get there when either NavId == id, or when g.NavAnyRequest is set (which is updated by NavUpdateAnyRequestFlag above) 8369 static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, const ImGuiID id) 8370 { 8371 ImGuiContext& g = *GImGui; 8372 //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. 8373 // return; 8374 8375 const ImGuiItemFlags item_flags = window->DC.ItemFlags; 8376 const ImRect nav_bb_rel(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos); 8377 8378 // Process Init Request 8379 if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent) 8380 { 8381 // Even if 'ImGuiItemFlags_NoNavDefaultFocus' is on (typically collapse/close button) we record the first ResultId so they can be used as a fallback 8382 if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus) || g.NavInitResultId == 0) 8383 { 8384 g.NavInitResultId = id; 8385 g.NavInitResultRectRel = nav_bb_rel; 8386 } 8387 if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus)) 8388 { 8389 g.NavInitRequest = false; // Found a match, clear request 8390 NavUpdateAnyRequestFlag(); 8391 } 8392 } 8393 8394 // Process Move Request (scoring for navigation) 8395 // FIXME-NAV: Consider policy for double scoring (scoring from NavScoringRectScreen + scoring from a rect wrapped according to current wrapping policy) 8396 if ((g.NavId != id || (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AllowCurrentNavId)) && !(item_flags & (ImGuiItemFlags_Disabled | ImGuiItemFlags_NoNav))) 8397 { 8398 ImGuiNavMoveResult* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther; 8399 #if IMGUI_DEBUG_NAV_SCORING 8400 // [DEBUG] Score all items in NavWindow at all times 8401 if (!g.NavMoveRequest) 8402 g.NavMoveDir = g.NavMoveDirLast; 8403 bool new_best = NavScoreItem(result, nav_bb) && g.NavMoveRequest; 8404 #else 8405 bool new_best = g.NavMoveRequest && NavScoreItem(result, nav_bb); 8406 #endif 8407 if (new_best) 8408 { 8409 result->Window = window; 8410 result->ID = id; 8411 result->FocusScopeId = window->DC.NavFocusScopeIdCurrent; 8412 result->RectRel = nav_bb_rel; 8413 } 8414 8415 // Features like PageUp/PageDown need to maintain a separate score for the visible set of items. 8416 const float VISIBLE_RATIO = 0.70f; 8417 if ((g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) && window->ClipRect.Overlaps(nav_bb)) 8418 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) 8419 if (NavScoreItem(&g.NavMoveResultLocalVisibleSet, nav_bb)) 8420 { 8421 result = &g.NavMoveResultLocalVisibleSet; 8422 result->Window = window; 8423 result->ID = id; 8424 result->FocusScopeId = window->DC.NavFocusScopeIdCurrent; 8425 result->RectRel = nav_bb_rel; 8426 } 8427 } 8428 8429 // Update window-relative bounding box of navigated item 8430 if (g.NavId == id) 8431 { 8432 g.NavWindow = window; // Always refresh g.NavWindow, because some operations such as FocusItem() don't have a window. 8433 g.NavLayer = window->DC.NavLayerCurrent; 8434 g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent; 8435 g.NavIdIsAlive = true; 8436 g.NavIdTabCounter = window->DC.FocusCounterTabStop; 8437 window->NavRectRel[window->DC.NavLayerCurrent] = nav_bb_rel; // Store item bounding box (relative to window position) 8438 } 8439 } 8440 8441 bool ImGui::NavMoveRequestButNoResultYet() 8442 { 8443 ImGuiContext& g = *GImGui; 8444 return g.NavMoveRequest && g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0; 8445 } 8446 8447 void ImGui::NavMoveRequestCancel() 8448 { 8449 ImGuiContext& g = *GImGui; 8450 g.NavMoveRequest = false; 8451 NavUpdateAnyRequestFlag(); 8452 } 8453 8454 void ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, const ImRect& bb_rel, ImGuiNavMoveFlags move_flags) 8455 { 8456 ImGuiContext& g = *GImGui; 8457 IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_None); 8458 NavMoveRequestCancel(); 8459 g.NavMoveDir = move_dir; 8460 g.NavMoveClipDir = clip_dir; 8461 g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued; 8462 g.NavMoveRequestFlags = move_flags; 8463 g.NavWindow->NavRectRel[g.NavLayer] = bb_rel; 8464 } 8465 8466 void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags) 8467 { 8468 ImGuiContext& g = *GImGui; 8469 8470 // Navigation wrap-around logic is delayed to the end of the frame because this operation is only valid after entire 8471 // popup is assembled and in case of appended popups it is not clear which EndPopup() call is final. 8472 g.NavWrapRequestWindow = window; 8473 g.NavWrapRequestFlags = move_flags; 8474 } 8475 8476 // FIXME: This could be replaced by updating a frame number in each window when (window == NavWindow) and (NavLayer == 0). 8477 // This way we could find the last focused window among our children. It would be much less confusing this way? 8478 static void ImGui::NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window) 8479 { 8480 ImGuiWindow* parent = nav_window; 8481 while (parent && (parent->Flags & ImGuiWindowFlags_ChildWindow) != 0 && (parent->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0) 8482 parent = parent->ParentWindow; 8483 if (parent && parent != nav_window) 8484 parent->NavLastChildNavWindow = nav_window; 8485 } 8486 8487 // Restore the last focused child. 8488 // Call when we are expected to land on the Main Layer (0) after FocusWindow() 8489 static ImGuiWindow* ImGui::NavRestoreLastChildNavWindow(ImGuiWindow* window) 8490 { 8491 if (window->NavLastChildNavWindow && window->NavLastChildNavWindow->WasActive) 8492 return window->NavLastChildNavWindow; 8493 return window; 8494 } 8495 8496 static void NavRestoreLayer(ImGuiNavLayer layer) 8497 { 8498 ImGuiContext& g = *GImGui; 8499 g.NavLayer = layer; 8500 if (layer == 0) 8501 g.NavWindow = ImGui::NavRestoreLastChildNavWindow(g.NavWindow); 8502 ImGuiWindow* window = g.NavWindow; 8503 if (layer == 0 && window->NavLastIds[0] != 0) 8504 ImGui::SetNavIDWithRectRel(window->NavLastIds[0], layer, 0, window->NavRectRel[0]); 8505 else 8506 ImGui::NavInitWindow(window, true); 8507 } 8508 8509 static inline void ImGui::NavUpdateAnyRequestFlag() 8510 { 8511 ImGuiContext& g = *GImGui; 8512 g.NavAnyRequest = g.NavMoveRequest || g.NavInitRequest || (IMGUI_DEBUG_NAV_SCORING && g.NavWindow != NULL); 8513 if (g.NavAnyRequest) 8514 IM_ASSERT(g.NavWindow != NULL); 8515 } 8516 8517 // This needs to be called before we submit any widget (aka in or before Begin) 8518 void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit) 8519 { 8520 ImGuiContext& g = *GImGui; 8521 IM_ASSERT(window == g.NavWindow); 8522 bool init_for_nav = false; 8523 if (!(window->Flags & ImGuiWindowFlags_NoNavInputs)) 8524 if (!(window->Flags & ImGuiWindowFlags_ChildWindow) || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit) 8525 init_for_nav = true; 8526 IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from NavInitWindow(), init_for_nav=%d, window=\"%s\", layer=%d\n", init_for_nav, window->Name, g.NavLayer); 8527 if (init_for_nav) 8528 { 8529 SetNavID(0, g.NavLayer, 0); 8530 g.NavInitRequest = true; 8531 g.NavInitRequestFromMove = false; 8532 g.NavInitResultId = 0; 8533 g.NavInitResultRectRel = ImRect(); 8534 NavUpdateAnyRequestFlag(); 8535 } 8536 else 8537 { 8538 g.NavId = window->NavLastIds[0]; 8539 g.NavFocusScopeId = 0; 8540 } 8541 } 8542 8543 static ImVec2 ImGui::NavCalcPreferredRefPos() 8544 { 8545 ImGuiContext& g = *GImGui; 8546 if (g.NavDisableHighlight || !g.NavDisableMouseHover || !g.NavWindow) 8547 { 8548 // Mouse (we need a fallback in case the mouse becomes invalid after being used) 8549 if (IsMousePosValid(&g.IO.MousePos)) 8550 return g.IO.MousePos; 8551 return g.LastValidMousePos; 8552 } 8553 else 8554 { 8555 // When navigation is active and mouse is disabled, decide on an arbitrary position around the bottom left of the currently navigated item. 8556 const ImRect& rect_rel = g.NavWindow->NavRectRel[g.NavLayer]; 8557 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())); 8558 ImRect visible_rect = GetViewportRect(); 8559 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. 8560 } 8561 } 8562 8563 float ImGui::GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode) 8564 { 8565 ImGuiContext& g = *GImGui; 8566 if (mode == ImGuiInputReadMode_Down) 8567 return g.IO.NavInputs[n]; // Instant, read analog input (0.0f..1.0f, as provided by user) 8568 8569 const float t = g.IO.NavInputsDownDuration[n]; 8570 if (t < 0.0f && mode == ImGuiInputReadMode_Released) // Return 1.0f when just released, no repeat, ignore analog input. 8571 return (g.IO.NavInputsDownDurationPrev[n] >= 0.0f ? 1.0f : 0.0f); 8572 if (t < 0.0f) 8573 return 0.0f; 8574 if (mode == ImGuiInputReadMode_Pressed) // Return 1.0f when just pressed, no repeat, ignore analog input. 8575 return (t == 0.0f) ? 1.0f : 0.0f; 8576 if (mode == ImGuiInputReadMode_Repeat) 8577 return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 0.72f, g.IO.KeyRepeatRate * 0.80f); 8578 if (mode == ImGuiInputReadMode_RepeatSlow) 8579 return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 1.25f, g.IO.KeyRepeatRate * 2.00f); 8580 if (mode == ImGuiInputReadMode_RepeatFast) 8581 return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 0.72f, g.IO.KeyRepeatRate * 0.30f); 8582 return 0.0f; 8583 } 8584 8585 ImVec2 ImGui::GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor, float fast_factor) 8586 { 8587 ImVec2 delta(0.0f, 0.0f); 8588 if (dir_sources & ImGuiNavDirSourceFlags_Keyboard) 8589 delta += ImVec2(GetNavInputAmount(ImGuiNavInput_KeyRight_, mode) - GetNavInputAmount(ImGuiNavInput_KeyLeft_, mode), GetNavInputAmount(ImGuiNavInput_KeyDown_, mode) - GetNavInputAmount(ImGuiNavInput_KeyUp_, mode)); 8590 if (dir_sources & ImGuiNavDirSourceFlags_PadDPad) 8591 delta += ImVec2(GetNavInputAmount(ImGuiNavInput_DpadRight, mode) - GetNavInputAmount(ImGuiNavInput_DpadLeft, mode), GetNavInputAmount(ImGuiNavInput_DpadDown, mode) - GetNavInputAmount(ImGuiNavInput_DpadUp, mode)); 8592 if (dir_sources & ImGuiNavDirSourceFlags_PadLStick) 8593 delta += ImVec2(GetNavInputAmount(ImGuiNavInput_LStickRight, mode) - GetNavInputAmount(ImGuiNavInput_LStickLeft, mode), GetNavInputAmount(ImGuiNavInput_LStickDown, mode) - GetNavInputAmount(ImGuiNavInput_LStickUp, mode)); 8594 if (slow_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakSlow)) 8595 delta *= slow_factor; 8596 if (fast_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakFast)) 8597 delta *= fast_factor; 8598 return delta; 8599 } 8600 8601 static void ImGui::NavUpdate() 8602 { 8603 ImGuiContext& g = *GImGui; 8604 ImGuiIO& io = g.IO; 8605 8606 io.WantSetMousePos = false; 8607 g.NavWrapRequestWindow = NULL; 8608 g.NavWrapRequestFlags = ImGuiNavMoveFlags_None; 8609 #if 0 8610 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); 8611 #endif 8612 8613 // Set input source as Gamepad when buttons are pressed (as some features differs when used with Gamepad vs Keyboard) 8614 // (do it before we map Keyboard input!) 8615 bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; 8616 bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; 8617 if (nav_gamepad_active && g.NavInputSource != ImGuiInputSource_NavGamepad) 8618 { 8619 if (io.NavInputs[ImGuiNavInput_Activate] > 0.0f || io.NavInputs[ImGuiNavInput_Input] > 0.0f || io.NavInputs[ImGuiNavInput_Cancel] > 0.0f || io.NavInputs[ImGuiNavInput_Menu] > 0.0f 8620 || io.NavInputs[ImGuiNavInput_DpadLeft] > 0.0f || io.NavInputs[ImGuiNavInput_DpadRight] > 0.0f || io.NavInputs[ImGuiNavInput_DpadUp] > 0.0f || io.NavInputs[ImGuiNavInput_DpadDown] > 0.0f) 8621 g.NavInputSource = ImGuiInputSource_NavGamepad; 8622 } 8623 8624 // Update Keyboard->Nav inputs mapping 8625 if (nav_keyboard_active) 8626 { 8627 #define NAV_MAP_KEY(_KEY, _NAV_INPUT) do { if (IsKeyDown(io.KeyMap[_KEY])) { io.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_NavKeyboard; } } while (0) 8628 NAV_MAP_KEY(ImGuiKey_Space, ImGuiNavInput_Activate ); 8629 NAV_MAP_KEY(ImGuiKey_Enter, ImGuiNavInput_Input ); 8630 NAV_MAP_KEY(ImGuiKey_Escape, ImGuiNavInput_Cancel ); 8631 NAV_MAP_KEY(ImGuiKey_LeftArrow, ImGuiNavInput_KeyLeft_ ); 8632 NAV_MAP_KEY(ImGuiKey_RightArrow,ImGuiNavInput_KeyRight_); 8633 NAV_MAP_KEY(ImGuiKey_UpArrow, ImGuiNavInput_KeyUp_ ); 8634 NAV_MAP_KEY(ImGuiKey_DownArrow, ImGuiNavInput_KeyDown_ ); 8635 if (io.KeyCtrl) 8636 io.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f; 8637 if (io.KeyShift) 8638 io.NavInputs[ImGuiNavInput_TweakFast] = 1.0f; 8639 if (io.KeyAlt && !io.KeyCtrl) // AltGR is Alt+Ctrl, also even on keyboards without AltGR we don't want Alt+Ctrl to open menu. 8640 io.NavInputs[ImGuiNavInput_KeyMenu_] = 1.0f; 8641 #undef NAV_MAP_KEY 8642 } 8643 memcpy(io.NavInputsDownDurationPrev, io.NavInputsDownDuration, sizeof(io.NavInputsDownDuration)); 8644 for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) 8645 io.NavInputsDownDuration[i] = (io.NavInputs[i] > 0.0f) ? (io.NavInputsDownDuration[i] < 0.0f ? 0.0f : io.NavInputsDownDuration[i] + io.DeltaTime) : -1.0f; 8646 8647 // Process navigation init request (select first/default focus) 8648 if (g.NavInitResultId != 0 && (!g.NavDisableHighlight || g.NavInitRequestFromMove)) 8649 NavUpdateInitResult(); 8650 g.NavInitRequest = false; 8651 g.NavInitRequestFromMove = false; 8652 g.NavInitResultId = 0; 8653 g.NavJustMovedToId = 0; 8654 8655 // Process navigation move request 8656 if (g.NavMoveRequest) 8657 NavUpdateMoveResult(); 8658 8659 // When a forwarded move request failed, we restore the highlight that we disabled during the forward frame 8660 if (g.NavMoveRequestForward == ImGuiNavForward_ForwardActive) 8661 { 8662 IM_ASSERT(g.NavMoveRequest); 8663 if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0) 8664 g.NavDisableHighlight = false; 8665 g.NavMoveRequestForward = ImGuiNavForward_None; 8666 } 8667 8668 // Apply application mouse position movement, after we had a chance to process move request result. 8669 if (g.NavMousePosDirty && g.NavIdIsAlive) 8670 { 8671 // Set mouse position given our knowledge of the navigated item position from last frame 8672 if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) && (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos)) 8673 { 8674 if (!g.NavDisableHighlight && g.NavDisableMouseHover && g.NavWindow) 8791 8675 { 8792 delta /= 100.0f; // Gamepad/keyboard tweak speeds in % of slider bounds 8793 if (IsNavInputDown(ImGuiNavInput_TweakSlow)) 8794 delta /= 10.0f; 8676 io.MousePos = io.MousePosPrev = NavCalcPreferredRefPos(); 8677 io.WantSetMousePos = true; 8795 8678 } 8796 if (IsNavInputDown(ImGuiNavInput_TweakFast)) 8797 delta *= 10.0f; 8798 set_new_value = true; 8799 if ((clicked_t >= 1.0f && delta > 0.0f) || (clicked_t <= 0.0f && delta < 0.0f)) // This is to avoid applying the saturation when already past the limits 8800 set_new_value = false; 8801 else 8802 clicked_t = ImSaturate(clicked_t + delta); 8803 } 8804 } 8805 8806 if (set_new_value) 8807 { 8808 float new_value; 8809 if (is_non_linear) 8810 { 8811 // Account for logarithmic scale on both sides of the zero 8812 if (clicked_t < linear_zero_pos) 8679 } 8680 g.NavMousePosDirty = false; 8681 } 8682 g.NavIdIsAlive = false; 8683 g.NavJustTabbedId = 0; 8684 IM_ASSERT(g.NavLayer == 0 || g.NavLayer == 1); 8685 8686 // 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 8687 if (g.NavWindow) 8688 NavSaveLastChildNavWindowIntoParent(g.NavWindow); 8689 if (g.NavWindow && g.NavWindow->NavLastChildNavWindow != NULL && g.NavLayer == ImGuiNavLayer_Main) 8690 g.NavWindow->NavLastChildNavWindow = NULL; 8691 8692 // Update CTRL+TAB and Windowing features (hold Square to move/resize/etc.) 8693 NavUpdateWindowing(); 8694 8695 // Set output flags for user application 8696 io.NavActive = (nav_keyboard_active || nav_gamepad_active) && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs); 8697 io.NavVisible = (io.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL); 8698 8699 // Process NavCancel input (to close a popup, get back to parent, clear focus) 8700 if (IsNavInputTest(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed)) 8701 { 8702 IMGUI_DEBUG_LOG_NAV("[nav] ImGuiNavInput_Cancel\n"); 8703 if (g.ActiveId != 0) 8704 { 8705 if (!IsActiveIdUsingNavInput(ImGuiNavInput_Cancel)) 8706 ClearActiveID(); 8707 } 8708 else if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow) && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow) 8709 { 8710 // Exit child window 8711 ImGuiWindow* child_window = g.NavWindow; 8712 ImGuiWindow* parent_window = g.NavWindow->ParentWindow; 8713 IM_ASSERT(child_window->ChildId != 0); 8714 FocusWindow(parent_window); 8715 SetNavID(child_window->ChildId, 0, 0); 8716 // Reassigning with same value, we're being explicit here. 8717 g.NavIdIsAlive = false; // -V1048 8718 if (g.NavDisableMouseHover) 8719 g.NavMousePosDirty = true; 8720 } 8721 else if (g.OpenPopupStack.Size > 0) 8722 { 8723 // Close open popup/menu 8724 if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal)) 8725 ClosePopupToLevel(g.OpenPopupStack.Size - 1, true); 8726 } 8727 else if (g.NavLayer != ImGuiNavLayer_Main) 8728 { 8729 // Leave the "menu" layer 8730 NavRestoreLayer(ImGuiNavLayer_Main); 8731 } 8732 else 8733 { 8734 // Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were 8735 if (g.NavWindow && ((g.NavWindow->Flags & ImGuiWindowFlags_Popup) || !(g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow))) 8736 g.NavWindow->NavLastIds[0] = 0; 8737 g.NavId = g.NavFocusScopeId = 0; 8738 } 8739 } 8740 8741 // Process manual activation request 8742 g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = 0; 8743 if (g.NavId != 0 && !g.NavDisableHighlight && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) 8744 { 8745 bool activate_down = IsNavInputDown(ImGuiNavInput_Activate); 8746 bool activate_pressed = activate_down && IsNavInputTest(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed); 8747 if (g.ActiveId == 0 && activate_pressed) 8748 g.NavActivateId = g.NavId; 8749 if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_down) 8750 g.NavActivateDownId = g.NavId; 8751 if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_pressed) 8752 g.NavActivatePressedId = g.NavId; 8753 if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && IsNavInputTest(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed)) 8754 g.NavInputId = g.NavId; 8755 } 8756 if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) 8757 g.NavDisableHighlight = true; 8758 if (g.NavActivateId != 0) 8759 IM_ASSERT(g.NavActivateDownId == g.NavActivateId); 8760 g.NavMoveRequest = false; 8761 8762 // Process programmatic activation request 8763 if (g.NavNextActivateId != 0) 8764 g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = g.NavNextActivateId; 8765 g.NavNextActivateId = 0; 8766 8767 // Initiate directional inputs request 8768 if (g.NavMoveRequestForward == ImGuiNavForward_None) 8769 { 8770 g.NavMoveDir = ImGuiDir_None; 8771 g.NavMoveRequestFlags = ImGuiNavMoveFlags_None; 8772 if (g.NavWindow && !g.NavWindowingTarget && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) 8773 { 8774 const ImGuiInputReadMode read_mode = ImGuiInputReadMode_Repeat; 8775 if (!IsActiveIdUsingNavDir(ImGuiDir_Left) && (IsNavInputTest(ImGuiNavInput_DpadLeft, read_mode) || IsNavInputTest(ImGuiNavInput_KeyLeft_, read_mode))) { g.NavMoveDir = ImGuiDir_Left; } 8776 if (!IsActiveIdUsingNavDir(ImGuiDir_Right) && (IsNavInputTest(ImGuiNavInput_DpadRight, read_mode) || IsNavInputTest(ImGuiNavInput_KeyRight_, read_mode))) { g.NavMoveDir = ImGuiDir_Right; } 8777 if (!IsActiveIdUsingNavDir(ImGuiDir_Up) && (IsNavInputTest(ImGuiNavInput_DpadUp, read_mode) || IsNavInputTest(ImGuiNavInput_KeyUp_, read_mode))) { g.NavMoveDir = ImGuiDir_Up; } 8778 if (!IsActiveIdUsingNavDir(ImGuiDir_Down) && (IsNavInputTest(ImGuiNavInput_DpadDown, read_mode) || IsNavInputTest(ImGuiNavInput_KeyDown_, read_mode))) { g.NavMoveDir = ImGuiDir_Down; } 8779 } 8780 g.NavMoveClipDir = g.NavMoveDir; 8781 } 8782 else 8783 { 8784 // 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) 8785 // (Preserve g.NavMoveRequestFlags, g.NavMoveClipDir which were set by the NavMoveRequestForward() function) 8786 IM_ASSERT(g.NavMoveDir != ImGuiDir_None && g.NavMoveClipDir != ImGuiDir_None); 8787 IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_ForwardQueued); 8788 IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequestForward %d\n", g.NavMoveDir); 8789 g.NavMoveRequestForward = ImGuiNavForward_ForwardActive; 8790 } 8791 8792 // Update PageUp/PageDown/Home/End scroll 8793 // FIXME-NAV: Consider enabling those keys even without the master ImGuiConfigFlags_NavEnableKeyboard flag? 8794 float nav_scoring_rect_offset_y = 0.0f; 8795 if (nav_keyboard_active) 8796 nav_scoring_rect_offset_y = NavUpdatePageUpPageDown(); 8797 8798 // 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 8799 if (g.NavMoveDir != ImGuiDir_None) 8800 { 8801 g.NavMoveRequest = true; 8802 g.NavMoveRequestKeyMods = io.KeyMods; 8803 g.NavMoveDirLast = g.NavMoveDir; 8804 } 8805 if (g.NavMoveRequest && g.NavId == 0) 8806 { 8807 IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", layer=%d\n", g.NavWindow->Name, g.NavLayer); 8808 g.NavInitRequest = g.NavInitRequestFromMove = true; 8809 // Reassigning with same value, we're being explicit here. 8810 g.NavInitResultId = 0; // -V1048 8811 g.NavDisableHighlight = false; 8812 } 8813 NavUpdateAnyRequestFlag(); 8814 8815 // Scrolling 8816 if (g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget) 8817 { 8818 // *Fallback* manual-scroll with Nav directional keys when window has no navigable item 8819 ImGuiWindow* window = g.NavWindow; 8820 const float scroll_speed = IM_ROUND(window->CalcFontSize() * 100 * io.DeltaTime); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported. 8821 if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest) 8822 { 8823 if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) 8824 SetScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed)); 8825 if (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) 8826 SetScrollY(window, ImFloor(window->Scroll.y + ((g.NavMoveDir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed)); 8827 } 8828 8829 // *Normal* Manual scroll with NavScrollXXX keys 8830 // Next movement request will clamp the NavId reference rectangle to the visible area, so navigation will resume within those bounds. 8831 ImVec2 scroll_dir = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down, 1.0f / 10.0f, 10.0f); 8832 if (scroll_dir.x != 0.0f && window->ScrollbarX) 8833 SetScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed)); 8834 if (scroll_dir.y != 0.0f) 8835 SetScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed)); 8836 } 8837 8838 // Reset search results 8839 g.NavMoveResultLocal.Clear(); 8840 g.NavMoveResultLocalVisibleSet.Clear(); 8841 g.NavMoveResultOther.Clear(); 8842 8843 // When using gamepad, we project the reference nav bounding box into window visible area. 8844 // This is to allow resuming navigation inside the visible area after doing a large amount of scrolling, since with gamepad every movements are relative 8845 // (can't focus a visible object like we can with the mouse). 8846 if (g.NavMoveRequest && g.NavInputSource == ImGuiInputSource_NavGamepad && g.NavLayer == ImGuiNavLayer_Main) 8847 { 8848 ImGuiWindow* window = g.NavWindow; 8849 ImRect window_rect_rel(window->InnerRect.Min - window->Pos - ImVec2(1, 1), window->InnerRect.Max - window->Pos + ImVec2(1, 1)); 8850 if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer])) 8851 { 8852 IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: clamp NavRectRel\n"); 8853 float pad = window->CalcFontSize() * 0.5f; 8854 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 8855 window->NavRectRel[g.NavLayer].ClipWithFull(window_rect_rel); 8856 g.NavId = g.NavFocusScopeId = 0; 8857 } 8858 } 8859 8860 // 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) 8861 ImRect nav_rect_rel = g.NavWindow ? g.NavWindow->NavRectRel[g.NavLayer] : ImRect(0, 0, 0, 0); 8862 g.NavScoringRect = g.NavWindow ? ImRect(g.NavWindow->Pos + nav_rect_rel.Min, g.NavWindow->Pos + nav_rect_rel.Max) : GetViewportRect(); 8863 g.NavScoringRect.TranslateY(nav_scoring_rect_offset_y); 8864 g.NavScoringRect.Min.x = ImMin(g.NavScoringRect.Min.x + 1.0f, g.NavScoringRect.Max.x); 8865 g.NavScoringRect.Max.x = g.NavScoringRect.Min.x; 8866 IM_ASSERT(!g.NavScoringRect.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allows us to remove extraneous ImFabs() calls in NavScoreItem(). 8867 //GetForegroundDrawList()->AddRect(g.NavScoringRectScreen.Min, g.NavScoringRectScreen.Max, IM_COL32(255,200,0,255)); // [DEBUG] 8868 g.NavScoringCount = 0; 8869 #if IMGUI_DEBUG_NAV_RECTS 8870 if (g.NavWindow) 8871 { 8872 ImDrawList* draw_list = GetForegroundDrawList(g.NavWindow); 8873 if (1) { for (int layer = 0; layer < 2; layer++) draw_list->AddRect(g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Min, g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Max, IM_COL32(255,200,0,255)); } // [DEBUG] 8874 if (1) { 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); draw_list->AddCircleFilled(p, 3.0f, col); draw_list->AddText(NULL, 13.0f, p + ImVec2(8,-4), col, buf); } 8875 } 8876 #endif 8877 } 8878 8879 static void ImGui::NavUpdateInitResult() 8880 { 8881 // In very rare cases g.NavWindow may be null (e.g. clearing focus after requesting an init request, which does happen when releasing Alt while clicking on void) 8882 ImGuiContext& g = *GImGui; 8883 if (!g.NavWindow) 8884 return; 8885 8886 // Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called) 8887 IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", g.NavInitResultId, g.NavLayer, g.NavWindow->Name); 8888 if (g.NavInitRequestFromMove) 8889 SetNavIDWithRectRel(g.NavInitResultId, g.NavLayer, 0, g.NavInitResultRectRel); 8890 else 8891 SetNavID(g.NavInitResultId, g.NavLayer, 0); 8892 g.NavWindow->NavRectRel[g.NavLayer] = g.NavInitResultRectRel; 8893 } 8894 8895 // Apply result from previous frame navigation directional move request 8896 static void ImGui::NavUpdateMoveResult() 8897 { 8898 ImGuiContext& g = *GImGui; 8899 if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0) 8900 { 8901 // 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) 8902 if (g.NavId != 0) 8903 { 8904 g.NavDisableHighlight = false; 8905 g.NavDisableMouseHover = true; 8906 } 8907 return; 8908 } 8909 8910 // Select which result to use 8911 ImGuiNavMoveResult* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : &g.NavMoveResultOther; 8912 8913 // PageUp/PageDown behavior first jumps to the bottom/top mostly visible item, _otherwise_ use the result from the previous/next page. 8914 if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) 8915 if (g.NavMoveResultLocalVisibleSet.ID != 0 && g.NavMoveResultLocalVisibleSet.ID != g.NavId) 8916 result = &g.NavMoveResultLocalVisibleSet; 8917 8918 // Maybe entering a flattened child from the outside? In this case solve the tie using the regular scoring rules. 8919 if (result != &g.NavMoveResultOther && g.NavMoveResultOther.ID != 0 && g.NavMoveResultOther.Window->ParentWindow == g.NavWindow) 8920 if ((g.NavMoveResultOther.DistBox < result->DistBox) || (g.NavMoveResultOther.DistBox == result->DistBox && g.NavMoveResultOther.DistCenter < result->DistCenter)) 8921 result = &g.NavMoveResultOther; 8922 IM_ASSERT(g.NavWindow && result->Window); 8923 8924 // Scroll to keep newly navigated item fully into view. 8925 if (g.NavLayer == ImGuiNavLayer_Main) 8926 { 8927 ImVec2 delta_scroll; 8928 if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_ScrollToEdge) 8929 { 8930 float scroll_target = (g.NavMoveDir == ImGuiDir_Up) ? result->Window->ScrollMax.y : 0.0f; 8931 delta_scroll.y = result->Window->Scroll.y - scroll_target; 8932 SetScrollY(result->Window, scroll_target); 8933 } 8934 else 8935 { 8936 ImRect rect_abs = ImRect(result->RectRel.Min + result->Window->Pos, result->RectRel.Max + result->Window->Pos); 8937 delta_scroll = ScrollToBringRectIntoView(result->Window, rect_abs); 8938 } 8939 8940 // Offset our result position so mouse position can be applied immediately after in NavUpdate() 8941 result->RectRel.TranslateX(-delta_scroll.x); 8942 result->RectRel.TranslateY(-delta_scroll.y); 8943 } 8944 8945 ClearActiveID(); 8946 g.NavWindow = result->Window; 8947 if (g.NavId != result->ID) 8948 { 8949 // Don't set NavJustMovedToId if just landed on the same spot (which may happen with ImGuiNavMoveFlags_AllowCurrentNavId) 8950 g.NavJustMovedToId = result->ID; 8951 g.NavJustMovedToFocusScopeId = result->FocusScopeId; 8952 g.NavJustMovedToKeyMods = g.NavMoveRequestKeyMods; 8953 } 8954 IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", result->ID, g.NavLayer, g.NavWindow->Name); 8955 SetNavIDWithRectRel(result->ID, g.NavLayer, result->FocusScopeId, result->RectRel); 8956 } 8957 8958 // Handle PageUp/PageDown/Home/End keys 8959 static float ImGui::NavUpdatePageUpPageDown() 8960 { 8961 ImGuiContext& g = *GImGui; 8962 ImGuiIO& io = g.IO; 8963 8964 if (g.NavMoveDir != ImGuiDir_None || g.NavWindow == NULL) 8965 return 0.0f; 8966 if ((g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) || g.NavWindowingTarget != NULL || g.NavLayer != ImGuiNavLayer_Main) 8967 return 0.0f; 8968 8969 ImGuiWindow* window = g.NavWindow; 8970 const bool page_up_held = IsKeyDown(io.KeyMap[ImGuiKey_PageUp]) && !IsActiveIdUsingKey(ImGuiKey_PageUp); 8971 const bool page_down_held = IsKeyDown(io.KeyMap[ImGuiKey_PageDown]) && !IsActiveIdUsingKey(ImGuiKey_PageDown); 8972 const bool home_pressed = IsKeyPressed(io.KeyMap[ImGuiKey_Home]) && !IsActiveIdUsingKey(ImGuiKey_Home); 8973 const bool end_pressed = IsKeyPressed(io.KeyMap[ImGuiKey_End]) && !IsActiveIdUsingKey(ImGuiKey_End); 8974 if (page_up_held != page_down_held || home_pressed != end_pressed) // If either (not both) are pressed 8975 { 8976 if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll) 8977 { 8978 // Fallback manual-scroll when window has no navigable item 8979 if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true)) 8980 SetScrollY(window, window->Scroll.y - window->InnerRect.GetHeight()); 8981 else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true)) 8982 SetScrollY(window, window->Scroll.y + window->InnerRect.GetHeight()); 8983 else if (home_pressed) 8984 SetScrollY(window, 0.0f); 8985 else if (end_pressed) 8986 SetScrollY(window, window->ScrollMax.y); 8987 } 8988 else 8989 { 8990 ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer]; 8991 const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight()); 8992 float nav_scoring_rect_offset_y = 0.0f; 8993 if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true)) 8813 8994 { 8814 // Negative: rescale to the negative range before powering8815 float a = 1.0f - (clicked_t / linear_zero_pos);8816 a = powf(a, power);8817 new_value = ImLerp(ImMin(v_max, 0.0f), v_min, a);8995 nav_scoring_rect_offset_y = -page_offset_y; 8996 g.NavMoveDir = ImGuiDir_Down; // Because our scoring rect is offset up, we request the down direction (so we can always land on the last item) 8997 g.NavMoveClipDir = ImGuiDir_Up; 8998 g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet; 8818 8999 } 8819 else 9000 else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true)) 8820 9001 { 8821 // Positive: rescale to the positive range before powering 8822 float a; 8823 if (fabsf(linear_zero_pos - 1.0f) > 1.e-6f) 8824 a = (clicked_t - linear_zero_pos) / (1.0f - linear_zero_pos); 8825 else 8826 a = clicked_t; 8827 a = powf(a, power); 8828 new_value = ImLerp(ImMax(v_min, 0.0f), v_max, a); 9002 nav_scoring_rect_offset_y = +page_offset_y; 9003 g.NavMoveDir = ImGuiDir_Up; // Because our scoring rect is offset down, we request the up direction (so we can always land on the last item) 9004 g.NavMoveClipDir = ImGuiDir_Down; 9005 g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet; 8829 9006 } 8830 } 8831 else 8832 { 8833 // Linear slider 8834 new_value = ImLerp(v_min, v_max, clicked_t); 8835 } 8836 8837 // Round past decimal precision 8838 new_value = RoundScalarWithFormat(format, new_value); 8839 if (*v != new_value) 8840 { 8841 *v = new_value; 8842 value_changed = true; 8843 } 8844 } 8845 } 8846 8847 // Draw 8848 float grab_t = SliderBehaviorCalcRatioFromValue(*v, v_min, v_max, power, linear_zero_pos); 8849 if (!is_horizontal) 8850 grab_t = 1.0f - grab_t; 8851 const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t); 8852 ImRect grab_bb; 8853 if (is_horizontal) 8854 grab_bb = ImRect(ImVec2(grab_pos - grab_sz * 0.5f, frame_bb.Min.y + grab_padding), ImVec2(grab_pos + grab_sz * 0.5f, frame_bb.Max.y - grab_padding)); 8855 else 8856 grab_bb = ImRect(ImVec2(frame_bb.Min.x + grab_padding, grab_pos - grab_sz * 0.5f), ImVec2(frame_bb.Max.x - grab_padding, grab_pos + grab_sz * 0.5f)); 8857 window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, GetColorU32(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding); 8858 8859 return value_changed; 8860 } 8861 8862 // Use power!=1.0 for logarithmic sliders. 8863 // Adjust format to decorate the value with a prefix or a suffix. 8864 // "%.3f" 1.234 8865 // "%5.2f secs" 01.23 secs 8866 // "Gold: %.0f" Gold: 1 8867 bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, float power) 8868 { 8869 ImGuiWindow* window = GetCurrentWindow(); 8870 if (window->SkipItems) 8871 return false; 8872 8873 ImGuiContext& g = *GImGui; 8874 const ImGuiStyle& style = g.Style; 8875 const ImGuiID id = window->GetID(label); 8876 const float w = CalcItemWidth(); 8877 8878 const ImVec2 label_size = CalcTextSize(label, NULL, true); 8879 const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f)); 8880 const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); 8881 8882 // NB- we don't call ItemSize() yet because we may turn into a text edit box below 8883 if (!ItemAdd(total_bb, id, &frame_bb)) 8884 { 8885 ItemSize(total_bb, style.FramePadding.y); 8886 return false; 8887 } 8888 const bool hovered = ItemHoverable(frame_bb, id); 8889 8890 if (!format) 8891 format = "%.3f"; 8892 8893 // Tabbing or CTRL-clicking on Slider turns it into an input box 8894 bool start_text_input = false; 8895 const bool tab_focus_requested = FocusableItemRegister(window, id); 8896 if (tab_focus_requested || (hovered && g.IO.MouseClicked[0]) || g.NavActivateId == id || (g.NavInputId == id && g.ScalarAsInputTextId != id)) 8897 { 8898 SetActiveID(id, window); 8899 SetFocusID(id, window); 8900 FocusWindow(window); 8901 g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); 8902 if (tab_focus_requested || g.IO.KeyCtrl || g.NavInputId == id) 8903 { 8904 start_text_input = true; 8905 g.ScalarAsInputTextId = 0; 8906 } 8907 } 8908 if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id)) 8909 return InputScalarAsWidgetReplacement(frame_bb, id, label, ImGuiDataType_Float, v, format); 8910 8911 // Actual slider behavior + render grab 8912 ItemSize(total_bb, style.FramePadding.y); 8913 const bool value_changed = SliderBehavior(frame_bb, id, v, v_min, v_max, format, power); 8914 8915 // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. 8916 char value_buf[64]; 8917 const char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), format, *v); 8918 RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f)); 8919 8920 if (label_size.x > 0.0f) 8921 RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); 8922 8923 return value_changed; 8924 } 8925 8926 bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format, float power) 8927 { 8928 ImGuiWindow* window = GetCurrentWindow(); 8929 if (window->SkipItems) 8930 return false; 8931 8932 ImGuiContext& g = *GImGui; 8933 const ImGuiStyle& style = g.Style; 8934 const ImGuiID id = window->GetID(label); 8935 8936 const ImVec2 label_size = CalcTextSize(label, NULL, true); 8937 const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size); 8938 const ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); 8939 8940 ItemSize(bb, style.FramePadding.y); 8941 if (!ItemAdd(frame_bb, id)) 8942 return false; 8943 const bool hovered = ItemHoverable(frame_bb, id); 8944 8945 if (!format) 8946 format = "%.3f"; 8947 8948 if ((hovered && g.IO.MouseClicked[0]) || g.NavActivateId == id || g.NavInputId == id) 8949 { 8950 SetActiveID(id, window); 8951 SetFocusID(id, window); 8952 FocusWindow(window); 8953 g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right); 8954 } 8955 8956 // Actual slider behavior + render grab 8957 bool value_changed = SliderBehavior(frame_bb, id, v, v_min, v_max, format, power, ImGuiSliderFlags_Vertical); 8958 8959 // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. 8960 // For the vertical slider we allow centered text to overlap the frame padding 8961 char value_buf[64]; 8962 char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), format, *v); 8963 RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.0f)); 8964 if (label_size.x > 0.0f) 8965 RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); 8966 8967 return value_changed; 8968 } 8969 8970 bool ImGui::SliderAngle(const char* label, float* v_rad, float v_degrees_min, float v_degrees_max) 8971 { 8972 float v_deg = (*v_rad) * 360.0f / (2 * IM_PI); 8973 bool value_changed = SliderFloat(label, &v_deg, v_degrees_min, v_degrees_max, "%.0f deg", 1.0f); 8974 *v_rad = v_deg * (2 * IM_PI) / 360.0f; 8975 return value_changed; 8976 } 8977 8978 bool ImGui::SliderInt(const char* label, int* v, int v_min, int v_max, const char* format) 8979 { 8980 if (!format) 8981 format = "%.0f"; 8982 float v_f = (float)*v; 8983 bool value_changed = SliderFloat(label, &v_f, (float)v_min, (float)v_max, format, 1.0f); 8984 *v = (int)v_f; 8985 return value_changed; 8986 } 8987 8988 bool ImGui::VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format) 8989 { 8990 if (!format) 8991 format = "%.0f"; 8992 float v_f = (float)*v; 8993 bool value_changed = VSliderFloat(label, size, &v_f, (float)v_min, (float)v_max, format, 1.0f); 8994 *v = (int)v_f; 8995 return value_changed; 8996 } 8997 8998 // Add multiple sliders on 1 line for compact edition of multiple components 8999 bool ImGui::SliderFloatN(const char* label, float* v, int components, float v_min, float v_max, const char* format, float power) 9000 { 9001 ImGuiWindow* window = GetCurrentWindow(); 9002 if (window->SkipItems) 9003 return false; 9004 9005 ImGuiContext& g = *GImGui; 9006 bool value_changed = false; 9007 BeginGroup(); 9008 PushID(label); 9009 PushMultiItemsWidths(components); 9010 for (int i = 0; i < components; i++) 9011 { 9012 PushID(i); 9013 value_changed |= SliderFloat("##v", &v[i], v_min, v_max, format, power); 9014 SameLine(0, g.Style.ItemInnerSpacing.x); 9015 PopID(); 9016 PopItemWidth(); 9017 } 9018 PopID(); 9019 9020 TextUnformatted(label, FindRenderedTextEnd(label)); 9021 EndGroup(); 9022 9023 return value_changed; 9024 } 9025 9026 bool ImGui::SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format, float power) 9027 { 9028 return SliderFloatN(label, v, 2, v_min, v_max, format, power); 9029 } 9030 9031 bool ImGui::SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format, float power) 9032 { 9033 return SliderFloatN(label, v, 3, v_min, v_max, format, power); 9034 } 9035 9036 bool ImGui::SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format, float power) 9037 { 9038 return SliderFloatN(label, v, 4, v_min, v_max, format, power); 9039 } 9040 9041 bool ImGui::SliderIntN(const char* label, int* v, int components, int v_min, int v_max, const char* format) 9042 { 9043 ImGuiWindow* window = GetCurrentWindow(); 9044 if (window->SkipItems) 9045 return false; 9046 9047 ImGuiContext& g = *GImGui; 9048 bool value_changed = false; 9049 BeginGroup(); 9050 PushID(label); 9051 PushMultiItemsWidths(components); 9052 for (int i = 0; i < components; i++) 9053 { 9054 PushID(i); 9055 value_changed |= SliderInt("##v", &v[i], v_min, v_max, format); 9056 SameLine(0, g.Style.ItemInnerSpacing.x); 9057 PopID(); 9058 PopItemWidth(); 9059 } 9060 PopID(); 9061 9062 TextUnformatted(label, FindRenderedTextEnd(label)); 9063 EndGroup(); 9064 9065 return value_changed; 9066 } 9067 9068 bool ImGui::SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format) 9069 { 9070 return SliderIntN(label, v, 2, v_min, v_max, format); 9071 } 9072 9073 bool ImGui::SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format) 9074 { 9075 return SliderIntN(label, v, 3, v_min, v_max, format); 9076 } 9077 9078 bool ImGui::SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format) 9079 { 9080 return SliderIntN(label, v, 4, v_min, v_max, format); 9081 } 9082 9083 bool ImGui::DragBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_speed, float v_min, float v_max, const char* format, float power) 9084 { 9085 ImGuiContext& g = *GImGui; 9086 const ImGuiStyle& style = g.Style; 9087 9088 // Draw frame 9089 const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); 9090 RenderNavHighlight(frame_bb, id); 9091 RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding); 9092 9093 // Process interacting with the drag 9094 if (g.ActiveId == id) 9095 { 9096 if (g.ActiveIdSource == ImGuiInputSource_Mouse && !g.IO.MouseDown[0]) 9097 ClearActiveID(); 9098 else if (g.ActiveIdSource == ImGuiInputSource_Nav && g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated) 9099 ClearActiveID(); 9100 } 9101 if (g.ActiveId != id) 9102 return false; 9103 9104 // Default tweak speed 9105 if (v_speed == 0.0f && (v_max - v_min) != 0.0f && (v_max - v_min) < FLT_MAX) 9106 v_speed = (v_max - v_min) * g.DragSpeedDefaultRatio; 9107 9108 if (g.ActiveIdIsJustActivated) 9109 { 9110 // Lock current value on click 9111 g.DragCurrentValue = *v; 9112 g.DragLastMouseDelta = ImVec2(0.f, 0.f); 9113 } 9114 9115 const ImVec2 mouse_drag_delta = GetMouseDragDelta(0, 1.0f); 9116 float adjust_delta = 0.0f; 9117 if (g.ActiveIdSource == ImGuiInputSource_Mouse && IsMousePosValid()) 9118 { 9119 adjust_delta = mouse_drag_delta.x - g.DragLastMouseDelta.x; 9120 if (g.IO.KeyShift && g.DragSpeedScaleFast >= 0.0f) 9121 adjust_delta *= g.DragSpeedScaleFast; 9122 if (g.IO.KeyAlt && g.DragSpeedScaleSlow >= 0.0f) 9123 adjust_delta *= g.DragSpeedScaleSlow; 9124 g.DragLastMouseDelta.x = mouse_drag_delta.x; 9125 } 9126 if (g.ActiveIdSource == ImGuiInputSource_Nav) 9127 { 9128 int decimal_precision = ParseFormatPrecision(format, 3); 9129 adjust_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard | ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_RepeatFast, 1.0f / 10.0f, 10.0f).x; 9130 v_speed = ImMax(v_speed, GetMinimumStepAtDecimalPrecision(decimal_precision)); 9131 } 9132 adjust_delta *= v_speed; 9133 9134 // Avoid applying the saturation when we are _already_ past the limits and heading in the same direction, so e.g. if range is 0..255, current value is 300 and we are pushing to the right side, keep the 300 9135 float v_cur = g.DragCurrentValue; 9136 if (v_min < v_max && ((v_cur >= v_max && adjust_delta > 0.0f) || (v_cur <= v_min && adjust_delta < 0.0f))) 9137 adjust_delta = 0.0f; 9138 9139 if (fabsf(adjust_delta) > 0.0f) 9140 { 9141 if (fabsf(power - 1.0f) > 0.001f) 9142 { 9143 // Logarithmic curve on both side of 0.0 9144 float v0_abs = v_cur >= 0.0f ? v_cur : -v_cur; 9145 float v0_sign = v_cur >= 0.0f ? 1.0f : -1.0f; 9146 float v1 = powf(v0_abs, 1.0f / power) + (adjust_delta * v0_sign); 9147 float v1_abs = v1 >= 0.0f ? v1 : -v1; 9148 float v1_sign = v1 >= 0.0f ? 1.0f : -1.0f; // Crossed sign line 9149 v_cur = powf(v1_abs, power) * v0_sign * v1_sign; // Reapply sign 9150 } 9151 else 9152 { 9153 v_cur += adjust_delta; 9154 } 9155 9156 // Clamp 9157 if (v_min < v_max) 9158 v_cur = ImClamp(v_cur, v_min, v_max); 9159 g.DragCurrentValue = v_cur; 9160 } 9161 9162 // Round to user desired precision, then apply 9163 bool value_changed = false; 9164 v_cur = RoundScalarWithFormat(format, v_cur); 9165 if (*v != v_cur) 9166 { 9167 *v = v_cur; 9168 value_changed = true; 9169 } 9170 9171 return value_changed; 9172 } 9173 9174 bool ImGui::DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, float power) 9175 { 9176 ImGuiWindow* window = GetCurrentWindow(); 9177 if (window->SkipItems) 9178 return false; 9179 9180 ImGuiContext& g = *GImGui; 9181 const ImGuiStyle& style = g.Style; 9182 const ImGuiID id = window->GetID(label); 9183 const float w = CalcItemWidth(); 9184 9185 const ImVec2 label_size = CalcTextSize(label, NULL, true); 9186 const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f)); 9187 const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding); 9188 const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); 9189 9190 // NB- we don't call ItemSize() yet because we may turn into a text edit box below 9191 if (!ItemAdd(total_bb, id, &frame_bb)) 9192 { 9193 ItemSize(total_bb, style.FramePadding.y); 9194 return false; 9195 } 9196 const bool hovered = ItemHoverable(frame_bb, id); 9197 9198 if (!format) 9199 format = "%.3f"; 9200 9201 // Tabbing or CTRL-clicking on Drag turns it into an input box 9202 bool start_text_input = false; 9203 const bool tab_focus_requested = FocusableItemRegister(window, id); 9204 if (tab_focus_requested || (hovered && (g.IO.MouseClicked[0] || g.IO.MouseDoubleClicked[0])) || g.NavActivateId == id || (g.NavInputId == id && g.ScalarAsInputTextId != id)) 9205 { 9206 SetActiveID(id, window); 9207 SetFocusID(id, window); 9208 FocusWindow(window); 9209 g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); 9210 if (tab_focus_requested || g.IO.KeyCtrl || g.IO.MouseDoubleClicked[0] || g.NavInputId == id) 9211 { 9212 start_text_input = true; 9213 g.ScalarAsInputTextId = 0; 9214 } 9215 } 9216 if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id)) 9217 return InputScalarAsWidgetReplacement(frame_bb, id, label, ImGuiDataType_Float, v, format); 9218 9219 // Actual drag behavior 9220 ItemSize(total_bb, style.FramePadding.y); 9221 const bool value_changed = DragBehavior(frame_bb, id, v, v_speed, v_min, v_max, format, power); 9222 9223 // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. 9224 char value_buf[64]; 9225 const char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), format, *v); 9226 RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f)); 9227 9228 if (label_size.x > 0.0f) 9229 RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label); 9230 9231 return value_changed; 9232 } 9233 9234 bool ImGui::DragFloatN(const char* label, float* v, int components, float v_speed, float v_min, float v_max, const char* format, float power) 9235 { 9236 ImGuiWindow* window = GetCurrentWindow(); 9237 if (window->SkipItems) 9238 return false; 9239 9240 ImGuiContext& g = *GImGui; 9241 bool value_changed = false; 9242 BeginGroup(); 9243 PushID(label); 9244 PushMultiItemsWidths(components); 9245 for (int i = 0; i < components; i++) 9246 { 9247 PushID(i); 9248 value_changed |= DragFloat("##v", &v[i], v_speed, v_min, v_max, format, power); 9249 SameLine(0, g.Style.ItemInnerSpacing.x); 9250 PopID(); 9251 PopItemWidth(); 9252 } 9253 PopID(); 9254 9255 TextUnformatted(label, FindRenderedTextEnd(label)); 9256 EndGroup(); 9257 9258 return value_changed; 9259 } 9260 9261 bool ImGui::DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* format, float power) 9262 { 9263 return DragFloatN(label, v, 2, v_speed, v_min, v_max, format, power); 9264 } 9265 9266 bool ImGui::DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, float power) 9267 { 9268 return DragFloatN(label, v, 3, v_speed, v_min, v_max, format, power); 9269 } 9270 9271 bool ImGui::DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* format, float power) 9272 { 9273 return DragFloatN(label, v, 4, v_speed, v_min, v_max, format, power); 9274 } 9275 9276 bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed, float v_min, float v_max, const char* format, const char* format_max, float power) 9277 { 9278 ImGuiWindow* window = GetCurrentWindow(); 9279 if (window->SkipItems) 9280 return false; 9281 9282 ImGuiContext& g = *GImGui; 9283 PushID(label); 9284 BeginGroup(); 9285 PushMultiItemsWidths(2); 9286 9287 bool value_changed = DragFloat("##min", v_current_min, v_speed, (v_min >= v_max) ? -FLT_MAX : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), format, power); 9288 PopItemWidth(); 9289 SameLine(0, g.Style.ItemInnerSpacing.x); 9290 value_changed |= DragFloat("##max", v_current_max, v_speed, (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min), (v_min >= v_max) ? FLT_MAX : v_max, format_max ? format_max : format, power); 9291 PopItemWidth(); 9292 SameLine(0, g.Style.ItemInnerSpacing.x); 9293 9294 TextUnformatted(label, FindRenderedTextEnd(label)); 9295 EndGroup(); 9296 PopID(); 9297 9298 return value_changed; 9299 } 9300 9301 // NB: v_speed is float to allow adjusting the drag speed with more precision 9302 bool ImGui::DragInt(const char* label, int* v, float v_speed, int v_min, int v_max, const char* format) 9303 { 9304 if (!format) 9305 format = "%.0f"; 9306 float v_f = (float)*v; 9307 bool value_changed = DragFloat(label, &v_f, v_speed, (float)v_min, (float)v_max, format); 9308 *v = (int)v_f; 9309 return value_changed; 9310 } 9311 9312 bool ImGui::DragIntN(const char* label, int* v, int components, float v_speed, int v_min, int v_max, const char* format) 9313 { 9314 ImGuiWindow* window = GetCurrentWindow(); 9315 if (window->SkipItems) 9316 return false; 9317 9318 ImGuiContext& g = *GImGui; 9319 bool value_changed = false; 9320 BeginGroup(); 9321 PushID(label); 9322 PushMultiItemsWidths(components); 9323 for (int i = 0; i < components; i++) 9324 { 9325 PushID(i); 9326 value_changed |= DragInt("##v", &v[i], v_speed, v_min, v_max, format); 9327 SameLine(0, g.Style.ItemInnerSpacing.x); 9328 PopID(); 9329 PopItemWidth(); 9330 } 9331 PopID(); 9332 9333 TextUnformatted(label, FindRenderedTextEnd(label)); 9334 EndGroup(); 9335 9336 return value_changed; 9337 } 9338 9339 bool ImGui::DragInt2(const char* label, int v[2], float v_speed, int v_min, int v_max, const char* format) 9340 { 9341 return DragIntN(label, v, 2, v_speed, v_min, v_max, format); 9342 } 9343 9344 bool ImGui::DragInt3(const char* label, int v[3], float v_speed, int v_min, int v_max, const char* format) 9345 { 9346 return DragIntN(label, v, 3, v_speed, v_min, v_max, format); 9347 } 9348 9349 bool ImGui::DragInt4(const char* label, int v[4], float v_speed, int v_min, int v_max, const char* format) 9350 { 9351 return DragIntN(label, v, 4, v_speed, v_min, v_max, format); 9352 } 9353 9354 bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed, int v_min, int v_max, const char* format, const char* format_max) 9355 { 9356 ImGuiWindow* window = GetCurrentWindow(); 9357 if (window->SkipItems) 9358 return false; 9359 9360 ImGuiContext& g = *GImGui; 9361 PushID(label); 9362 BeginGroup(); 9363 PushMultiItemsWidths(2); 9364 9365 bool value_changed = DragInt("##min", v_current_min, v_speed, (v_min >= v_max) ? INT_MIN : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), format); 9366 PopItemWidth(); 9367 SameLine(0, g.Style.ItemInnerSpacing.x); 9368 value_changed |= DragInt("##max", v_current_max, v_speed, (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min), (v_min >= v_max) ? INT_MAX : v_max, format_max ? format_max : format); 9369 PopItemWidth(); 9370 SameLine(0, g.Style.ItemInnerSpacing.x); 9371 9372 TextUnformatted(label, FindRenderedTextEnd(label)); 9373 EndGroup(); 9374 PopID(); 9375 9376 return value_changed; 9377 } 9378 9379 void ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size) 9380 { 9381 ImGuiWindow* window = GetCurrentWindow(); 9382 if (window->SkipItems) 9383 return; 9384 9385 ImGuiContext& g = *GImGui; 9386 const ImGuiStyle& style = g.Style; 9387 9388 const ImVec2 label_size = CalcTextSize(label, NULL, true); 9389 if (graph_size.x == 0.0f) 9390 graph_size.x = CalcItemWidth(); 9391 if (graph_size.y == 0.0f) 9392 graph_size.y = label_size.y + (style.FramePadding.y * 2); 9393 9394 const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(graph_size.x, graph_size.y)); 9395 const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding); 9396 const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0)); 9397 ItemSize(total_bb, style.FramePadding.y); 9398 if (!ItemAdd(total_bb, 0, &frame_bb)) 9399 return; 9400 const bool hovered = ItemHoverable(inner_bb, 0); 9401 9402 // Determine scale from values if not specified 9403 if (scale_min == FLT_MAX || scale_max == FLT_MAX) 9404 { 9405 float v_min = FLT_MAX; 9406 float v_max = -FLT_MAX; 9407 for (int i = 0; i < values_count; i++) 9408 { 9409 const float v = values_getter(data, i); 9410 v_min = ImMin(v_min, v); 9411 v_max = ImMax(v_max, v); 9412 } 9413 if (scale_min == FLT_MAX) 9414 scale_min = v_min; 9415 if (scale_max == FLT_MAX) 9416 scale_max = v_max; 9417 } 9418 9419 RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); 9420 9421 if (values_count > 0) 9422 { 9423 int res_w = ImMin((int)graph_size.x, values_count) + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0); 9424 int item_count = values_count + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0); 9425 9426 // Tooltip on hover 9427 int v_hovered = -1; 9428 if (hovered) 9429 { 9430 const float t = ImClamp((g.IO.MousePos.x - inner_bb.Min.x) / (inner_bb.Max.x - inner_bb.Min.x), 0.0f, 0.9999f); 9431 const int v_idx = (int)(t * item_count); 9432 IM_ASSERT(v_idx >= 0 && v_idx < values_count); 9433 9434 const float v0 = values_getter(data, (v_idx + values_offset) % values_count); 9435 const float v1 = values_getter(data, (v_idx + 1 + values_offset) % values_count); 9436 if (plot_type == ImGuiPlotType_Lines) 9437 SetTooltip("%d: %8.4g\n%d: %8.4g", v_idx, v0, v_idx + 1, v1); 9438 else if (plot_type == ImGuiPlotType_Histogram) 9439 SetTooltip("%d: %8.4g", v_idx, v0); 9440 v_hovered = v_idx; 9441 } 9442 9443 const float t_step = 1.0f / (float)res_w; 9444 const float inv_scale = (scale_min == scale_max) ? 0.0f : (1.0f / (scale_max - scale_min)); 9445 9446 float v0 = values_getter(data, (0 + values_offset) % values_count); 9447 float t0 = 0.0f; 9448 ImVec2 tp0 = ImVec2(t0, 1.0f - ImSaturate((v0 - scale_min) * inv_scale)); // Point in the normalized space of our target rectangle 9449 float histogram_zero_line_t = (scale_min * scale_max < 0.0f) ? (-scale_min * inv_scale) : (scale_min < 0.0f ? 0.0f : 1.0f); // Where does the zero line stands 9450 9451 const ImU32 col_base = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLines : ImGuiCol_PlotHistogram); 9452 const ImU32 col_hovered = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLinesHovered : ImGuiCol_PlotHistogramHovered); 9453 9454 for (int n = 0; n < res_w; n++) 9455 { 9456 const float t1 = t0 + t_step; 9457 const int v1_idx = (int)(t0 * item_count + 0.5f); 9458 IM_ASSERT(v1_idx >= 0 && v1_idx < values_count); 9459 const float v1 = values_getter(data, (v1_idx + values_offset + 1) % values_count); 9460 const ImVec2 tp1 = ImVec2(t1, 1.0f - ImSaturate((v1 - scale_min) * inv_scale)); 9461 9462 // NB: Draw calls are merged together by the DrawList system. Still, we should render our batch are lower level to save a bit of CPU. 9463 ImVec2 pos0 = ImLerp(inner_bb.Min, inner_bb.Max, tp0); 9464 ImVec2 pos1 = ImLerp(inner_bb.Min, inner_bb.Max, (plot_type == ImGuiPlotType_Lines) ? tp1 : ImVec2(tp1.x, histogram_zero_line_t)); 9465 if (plot_type == ImGuiPlotType_Lines) 9466 { 9467 window->DrawList->AddLine(pos0, pos1, v_hovered == v1_idx ? col_hovered : col_base); 9468 } 9469 else if (plot_type == ImGuiPlotType_Histogram) 9470 { 9471 if (pos1.x >= pos0.x + 2.0f) 9472 pos1.x -= 1.0f; 9473 window->DrawList->AddRectFilled(pos0, pos1, v_hovered == v1_idx ? col_hovered : col_base); 9474 } 9475 9476 t0 = t1; 9477 tp0 = tp1; 9478 } 9479 } 9480 9481 // Text overlay 9482 if (overlay_text) 9483 RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, overlay_text, NULL, NULL, ImVec2(0.5f, 0.0f)); 9484 9485 if (label_size.x > 0.0f) 9486 RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label); 9487 } 9488 9489 struct ImGuiPlotArrayGetterData 9490 { 9491 const float* Values; 9492 int Stride; 9493 9494 ImGuiPlotArrayGetterData(const float* values, int stride) { Values = values; Stride = stride; } 9495 }; 9496 9497 static float Plot_ArrayGetter(void* data, int idx) 9498 { 9499 ImGuiPlotArrayGetterData* plot_data = (ImGuiPlotArrayGetterData*)data; 9500 const float v = *(const float*)(const void*)((const unsigned char*)plot_data->Values + (size_t)idx * plot_data->Stride); 9501 return v; 9502 } 9503 9504 void ImGui::PlotLines(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride) 9505 { 9506 ImGuiPlotArrayGetterData data(values, stride); 9507 PlotEx(ImGuiPlotType_Lines, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size); 9508 } 9509 9510 void ImGui::PlotLines(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size) 9511 { 9512 PlotEx(ImGuiPlotType_Lines, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size); 9513 } 9514 9515 void ImGui::PlotHistogram(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride) 9516 { 9517 ImGuiPlotArrayGetterData data(values, stride); 9518 PlotEx(ImGuiPlotType_Histogram, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size); 9519 } 9520 9521 void ImGui::PlotHistogram(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size) 9522 { 9523 PlotEx(ImGuiPlotType_Histogram, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size); 9524 } 9525 9526 // size_arg (for each axis) < 0.0f: align to end, 0.0f: auto, > 0.0f: specified size 9527 void ImGui::ProgressBar(float fraction, const ImVec2& size_arg, const char* overlay) 9528 { 9529 ImGuiWindow* window = GetCurrentWindow(); 9530 if (window->SkipItems) 9531 return; 9532 9533 ImGuiContext& g = *GImGui; 9534 const ImGuiStyle& style = g.Style; 9535 9536 ImVec2 pos = window->DC.CursorPos; 9537 ImRect bb(pos, pos + CalcItemSize(size_arg, CalcItemWidth(), g.FontSize + style.FramePadding.y*2.0f)); 9538 ItemSize(bb, style.FramePadding.y); 9539 if (!ItemAdd(bb, 0)) 9540 return; 9541 9542 // Render 9543 fraction = ImSaturate(fraction); 9544 RenderFrame(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); 9545 bb.Expand(ImVec2(-style.FrameBorderSize, -style.FrameBorderSize)); 9546 const ImVec2 fill_br = ImVec2(ImLerp(bb.Min.x, bb.Max.x, fraction), bb.Max.y); 9547 RenderRectFilledRangeH(window->DrawList, bb, GetColorU32(ImGuiCol_PlotHistogram), 0.0f, fraction, style.FrameRounding); 9548 9549 // Default displaying the fraction as percentage string, but user can override it 9550 char overlay_buf[32]; 9551 if (!overlay) 9552 { 9553 ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%.0f%%", fraction * 100 + 0.01f); 9554 overlay = overlay_buf; 9555 } 9556 9557 ImVec2 overlay_size = CalcTextSize(overlay, NULL); 9558 if (overlay_size.x > 0.0f) 9559 RenderTextClipped(ImVec2(ImClamp(fill_br.x + style.ItemSpacing.x, bb.Min.x, bb.Max.x - overlay_size.x - style.ItemInnerSpacing.x), bb.Min.y), bb.Max, overlay, NULL, &overlay_size, ImVec2(0.0f, 0.5f), &bb); 9560 } 9561 9562 bool ImGui::Checkbox(const char* label, bool* v) 9563 { 9564 ImGuiWindow* window = GetCurrentWindow(); 9565 if (window->SkipItems) 9566 return false; 9567 9568 ImGuiContext& g = *GImGui; 9569 const ImGuiStyle& style = g.Style; 9570 const ImGuiID id = window->GetID(label); 9571 const ImVec2 label_size = CalcTextSize(label, NULL, true); 9572 9573 const ImRect check_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(label_size.y + style.FramePadding.y * 2, label_size.y + style.FramePadding.y * 2)); // We want a square shape to we use Y twice 9574 ItemSize(check_bb, style.FramePadding.y); 9575 9576 ImRect total_bb = check_bb; 9577 if (label_size.x > 0) 9578 SameLine(0, style.ItemInnerSpacing.x); 9579 const ImRect text_bb(window->DC.CursorPos + ImVec2(0, style.FramePadding.y), window->DC.CursorPos + ImVec2(0, style.FramePadding.y) + label_size); 9580 if (label_size.x > 0) 9581 { 9582 ItemSize(ImVec2(text_bb.GetWidth(), check_bb.GetHeight()), style.FramePadding.y); 9583 total_bb = ImRect(ImMin(check_bb.Min, text_bb.Min), ImMax(check_bb.Max, text_bb.Max)); 9584 } 9585 9586 if (!ItemAdd(total_bb, id)) 9587 return false; 9588 9589 bool hovered, held; 9590 bool pressed = ButtonBehavior(total_bb, id, &hovered, &held); 9591 if (pressed) 9592 *v = !(*v); 9593 9594 RenderNavHighlight(total_bb, id); 9595 RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding); 9596 if (*v) 9597 { 9598 const float check_sz = ImMin(check_bb.GetWidth(), check_bb.GetHeight()); 9599 const float pad = ImMax(1.0f, (float)(int)(check_sz / 6.0f)); 9600 RenderCheckMark(check_bb.Min + ImVec2(pad, pad), GetColorU32(ImGuiCol_CheckMark), check_bb.GetWidth() - pad * 2.0f); 9601 } 9602 9603 if (g.LogEnabled) 9604 LogRenderedText(&text_bb.Min, *v ? "[x]" : "[ ]"); 9605 if (label_size.x > 0.0f) 9606 RenderText(text_bb.Min, label); 9607 9608 return pressed; 9609 } 9610 9611 bool ImGui::CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value) 9612 { 9613 bool v = ((*flags & flags_value) == flags_value); 9614 bool pressed = Checkbox(label, &v); 9615 if (pressed) 9616 { 9617 if (v) 9618 *flags |= flags_value; 9619 else 9620 *flags &= ~flags_value; 9621 } 9622 9623 return pressed; 9624 } 9625 9626 bool ImGui::RadioButton(const char* label, bool active) 9627 { 9628 ImGuiWindow* window = GetCurrentWindow(); 9629 if (window->SkipItems) 9630 return false; 9631 9632 ImGuiContext& g = *GImGui; 9633 const ImGuiStyle& style = g.Style; 9634 const ImGuiID id = window->GetID(label); 9635 const ImVec2 label_size = CalcTextSize(label, NULL, true); 9636 9637 const ImRect check_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(label_size.y + style.FramePadding.y * 2 - 1, label_size.y + style.FramePadding.y * 2 - 1)); 9638 ItemSize(check_bb, style.FramePadding.y); 9639 9640 ImRect total_bb = check_bb; 9641 if (label_size.x > 0) 9642 SameLine(0, style.ItemInnerSpacing.x); 9643 const ImRect text_bb(window->DC.CursorPos + ImVec2(0, style.FramePadding.y), window->DC.CursorPos + ImVec2(0, style.FramePadding.y) + label_size); 9644 if (label_size.x > 0) 9645 { 9646 ItemSize(ImVec2(text_bb.GetWidth(), check_bb.GetHeight()), style.FramePadding.y); 9647 total_bb.Add(text_bb); 9648 } 9649 9650 if (!ItemAdd(total_bb, id)) 9651 return false; 9652 9653 ImVec2 center = check_bb.GetCenter(); 9654 center.x = (float)(int)center.x + 0.5f; 9655 center.y = (float)(int)center.y + 0.5f; 9656 const float radius = check_bb.GetHeight() * 0.5f; 9657 9658 bool hovered, held; 9659 bool pressed = ButtonBehavior(total_bb, id, &hovered, &held); 9660 9661 RenderNavHighlight(total_bb, id); 9662 window->DrawList->AddCircleFilled(center, radius, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), 16); 9663 if (active) 9664 { 9665 const float check_sz = ImMin(check_bb.GetWidth(), check_bb.GetHeight()); 9666 const float pad = ImMax(1.0f, (float)(int)(check_sz / 6.0f)); 9667 window->DrawList->AddCircleFilled(center, radius - pad, GetColorU32(ImGuiCol_CheckMark), 16); 9668 } 9669 9670 if (style.FrameBorderSize > 0.0f) 9671 { 9672 window->DrawList->AddCircle(center + ImVec2(1, 1), radius, GetColorU32(ImGuiCol_BorderShadow), 16, style.FrameBorderSize); 9673 window->DrawList->AddCircle(center, radius, GetColorU32(ImGuiCol_Border), 16, style.FrameBorderSize); 9674 } 9675 9676 if (g.LogEnabled) 9677 LogRenderedText(&text_bb.Min, active ? "(x)" : "( )"); 9678 if (label_size.x > 0.0f) 9679 RenderText(text_bb.Min, label); 9680 9681 return pressed; 9682 } 9683 9684 bool ImGui::RadioButton(const char* label, int* v, int v_button) 9685 { 9686 const bool pressed = RadioButton(label, *v == v_button); 9687 if (pressed) 9688 { 9689 *v = v_button; 9690 } 9691 return pressed; 9692 } 9693 9694 static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end) 9695 { 9696 int line_count = 0; 9697 const char* s = text_begin; 9698 while (char c = *s++) // We are only matching for \n so we can ignore UTF-8 decoding 9699 if (c == '\n') 9700 line_count++; 9701 s--; 9702 if (s[0] != '\n' && s[0] != '\r') 9703 line_count++; 9704 *out_text_end = s; 9705 return line_count; 9706 } 9707 9708 static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining, ImVec2* out_offset, bool stop_on_new_line) 9709 { 9710 ImFont* font = GImGui->Font; 9711 const float line_height = GImGui->FontSize; 9712 const float scale = line_height / font->FontSize; 9713 9714 ImVec2 text_size = ImVec2(0, 0); 9715 float line_width = 0.0f; 9716 9717 const ImWchar* s = text_begin; 9718 while (s < text_end) 9719 { 9720 unsigned int c = (unsigned int)(*s++); 9721 if (c == '\n') 9722 { 9723 text_size.x = ImMax(text_size.x, line_width); 9724 text_size.y += line_height; 9725 line_width = 0.0f; 9726 if (stop_on_new_line) 9727 break; 9728 continue; 9729 } 9730 if (c == '\r') 9731 continue; 9732 9733 const float char_width = font->GetCharAdvance((unsigned short)c) * scale; 9734 line_width += char_width; 9735 } 9736 9737 if (text_size.x < line_width) 9738 text_size.x = line_width; 9739 9740 if (out_offset) 9741 *out_offset = ImVec2(line_width, text_size.y + line_height); // offset allow for the possibility of sitting after a trailing \n 9742 9743 if (line_width > 0 || text_size.y == 0.0f) // whereas size.y will ignore the trailing \n 9744 text_size.y += line_height; 9745 9746 if (remaining) 9747 *remaining = s; 9748 9749 return text_size; 9750 } 9751 9752 // Wrapper for stb_textedit.h to edit text (our wrapper is for: statically sized buffer, single-line, wchar characters. InputText converts between UTF-8 and wchar) 9753 namespace ImGuiStb 9754 { 9755 9756 static int STB_TEXTEDIT_STRINGLEN(const STB_TEXTEDIT_STRING* obj) { return obj->CurLenW; } 9757 static ImWchar STB_TEXTEDIT_GETCHAR(const STB_TEXTEDIT_STRING* obj, int idx) { return obj->Text[idx]; } 9758 static float STB_TEXTEDIT_GETWIDTH(STB_TEXTEDIT_STRING* obj, int line_start_idx, int char_idx) { ImWchar c = obj->Text[line_start_idx + char_idx]; if (c == '\n') return STB_TEXTEDIT_GETWIDTH_NEWLINE; return GImGui->Font->GetCharAdvance(c) * (GImGui->FontSize / GImGui->Font->FontSize); } 9759 static int STB_TEXTEDIT_KEYTOTEXT(int key) { return key >= 0x10000 ? 0 : key; } 9760 static ImWchar STB_TEXTEDIT_NEWLINE = '\n'; 9761 static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, STB_TEXTEDIT_STRING* obj, int line_start_idx) 9762 { 9763 const ImWchar* text = obj->Text.Data; 9764 const ImWchar* text_remaining = NULL; 9765 const ImVec2 size = InputTextCalcTextSizeW(text + line_start_idx, text + obj->CurLenW, &text_remaining, NULL, true); 9766 r->x0 = 0.0f; 9767 r->x1 = size.x; 9768 r->baseline_y_delta = size.y; 9769 r->ymin = 0.0f; 9770 r->ymax = size.y; 9771 r->num_chars = (int)(text_remaining - (text + line_start_idx)); 9772 } 9773 9774 static bool is_separator(unsigned int c) { return ImCharIsSpace(c) || c == ',' || c == ';' || c == '(' || c == ')' || c == '{' || c == '}' || c == '[' || c == ']' || c == '|'; } 9775 static int is_word_boundary_from_right(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (is_separator(obj->Text[idx - 1]) && !is_separator(obj->Text[idx])) : 1; } 9776 static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx--; while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; } 9777 #ifdef __APPLE__ // FIXME: Move setting to IO structure 9778 static int is_word_boundary_from_left(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (!is_separator(obj->Text[idx - 1]) && is_separator(obj->Text[idx])) : 1; } 9779 static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; } 9780 #else 9781 static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; } 9782 #endif 9783 #define STB_TEXTEDIT_MOVEWORDLEFT STB_TEXTEDIT_MOVEWORDLEFT_IMPL // They need to be #define for stb_textedit.h 9784 #define STB_TEXTEDIT_MOVEWORDRIGHT STB_TEXTEDIT_MOVEWORDRIGHT_IMPL 9785 9786 static void STB_TEXTEDIT_DELETECHARS(STB_TEXTEDIT_STRING* obj, int pos, int n) 9787 { 9788 ImWchar* dst = obj->Text.Data + pos; 9789 9790 // We maintain our buffer length in both UTF-8 and wchar formats 9791 obj->CurLenA -= ImTextCountUtf8BytesFromStr(dst, dst + n); 9792 obj->CurLenW -= n; 9793 9794 // Offset remaining text 9795 const ImWchar* src = obj->Text.Data + pos + n; 9796 while (ImWchar c = *src++) 9797 *dst++ = c; 9798 *dst = '\0'; 9799 } 9800 9801 static bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING* obj, int pos, const ImWchar* new_text, int new_text_len) 9802 { 9803 const int text_len = obj->CurLenW; 9804 IM_ASSERT(pos <= text_len); 9805 if (new_text_len + text_len + 1 > obj->Text.Size) 9806 return false; 9807 9808 const int new_text_len_utf8 = ImTextCountUtf8BytesFromStr(new_text, new_text + new_text_len); 9809 if (new_text_len_utf8 + obj->CurLenA + 1 > obj->BufSizeA) 9810 return false; 9811 9812 ImWchar* text = obj->Text.Data; 9813 if (pos != text_len) 9814 memmove(text + pos + new_text_len, text + pos, (size_t)(text_len - pos) * sizeof(ImWchar)); 9815 memcpy(text + pos, new_text, (size_t)new_text_len * sizeof(ImWchar)); 9816 9817 obj->CurLenW += new_text_len; 9818 obj->CurLenA += new_text_len_utf8; 9819 obj->Text[obj->CurLenW] = '\0'; 9820 9821 return true; 9822 } 9823 9824 // We don't use an enum so we can build even with conflicting symbols (if another user of stb_textedit.h leak their STB_TEXTEDIT_K_* symbols) 9825 #define STB_TEXTEDIT_K_LEFT 0x10000 // keyboard input to move cursor left 9826 #define STB_TEXTEDIT_K_RIGHT 0x10001 // keyboard input to move cursor right 9827 #define STB_TEXTEDIT_K_UP 0x10002 // keyboard input to move cursor up 9828 #define STB_TEXTEDIT_K_DOWN 0x10003 // keyboard input to move cursor down 9829 #define STB_TEXTEDIT_K_LINESTART 0x10004 // keyboard input to move cursor to start of line 9830 #define STB_TEXTEDIT_K_LINEEND 0x10005 // keyboard input to move cursor to end of line 9831 #define STB_TEXTEDIT_K_TEXTSTART 0x10006 // keyboard input to move cursor to start of text 9832 #define STB_TEXTEDIT_K_TEXTEND 0x10007 // keyboard input to move cursor to end of text 9833 #define STB_TEXTEDIT_K_DELETE 0x10008 // keyboard input to delete selection or character under cursor 9834 #define STB_TEXTEDIT_K_BACKSPACE 0x10009 // keyboard input to delete selection or character left of cursor 9835 #define STB_TEXTEDIT_K_UNDO 0x1000A // keyboard input to perform undo 9836 #define STB_TEXTEDIT_K_REDO 0x1000B // keyboard input to perform redo 9837 #define STB_TEXTEDIT_K_WORDLEFT 0x1000C // keyboard input to move cursor left one word 9838 #define STB_TEXTEDIT_K_WORDRIGHT 0x1000D // keyboard input to move cursor right one word 9839 #define STB_TEXTEDIT_K_SHIFT 0x20000 9840 9841 #define STB_TEXTEDIT_IMPLEMENTATION 9842 #include "stb_textedit.h" 9843 9844 } 9845 9846 void ImGuiTextEditState::OnKeyPressed(int key) 9847 { 9848 stb_textedit_key(this, &StbState, key); 9849 CursorFollow = true; 9850 CursorAnimReset(); 9851 } 9852 9853 // Public API to manipulate UTF-8 text 9854 // We expose UTF-8 to the user (unlike the STB_TEXTEDIT_* functions which are manipulating wchar) 9855 // FIXME: The existence of this rarely exercised code path is a bit of a nuisance. 9856 void ImGuiTextEditCallbackData::DeleteChars(int pos, int bytes_count) 9857 { 9858 IM_ASSERT(pos + bytes_count <= BufTextLen); 9859 char* dst = Buf + pos; 9860 const char* src = Buf + pos + bytes_count; 9861 while (char c = *src++) 9862 *dst++ = c; 9863 *dst = '\0'; 9864 9865 if (CursorPos + bytes_count >= pos) 9866 CursorPos -= bytes_count; 9867 else if (CursorPos >= pos) 9868 CursorPos = pos; 9869 SelectionStart = SelectionEnd = CursorPos; 9870 BufDirty = true; 9871 BufTextLen -= bytes_count; 9872 } 9873 9874 void ImGuiTextEditCallbackData::InsertChars(int pos, const char* new_text, const char* new_text_end) 9875 { 9876 const int new_text_len = new_text_end ? (int)(new_text_end - new_text) : (int)strlen(new_text); 9877 if (new_text_len + BufTextLen + 1 >= BufSize) 9878 return; 9879 9880 if (BufTextLen != pos) 9881 memmove(Buf + pos + new_text_len, Buf + pos, (size_t)(BufTextLen - pos)); 9882 memcpy(Buf + pos, new_text, (size_t)new_text_len * sizeof(char)); 9883 Buf[BufTextLen + new_text_len] = '\0'; 9884 9885 if (CursorPos >= pos) 9886 CursorPos += new_text_len; 9887 SelectionStart = SelectionEnd = CursorPos; 9888 BufDirty = true; 9889 BufTextLen += new_text_len; 9890 } 9891 9892 // Return false to discard a character. 9893 static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data) 9894 { 9895 unsigned int c = *p_char; 9896 9897 if (c < 128 && c != ' ' && !isprint((int)(c & 0xFF))) 9898 { 9899 bool pass = false; 9900 pass |= (c == '\n' && (flags & ImGuiInputTextFlags_Multiline)); 9901 pass |= (c == '\t' && (flags & ImGuiInputTextFlags_AllowTabInput)); 9902 if (!pass) 9903 return false; 9904 } 9905 9906 if (c >= 0xE000 && c <= 0xF8FF) // Filter private Unicode range. I don't imagine anybody would want to input them. GLFW on OSX seems to send private characters for special keys like arrow keys. 9907 return false; 9908 9909 if (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase | ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_CharsScientific)) 9910 { 9911 if (flags & ImGuiInputTextFlags_CharsDecimal) 9912 if (!(c >= '0' && c <= '9') && (c != '.') && (c != '-') && (c != '+') && (c != '*') && (c != '/')) 9913 return false; 9914 9915 if (flags & ImGuiInputTextFlags_CharsScientific) 9916 if (!(c >= '0' && c <= '9') && (c != '.') && (c != '-') && (c != '+') && (c != '*') && (c != '/') && (c != 'e') && (c != 'E')) 9917 return false; 9918 9919 if (flags & ImGuiInputTextFlags_CharsHexadecimal) 9920 if (!(c >= '0' && c <= '9') && !(c >= 'a' && c <= 'f') && !(c >= 'A' && c <= 'F')) 9921 return false; 9922 9923 if (flags & ImGuiInputTextFlags_CharsUppercase) 9924 if (c >= 'a' && c <= 'z') 9925 *p_char = (c += (unsigned int)('A' - 'a')); 9926 9927 if (flags & ImGuiInputTextFlags_CharsNoBlank) 9928 if (ImCharIsSpace(c)) 9929 return false; 9930 } 9931 9932 if (flags & ImGuiInputTextFlags_CallbackCharFilter) 9933 { 9934 ImGuiTextEditCallbackData callback_data; 9935 memset(&callback_data, 0, sizeof(ImGuiTextEditCallbackData)); 9936 callback_data.EventFlag = ImGuiInputTextFlags_CallbackCharFilter; 9937 callback_data.EventChar = (ImWchar)c; 9938 callback_data.Flags = flags; 9939 callback_data.UserData = user_data; 9940 if (callback(&callback_data) != 0) 9941 return false; 9942 *p_char = callback_data.EventChar; 9943 if (!callback_data.EventChar) 9944 return false; 9945 } 9946 9947 return true; 9948 } 9949 9950 // Edit a string of text 9951 // NB: when active, hold on a privately held copy of the text (and apply back to 'buf'). So changing 'buf' while active has no effect. 9952 // FIXME: Rather messy function partly because we are doing UTF8 > u16 > UTF8 conversions on the go to more easily handle stb_textedit calls. Ideally we should stay in UTF-8 all the time. See https://github.com/nothings/stb/issues/188 9953 bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data) 9954 { 9955 ImGuiWindow* window = GetCurrentWindow(); 9956 if (window->SkipItems) 9957 return false; 9958 9959 IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackHistory) && (flags & ImGuiInputTextFlags_Multiline))); // Can't use both together (they both use up/down keys) 9960 IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackCompletion) && (flags & ImGuiInputTextFlags_AllowTabInput))); // Can't use both together (they both use tab key) 9961 9962 ImGuiContext& g = *GImGui; 9963 const ImGuiIO& io = g.IO; 9964 const ImGuiStyle& style = g.Style; 9965 9966 const bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0; 9967 const bool is_editable = (flags & ImGuiInputTextFlags_ReadOnly) == 0; 9968 const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0; 9969 const bool is_undoable = (flags & ImGuiInputTextFlags_NoUndoRedo) == 0; 9970 9971 if (is_multiline) // Open group before calling GetID() because groups tracks id created during their spawn 9972 BeginGroup(); 9973 const ImGuiID id = window->GetID(label); 9974 const ImVec2 label_size = CalcTextSize(label, NULL, true); 9975 ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), (is_multiline ? GetTextLineHeight() * 8.0f : label_size.y) + style.FramePadding.y*2.0f); // Arbitrary default of 8 lines high for multi-line 9976 const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size); 9977 const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? (style.ItemInnerSpacing.x + label_size.x) : 0.0f, 0.0f)); 9978 9979 ImGuiWindow* draw_window = window; 9980 if (is_multiline) 9981 { 9982 ItemAdd(total_bb, id, &frame_bb); 9983 if (!BeginChildFrame(id, frame_bb.GetSize())) 9984 { 9985 EndChildFrame(); 9986 EndGroup(); 9987 return false; 9988 } 9989 draw_window = GetCurrentWindow(); 9990 size.x -= draw_window->ScrollbarSizes.x; 9991 } 9992 else 9993 { 9994 ItemSize(total_bb, style.FramePadding.y); 9995 if (!ItemAdd(total_bb, id, &frame_bb)) 9996 return false; 9997 } 9998 const bool hovered = ItemHoverable(frame_bb, id); 9999 if (hovered) 10000 g.MouseCursor = ImGuiMouseCursor_TextInput; 10001 10002 // Password pushes a temporary font with only a fallback glyph 10003 if (is_password) 10004 { 10005 const ImFontGlyph* glyph = g.Font->FindGlyph('*'); 10006 ImFont* password_font = &g.InputTextPasswordFont; 10007 password_font->FontSize = g.Font->FontSize; 10008 password_font->Scale = g.Font->Scale; 10009 password_font->DisplayOffset = g.Font->DisplayOffset; 10010 password_font->Ascent = g.Font->Ascent; 10011 password_font->Descent = g.Font->Descent; 10012 password_font->ContainerAtlas = g.Font->ContainerAtlas; 10013 password_font->FallbackGlyph = glyph; 10014 password_font->FallbackAdvanceX = glyph->AdvanceX; 10015 IM_ASSERT(password_font->Glyphs.empty() && password_font->IndexAdvanceX.empty() && password_font->IndexLookup.empty()); 10016 PushFont(password_font); 10017 } 10018 10019 // NB: we are only allowed to access 'edit_state' if we are the active widget. 10020 ImGuiTextEditState& edit_state = g.InputTextState; 10021 10022 const bool focus_requested = FocusableItemRegister(window, id, (flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_AllowTabInput)) == 0); // Using completion callback disable keyboard tabbing 10023 const bool focus_requested_by_code = focus_requested && (window->FocusIdxAllCounter == window->FocusIdxAllRequestCurrent); 10024 const bool focus_requested_by_tab = focus_requested && !focus_requested_by_code; 10025 10026 const bool user_clicked = hovered && io.MouseClicked[0]; 10027 const bool user_scrolled = is_multiline && g.ActiveId == 0 && edit_state.Id == id && g.ActiveIdPreviousFrame == draw_window->GetIDNoKeepAlive("#SCROLLY"); 10028 const bool user_nav_input_start = (g.ActiveId != id) && ((g.NavInputId == id) || (g.NavActivateId == id && g.NavInputSource == ImGuiInputSource_NavKeyboard)); 10029 10030 bool clear_active_id = false; 10031 10032 bool select_all = (g.ActiveId != id) && ((flags & ImGuiInputTextFlags_AutoSelectAll) != 0 || user_nav_input_start) && (!is_multiline); 10033 if (focus_requested || user_clicked || user_scrolled || user_nav_input_start) 10034 { 10035 if (g.ActiveId != id) 10036 { 10037 // Start edition 10038 // Take a copy of the initial buffer value (both in original UTF-8 format and converted to wchar) 10039 // From the moment we focused we are ignoring the content of 'buf' (unless we are in read-only mode) 10040 const int prev_len_w = edit_state.CurLenW; 10041 edit_state.Text.resize(buf_size + 1); // wchar count <= UTF-8 count. we use +1 to make sure that .Data isn't NULL so it doesn't crash. 10042 edit_state.InitialText.resize(buf_size + 1); // UTF-8. we use +1 to make sure that .Data isn't NULL so it doesn't crash. 10043 ImStrncpy(edit_state.InitialText.Data, buf, edit_state.InitialText.Size); 10044 const char* buf_end = NULL; 10045 edit_state.CurLenW = ImTextStrFromUtf8(edit_state.Text.Data, edit_state.Text.Size, buf, NULL, &buf_end); 10046 edit_state.CurLenA = (int)(buf_end - buf); // We can't get the result from ImFormatString() above because it is not UTF-8 aware. Here we'll cut off malformed UTF-8. 10047 edit_state.CursorAnimReset(); 10048 10049 // Preserve cursor position and undo/redo stack if we come back to same widget 10050 // FIXME: We should probably compare the whole buffer to be on the safety side. Comparing buf (utf8) and edit_state.Text (wchar). 10051 const bool recycle_state = (edit_state.Id == id) && (prev_len_w == edit_state.CurLenW); 10052 if (recycle_state) 10053 { 10054 // Recycle existing cursor/selection/undo stack but clamp position 10055 // Note a single mouse click will override the cursor/position immediately by calling stb_textedit_click handler. 10056 edit_state.CursorClamp(); 10057 } 10058 else 10059 { 10060 edit_state.Id = id; 10061 edit_state.ScrollX = 0.0f; 10062 stb_textedit_initialize_state(&edit_state.StbState, !is_multiline); 10063 if (!is_multiline && focus_requested_by_code) 10064 select_all = true; 10065 } 10066 if (flags & ImGuiInputTextFlags_AlwaysInsertMode) 10067 edit_state.StbState.insert_mode = true; 10068 if (!is_multiline && (focus_requested_by_tab || (user_clicked && io.KeyCtrl))) 10069 select_all = true; 10070 } 10071 SetActiveID(id, window); 10072 SetFocusID(id, window); 10073 FocusWindow(window); 10074 if (!is_multiline && !(flags & ImGuiInputTextFlags_CallbackHistory)) 10075 g.ActiveIdAllowNavDirFlags |= ((1 << ImGuiDir_Up) | (1 << ImGuiDir_Down)); 10076 } 10077 else if (io.MouseClicked[0]) 10078 { 10079 // Release focus when we click outside 10080 clear_active_id = true; 10081 } 10082 10083 bool value_changed = false; 10084 bool enter_pressed = false; 10085 10086 if (g.ActiveId == id) 10087 { 10088 if (!is_editable && !g.ActiveIdIsJustActivated) 10089 { 10090 // When read-only we always use the live data passed to the function 10091 edit_state.Text.resize(buf_size + 1); 10092 const char* buf_end = NULL; 10093 edit_state.CurLenW = ImTextStrFromUtf8(edit_state.Text.Data, edit_state.Text.Size, buf, NULL, &buf_end); 10094 edit_state.CurLenA = (int)(buf_end - buf); 10095 edit_state.CursorClamp(); 10096 } 10097 10098 edit_state.BufSizeA = buf_size; 10099 10100 // Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget. 10101 // Down the line we should have a cleaner library-wide concept of Selected vs Active. 10102 g.ActiveIdAllowOverlap = !io.MouseDown[0]; 10103 g.WantTextInputNextFrame = 1; 10104 10105 // Edit in progress 10106 const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + edit_state.ScrollX; 10107 const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y - style.FramePadding.y) : (g.FontSize*0.5f)); 10108 10109 const bool is_osx = io.OptMacOSXBehaviors; 10110 if (select_all || (hovered && !is_osx && io.MouseDoubleClicked[0])) 10111 { 10112 edit_state.SelectAll(); 10113 edit_state.SelectedAllMouseLock = true; 10114 } 10115 else if (hovered && is_osx && io.MouseDoubleClicked[0]) 10116 { 10117 // Double-click select a word only, OS X style (by simulating keystrokes) 10118 edit_state.OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT); 10119 edit_state.OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT); 10120 } 10121 else if (io.MouseClicked[0] && !edit_state.SelectedAllMouseLock) 10122 { 10123 if (hovered) 10124 { 10125 stb_textedit_click(&edit_state, &edit_state.StbState, mouse_x, mouse_y); 10126 edit_state.CursorAnimReset(); 10127 } 10128 } 10129 else if (io.MouseDown[0] && !edit_state.SelectedAllMouseLock && (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f)) 10130 { 10131 stb_textedit_drag(&edit_state, &edit_state.StbState, mouse_x, mouse_y); 10132 edit_state.CursorAnimReset(); 10133 edit_state.CursorFollow = true; 10134 } 10135 if (edit_state.SelectedAllMouseLock && !io.MouseDown[0]) 10136 edit_state.SelectedAllMouseLock = false; 10137 10138 if (io.InputCharacters[0]) 10139 { 10140 // Process text input (before we check for Return because using some IME will effectively send a Return?) 10141 // We ignore CTRL inputs, but need to allow ALT+CTRL as some keyboards (e.g. German) use AltGR (which _is_ Alt+Ctrl) to input certain characters. 10142 bool ignore_inputs = (io.KeyCtrl && !io.KeyAlt) || (is_osx && io.KeySuper); 10143 if (!ignore_inputs && is_editable && !user_nav_input_start) 10144 for (int n = 0; n < IM_ARRAYSIZE(io.InputCharacters) && io.InputCharacters[n]; n++) 9007 else if (home_pressed) 10145 9008 { 10146 // Insert character if they pass filtering 10147 unsigned int c = (unsigned int)io.InputCharacters[n]; 10148 if (InputTextFilterCharacter(&c, flags, callback, user_data)) 10149 edit_state.OnKeyPressed((int)c); 9009 // FIXME-NAV: handling of Home/End is assuming that the top/bottom most item will be visible with Scroll.y == 0/ScrollMax.y 9010 // Scrolling will be handled via the ImGuiNavMoveFlags_ScrollToEdge flag, we don't scroll immediately to avoid scrolling happening before nav result. 9011 // Preserve current horizontal position if we have any. 9012 nav_rect_rel.Min.y = nav_rect_rel.Max.y = -window->Scroll.y; 9013 if (nav_rect_rel.IsInverted()) 9014 nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f; 9015 g.NavMoveDir = ImGuiDir_Down; 9016 g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge; 10150 9017 } 10151 10152 // Consume characters 10153 memset(g.IO.InputCharacters, 0, sizeof(g.IO.InputCharacters)); 10154 } 10155 } 10156 10157 bool cancel_edit = false; 10158 if (g.ActiveId == id && !g.ActiveIdIsJustActivated && !clear_active_id) 10159 { 10160 // Handle key-presses 10161 const int k_mask = (io.KeyShift ? STB_TEXTEDIT_K_SHIFT : 0); 10162 const bool is_osx = io.OptMacOSXBehaviors; 10163 const bool is_shortcut_key = (is_osx ? (io.KeySuper && !io.KeyCtrl) : (io.KeyCtrl && !io.KeySuper)) && !io.KeyAlt && !io.KeyShift; // OS X style: Shortcuts using Cmd/Super instead of Ctrl 10164 const bool is_osx_shift_shortcut = is_osx && io.KeySuper && io.KeyShift && !io.KeyCtrl && !io.KeyAlt; 10165 const bool is_wordmove_key_down = is_osx ? io.KeyAlt : io.KeyCtrl; // OS X style: Text editing cursor movement using Alt instead of Ctrl 10166 const bool is_startend_key_down = is_osx && io.KeySuper && !io.KeyCtrl && !io.KeyAlt; // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End 10167 const bool is_ctrl_key_only = io.KeyCtrl && !io.KeyShift && !io.KeyAlt && !io.KeySuper; 10168 const bool is_shift_key_only = io.KeyShift && !io.KeyCtrl && !io.KeyAlt && !io.KeySuper; 10169 10170 const bool is_cut = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_X)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Delete))) && is_editable && !is_password && (!is_multiline || edit_state.HasSelection()); 10171 const bool is_copy = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_C)) || (is_ctrl_key_only && IsKeyPressedMap(ImGuiKey_Insert))) && !is_password && (!is_multiline || edit_state.HasSelection()); 10172 const bool is_paste = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_V)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Insert))) && is_editable; 10173 const bool is_undo = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Z)) && is_editable && is_undoable); 10174 const bool is_redo = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Y)) || (is_osx_shift_shortcut && IsKeyPressedMap(ImGuiKey_Z))) && is_editable && is_undoable; 10175 10176 if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); } 10177 else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); } 10178 else if (IsKeyPressedMap(ImGuiKey_UpArrow) && is_multiline) { if (io.KeyCtrl) SetWindowScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); } 10179 else if (IsKeyPressedMap(ImGuiKey_DownArrow) && is_multiline) { if (io.KeyCtrl) SetWindowScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); } 10180 else if (IsKeyPressedMap(ImGuiKey_Home)) { edit_state.OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); } 10181 else if (IsKeyPressedMap(ImGuiKey_End)) { edit_state.OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); } 10182 else if (IsKeyPressedMap(ImGuiKey_Delete) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); } 10183 else if (IsKeyPressedMap(ImGuiKey_Backspace) && is_editable) 10184 { 10185 if (!edit_state.HasSelection()) 10186 { 10187 if (is_wordmove_key_down) edit_state.OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT); 10188 else if (is_osx && io.KeySuper && !io.KeyAlt && !io.KeyCtrl) edit_state.OnKeyPressed(STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT); 10189 } 10190 edit_state.OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask); 10191 } 10192 else if (IsKeyPressedMap(ImGuiKey_Enter)) 10193 { 10194 bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0; 10195 if (!is_multiline || (ctrl_enter_for_new_line && !io.KeyCtrl) || (!ctrl_enter_for_new_line && io.KeyCtrl)) 10196 { 10197 enter_pressed = clear_active_id = true; 10198 } 10199 else if (is_editable) 10200 { 10201 unsigned int c = '\n'; // Insert new line 10202 if (InputTextFilterCharacter(&c, flags, callback, user_data)) 10203 edit_state.OnKeyPressed((int)c); 10204 } 10205 } 10206 else if ((flags & ImGuiInputTextFlags_AllowTabInput) && IsKeyPressedMap(ImGuiKey_Tab) && !io.KeyCtrl && !io.KeyShift && !io.KeyAlt && is_editable) 10207 { 10208 unsigned int c = '\t'; // Insert TAB 10209 if (InputTextFilterCharacter(&c, flags, callback, user_data)) 10210 edit_state.OnKeyPressed((int)c); 10211 } 10212 else if (IsKeyPressedMap(ImGuiKey_Escape)) 10213 { 10214 clear_active_id = cancel_edit = true; 10215 } 10216 else if (is_undo || is_redo) 10217 { 10218 edit_state.OnKeyPressed(is_undo ? STB_TEXTEDIT_K_UNDO : STB_TEXTEDIT_K_REDO); 10219 edit_state.ClearSelection(); 10220 } 10221 else if (is_shortcut_key && IsKeyPressedMap(ImGuiKey_A)) 10222 { 10223 edit_state.SelectAll(); 10224 edit_state.CursorFollow = true; 10225 } 10226 else if (is_cut || is_copy) 10227 { 10228 // Cut, Copy 10229 if (io.SetClipboardTextFn) 10230 { 10231 const int ib = edit_state.HasSelection() ? ImMin(edit_state.StbState.select_start, edit_state.StbState.select_end) : 0; 10232 const int ie = edit_state.HasSelection() ? ImMax(edit_state.StbState.select_start, edit_state.StbState.select_end) : edit_state.CurLenW; 10233 edit_state.TempTextBuffer.resize((ie - ib) * 4 + 1); 10234 ImTextStrToUtf8(edit_state.TempTextBuffer.Data, edit_state.TempTextBuffer.Size, edit_state.Text.Data + ib, edit_state.Text.Data + ie); 10235 SetClipboardText(edit_state.TempTextBuffer.Data); 10236 } 10237 if (is_cut) 10238 { 10239 if (!edit_state.HasSelection()) 10240 edit_state.SelectAll(); 10241 edit_state.CursorFollow = true; 10242 stb_textedit_cut(&edit_state, &edit_state.StbState); 10243 } 10244 } 10245 else if (is_paste) 10246 { 10247 if (const char* clipboard = GetClipboardText()) 10248 { 10249 // Filter pasted buffer 10250 const int clipboard_len = (int)strlen(clipboard); 10251 ImWchar* clipboard_filtered = (ImWchar*)ImGui::MemAlloc((clipboard_len + 1) * sizeof(ImWchar)); 10252 int clipboard_filtered_len = 0; 10253 for (const char* s = clipboard; *s; ) 9018 else if (end_pressed) 10254 9019 { 10255 unsigned int c; 10256 s += ImTextCharFromUtf8(&c, s, NULL); 10257 if (c == 0) 10258 break; 10259 if (c >= 0x10000 || !InputTextFilterCharacter(&c, flags, callback, user_data)) 10260 continue; 10261 clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c; 9020 nav_rect_rel.Min.y = nav_rect_rel.Max.y = window->ScrollMax.y + window->SizeFull.y - window->Scroll.y; 9021 if (nav_rect_rel.IsInverted()) 9022 nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f; 9023 g.NavMoveDir = ImGuiDir_Up; 9024 g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge; 10262 9025 } 10263 clipboard_filtered[clipboard_filtered_len] = 0; 10264 if (clipboard_filtered_len > 0) // If everything was filtered, ignore the pasting operation 9026 return nav_scoring_rect_offset_y; 9027 } 9028 } 9029 return 0.0f; 9030 } 9031 9032 static void ImGui::NavEndFrame() 9033 { 9034 ImGuiContext& g = *GImGui; 9035 9036 // Show CTRL+TAB list window 9037 if (g.NavWindowingTarget != NULL) 9038 NavUpdateWindowingOverlay(); 9039 9040 // Perform wrap-around in menus 9041 ImGuiWindow* window = g.NavWrapRequestWindow; 9042 ImGuiNavMoveFlags move_flags = g.NavWrapRequestFlags; 9043 if (window != NULL && g.NavWindow == window && NavMoveRequestButNoResultYet() && g.NavMoveRequestForward == ImGuiNavForward_None && g.NavLayer == ImGuiNavLayer_Main) 9044 { 9045 IM_ASSERT(move_flags != 0); // No points calling this with no wrapping 9046 ImRect bb_rel = window->NavRectRel[0]; 9047 9048 ImGuiDir clip_dir = g.NavMoveDir; 9049 if (g.NavMoveDir == ImGuiDir_Left && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX))) 9050 { 9051 bb_rel.Min.x = bb_rel.Max.x = 9052 ImMax(window->SizeFull.x, window->ContentSize.x + window->WindowPadding.x * 2.0f) - window->Scroll.x; 9053 if (move_flags & ImGuiNavMoveFlags_WrapX) 10265 9054 { 10266 stb_textedit_paste(&edit_state, &edit_state.StbState, clipboard_filtered, clipboard_filtered_len);10267 edit_state.CursorFollow = true;9055 bb_rel.TranslateY(-bb_rel.GetHeight()); 9056 clip_dir = ImGuiDir_Up; 10268 9057 } 10269 ImGui::MemFree(clipboard_filtered); 10270 } 10271 } 10272 } 10273 10274 if (g.ActiveId == id) 10275 { 10276 if (cancel_edit) 10277 { 10278 // Restore initial value. Only return true if restoring to the initial value changes the current buffer contents. 10279 if (is_editable && strncmp(buf, edit_state.InitialText.Data, buf_size) != 0) 10280 { 10281 ImStrncpy(buf, edit_state.InitialText.Data, buf_size); 10282 value_changed = true; 10283 } 10284 } 10285 10286 // When using 'ImGuiInputTextFlags_EnterReturnsTrue' as a special case we reapply the live buffer back to the input buffer before clearing ActiveId, even though strictly speaking it wasn't modified on this frame. 10287 // If we didn't do that, code like InputInt() with ImGuiInputTextFlags_EnterReturnsTrue would fail. Also this allows the user to use InputText() with ImGuiInputTextFlags_EnterReturnsTrue without maintaining any user-side storage. 10288 bool apply_edit_back_to_user_buffer = !cancel_edit || (enter_pressed && (flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0); 10289 if (apply_edit_back_to_user_buffer) 10290 { 10291 // Apply new value immediately - copy modified buffer back 10292 // Note that as soon as the input box is active, the in-widget value gets priority over any underlying modification of the input buffer 10293 // FIXME: We actually always render 'buf' when calling DrawList->AddText, making the comment above incorrect. 10294 // FIXME-OPT: CPU waste to do this every time the widget is active, should mark dirty state from the stb_textedit callbacks. 10295 if (is_editable) 10296 { 10297 edit_state.TempTextBuffer.resize(edit_state.Text.Size * 4); 10298 ImTextStrToUtf8(edit_state.TempTextBuffer.Data, edit_state.TempTextBuffer.Size, edit_state.Text.Data, NULL); 10299 } 10300 10301 // User callback 10302 if ((flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory | ImGuiInputTextFlags_CallbackAlways)) != 0) 10303 { 10304 IM_ASSERT(callback != NULL); 10305 10306 // The reason we specify the usage semantic (Completion/History) is that Completion needs to disable keyboard TABBING at the moment. 10307 ImGuiInputTextFlags event_flag = 0; 10308 ImGuiKey event_key = ImGuiKey_COUNT; 10309 if ((flags & ImGuiInputTextFlags_CallbackCompletion) != 0 && IsKeyPressedMap(ImGuiKey_Tab)) 9058 NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); 9059 } 9060 if (g.NavMoveDir == ImGuiDir_Right && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX))) 9061 { 9062 bb_rel.Min.x = bb_rel.Max.x = -window->Scroll.x; 9063 if (move_flags & ImGuiNavMoveFlags_WrapX) 10310 9064 { 10311 event_flag = ImGuiInputTextFlags_CallbackCompletion;10312 event_key = ImGuiKey_Tab;9065 bb_rel.TranslateY(+bb_rel.GetHeight()); 9066 clip_dir = ImGuiDir_Down; 10313 9067 } 10314 else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressedMap(ImGuiKey_UpArrow)) 9068 NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); 9069 } 9070 if (g.NavMoveDir == ImGuiDir_Up && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY))) 9071 { 9072 bb_rel.Min.y = bb_rel.Max.y = 9073 ImMax(window->SizeFull.y, window->ContentSize.y + window->WindowPadding.y * 2.0f) - window->Scroll.y; 9074 if (move_flags & ImGuiNavMoveFlags_WrapY) 10315 9075 { 10316 event_flag = ImGuiInputTextFlags_CallbackHistory;10317 event_key = ImGuiKey_UpArrow;9076 bb_rel.TranslateX(-bb_rel.GetWidth()); 9077 clip_dir = ImGuiDir_Left; 10318 9078 } 10319 else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressedMap(ImGuiKey_DownArrow)) 9079 NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); 9080 } 9081 if (g.NavMoveDir == ImGuiDir_Down && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY))) 9082 { 9083 bb_rel.Min.y = bb_rel.Max.y = -window->Scroll.y; 9084 if (move_flags & ImGuiNavMoveFlags_WrapY) 10320 9085 { 10321 event_flag = ImGuiInputTextFlags_CallbackHistory;10322 event_key = ImGuiKey_DownArrow;9086 bb_rel.TranslateX(+bb_rel.GetWidth()); 9087 clip_dir = ImGuiDir_Right; 10323 9088 } 10324 else if (flags & ImGuiInputTextFlags_CallbackAlways) 10325 event_flag = ImGuiInputTextFlags_CallbackAlways; 10326 10327 if (event_flag) 10328 { 10329 ImGuiTextEditCallbackData callback_data; 10330 memset(&callback_data, 0, sizeof(ImGuiTextEditCallbackData)); 10331 callback_data.EventFlag = event_flag; 10332 callback_data.Flags = flags; 10333 callback_data.UserData = user_data; 10334 callback_data.ReadOnly = !is_editable; 10335 10336 callback_data.EventKey = event_key; 10337 callback_data.Buf = edit_state.TempTextBuffer.Data; 10338 callback_data.BufTextLen = edit_state.CurLenA; 10339 callback_data.BufSize = edit_state.BufSizeA; 10340 callback_data.BufDirty = false; 10341 10342 // We have to convert from wchar-positions to UTF-8-positions, which can be pretty slow (an incentive to ditch the ImWchar buffer, see https://github.com/nothings/stb/issues/188) 10343 ImWchar* text = edit_state.Text.Data; 10344 const int utf8_cursor_pos = callback_data.CursorPos = ImTextCountUtf8BytesFromStr(text, text + edit_state.StbState.cursor); 10345 const int utf8_selection_start = callback_data.SelectionStart = ImTextCountUtf8BytesFromStr(text, text + edit_state.StbState.select_start); 10346 const int utf8_selection_end = callback_data.SelectionEnd = ImTextCountUtf8BytesFromStr(text, text + edit_state.StbState.select_end); 10347 10348 // Call user code 10349 callback(&callback_data); 10350 10351 // Read back what user may have modified 10352 IM_ASSERT(callback_data.Buf == edit_state.TempTextBuffer.Data); // Invalid to modify those fields 10353 IM_ASSERT(callback_data.BufSize == edit_state.BufSizeA); 10354 IM_ASSERT(callback_data.Flags == flags); 10355 if (callback_data.CursorPos != utf8_cursor_pos) edit_state.StbState.cursor = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.CursorPos); 10356 if (callback_data.SelectionStart != utf8_selection_start) edit_state.StbState.select_start = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionStart); 10357 if (callback_data.SelectionEnd != utf8_selection_end) edit_state.StbState.select_end = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd); 10358 if (callback_data.BufDirty) 10359 { 10360 IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text! 10361 edit_state.CurLenW = ImTextStrFromUtf8(edit_state.Text.Data, edit_state.Text.Size, callback_data.Buf, NULL); 10362 edit_state.CurLenA = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, saves us an extra strlen() 10363 edit_state.CursorAnimReset(); 10364 } 10365 } 10366 } 10367 10368 // Copy back to user buffer 10369 if (is_editable && strcmp(edit_state.TempTextBuffer.Data, buf) != 0) 10370 { 10371 ImStrncpy(buf, edit_state.TempTextBuffer.Data, buf_size); 10372 value_changed = true; 10373 } 10374 } 10375 } 10376 10377 // Release active ID at the end of the function (so e.g. pressing Return still does a final application of the value) 10378 if (clear_active_id && g.ActiveId == id) 10379 ClearActiveID(); 10380 10381 // Render 10382 // Select which buffer we are going to display. When ImGuiInputTextFlags_NoLiveEdit is set 'buf' might still be the old value. We set buf to NULL to prevent accidental usage from now on. 10383 const char* buf_display = (g.ActiveId == id && is_editable) ? edit_state.TempTextBuffer.Data : buf; buf = NULL; 10384 10385 RenderNavHighlight(frame_bb, id); 10386 if (!is_multiline) 10387 RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); 10388 10389 const ImVec4 clip_rect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + size.x, frame_bb.Min.y + size.y); // Not using frame_bb.Max because we have adjusted size 10390 ImVec2 render_pos = is_multiline ? draw_window->DC.CursorPos : frame_bb.Min + style.FramePadding; 10391 ImVec2 text_size(0.f, 0.f); 10392 const bool is_currently_scrolling = (edit_state.Id == id && is_multiline && g.ActiveId == draw_window->GetIDNoKeepAlive("#SCROLLY")); 10393 if (g.ActiveId == id || is_currently_scrolling) 10394 { 10395 edit_state.CursorAnim += io.DeltaTime; 10396 10397 // This is going to be messy. We need to: 10398 // - Display the text (this alone can be more easily clipped) 10399 // - Handle scrolling, highlight selection, display cursor (those all requires some form of 1d->2d cursor position calculation) 10400 // - Measure text height (for scrollbar) 10401 // We are attempting to do most of that in **one main pass** to minimize the computation cost (non-negligible for large amount of text) + 2nd pass for selection rendering (we could merge them by an extra refactoring effort) 10402 // FIXME: This should occur on buf_display but we'd need to maintain cursor/select_start/select_end for UTF-8. 10403 const ImWchar* text_begin = edit_state.Text.Data; 10404 ImVec2 cursor_offset, select_start_offset; 10405 10406 { 10407 // Count lines + find lines numbers straddling 'cursor' and 'select_start' position. 10408 const ImWchar* searches_input_ptr[2]; 10409 searches_input_ptr[0] = text_begin + edit_state.StbState.cursor; 10410 searches_input_ptr[1] = NULL; 10411 int searches_remaining = 1; 10412 int searches_result_line_number[2] = { -1, -999 }; 10413 if (edit_state.StbState.select_start != edit_state.StbState.select_end) 10414 { 10415 searches_input_ptr[1] = text_begin + ImMin(edit_state.StbState.select_start, edit_state.StbState.select_end); 10416 searches_result_line_number[1] = -1; 10417 searches_remaining++; 10418 } 10419 10420 // Iterate all lines to find our line numbers 10421 // In multi-line mode, we never exit the loop until all lines are counted, so add one extra to the searches_remaining counter. 10422 searches_remaining += is_multiline ? 1 : 0; 10423 int line_count = 0; 10424 for (const ImWchar* s = text_begin; *s != 0; s++) 10425 if (*s == '\n') 10426 { 10427 line_count++; 10428 if (searches_result_line_number[0] == -1 && s >= searches_input_ptr[0]) { searches_result_line_number[0] = line_count; if (--searches_remaining <= 0) break; } 10429 if (searches_result_line_number[1] == -1 && s >= searches_input_ptr[1]) { searches_result_line_number[1] = line_count; if (--searches_remaining <= 0) break; } 10430 } 10431 line_count++; 10432 if (searches_result_line_number[0] == -1) searches_result_line_number[0] = line_count; 10433 if (searches_result_line_number[1] == -1) searches_result_line_number[1] = line_count; 10434 10435 // Calculate 2d position by finding the beginning of the line and measuring distance 10436 cursor_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[0], text_begin), searches_input_ptr[0]).x; 10437 cursor_offset.y = searches_result_line_number[0] * g.FontSize; 10438 if (searches_result_line_number[1] >= 0) 10439 { 10440 select_start_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x; 10441 select_start_offset.y = searches_result_line_number[1] * g.FontSize; 10442 } 10443 10444 // Store text height (note that we haven't calculated text width at all, see GitHub issues #383, #1224) 10445 if (is_multiline) 10446 text_size = ImVec2(size.x, line_count * g.FontSize); 10447 } 10448 10449 // Scroll 10450 if (edit_state.CursorFollow) 10451 { 10452 // Horizontal scroll in chunks of quarter width 10453 if (!(flags & ImGuiInputTextFlags_NoHorizontalScroll)) 10454 { 10455 const float scroll_increment_x = size.x * 0.25f; 10456 if (cursor_offset.x < edit_state.ScrollX) 10457 edit_state.ScrollX = (float)(int)ImMax(0.0f, cursor_offset.x - scroll_increment_x); 10458 else if (cursor_offset.x - size.x >= edit_state.ScrollX) 10459 edit_state.ScrollX = (float)(int)(cursor_offset.x - size.x + scroll_increment_x); 10460 } 10461 else 10462 { 10463 edit_state.ScrollX = 0.0f; 10464 } 10465 10466 // Vertical scroll 10467 if (is_multiline) 10468 { 10469 float scroll_y = draw_window->Scroll.y; 10470 if (cursor_offset.y - g.FontSize < scroll_y) 10471 scroll_y = ImMax(0.0f, cursor_offset.y - g.FontSize); 10472 else if (cursor_offset.y - size.y >= scroll_y) 10473 scroll_y = cursor_offset.y - size.y; 10474 draw_window->DC.CursorPos.y += (draw_window->Scroll.y - scroll_y); // To avoid a frame of lag 10475 draw_window->Scroll.y = scroll_y; 10476 render_pos.y = draw_window->DC.CursorPos.y; 10477 } 10478 } 10479 edit_state.CursorFollow = false; 10480 const ImVec2 render_scroll = ImVec2(edit_state.ScrollX, 0.0f); 10481 10482 // Draw selection 10483 if (edit_state.StbState.select_start != edit_state.StbState.select_end) 10484 { 10485 const ImWchar* text_selected_begin = text_begin + ImMin(edit_state.StbState.select_start, edit_state.StbState.select_end); 10486 const ImWchar* text_selected_end = text_begin + ImMax(edit_state.StbState.select_start, edit_state.StbState.select_end); 10487 10488 float bg_offy_up = is_multiline ? 0.0f : -1.0f; // FIXME: those offsets should be part of the style? they don't play so well with multi-line selection. 10489 float bg_offy_dn = is_multiline ? 0.0f : 2.0f; 10490 ImU32 bg_color = GetColorU32(ImGuiCol_TextSelectedBg); 10491 ImVec2 rect_pos = render_pos + select_start_offset - render_scroll; 10492 for (const ImWchar* p = text_selected_begin; p < text_selected_end; ) 10493 { 10494 if (rect_pos.y > clip_rect.w + g.FontSize) 10495 break; 10496 if (rect_pos.y < clip_rect.y) 10497 { 10498 while (p < text_selected_end) 10499 if (*p++ == '\n') 10500 break; 10501 } 10502 else 10503 { 10504 ImVec2 rect_size = InputTextCalcTextSizeW(p, text_selected_end, &p, NULL, true); 10505 if (rect_size.x <= 0.0f) rect_size.x = (float)(int)(g.Font->GetCharAdvance((unsigned short)' ') * 0.50f); // So we can see selected empty lines 10506 ImRect rect(rect_pos + ImVec2(0.0f, bg_offy_up - g.FontSize), rect_pos + ImVec2(rect_size.x, bg_offy_dn)); 10507 rect.ClipWith(clip_rect); 10508 if (rect.Overlaps(clip_rect)) 10509 draw_window->DrawList->AddRectFilled(rect.Min, rect.Max, bg_color); 10510 } 10511 rect_pos.x = render_pos.x - render_scroll.x; 10512 rect_pos.y += g.FontSize; 10513 } 10514 } 10515 10516 draw_window->DrawList->AddText(g.Font, g.FontSize, render_pos - render_scroll, GetColorU32(ImGuiCol_Text), buf_display, buf_display + edit_state.CurLenA, 0.0f, is_multiline ? NULL : &clip_rect); 10517 10518 // Draw blinking cursor 10519 bool cursor_is_visible = (!g.IO.OptCursorBlink) || (g.InputTextState.CursorAnim <= 0.0f) || fmodf(g.InputTextState.CursorAnim, 1.20f) <= 0.80f; 10520 ImVec2 cursor_screen_pos = render_pos + cursor_offset - render_scroll; 10521 ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y - g.FontSize + 0.5f, cursor_screen_pos.x + 1.0f, cursor_screen_pos.y - 1.5f); 10522 if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect)) 10523 draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_Text)); 10524 10525 // Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.) 10526 if (is_editable) 10527 g.PlatformImePos = ImVec2(cursor_screen_pos.x - 1, cursor_screen_pos.y - g.FontSize); 10528 } 10529 else 10530 { 10531 // Render text only 10532 const char* buf_end = NULL; 10533 if (is_multiline) 10534 text_size = ImVec2(size.x, InputTextCalcTextLenAndLineCount(buf_display, &buf_end) * g.FontSize); // We don't need width 10535 draw_window->DrawList->AddText(g.Font, g.FontSize, render_pos, GetColorU32(ImGuiCol_Text), buf_display, buf_end, 0.0f, is_multiline ? NULL : &clip_rect); 10536 } 10537 10538 if (is_multiline) 10539 { 10540 Dummy(text_size + ImVec2(0.0f, g.FontSize)); // Always add room to scroll an extra line 10541 EndChildFrame(); 10542 EndGroup(); 10543 } 10544 10545 if (is_password) 10546 PopFont(); 10547 10548 // Log as text 10549 if (g.LogEnabled && !is_password) 10550 LogRenderedText(&render_pos, buf_display, NULL); 10551 10552 if (label_size.x > 0) 10553 RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); 10554 10555 if ((flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0) 10556 return enter_pressed; 10557 else 10558 return value_changed; 10559 } 10560 10561 bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data) 10562 { 10563 IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline() 10564 return InputTextEx(label, buf, (int)buf_size, ImVec2(0, 0), flags, callback, user_data); 10565 } 10566 10567 bool ImGui::InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data) 10568 { 10569 return InputTextEx(label, buf, (int)buf_size, size, flags | ImGuiInputTextFlags_Multiline, callback, user_data); 10570 } 10571 10572 // NB: scalar_format here must be a simple "%xx" format string with no prefix/suffix (unlike the Drag/Slider functions "format" argument) 10573 bool ImGui::InputScalarEx(const char* label, ImGuiDataType data_type, void* data_ptr, void* step_ptr, void* step_fast_ptr, const char* scalar_format, ImGuiInputTextFlags extra_flags) 10574 { 10575 ImGuiWindow* window = GetCurrentWindow(); 10576 if (window->SkipItems) 10577 return false; 10578 10579 ImGuiContext& g = *GImGui; 10580 const ImGuiStyle& style = g.Style; 10581 10582 char buf[64]; 10583 DataTypeFormatString(buf, IM_ARRAYSIZE(buf), data_type, data_ptr, scalar_format); 10584 10585 bool value_changed = false; 10586 if ((extra_flags & (ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsScientific)) == 0) 10587 extra_flags |= ImGuiInputTextFlags_CharsDecimal; 10588 extra_flags |= ImGuiInputTextFlags_AutoSelectAll; 10589 10590 if (step_ptr) 10591 { 10592 const float button_size = GetFrameHeight(); 10593 10594 BeginGroup(); // The only purpose of the group here is to allow the caller to query item data e.g. IsItemActive() 10595 PushID(label); 10596 PushItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2)); 10597 if (InputText("", buf, IM_ARRAYSIZE(buf), extra_flags)) // PushId(label) + "" gives us the expected ID from outside point of view 10598 value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialText.Data, data_type, data_ptr, scalar_format); 10599 PopItemWidth(); 10600 10601 // Step buttons 10602 SameLine(0, style.ItemInnerSpacing.x); 10603 if (ButtonEx("-", ImVec2(button_size, button_size), ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups)) 10604 { 10605 DataTypeApplyOp(data_type, '-', data_ptr, data_ptr, g.IO.KeyCtrl && step_fast_ptr ? step_fast_ptr : step_ptr); 10606 value_changed = true; 10607 } 10608 SameLine(0, style.ItemInnerSpacing.x); 10609 if (ButtonEx("+", ImVec2(button_size, button_size), ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups)) 10610 { 10611 DataTypeApplyOp(data_type, '+', data_ptr, data_ptr, g.IO.KeyCtrl && step_fast_ptr ? step_fast_ptr : step_ptr); 10612 value_changed = true; 10613 } 10614 SameLine(0, style.ItemInnerSpacing.x); 10615 TextUnformatted(label, FindRenderedTextEnd(label)); 10616 10617 PopID(); 10618 EndGroup(); 10619 } 10620 else 10621 { 10622 if (InputText(label, buf, IM_ARRAYSIZE(buf), extra_flags)) 10623 value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialText.Data, data_type, data_ptr, scalar_format); 10624 } 10625 10626 return value_changed; 10627 } 10628 10629 bool ImGui::InputFloat(const char* label, float* v, float step, float step_fast, const char* format, ImGuiInputTextFlags extra_flags) 10630 { 10631 extra_flags |= ImGuiInputTextFlags_CharsScientific; 10632 return InputScalarEx(label, ImGuiDataType_Float, (void*)v, (void*)(step>0.0f ? &step : NULL), (void*)(step_fast>0.0f ? &step_fast : NULL), format, extra_flags); 10633 } 10634 10635 bool ImGui::InputDouble(const char* label, double* v, double step, double step_fast, const char* format, ImGuiInputTextFlags extra_flags) 10636 { 10637 extra_flags |= ImGuiInputTextFlags_CharsScientific; 10638 return InputScalarEx(label, ImGuiDataType_Double, (void*)v, (void*)(step>0.0 ? &step : NULL), (void*)(step_fast>0.0 ? &step_fast : NULL), format, extra_flags); 10639 } 10640 10641 bool ImGui::InputInt(const char* label, int* v, int step, int step_fast, ImGuiInputTextFlags extra_flags) 10642 { 10643 // Hexadecimal input provided as a convenience but the flag name is awkward. Typically you'd use InputText() to parse your own data, if you want to handle prefixes. 10644 const char* format = (extra_flags & ImGuiInputTextFlags_CharsHexadecimal) ? "%08X" : "%d"; 10645 return InputScalarEx(label, ImGuiDataType_Int32, (void*)v, (void*)(step>0 ? &step : NULL), (void*)(step_fast>0 ? &step_fast : NULL), format, extra_flags); 10646 } 10647 10648 bool ImGui::InputFloatN(const char* label, float* v, int components, const char* format, ImGuiInputTextFlags extra_flags) 10649 { 10650 ImGuiWindow* window = GetCurrentWindow(); 10651 if (window->SkipItems) 10652 return false; 10653 10654 ImGuiContext& g = *GImGui; 10655 bool value_changed = false; 10656 BeginGroup(); 10657 PushID(label); 10658 PushMultiItemsWidths(components); 10659 for (int i = 0; i < components; i++) 10660 { 10661 PushID(i); 10662 value_changed |= InputFloat("##v", &v[i], 0, 0, format, extra_flags); 10663 SameLine(0, g.Style.ItemInnerSpacing.x); 10664 PopID(); 10665 PopItemWidth(); 10666 } 10667 PopID(); 10668 10669 TextUnformatted(label, FindRenderedTextEnd(label)); 10670 EndGroup(); 10671 10672 return value_changed; 10673 } 10674 10675 bool ImGui::InputFloat2(const char* label, float v[2], const char* format, ImGuiInputTextFlags extra_flags) 10676 { 10677 return InputFloatN(label, v, 2, format, extra_flags); 10678 } 10679 10680 bool ImGui::InputFloat3(const char* label, float v[3], const char* format, ImGuiInputTextFlags extra_flags) 10681 { 10682 return InputFloatN(label, v, 3, format, extra_flags); 10683 } 10684 10685 bool ImGui::InputFloat4(const char* label, float v[4], const char* format, ImGuiInputTextFlags extra_flags) 10686 { 10687 return InputFloatN(label, v, 4, format, extra_flags); 10688 } 10689 10690 // Prefer using "const char* format" directly, which is more flexible and consistent with other API. 10691 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS 10692 bool ImGui::InputFloat(const char* label, float* v, float step, float step_fast, int decimal_precision, ImGuiInputTextFlags extra_flags) 10693 { 10694 char format[16] = "%f"; 10695 if (decimal_precision >= 0) 10696 ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision); 10697 return InputFloat(label, v, step, step_fast, format, extra_flags); 10698 } 10699 10700 bool ImGui::InputFloat2(const char* label, float v[2], int decimal_precision, ImGuiInputTextFlags extra_flags) 10701 { 10702 char format[16] = "%f"; 10703 if (decimal_precision >= 0) 10704 ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision); 10705 return InputFloatN(label, v, 2, format, extra_flags); 10706 } 10707 10708 bool ImGui::InputFloat3(const char* label, float v[3], int decimal_precision, ImGuiInputTextFlags extra_flags) 10709 { 10710 char format[16] = "%f"; 10711 if (decimal_precision >= 0) 10712 ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision); 10713 return InputFloatN(label, v, 3, format, extra_flags); 10714 } 10715 10716 bool ImGui::InputFloat4(const char* label, float v[4], int decimal_precision, ImGuiInputTextFlags extra_flags) 10717 { 10718 char format[16] = "%f"; 10719 if (decimal_precision >= 0) 10720 ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision); 10721 return InputFloatN(label, v, 4, format, extra_flags); 10722 } 10723 #endif // IMGUI_DISABLE_OBSOLETE_FUNCTIONS 10724 10725 bool ImGui::InputIntN(const char* label, int* v, int components, ImGuiInputTextFlags extra_flags) 10726 { 10727 ImGuiWindow* window = GetCurrentWindow(); 10728 if (window->SkipItems) 10729 return false; 10730 10731 ImGuiContext& g = *GImGui; 10732 bool value_changed = false; 10733 BeginGroup(); 10734 PushID(label); 10735 PushMultiItemsWidths(components); 10736 for (int i = 0; i < components; i++) 10737 { 10738 PushID(i); 10739 value_changed |= InputInt("##v", &v[i], 0, 0, extra_flags); 10740 SameLine(0, g.Style.ItemInnerSpacing.x); 10741 PopID(); 10742 PopItemWidth(); 10743 } 10744 PopID(); 10745 10746 TextUnformatted(label, FindRenderedTextEnd(label)); 10747 EndGroup(); 10748 10749 return value_changed; 10750 } 10751 10752 bool ImGui::InputInt2(const char* label, int v[2], ImGuiInputTextFlags extra_flags) 10753 { 10754 return InputIntN(label, v, 2, extra_flags); 10755 } 10756 10757 bool ImGui::InputInt3(const char* label, int v[3], ImGuiInputTextFlags extra_flags) 10758 { 10759 return InputIntN(label, v, 3, extra_flags); 10760 } 10761 10762 bool ImGui::InputInt4(const char* label, int v[4], ImGuiInputTextFlags extra_flags) 10763 { 10764 return InputIntN(label, v, 4, extra_flags); 10765 } 10766 10767 static float CalcMaxPopupHeightFromItemCount(int items_count) 10768 { 10769 ImGuiContext& g = *GImGui; 10770 if (items_count <= 0) 10771 return FLT_MAX; 10772 return (g.FontSize + g.Style.ItemSpacing.y) * items_count - g.Style.ItemSpacing.y + (g.Style.WindowPadding.y * 2); 10773 } 10774 10775 bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags) 10776 { 10777 // Always consume the SetNextWindowSizeConstraint() call in our early return paths 10778 ImGuiContext& g = *GImGui; 10779 ImGuiCond backup_next_window_size_constraint = g.NextWindowData.SizeConstraintCond; 10780 g.NextWindowData.SizeConstraintCond = 0; 10781 10782 ImGuiWindow* window = GetCurrentWindow(); 10783 if (window->SkipItems) 10784 return false; 10785 10786 IM_ASSERT((flags & (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)) != (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)); // Can't use both flags together 10787 10788 const ImGuiStyle& style = g.Style; 10789 const ImGuiID id = window->GetID(label); 10790 10791 const float arrow_size = (flags & ImGuiComboFlags_NoArrowButton) ? 0.0f : GetFrameHeight(); 10792 const ImVec2 label_size = CalcTextSize(label, NULL, true); 10793 const float w = (flags & ImGuiComboFlags_NoPreview) ? arrow_size : CalcItemWidth(); 10794 const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f)); 10795 const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); 10796 ItemSize(total_bb, style.FramePadding.y); 10797 if (!ItemAdd(total_bb, id, &frame_bb)) 10798 return false; 10799 10800 bool hovered, held; 10801 bool pressed = ButtonBehavior(frame_bb, id, &hovered, &held); 10802 bool popup_open = IsPopupOpen(id); 10803 10804 const ImRect value_bb(frame_bb.Min, frame_bb.Max - ImVec2(arrow_size, 0.0f)); 10805 const ImU32 frame_col = GetColorU32(hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); 10806 RenderNavHighlight(frame_bb, id); 10807 if (!(flags & ImGuiComboFlags_NoPreview)) 10808 window->DrawList->AddRectFilled(frame_bb.Min, ImVec2(frame_bb.Max.x - arrow_size, frame_bb.Max.y), frame_col, style.FrameRounding, ImDrawCornerFlags_Left); 10809 if (!(flags & ImGuiComboFlags_NoArrowButton)) 10810 { 10811 window->DrawList->AddRectFilled(ImVec2(frame_bb.Max.x - arrow_size, frame_bb.Min.y), frame_bb.Max, GetColorU32((popup_open || hovered) ? ImGuiCol_ButtonHovered : ImGuiCol_Button), style.FrameRounding, (w <= arrow_size) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Right); 10812 RenderArrow(ImVec2(frame_bb.Max.x - arrow_size + style.FramePadding.y, frame_bb.Min.y + style.FramePadding.y), ImGuiDir_Down); 10813 } 10814 RenderFrameBorder(frame_bb.Min, frame_bb.Max, style.FrameRounding); 10815 if (preview_value != NULL && !(flags & ImGuiComboFlags_NoPreview)) 10816 RenderTextClipped(frame_bb.Min + style.FramePadding, value_bb.Max, preview_value, NULL, NULL, ImVec2(0.0f, 0.0f)); 10817 if (label_size.x > 0) 10818 RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); 10819 10820 if ((pressed || g.NavActivateId == id) && !popup_open) 10821 { 10822 if (window->DC.NavLayerCurrent == 0) 10823 window->NavLastIds[0] = id; 10824 OpenPopupEx(id); 10825 popup_open = true; 10826 } 10827 10828 if (!popup_open) 10829 return false; 10830 10831 if (backup_next_window_size_constraint) 10832 { 10833 g.NextWindowData.SizeConstraintCond = backup_next_window_size_constraint; 10834 g.NextWindowData.SizeConstraintRect.Min.x = ImMax(g.NextWindowData.SizeConstraintRect.Min.x, w); 10835 } 10836 else 10837 { 10838 if ((flags & ImGuiComboFlags_HeightMask_) == 0) 10839 flags |= ImGuiComboFlags_HeightRegular; 10840 IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiComboFlags_HeightMask_)); // Only one 10841 int popup_max_height_in_items = -1; 10842 if (flags & ImGuiComboFlags_HeightRegular) popup_max_height_in_items = 8; 10843 else if (flags & ImGuiComboFlags_HeightSmall) popup_max_height_in_items = 4; 10844 else if (flags & ImGuiComboFlags_HeightLarge) popup_max_height_in_items = 20; 10845 SetNextWindowSizeConstraints(ImVec2(w, 0.0f), ImVec2(FLT_MAX, CalcMaxPopupHeightFromItemCount(popup_max_height_in_items))); 10846 } 10847 10848 char name[16]; 10849 ImFormatString(name, IM_ARRAYSIZE(name), "##Combo_%02d", g.CurrentPopupStack.Size); // Recycle windows based on depth 10850 10851 // Peak into expected window size so we can position it 10852 if (ImGuiWindow* popup_window = FindWindowByName(name)) 10853 if (popup_window->WasActive) 10854 { 10855 ImVec2 size_contents = CalcSizeContents(popup_window); 10856 ImVec2 size_expected = CalcSizeAfterConstraint(popup_window, CalcSizeAutoFit(popup_window, size_contents)); 10857 if (flags & ImGuiComboFlags_PopupAlignLeft) 10858 popup_window->AutoPosLastDirection = ImGuiDir_Left; 10859 ImRect r_outer = FindAllowedExtentRectForWindow(popup_window); 10860 ImVec2 pos = FindBestWindowPosForPopupEx(frame_bb.GetBL(), size_expected, &popup_window->AutoPosLastDirection, r_outer, frame_bb, ImGuiPopupPositionPolicy_ComboBox); 10861 SetNextWindowPos(pos); 10862 } 10863 10864 ImGuiWindowFlags window_flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings; 10865 if (!Begin(name, NULL, window_flags)) 10866 { 10867 EndPopup(); 10868 IM_ASSERT(0); // This should never happen as we tested for IsPopupOpen() above 10869 return false; 10870 } 10871 10872 // Horizontally align ourselves with the framed text 10873 if (style.FramePadding.x != style.WindowPadding.x) 10874 Indent(style.FramePadding.x - style.WindowPadding.x); 10875 10876 return true; 10877 } 10878 10879 void ImGui::EndCombo() 10880 { 10881 const ImGuiStyle& style = GImGui->Style; 10882 if (style.FramePadding.x != style.WindowPadding.x) 10883 Unindent(style.FramePadding.x - style.WindowPadding.x); 10884 EndPopup(); 10885 } 10886 10887 // Old API, prefer using BeginCombo() nowadays if you can. 10888 bool ImGui::Combo(const char* label, int* current_item, bool(*items_getter)(void*, int, const char**), void* data, int items_count, int popup_max_height_in_items) 10889 { 10890 ImGuiContext& g = *GImGui; 10891 10892 const char* preview_text = NULL; 10893 if (*current_item >= 0 && *current_item < items_count) 10894 items_getter(data, *current_item, &preview_text); 10895 10896 // The old Combo() API exposed "popup_max_height_in_items", however the new more general BeginCombo() API doesn't, so we emulate it here. 10897 if (popup_max_height_in_items != -1 && !g.NextWindowData.SizeConstraintCond) 10898 { 10899 float popup_max_height = CalcMaxPopupHeightFromItemCount(popup_max_height_in_items); 10900 SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, popup_max_height)); 10901 } 10902 10903 if (!BeginCombo(label, preview_text, 0)) 10904 return false; 10905 10906 // Display items 10907 // FIXME-OPT: Use clipper (but we need to disable it on the appearing frame to make sure our call to SetItemDefaultFocus() is processed) 10908 bool value_changed = false; 10909 for (int i = 0; i < items_count; i++) 10910 { 10911 PushID((void*)(intptr_t)i); 10912 const bool item_selected = (i == *current_item); 10913 const char* item_text; 10914 if (!items_getter(data, i, &item_text)) 10915 item_text = "*Unknown item*"; 10916 if (Selectable(item_text, item_selected)) 10917 { 10918 value_changed = true; 10919 *current_item = i; 10920 } 10921 if (item_selected) 10922 SetItemDefaultFocus(); 10923 PopID(); 10924 } 10925 10926 EndCombo(); 10927 return value_changed; 10928 } 10929 10930 static bool Items_ArrayGetter(void* data, int idx, const char** out_text) 10931 { 10932 const char* const* items = (const char* const*)data; 10933 if (out_text) 10934 *out_text = items[idx]; 10935 return true; 10936 } 10937 10938 static bool Items_SingleStringGetter(void* data, int idx, const char** out_text) 10939 { 10940 // FIXME-OPT: we could pre-compute the indices to fasten this. But only 1 active combo means the waste is limited. 10941 const char* items_separated_by_zeros = (const char*)data; 10942 int items_count = 0; 10943 const char* p = items_separated_by_zeros; 10944 while (*p) 10945 { 10946 if (idx == items_count) 10947 break; 10948 p += strlen(p) + 1; 10949 items_count++; 10950 } 10951 if (!*p) 10952 return false; 10953 if (out_text) 10954 *out_text = p; 10955 return true; 10956 } 10957 10958 // Combo box helper allowing to pass an array of strings. 10959 bool ImGui::Combo(const char* label, int* current_item, const char* const items[], int items_count, int height_in_items) 10960 { 10961 const bool value_changed = Combo(label, current_item, Items_ArrayGetter, (void*)items, items_count, height_in_items); 10962 return value_changed; 10963 } 10964 10965 // Combo box helper allowing to pass all items in a single string. 10966 bool ImGui::Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int height_in_items) 10967 { 10968 int items_count = 0; 10969 const char* p = items_separated_by_zeros; // FIXME-OPT: Avoid computing this, or at least only when combo is open 10970 while (*p) 10971 { 10972 p += strlen(p) + 1; 10973 items_count++; 10974 } 10975 bool value_changed = Combo(label, current_item, Items_SingleStringGetter, (void*)items_separated_by_zeros, items_count, height_in_items); 10976 return value_changed; 10977 } 10978 10979 // Tip: pass an empty label (e.g. "##dummy") then you can use the space to draw other text or image. 10980 // But you need to make sure the ID is unique, e.g. enclose calls in PushID/PopID. 10981 bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags flags, const ImVec2& size_arg) 10982 { 10983 ImGuiWindow* window = GetCurrentWindow(); 10984 if (window->SkipItems) 10985 return false; 10986 10987 ImGuiContext& g = *GImGui; 10988 const ImGuiStyle& style = g.Style; 10989 10990 if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsSet) // FIXME-OPT: Avoid if vertically clipped. 10991 PopClipRect(); 10992 10993 ImGuiID id = window->GetID(label); 10994 ImVec2 label_size = CalcTextSize(label, NULL, true); 10995 ImVec2 size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y); 10996 ImVec2 pos = window->DC.CursorPos; 10997 pos.y += window->DC.CurrentLineTextBaseOffset; 10998 ImRect bb(pos, pos + size); 10999 ItemSize(bb); 11000 11001 // Fill horizontal space. 11002 ImVec2 window_padding = window->WindowPadding; 11003 float max_x = (flags & ImGuiSelectableFlags_SpanAllColumns) ? GetWindowContentRegionMax().x : GetContentRegionMax().x; 11004 float w_draw = ImMax(label_size.x, window->Pos.x + max_x - window_padding.x - window->DC.CursorPos.x); 11005 ImVec2 size_draw((size_arg.x != 0 && !(flags & ImGuiSelectableFlags_DrawFillAvailWidth)) ? size_arg.x : w_draw, size_arg.y != 0.0f ? size_arg.y : size.y); 11006 ImRect bb_with_spacing(pos, pos + size_draw); 11007 if (size_arg.x == 0.0f || (flags & ImGuiSelectableFlags_DrawFillAvailWidth)) 11008 bb_with_spacing.Max.x += window_padding.x; 11009 11010 // Selectables are tightly packed together, we extend the box to cover spacing between selectable. 11011 float spacing_L = (float)(int)(style.ItemSpacing.x * 0.5f); 11012 float spacing_U = (float)(int)(style.ItemSpacing.y * 0.5f); 11013 float spacing_R = style.ItemSpacing.x - spacing_L; 11014 float spacing_D = style.ItemSpacing.y - spacing_U; 11015 bb_with_spacing.Min.x -= spacing_L; 11016 bb_with_spacing.Min.y -= spacing_U; 11017 bb_with_spacing.Max.x += spacing_R; 11018 bb_with_spacing.Max.y += spacing_D; 11019 if (!ItemAdd(bb_with_spacing, (flags & ImGuiSelectableFlags_Disabled) ? 0 : id)) 11020 { 11021 if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsSet) 11022 PushColumnClipRect(); 11023 return false; 11024 } 11025 11026 ImGuiButtonFlags button_flags = 0; 11027 if (flags & ImGuiSelectableFlags_Menu) button_flags |= ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_NoHoldingActiveID; 11028 if (flags & ImGuiSelectableFlags_MenuItem) button_flags |= ImGuiButtonFlags_PressedOnRelease; 11029 if (flags & ImGuiSelectableFlags_Disabled) button_flags |= ImGuiButtonFlags_Disabled; 11030 if (flags & ImGuiSelectableFlags_AllowDoubleClick) button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; 11031 bool hovered, held; 11032 bool pressed = ButtonBehavior(bb_with_spacing, id, &hovered, &held, button_flags); 11033 if (flags & ImGuiSelectableFlags_Disabled) 11034 selected = false; 11035 11036 // Hovering selectable with mouse updates NavId accordingly so navigation can be resumed with gamepad/keyboard (this doesn't happen on most widgets) 11037 if (pressed || hovered) 11038 if (!g.NavDisableMouseHover && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent) 11039 { 11040 g.NavDisableHighlight = true; 11041 SetNavID(id, window->DC.NavLayerCurrent); 11042 } 11043 11044 // Render 11045 if (hovered || selected) 11046 { 11047 const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); 11048 RenderFrame(bb_with_spacing.Min, bb_with_spacing.Max, col, false, 0.0f); 11049 RenderNavHighlight(bb_with_spacing, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding); 11050 } 11051 11052 if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsSet) 11053 { 11054 PushColumnClipRect(); 11055 bb_with_spacing.Max.x -= (GetContentRegionMax().x - max_x); 11056 } 11057 11058 if (flags & ImGuiSelectableFlags_Disabled) PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); 11059 RenderTextClipped(bb.Min, bb_with_spacing.Max, label, NULL, &label_size, ImVec2(0.0f, 0.0f)); 11060 if (flags & ImGuiSelectableFlags_Disabled) PopStyleColor(); 11061 11062 // Automatically close popups 11063 if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_DontClosePopups) && !(window->DC.ItemFlags & ImGuiItemFlags_SelectableDontClosePopup)) 11064 CloseCurrentPopup(); 11065 return pressed; 11066 } 11067 11068 bool ImGui::Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags, const ImVec2& size_arg) 11069 { 11070 if (Selectable(label, *p_selected, flags, size_arg)) 11071 { 11072 *p_selected = !*p_selected; 11073 return true; 11074 } 11075 return false; 11076 } 11077 11078 // Helper to calculate the size of a listbox and display a label on the right. 11079 // Tip: To have a list filling the entire window width, PushItemWidth(-1) and pass an empty label "##empty" 11080 bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg) 11081 { 11082 ImGuiWindow* window = GetCurrentWindow(); 11083 if (window->SkipItems) 11084 return false; 11085 11086 const ImGuiStyle& style = GetStyle(); 11087 const ImGuiID id = GetID(label); 11088 const ImVec2 label_size = CalcTextSize(label, NULL, true); 11089 11090 // Size default to hold ~7 items. Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar. 11091 ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), GetTextLineHeightWithSpacing() * 7.4f + style.ItemSpacing.y); 11092 ImVec2 frame_size = ImVec2(size.x, ImMax(size.y, label_size.y)); 11093 ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); 11094 ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); 11095 window->DC.LastItemRect = bb; // Forward storage for ListBoxFooter.. dodgy. 11096 11097 BeginGroup(); 11098 if (label_size.x > 0) 11099 RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); 11100 11101 BeginChildFrame(id, frame_bb.GetSize()); 11102 return true; 11103 } 11104 11105 bool ImGui::ListBoxHeader(const char* label, int items_count, int height_in_items) 11106 { 11107 // Size default to hold ~7 items. Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar. 11108 // However we don't add +0.40f if items_count <= height_in_items. It is slightly dodgy, because it means a dynamic list of items will make the widget resize occasionally when it crosses that size. 11109 // I am expecting that someone will come and complain about this behavior in a remote future, then we can advise on a better solution. 11110 if (height_in_items < 0) 11111 height_in_items = ImMin(items_count, 7); 11112 float height_in_items_f = height_in_items < items_count ? (height_in_items + 0.40f) : (height_in_items + 0.00f); 11113 11114 // We include ItemSpacing.y so that a list sized for the exact number of items doesn't make a scrollbar appears. We could also enforce that by passing a flag to BeginChild(). 11115 ImVec2 size; 11116 size.x = 0.0f; 11117 size.y = GetTextLineHeightWithSpacing() * height_in_items_f + GetStyle().ItemSpacing.y; 11118 return ListBoxHeader(label, size); 11119 } 11120 11121 void ImGui::ListBoxFooter() 11122 { 11123 ImGuiWindow* parent_window = GetCurrentWindow()->ParentWindow; 11124 const ImRect bb = parent_window->DC.LastItemRect; 11125 const ImGuiStyle& style = GetStyle(); 11126 11127 EndChildFrame(); 11128 11129 // Redeclare item size so that it includes the label (we have stored the full size in LastItemRect) 11130 // We call SameLine() to restore DC.CurrentLine* data 11131 SameLine(); 11132 parent_window->DC.CursorPos = bb.Min; 11133 ItemSize(bb, style.FramePadding.y); 11134 EndGroup(); 11135 } 11136 11137 bool ImGui::ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_items) 11138 { 11139 const bool value_changed = ListBox(label, current_item, Items_ArrayGetter, (void*)items, items_count, height_items); 11140 return value_changed; 11141 } 11142 11143 bool ImGui::ListBox(const char* label, int* current_item, bool(*items_getter)(void*, int, const char**), void* data, int items_count, int height_in_items) 11144 { 11145 if (!ListBoxHeader(label, items_count, height_in_items)) 11146 return false; 11147 11148 // Assume all items have even height (= 1 line of text). If you need items of different or variable sizes you can create a custom version of ListBox() in your code without using the clipper. 11149 bool value_changed = false; 11150 ImGuiListClipper clipper(items_count, GetTextLineHeightWithSpacing()); // We know exactly our line height here so we pass it as a minor optimization, but generally you don't need to. 11151 while (clipper.Step()) 11152 for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) 11153 { 11154 const bool item_selected = (i == *current_item); 11155 const char* item_text; 11156 if (!items_getter(data, i, &item_text)) 11157 item_text = "*Unknown item*"; 11158 11159 PushID(i); 11160 if (Selectable(item_text, item_selected)) 11161 { 11162 *current_item = i; 11163 value_changed = true; 11164 } 11165 if (item_selected) 11166 SetItemDefaultFocus(); 11167 PopID(); 11168 } 11169 ListBoxFooter(); 11170 return value_changed; 11171 } 11172 11173 bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, bool enabled) 11174 { 11175 ImGuiWindow* window = GetCurrentWindow(); 11176 if (window->SkipItems) 11177 return false; 11178 11179 ImGuiContext& g = *GImGui; 11180 ImGuiStyle& style = g.Style; 11181 ImVec2 pos = window->DC.CursorPos; 11182 ImVec2 label_size = CalcTextSize(label, NULL, true); 11183 11184 ImGuiSelectableFlags flags = ImGuiSelectableFlags_MenuItem | (enabled ? 0 : ImGuiSelectableFlags_Disabled); 11185 bool pressed; 11186 if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) 11187 { 11188 // Mimic the exact layout spacing of BeginMenu() to allow MenuItem() inside a menu bar, which is a little misleading but may be useful 11189 // Note that in this situation we render neither the shortcut neither the selected tick mark 11190 float w = label_size.x; 11191 window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f); 11192 PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing * 2.0f); 11193 pressed = Selectable(label, false, flags, ImVec2(w, 0.0f)); 11194 PopStyleVar(); 11195 window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar(). 11196 } 11197 else 11198 { 11199 ImVec2 shortcut_size = shortcut ? CalcTextSize(shortcut, NULL) : ImVec2(0.0f, 0.0f); 11200 float w = window->MenuColumns.DeclColumns(label_size.x, shortcut_size.x, (float)(int)(g.FontSize * 1.20f)); // Feedback for next frame 11201 float extra_w = ImMax(0.0f, GetContentRegionAvail().x - w); 11202 pressed = Selectable(label, false, flags | ImGuiSelectableFlags_DrawFillAvailWidth, ImVec2(w, 0.0f)); 11203 if (shortcut_size.x > 0.0f) 11204 { 11205 PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); 11206 RenderText(pos + ImVec2(window->MenuColumns.Pos[1] + extra_w, 0.0f), shortcut, NULL, false); 11207 PopStyleColor(); 11208 } 11209 if (selected) 11210 RenderCheckMark(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), GetColorU32(enabled ? ImGuiCol_Text : ImGuiCol_TextDisabled), g.FontSize * 0.866f); 11211 } 11212 return pressed; 11213 } 11214 11215 bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled) 11216 { 11217 if (MenuItem(label, shortcut, p_selected ? *p_selected : false, enabled)) 11218 { 11219 if (p_selected) 11220 *p_selected = !*p_selected; 11221 return true; 11222 } 11223 return false; 11224 } 11225 11226 // For the main menu bar, which cannot be moved, we honor g.Style.DisplaySafeAreaPadding to ensure text can be visible on a TV set. 11227 bool ImGui::BeginMainMenuBar() 11228 { 11229 ImGuiContext& g = *GImGui; 11230 g.NextWindowData.MenuBarOffsetMinVal = ImVec2(g.Style.DisplaySafeAreaPadding.x, ImMax(g.Style.DisplaySafeAreaPadding.y - g.Style.FramePadding.y, 0.0f)); 11231 SetNextWindowPos(ImVec2(0.0f, 0.0f)); 11232 SetNextWindowSize(ImVec2(g.IO.DisplaySize.x, g.NextWindowData.MenuBarOffsetMinVal.y + g.FontBaseSize + g.Style.FramePadding.y)); 11233 PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); 11234 PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0, 0)); 11235 ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar; 11236 bool is_open = Begin("##MainMenuBar", NULL, window_flags) && BeginMenuBar(); 11237 g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f); 11238 if (!is_open) 11239 { 11240 End(); 11241 PopStyleVar(2); 11242 return false; 11243 } 11244 return true; 11245 } 11246 11247 void ImGui::EndMainMenuBar() 11248 { 11249 EndMenuBar(); 11250 11251 // When the user has left the menu layer (typically: closed menus through activation of an item), we restore focus to the previous window 11252 ImGuiContext& g = *GImGui; 11253 if (g.CurrentWindow == g.NavWindow && g.NavLayer == 0) 11254 FocusFrontMostActiveWindow(g.NavWindow); 11255 11256 End(); 11257 PopStyleVar(2); 11258 } 11259 11260 bool ImGui::BeginMenuBar() 11261 { 11262 ImGuiWindow* window = GetCurrentWindow(); 11263 if (window->SkipItems) 11264 return false; 11265 if (!(window->Flags & ImGuiWindowFlags_MenuBar)) 11266 return false; 11267 11268 IM_ASSERT(!window->DC.MenuBarAppending); 11269 BeginGroup(); // Save position 11270 PushID("##menubar"); 11271 11272 // We don't clip with current window clipping rectangle as it is already set to the area below. However we clip with window full rect. 11273 // We remove 1 worth of rounding to Max.x to that text in long menus and small windows don't tend to display over the lower-right rounded area, which looks particularly glitchy. 11274 ImRect bar_rect = window->MenuBarRect(); 11275 ImRect clip_rect(ImFloor(bar_rect.Min.x + 0.5f), ImFloor(bar_rect.Min.y + window->WindowBorderSize + 0.5f), ImFloor(ImMax(bar_rect.Min.x, bar_rect.Max.x - window->WindowRounding) + 0.5f), ImFloor(bar_rect.Max.y + 0.5f)); 11276 clip_rect.ClipWith(window->WindowRectClipped); 11277 PushClipRect(clip_rect.Min, clip_rect.Max, false); 11278 11279 window->DC.CursorPos = ImVec2(bar_rect.Min.x + window->DC.MenuBarOffset.x, bar_rect.Min.y + window->DC.MenuBarOffset.y); 11280 window->DC.LayoutType = ImGuiLayoutType_Horizontal; 11281 window->DC.NavLayerCurrent++; 11282 window->DC.NavLayerCurrentMask <<= 1; 11283 window->DC.MenuBarAppending = true; 11284 AlignTextToFramePadding(); 11285 return true; 11286 } 11287 11288 void ImGui::EndMenuBar() 11289 { 11290 ImGuiWindow* window = GetCurrentWindow(); 11291 if (window->SkipItems) 11292 return; 11293 ImGuiContext& g = *GImGui; 11294 11295 // Nav: When a move request within one of our child menu failed, capture the request to navigate among our siblings. 11296 if (NavMoveRequestButNoResultYet() && (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) && (g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu)) 11297 { 11298 ImGuiWindow* nav_earliest_child = g.NavWindow; 11299 while (nav_earliest_child->ParentWindow && (nav_earliest_child->ParentWindow->Flags & ImGuiWindowFlags_ChildMenu)) 11300 nav_earliest_child = nav_earliest_child->ParentWindow; 11301 if (nav_earliest_child->ParentWindow == window && nav_earliest_child->DC.ParentLayoutType == ImGuiLayoutType_Horizontal && g.NavMoveRequestForward == ImGuiNavForward_None) 11302 { 11303 // To do so we claim focus back, restore NavId and then process the movement request for yet another frame. 11304 // This involve a one-frame delay which isn't very problematic in this situation. We could remove it by scoring in advance for multiple window (probably not worth the hassle/cost) 11305 IM_ASSERT(window->DC.NavLayerActiveMaskNext & 0x02); // Sanity check 11306 FocusWindow(window); 11307 SetNavIDWithRectRel(window->NavLastIds[1], 1, window->NavRectRel[1]); 11308 g.NavLayer = 1; 11309 g.NavDisableHighlight = true; // Hide highlight for the current frame so we don't see the intermediary selection. 11310 g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued; 11311 NavMoveRequestCancel(); 11312 } 11313 } 11314 11315 IM_ASSERT(window->Flags & ImGuiWindowFlags_MenuBar); 11316 IM_ASSERT(window->DC.MenuBarAppending); 11317 PopClipRect(); 11318 PopID(); 11319 window->DC.MenuBarOffset.x = window->DC.CursorPos.x - window->MenuBarRect().Min.x; // Save horizontal position so next append can reuse it. This is kinda equivalent to a per-layer CursorPos. 11320 window->DC.GroupStack.back().AdvanceCursor = false; 11321 EndGroup(); 11322 window->DC.LayoutType = ImGuiLayoutType_Vertical; 11323 window->DC.NavLayerCurrent--; 11324 window->DC.NavLayerCurrentMask >>= 1; 11325 window->DC.MenuBarAppending = false; 11326 } 11327 11328 bool ImGui::BeginMenu(const char* label, bool enabled) 11329 { 11330 ImGuiWindow* window = GetCurrentWindow(); 11331 if (window->SkipItems) 11332 return false; 11333 11334 ImGuiContext& g = *GImGui; 11335 const ImGuiStyle& style = g.Style; 11336 const ImGuiID id = window->GetID(label); 11337 11338 ImVec2 label_size = CalcTextSize(label, NULL, true); 11339 11340 bool pressed; 11341 bool menu_is_open = IsPopupOpen(id); 11342 bool menuset_is_open = !(window->Flags & ImGuiWindowFlags_Popup) && (g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].OpenParentId == window->IDStack.back()); 11343 ImGuiWindow* backed_nav_window = g.NavWindow; 11344 if (menuset_is_open) 11345 g.NavWindow = window; // Odd hack to allow hovering across menus of a same menu-set (otherwise we wouldn't be able to hover parent) 11346 11347 // The reference position stored in popup_pos will be used by Begin() to find a suitable position for the child menu (using FindBestWindowPosForPopup). 11348 ImVec2 popup_pos, pos = window->DC.CursorPos; 11349 if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) 11350 { 11351 // Menu inside an horizontal menu bar 11352 // Selectable extend their highlight by half ItemSpacing in each direction. 11353 // For ChildMenu, the popup position will be overwritten by the call to FindBestWindowPosForPopup() in Begin() 11354 popup_pos = ImVec2(pos.x - window->WindowPadding.x, pos.y - style.FramePadding.y + window->MenuBarHeight()); 11355 window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f); 11356 PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing * 2.0f); 11357 float w = label_size.x; 11358 pressed = Selectable(label, menu_is_open, ImGuiSelectableFlags_Menu | ImGuiSelectableFlags_DontClosePopups | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f)); 11359 PopStyleVar(); 11360 window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar(). 11361 } 11362 else 11363 { 11364 // Menu inside a menu 11365 popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y); 11366 float w = window->MenuColumns.DeclColumns(label_size.x, 0.0f, (float)(int)(g.FontSize * 1.20f)); // Feedback to next frame 11367 float extra_w = ImMax(0.0f, GetContentRegionAvail().x - w); 11368 pressed = Selectable(label, menu_is_open, ImGuiSelectableFlags_Menu | ImGuiSelectableFlags_DontClosePopups | ImGuiSelectableFlags_DrawFillAvailWidth | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f)); 11369 if (!enabled) PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); 11370 RenderArrow(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.30f, 0.0f), ImGuiDir_Right); 11371 if (!enabled) PopStyleColor(); 11372 } 11373 11374 const bool hovered = enabled && ItemHoverable(window->DC.LastItemRect, id); 11375 if (menuset_is_open) 11376 g.NavWindow = backed_nav_window; 11377 11378 bool want_open = false, want_close = false; 11379 if (window->DC.LayoutType == ImGuiLayoutType_Vertical) // (window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu)) 11380 { 11381 // Implement http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown to avoid using timers, so menus feels more reactive. 11382 bool moving_within_opened_triangle = false; 11383 if (g.HoveredWindow == window && g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].ParentWindow == window && !(window->Flags & ImGuiWindowFlags_MenuBar)) 11384 { 11385 if (ImGuiWindow* next_window = g.OpenPopupStack[g.CurrentPopupStack.Size].Window) 11386 { 11387 ImRect next_window_rect = next_window->Rect(); 11388 ImVec2 ta = g.IO.MousePos - g.IO.MouseDelta; 11389 ImVec2 tb = (window->Pos.x < next_window->Pos.x) ? next_window_rect.GetTL() : next_window_rect.GetTR(); 11390 ImVec2 tc = (window->Pos.x < next_window->Pos.x) ? next_window_rect.GetBL() : next_window_rect.GetBR(); 11391 float extra = ImClamp(fabsf(ta.x - tb.x) * 0.30f, 5.0f, 30.0f); // add a bit of extra slack. 11392 ta.x += (window->Pos.x < next_window->Pos.x) ? -0.5f : +0.5f; // to avoid numerical issues 11393 tb.y = ta.y + ImMax((tb.y - extra) - ta.y, -100.0f); // triangle is maximum 200 high to limit the slope and the bias toward large sub-menus // FIXME: Multiply by fb_scale? 11394 tc.y = ta.y + ImMin((tc.y + extra) - ta.y, +100.0f); 11395 moving_within_opened_triangle = ImTriangleContainsPoint(ta, tb, tc, g.IO.MousePos); 11396 //window->DrawList->PushClipRectFullScreen(); window->DrawList->AddTriangleFilled(ta, tb, tc, moving_within_opened_triangle ? IM_COL32(0,128,0,128) : IM_COL32(128,0,0,128)); window->DrawList->PopClipRect(); // Debug 11397 } 11398 } 11399 11400 want_close = (menu_is_open && !hovered && g.HoveredWindow == window && g.HoveredIdPreviousFrame != 0 && g.HoveredIdPreviousFrame != id && !moving_within_opened_triangle); 11401 want_open = (!menu_is_open && hovered && !moving_within_opened_triangle) || (!menu_is_open && hovered && pressed); 11402 11403 if (g.NavActivateId == id) 11404 { 11405 want_close = menu_is_open; 11406 want_open = !menu_is_open; 11407 } 11408 if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Right) // Nav-Right to open 11409 { 11410 want_open = true; 11411 NavMoveRequestCancel(); 11412 } 11413 } 11414 else 11415 { 11416 // Menu bar 11417 if (menu_is_open && pressed && menuset_is_open) // Click an open menu again to close it 11418 { 11419 want_close = true; 11420 want_open = menu_is_open = false; 11421 } 11422 else if (pressed || (hovered && menuset_is_open && !menu_is_open)) // First click to open, then hover to open others 11423 { 11424 want_open = true; 11425 } 11426 else if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Down) // Nav-Down to open 11427 { 11428 want_open = true; 11429 NavMoveRequestCancel(); 11430 } 11431 } 11432 11433 if (!enabled) // explicitly close if an open menu becomes disabled, facilitate users code a lot in pattern such as 'if (BeginMenu("options", has_object)) { ..use object.. }' 11434 want_close = true; 11435 if (want_close && IsPopupOpen(id)) 11436 ClosePopupToLevel(g.CurrentPopupStack.Size); 11437 11438 if (!menu_is_open && want_open && g.OpenPopupStack.Size > g.CurrentPopupStack.Size) 11439 { 11440 // Don't recycle same menu level in the same frame, first close the other menu and yield for a frame. 11441 OpenPopup(label); 11442 return false; 11443 } 11444 11445 menu_is_open |= want_open; 11446 if (want_open) 11447 OpenPopup(label); 11448 11449 if (menu_is_open) 11450 { 11451 // Sub-menus are ChildWindow so that mouse can be hovering across them (otherwise top-most popup menu would steal focus and not allow hovering on parent menu) 11452 SetNextWindowPos(popup_pos, ImGuiCond_Always); 11453 ImGuiWindowFlags flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings | ((window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) ? ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_ChildWindow : ImGuiWindowFlags_ChildMenu); 11454 menu_is_open = BeginPopupEx(id, flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display) 11455 } 11456 11457 return menu_is_open; 11458 } 11459 11460 void ImGui::EndMenu() 11461 { 11462 // Nav: When a left move request _within our child menu_ failed, close the menu. 11463 // A menu doesn't close itself because EndMenuBar() wants the catch the last Left<>Right inputs. 11464 // However it means that with the current code, a BeginMenu() from outside another menu or a menu-bar won't be closable with the Left direction. 11465 ImGuiContext& g = *GImGui; 11466 ImGuiWindow* window = g.CurrentWindow; 11467 if (g.NavWindow && g.NavWindow->ParentWindow == window && g.NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet() && window->DC.LayoutType == ImGuiLayoutType_Vertical) 11468 { 11469 ClosePopupToLevel(g.OpenPopupStack.Size - 1); 11470 NavMoveRequestCancel(); 11471 } 11472 11473 EndPopup(); 11474 } 11475 11476 // Note: only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set. 11477 void ImGui::ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags) 11478 { 11479 ImGuiContext& g = *GImGui; 11480 11481 int cr = IM_F32_TO_INT8_SAT(col[0]), cg = IM_F32_TO_INT8_SAT(col[1]), cb = IM_F32_TO_INT8_SAT(col[2]), ca = (flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT(col[3]); 11482 BeginTooltipEx(0, true); 11483 11484 const char* text_end = text ? FindRenderedTextEnd(text, NULL) : text; 11485 if (text_end > text) 11486 { 11487 TextUnformatted(text, text_end); 11488 Separator(); 11489 } 11490 11491 ImVec2 sz(g.FontSize * 3 + g.Style.FramePadding.y * 2, g.FontSize * 3 + g.Style.FramePadding.y * 2); 11492 ColorButton("##preview", ImVec4(col[0], col[1], col[2], col[3]), (flags & (ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf)) | ImGuiColorEditFlags_NoTooltip, sz); 11493 SameLine(); 11494 if (flags & ImGuiColorEditFlags_NoAlpha) 11495 Text("#%02X%02X%02X\nR: %d, G: %d, B: %d\n(%.3f, %.3f, %.3f)", cr, cg, cb, cr, cg, cb, col[0], col[1], col[2]); 11496 else 11497 Text("#%02X%02X%02X%02X\nR:%d, G:%d, B:%d, A:%d\n(%.3f, %.3f, %.3f, %.3f)", cr, cg, cb, ca, cr, cg, cb, ca, col[0], col[1], col[2], col[3]); 11498 EndTooltip(); 11499 } 11500 11501 static inline ImU32 ImAlphaBlendColor(ImU32 col_a, ImU32 col_b) 11502 { 11503 float t = ((col_b >> IM_COL32_A_SHIFT) & 0xFF) / 255.f; 11504 int r = ImLerp((int)(col_a >> IM_COL32_R_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_R_SHIFT) & 0xFF, t); 11505 int g = ImLerp((int)(col_a >> IM_COL32_G_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_G_SHIFT) & 0xFF, t); 11506 int b = ImLerp((int)(col_a >> IM_COL32_B_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_B_SHIFT) & 0xFF, t); 11507 return IM_COL32(r, g, b, 0xFF); 11508 } 11509 11510 // NB: This is rather brittle and will show artifact when rounding this enabled if rounded corners overlap multiple cells. Caller currently responsible for avoiding that. 11511 // I spent a non reasonable amount of time trying to getting this right for ColorButton with rounding+anti-aliasing+ImGuiColorEditFlags_HalfAlphaPreview flag + various grid sizes and offsets, and eventually gave up... probably more reasonable to disable rounding alltogether. 11512 void ImGui::RenderColorRectWithAlphaCheckerboard(ImVec2 p_min, ImVec2 p_max, ImU32 col, float grid_step, ImVec2 grid_off, float rounding, int rounding_corners_flags) 11513 { 11514 ImGuiWindow* window = GetCurrentWindow(); 11515 if (((col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT) < 0xFF) 11516 { 11517 ImU32 col_bg1 = GetColorU32(ImAlphaBlendColor(IM_COL32(204, 204, 204, 255), col)); 11518 ImU32 col_bg2 = GetColorU32(ImAlphaBlendColor(IM_COL32(128, 128, 128, 255), col)); 11519 window->DrawList->AddRectFilled(p_min, p_max, col_bg1, rounding, rounding_corners_flags); 11520 11521 int yi = 0; 11522 for (float y = p_min.y + grid_off.y; y < p_max.y; y += grid_step, yi++) 11523 { 11524 float y1 = ImClamp(y, p_min.y, p_max.y), y2 = ImMin(y + grid_step, p_max.y); 11525 if (y2 <= y1) 9089 NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); 9090 } 9091 } 9092 } 9093 9094 static int ImGui::FindWindowFocusIndex(ImGuiWindow* window) // FIXME-OPT O(N) 9095 { 9096 ImGuiContext& g = *GImGui; 9097 for (int i = g.WindowsFocusOrder.Size - 1; i >= 0; i--) 9098 if (g.WindowsFocusOrder[i] == window) 9099 return i; 9100 return -1; 9101 } 9102 9103 static ImGuiWindow* FindWindowNavFocusable(int i_start, int i_stop, int dir) // FIXME-OPT O(N) 9104 { 9105 ImGuiContext& g = *GImGui; 9106 for (int i = i_start; i >= 0 && i < g.WindowsFocusOrder.Size && i != i_stop; i += dir) 9107 if (ImGui::IsWindowNavFocusable(g.WindowsFocusOrder[i])) 9108 return g.WindowsFocusOrder[i]; 9109 return NULL; 9110 } 9111 9112 static void NavUpdateWindowingHighlightWindow(int focus_change_dir) 9113 { 9114 ImGuiContext& g = *GImGui; 9115 IM_ASSERT(g.NavWindowingTarget); 9116 if (g.NavWindowingTarget->Flags & ImGuiWindowFlags_Modal) 9117 return; 9118 9119 const int i_current = ImGui::FindWindowFocusIndex(g.NavWindowingTarget); 9120 ImGuiWindow* window_target = FindWindowNavFocusable(i_current + focus_change_dir, -INT_MAX, focus_change_dir); 9121 if (!window_target) 9122 window_target = FindWindowNavFocusable((focus_change_dir < 0) ? (g.WindowsFocusOrder.Size - 1) : 0, i_current, focus_change_dir); 9123 if (window_target) // Don't reset windowing target if there's a single window in the list 9124 g.NavWindowingTarget = g.NavWindowingTargetAnim = window_target; 9125 g.NavWindowingToggleLayer = false; 9126 } 9127 9128 // Windowing management mode 9129 // Keyboard: CTRL+Tab (change focus/move/resize), Alt (toggle menu layer) 9130 // Gamepad: Hold Menu/Square (change focus/move/resize), Tap Menu/Square (toggle menu layer) 9131 static void ImGui::NavUpdateWindowing() 9132 { 9133 ImGuiContext& g = *GImGui; 9134 ImGuiWindow* apply_focus_window = NULL; 9135 bool apply_toggle_layer = false; 9136 9137 ImGuiWindow* modal_window = GetTopMostPopupModal(); 9138 bool allow_windowing = (modal_window == NULL); 9139 if (!allow_windowing) 9140 g.NavWindowingTarget = NULL; 9141 9142 // Fade out 9143 if (g.NavWindowingTargetAnim && g.NavWindowingTarget == NULL) 9144 { 9145 g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha - g.IO.DeltaTime * 10.0f, 0.0f); 9146 if (g.DimBgRatio <= 0.0f && g.NavWindowingHighlightAlpha <= 0.0f) 9147 g.NavWindowingTargetAnim = NULL; 9148 } 9149 9150 // Start CTRL-TAB or Square+L/R window selection 9151 bool start_windowing_with_gamepad = allow_windowing && !g.NavWindowingTarget && IsNavInputTest(ImGuiNavInput_Menu, ImGuiInputReadMode_Pressed); 9152 bool start_windowing_with_keyboard = allow_windowing && !g.NavWindowingTarget && g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab) && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard); 9153 if (start_windowing_with_gamepad || start_windowing_with_keyboard) 9154 if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavFocusable(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1)) 9155 { 9156 g.NavWindowingTarget = g.NavWindowingTargetAnim = window->RootWindow; // FIXME-DOCK: Will need to use RootWindowDockStop 9157 g.NavWindowingTimer = g.NavWindowingHighlightAlpha = 0.0f; 9158 g.NavWindowingToggleLayer = start_windowing_with_keyboard ? false : true; 9159 g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_NavKeyboard : ImGuiInputSource_NavGamepad; 9160 } 9161 9162 // Gamepad update 9163 g.NavWindowingTimer += g.IO.DeltaTime; 9164 if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavGamepad) 9165 { 9166 // 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 9167 g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); 9168 9169 // Select window to focus 9170 const int focus_change_dir = (int)IsNavInputTest(ImGuiNavInput_FocusPrev, ImGuiInputReadMode_RepeatSlow) - (int)IsNavInputTest(ImGuiNavInput_FocusNext, ImGuiInputReadMode_RepeatSlow); 9171 if (focus_change_dir != 0) 9172 { 9173 NavUpdateWindowingHighlightWindow(focus_change_dir); 9174 g.NavWindowingHighlightAlpha = 1.0f; 9175 } 9176 9177 // Single press toggles NavLayer, long press with L/R apply actual focus on release (until then the window was merely rendered top-most) 9178 if (!IsNavInputDown(ImGuiNavInput_Menu)) 9179 { 9180 g.NavWindowingToggleLayer &= (g.NavWindowingHighlightAlpha < 1.0f); // Once button was held long enough we don't consider it a tap-to-toggle-layer press anymore. 9181 if (g.NavWindowingToggleLayer && g.NavWindow) 9182 apply_toggle_layer = true; 9183 else if (!g.NavWindowingToggleLayer) 9184 apply_focus_window = g.NavWindowingTarget; 9185 g.NavWindowingTarget = NULL; 9186 } 9187 } 9188 9189 // Keyboard: Focus 9190 if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavKeyboard) 9191 { 9192 // Visuals only appears after a brief time after pressing TAB the first time, so that a fast CTRL+TAB doesn't add visual noise 9193 g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); // 1.0f 9194 if (IsKeyPressedMap(ImGuiKey_Tab, true)) 9195 NavUpdateWindowingHighlightWindow(g.IO.KeyShift ? +1 : -1); 9196 if (!g.IO.KeyCtrl) 9197 apply_focus_window = g.NavWindowingTarget; 9198 } 9199 9200 // Keyboard: Press and Release ALT to toggle menu layer 9201 // 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 9202 if (IsNavInputTest(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Pressed)) 9203 g.NavWindowingToggleLayer = true; 9204 if ((g.ActiveId == 0 || g.ActiveIdAllowOverlap) && g.NavWindowingToggleLayer && IsNavInputTest(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Released)) 9205 if (IsMousePosValid(&g.IO.MousePos) == IsMousePosValid(&g.IO.MousePosPrev)) 9206 apply_toggle_layer = true; 9207 9208 // Move window 9209 if (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoMove)) 9210 { 9211 ImVec2 move_delta; 9212 if (g.NavInputSource == ImGuiInputSource_NavKeyboard && !g.IO.KeyShift) 9213 move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down); 9214 if (g.NavInputSource == ImGuiInputSource_NavGamepad) 9215 move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down); 9216 if (move_delta.x != 0.0f || move_delta.y != 0.0f) 9217 { 9218 const float NAV_MOVE_SPEED = 800.0f; 9219 const float move_speed = ImFloor(NAV_MOVE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y)); // FIXME: Doesn't handle variable framerate very well 9220 ImGuiWindow* moving_window = g.NavWindowingTarget->RootWindow; 9221 SetWindowPos(moving_window, moving_window->Pos + move_delta * move_speed, ImGuiCond_Always); 9222 MarkIniSettingsDirty(moving_window); 9223 g.NavDisableMouseHover = true; 9224 } 9225 } 9226 9227 // Apply final focus 9228 if (apply_focus_window && (g.NavWindow == NULL || apply_focus_window != g.NavWindow->RootWindow)) 9229 { 9230 ClearActiveID(); 9231 g.NavDisableHighlight = false; 9232 g.NavDisableMouseHover = true; 9233 apply_focus_window = NavRestoreLastChildNavWindow(apply_focus_window); 9234 ClosePopupsOverWindow(apply_focus_window, false); 9235 FocusWindow(apply_focus_window); 9236 if (apply_focus_window->NavLastIds[0] == 0) 9237 NavInitWindow(apply_focus_window, false); 9238 9239 // If the window only has a menu layer, select it directly 9240 if (apply_focus_window->DC.NavLayerActiveMask == (1 << ImGuiNavLayer_Menu)) 9241 g.NavLayer = ImGuiNavLayer_Menu; 9242 } 9243 if (apply_focus_window) 9244 g.NavWindowingTarget = NULL; 9245 9246 // Apply menu/layer toggle 9247 if (apply_toggle_layer && g.NavWindow) 9248 { 9249 // Move to parent menu if necessary 9250 ImGuiWindow* new_nav_window = g.NavWindow; 9251 while (new_nav_window->ParentWindow 9252 && (new_nav_window->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) == 0 9253 && (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 9254 && (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0) 9255 new_nav_window = new_nav_window->ParentWindow; 9256 if (new_nav_window != g.NavWindow) 9257 { 9258 ImGuiWindow* old_nav_window = g.NavWindow; 9259 FocusWindow(new_nav_window); 9260 new_nav_window->NavLastChildNavWindow = old_nav_window; 9261 } 9262 g.NavDisableHighlight = false; 9263 g.NavDisableMouseHover = true; 9264 9265 // When entering a regular menu bar with the Alt key, we always reinitialize the navigation ID. 9266 const ImGuiNavLayer new_nav_layer = (g.NavWindow->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) ? (ImGuiNavLayer)((int)g.NavLayer ^ 1) : ImGuiNavLayer_Main; 9267 NavRestoreLayer(new_nav_layer); 9268 } 9269 } 9270 9271 // Window has already passed the IsWindowNavFocusable() 9272 static const char* GetFallbackWindowNameForWindowingList(ImGuiWindow* window) 9273 { 9274 if (window->Flags & ImGuiWindowFlags_Popup) 9275 return "(Popup)"; 9276 if ((window->Flags & ImGuiWindowFlags_MenuBar) && strcmp(window->Name, "##MainMenuBar") == 0) 9277 return "(Main menu bar)"; 9278 return "(Untitled)"; 9279 } 9280 9281 // Overlay displayed when using CTRL+TAB. Called by EndFrame(). 9282 void ImGui::NavUpdateWindowingOverlay() 9283 { 9284 ImGuiContext& g = *GImGui; 9285 IM_ASSERT(g.NavWindowingTarget != NULL); 9286 9287 if (g.NavWindowingTimer < NAV_WINDOWING_LIST_APPEAR_DELAY) 9288 return; 9289 9290 if (g.NavWindowingListWindow == NULL) 9291 g.NavWindowingListWindow = FindWindowByName("###NavWindowingList"); 9292 SetNextWindowSizeConstraints(ImVec2(g.IO.DisplaySize.x * 0.20f, g.IO.DisplaySize.y * 0.20f), ImVec2(FLT_MAX, FLT_MAX)); 9293 SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f)); 9294 PushStyleVar(ImGuiStyleVar_WindowPadding, g.Style.WindowPadding * 2.0f); 9295 Begin("###NavWindowingList", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings); 9296 for (int n = g.WindowsFocusOrder.Size - 1; n >= 0; n--) 9297 { 9298 ImGuiWindow* window = g.WindowsFocusOrder[n]; 9299 if (!IsWindowNavFocusable(window)) 11526 9300 continue; 11527 for (float x = p_min.x + grid_off.x + (yi & 1) * grid_step; x < p_max.x; x += grid_step * 2.0f) 11528 { 11529 float x1 = ImClamp(x, p_min.x, p_max.x), x2 = ImMin(x + grid_step, p_max.x); 11530 if (x2 <= x1) 11531 continue; 11532 int rounding_corners_flags_cell = 0; 11533 if (y1 <= p_min.y) { if (x1 <= p_min.x) rounding_corners_flags_cell |= ImDrawCornerFlags_TopLeft; if (x2 >= p_max.x) rounding_corners_flags_cell |= ImDrawCornerFlags_TopRight; } 11534 if (y2 >= p_max.y) { if (x1 <= p_min.x) rounding_corners_flags_cell |= ImDrawCornerFlags_BotLeft; if (x2 >= p_max.x) rounding_corners_flags_cell |= ImDrawCornerFlags_BotRight; } 11535 rounding_corners_flags_cell &= rounding_corners_flags; 11536 window->DrawList->AddRectFilled(ImVec2(x1, y1), ImVec2(x2, y2), col_bg2, rounding_corners_flags_cell ? rounding : 0.0f, rounding_corners_flags_cell); 11537 } 11538 } 11539 } 11540 else 11541 { 11542 window->DrawList->AddRectFilled(p_min, p_max, col, rounding, rounding_corners_flags); 11543 } 11544 } 11545 11546 void ImGui::SetColorEditOptions(ImGuiColorEditFlags flags) 11547 { 11548 ImGuiContext& g = *GImGui; 11549 if ((flags & ImGuiColorEditFlags__InputsMask) == 0) 11550 flags |= ImGuiColorEditFlags__OptionsDefault & ImGuiColorEditFlags__InputsMask; 11551 if ((flags & ImGuiColorEditFlags__DataTypeMask) == 0) 11552 flags |= ImGuiColorEditFlags__OptionsDefault & ImGuiColorEditFlags__DataTypeMask; 11553 if ((flags & ImGuiColorEditFlags__PickerMask) == 0) 11554 flags |= ImGuiColorEditFlags__OptionsDefault & ImGuiColorEditFlags__PickerMask; 11555 IM_ASSERT(ImIsPowerOfTwo((int)(flags & ImGuiColorEditFlags__InputsMask))); // Check only 1 option is selected 11556 IM_ASSERT(ImIsPowerOfTwo((int)(flags & ImGuiColorEditFlags__DataTypeMask))); // Check only 1 option is selected 11557 IM_ASSERT(ImIsPowerOfTwo((int)(flags & ImGuiColorEditFlags__PickerMask))); // Check only 1 option is selected 11558 g.ColorEditOptions = flags; 11559 } 11560 11561 // A little colored square. Return true when clicked. 11562 // FIXME: May want to display/ignore the alpha component in the color display? Yet show it in the tooltip. 11563 // 'desc_id' is not called 'label' because we don't display it next to the button, but only in the tooltip. 11564 bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFlags flags, ImVec2 size) 11565 { 11566 ImGuiWindow* window = GetCurrentWindow(); 11567 if (window->SkipItems) 11568 return false; 11569 11570 ImGuiContext& g = *GImGui; 11571 const ImGuiID id = window->GetID(desc_id); 11572 float default_size = GetFrameHeight(); 11573 if (size.x == 0.0f) 11574 size.x = default_size; 11575 if (size.y == 0.0f) 11576 size.y = default_size; 11577 const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); 11578 ItemSize(bb, (size.y >= default_size) ? g.Style.FramePadding.y : 0.0f); 11579 if (!ItemAdd(bb, id)) 11580 return false; 11581 11582 bool hovered, held; 11583 bool pressed = ButtonBehavior(bb, id, &hovered, &held); 11584 11585 if (flags & ImGuiColorEditFlags_NoAlpha) 11586 flags &= ~(ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf); 11587 11588 ImVec4 col_without_alpha(col.x, col.y, col.z, 1.0f); 11589 float grid_step = ImMin(size.x, size.y) / 2.99f; 11590 float rounding = ImMin(g.Style.FrameRounding, grid_step * 0.5f); 11591 ImRect bb_inner = bb; 11592 float off = -0.75f; // The border (using Col_FrameBg) tends to look off when color is near-opaque and rounding is enabled. This offset seemed like a good middle ground to reduce those artifacts. 11593 bb_inner.Expand(off); 11594 if ((flags & ImGuiColorEditFlags_AlphaPreviewHalf) && col.w < 1.0f) 11595 { 11596 float mid_x = (float)(int)((bb_inner.Min.x + bb_inner.Max.x) * 0.5f + 0.5f); 11597 RenderColorRectWithAlphaCheckerboard(ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, GetColorU32(col), grid_step, ImVec2(-grid_step + off, off), rounding, ImDrawCornerFlags_TopRight | ImDrawCornerFlags_BotRight); 11598 window->DrawList->AddRectFilled(bb_inner.Min, ImVec2(mid_x, bb_inner.Max.y), GetColorU32(col_without_alpha), rounding, ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotLeft); 11599 } 11600 else 11601 { 11602 // Because GetColorU32() multiplies by the global style Alpha and we don't want to display a checkerboard if the source code had no alpha 11603 ImVec4 col_source = (flags & ImGuiColorEditFlags_AlphaPreview) ? col : col_without_alpha; 11604 if (col_source.w < 1.0f) 11605 RenderColorRectWithAlphaCheckerboard(bb_inner.Min, bb_inner.Max, GetColorU32(col_source), grid_step, ImVec2(off, off), rounding); 11606 else 11607 window->DrawList->AddRectFilled(bb_inner.Min, bb_inner.Max, GetColorU32(col_source), rounding, ImDrawCornerFlags_All); 11608 } 11609 RenderNavHighlight(bb, id); 11610 if (g.Style.FrameBorderSize > 0.0f) 11611 RenderFrameBorder(bb.Min, bb.Max, rounding); 11612 else 11613 window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding); // Color button are often in need of some sort of border 11614 11615 // Drag and Drop Source 11616 if (g.ActiveId == id && BeginDragDropSource()) // NB: The ActiveId test is merely an optional micro-optimization 11617 { 11618 if (flags & ImGuiColorEditFlags_NoAlpha) 11619 SetDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F, &col, sizeof(float) * 3, ImGuiCond_Once); 11620 else 11621 SetDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, &col, sizeof(float) * 4, ImGuiCond_Once); 11622 ColorButton(desc_id, col, flags); 11623 SameLine(); 11624 TextUnformatted("Color"); 11625 EndDragDropSource(); 11626 hovered = false; 11627 } 11628 11629 // Tooltip 11630 if (!(flags & ImGuiColorEditFlags_NoTooltip) && hovered) 11631 ColorTooltip(desc_id, &col.x, flags & (ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf)); 11632 11633 return pressed; 11634 } 11635 11636 bool ImGui::ColorEdit3(const char* label, float col[3], ImGuiColorEditFlags flags) 11637 { 11638 return ColorEdit4(label, col, flags | ImGuiColorEditFlags_NoAlpha); 11639 } 11640 11641 void ImGui::ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags) 11642 { 11643 bool allow_opt_inputs = !(flags & ImGuiColorEditFlags__InputsMask); 11644 bool allow_opt_datatype = !(flags & ImGuiColorEditFlags__DataTypeMask); 11645 if ((!allow_opt_inputs && !allow_opt_datatype) || !BeginPopup("context")) 11646 return; 11647 ImGuiContext& g = *GImGui; 11648 ImGuiColorEditFlags opts = g.ColorEditOptions; 11649 if (allow_opt_inputs) 11650 { 11651 if (RadioButton("RGB", (opts & ImGuiColorEditFlags_RGB) != 0)) opts = (opts & ~ImGuiColorEditFlags__InputsMask) | ImGuiColorEditFlags_RGB; 11652 if (RadioButton("HSV", (opts & ImGuiColorEditFlags_HSV) != 0)) opts = (opts & ~ImGuiColorEditFlags__InputsMask) | ImGuiColorEditFlags_HSV; 11653 if (RadioButton("HEX", (opts & ImGuiColorEditFlags_HEX) != 0)) opts = (opts & ~ImGuiColorEditFlags__InputsMask) | ImGuiColorEditFlags_HEX; 11654 } 11655 if (allow_opt_datatype) 11656 { 11657 if (allow_opt_inputs) Separator(); 11658 if (RadioButton("0..255", (opts & ImGuiColorEditFlags_Uint8) != 0)) opts = (opts & ~ImGuiColorEditFlags__DataTypeMask) | ImGuiColorEditFlags_Uint8; 11659 if (RadioButton("0.00..1.00", (opts & ImGuiColorEditFlags_Float) != 0)) opts = (opts & ~ImGuiColorEditFlags__DataTypeMask) | ImGuiColorEditFlags_Float; 11660 } 11661 11662 if (allow_opt_inputs || allow_opt_datatype) 11663 Separator(); 11664 if (Button("Copy as..", ImVec2(-1, 0))) 11665 OpenPopup("Copy"); 11666 if (BeginPopup("Copy")) 11667 { 11668 int cr = IM_F32_TO_INT8_SAT(col[0]), cg = IM_F32_TO_INT8_SAT(col[1]), cb = IM_F32_TO_INT8_SAT(col[2]), ca = (flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT(col[3]); 11669 char buf[64]; 11670 ImFormatString(buf, IM_ARRAYSIZE(buf), "(%.3ff, %.3ff, %.3ff, %.3ff)", col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]); 11671 if (Selectable(buf)) 11672 SetClipboardText(buf); 11673 ImFormatString(buf, IM_ARRAYSIZE(buf), "(%d,%d,%d,%d)", cr, cg, cb, ca); 11674 if (Selectable(buf)) 11675 SetClipboardText(buf); 11676 if (flags & ImGuiColorEditFlags_NoAlpha) 11677 ImFormatString(buf, IM_ARRAYSIZE(buf), "0x%02X%02X%02X", cr, cg, cb); 11678 else 11679 ImFormatString(buf, IM_ARRAYSIZE(buf), "0x%02X%02X%02X%02X", cr, cg, cb, ca); 11680 if (Selectable(buf)) 11681 SetClipboardText(buf); 11682 EndPopup(); 11683 } 11684 11685 g.ColorEditOptions = opts; 11686 EndPopup(); 11687 } 11688 11689 static void ColorPickerOptionsPopup(ImGuiColorEditFlags flags, const float* ref_col) 11690 { 11691 bool allow_opt_picker = !(flags & ImGuiColorEditFlags__PickerMask); 11692 bool allow_opt_alpha_bar = !(flags & ImGuiColorEditFlags_NoAlpha) && !(flags & ImGuiColorEditFlags_AlphaBar); 11693 if ((!allow_opt_picker && !allow_opt_alpha_bar) || !ImGui::BeginPopup("context")) 11694 return; 11695 ImGuiContext& g = *GImGui; 11696 if (allow_opt_picker) 11697 { 11698 ImVec2 picker_size(g.FontSize * 8, ImMax(g.FontSize * 8 - (ImGui::GetFrameHeight() + g.Style.ItemInnerSpacing.x), 1.0f)); // FIXME: Picker size copied from main picker function 11699 ImGui::PushItemWidth(picker_size.x); 11700 for (int picker_type = 0; picker_type < 2; picker_type++) 11701 { 11702 // Draw small/thumbnail version of each picker type (over an invisible button for selection) 11703 if (picker_type > 0) ImGui::Separator(); 11704 ImGui::PushID(picker_type); 11705 ImGuiColorEditFlags picker_flags = ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoSidePreview | (flags & ImGuiColorEditFlags_NoAlpha); 11706 if (picker_type == 0) picker_flags |= ImGuiColorEditFlags_PickerHueBar; 11707 if (picker_type == 1) picker_flags |= ImGuiColorEditFlags_PickerHueWheel; 11708 ImVec2 backup_pos = ImGui::GetCursorScreenPos(); 11709 if (ImGui::Selectable("##selectable", false, 0, picker_size)) // By default, Selectable() is closing popup 11710 g.ColorEditOptions = (g.ColorEditOptions & ~ImGuiColorEditFlags__PickerMask) | (picker_flags & ImGuiColorEditFlags__PickerMask); 11711 ImGui::SetCursorScreenPos(backup_pos); 11712 ImVec4 dummy_ref_col; 11713 memcpy(&dummy_ref_col.x, ref_col, sizeof(float) * (picker_flags & ImGuiColorEditFlags_NoAlpha ? 3 : 4)); 11714 ImGui::ColorPicker4("##dummypicker", &dummy_ref_col.x, picker_flags); 11715 ImGui::PopID(); 11716 } 11717 ImGui::PopItemWidth(); 11718 } 11719 if (allow_opt_alpha_bar) 11720 { 11721 if (allow_opt_picker) ImGui::Separator(); 11722 ImGui::CheckboxFlags("Alpha Bar", (unsigned int*)&g.ColorEditOptions, ImGuiColorEditFlags_AlphaBar); 11723 } 11724 ImGui::EndPopup(); 11725 } 11726 11727 // Edit colors components (each component in 0.0f..1.0f range). 11728 // See enum ImGuiColorEditFlags_ for available options. e.g. Only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set. 11729 // With typical options: Left-click on colored square to open color picker. Right-click to open option menu. CTRL-Click over input fields to edit them and TAB to go to next item. 11730 bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags) 11731 { 11732 ImGuiWindow* window = GetCurrentWindow(); 11733 if (window->SkipItems) 11734 return false; 11735 11736 ImGuiContext& g = *GImGui; 11737 const ImGuiStyle& style = g.Style; 11738 const float square_sz = GetFrameHeight(); 11739 const float w_extra = (flags & ImGuiColorEditFlags_NoSmallPreview) ? 0.0f : (square_sz + style.ItemInnerSpacing.x); 11740 const float w_items_all = CalcItemWidth() - w_extra; 11741 const char* label_display_end = FindRenderedTextEnd(label); 11742 11743 const bool alpha = (flags & ImGuiColorEditFlags_NoAlpha) == 0; 11744 const bool hdr = (flags & ImGuiColorEditFlags_HDR) != 0; 11745 const int components = alpha ? 4 : 3; 11746 const ImGuiColorEditFlags flags_untouched = flags; 11747 11748 BeginGroup(); 11749 PushID(label); 11750 11751 // If we're not showing any slider there's no point in doing any HSV conversions 11752 if (flags & ImGuiColorEditFlags_NoInputs) 11753 flags = (flags & (~ImGuiColorEditFlags__InputsMask)) | ImGuiColorEditFlags_RGB | ImGuiColorEditFlags_NoOptions; 11754 11755 // Context menu: display and modify options (before defaults are applied) 11756 if (!(flags & ImGuiColorEditFlags_NoOptions)) 11757 ColorEditOptionsPopup(col, flags); 11758 11759 // Read stored options 11760 if (!(flags & ImGuiColorEditFlags__InputsMask)) 11761 flags |= (g.ColorEditOptions & ImGuiColorEditFlags__InputsMask); 11762 if (!(flags & ImGuiColorEditFlags__DataTypeMask)) 11763 flags |= (g.ColorEditOptions & ImGuiColorEditFlags__DataTypeMask); 11764 if (!(flags & ImGuiColorEditFlags__PickerMask)) 11765 flags |= (g.ColorEditOptions & ImGuiColorEditFlags__PickerMask); 11766 flags |= (g.ColorEditOptions & ~(ImGuiColorEditFlags__InputsMask | ImGuiColorEditFlags__DataTypeMask | ImGuiColorEditFlags__PickerMask)); 11767 11768 // Convert to the formats we need 11769 float f[4] = { col[0], col[1], col[2], alpha ? col[3] : 1.0f }; 11770 if (flags & ImGuiColorEditFlags_HSV) 11771 ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]); 11772 int i[4] = { IM_F32_TO_INT8_UNBOUND(f[0]), IM_F32_TO_INT8_UNBOUND(f[1]), IM_F32_TO_INT8_UNBOUND(f[2]), IM_F32_TO_INT8_UNBOUND(f[3]) }; 11773 11774 bool value_changed = false; 11775 bool value_changed_as_float = false; 11776 11777 if ((flags & (ImGuiColorEditFlags_RGB | ImGuiColorEditFlags_HSV)) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0) 11778 { 11779 // RGB/HSV 0..255 Sliders 11780 const float w_item_one = ImMax(1.0f, (float)(int)((w_items_all - (style.ItemInnerSpacing.x) * (components - 1)) / (float)components)); 11781 const float w_item_last = ImMax(1.0f, (float)(int)(w_items_all - (w_item_one + style.ItemInnerSpacing.x) * (components - 1))); 11782 11783 const bool hide_prefix = (w_item_one <= CalcTextSize((flags & ImGuiColorEditFlags_Float) ? "M:0.000" : "M:000").x); 11784 const char* ids[4] = { "##X", "##Y", "##Z", "##W" }; 11785 const char* fmt_table_int[3][4] = 11786 { 11787 { "%3.0f", "%3.0f", "%3.0f", "%3.0f" }, // Short display 11788 { "R:%3.0f", "G:%3.0f", "B:%3.0f", "A:%3.0f" }, // Long display for RGBA 11789 { "H:%3.0f", "S:%3.0f", "V:%3.0f", "A:%3.0f" } // Long display for HSVA 11790 }; 11791 const char* fmt_table_float[3][4] = 11792 { 11793 { "%0.3f", "%0.3f", "%0.3f", "%0.3f" }, // Short display 11794 { "R:%0.3f", "G:%0.3f", "B:%0.3f", "A:%0.3f" }, // Long display for RGBA 11795 { "H:%0.3f", "S:%0.3f", "V:%0.3f", "A:%0.3f" } // Long display for HSVA 11796 }; 11797 const int fmt_idx = hide_prefix ? 0 : (flags & ImGuiColorEditFlags_HSV) ? 2 : 1; 11798 11799 PushItemWidth(w_item_one); 11800 for (int n = 0; n < components; n++) 11801 { 11802 if (n > 0) 11803 SameLine(0, style.ItemInnerSpacing.x); 11804 if (n + 1 == components) 11805 PushItemWidth(w_item_last); 11806 if (flags & ImGuiColorEditFlags_Float) 11807 value_changed = value_changed_as_float = value_changed | DragFloat(ids[n], &f[n], 1.0f / 255.0f, 0.0f, hdr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]); 11808 else 11809 value_changed |= DragInt(ids[n], &i[n], 1.0f, 0, hdr ? 0 : 255, fmt_table_int[fmt_idx][n]); 11810 if (!(flags & ImGuiColorEditFlags_NoOptions)) 11811 OpenPopupOnItemClick("context"); 11812 } 11813 PopItemWidth(); 11814 PopItemWidth(); 11815 } 11816 else if ((flags & ImGuiColorEditFlags_HEX) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0) 11817 { 11818 // RGB Hexadecimal Input 11819 char buf[64]; 11820 if (alpha) 11821 ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X%02X", ImClamp(i[0], 0, 255), ImClamp(i[1], 0, 255), ImClamp(i[2], 0, 255), ImClamp(i[3], 0, 255)); 11822 else 11823 ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", ImClamp(i[0], 0, 255), ImClamp(i[1], 0, 255), ImClamp(i[2], 0, 255)); 11824 PushItemWidth(w_items_all); 11825 if (InputText("##Text", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase)) 11826 { 11827 value_changed = true; 11828 char* p = buf; 11829 while (*p == '#' || ImCharIsSpace((unsigned int)*p)) 11830 p++; 11831 i[0] = i[1] = i[2] = i[3] = 0; 11832 if (alpha) 11833 sscanf(p, "%02X%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2], (unsigned int*)&i[3]); // Treat at unsigned (%X is unsigned) 11834 else 11835 sscanf(p, "%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2]); 11836 } 11837 if (!(flags & ImGuiColorEditFlags_NoOptions)) 11838 OpenPopupOnItemClick("context"); 11839 PopItemWidth(); 11840 } 11841 11842 ImGuiWindow* picker_active_window = NULL; 11843 if (!(flags & ImGuiColorEditFlags_NoSmallPreview)) 11844 { 11845 if (!(flags & ImGuiColorEditFlags_NoInputs)) 11846 SameLine(0, style.ItemInnerSpacing.x); 11847 11848 const ImVec4 col_v4(col[0], col[1], col[2], alpha ? col[3] : 1.0f); 11849 if (ColorButton("##ColorButton", col_v4, flags)) 11850 { 11851 if (!(flags & ImGuiColorEditFlags_NoPicker)) 11852 { 11853 // Store current color and open a picker 11854 g.ColorPickerRef = col_v4; 11855 OpenPopup("picker"); 11856 SetNextWindowPos(window->DC.LastItemRect.GetBL() + ImVec2(-1, style.ItemSpacing.y)); 11857 } 11858 } 11859 if (!(flags & ImGuiColorEditFlags_NoOptions)) 11860 OpenPopupOnItemClick("context"); 11861 11862 if (BeginPopup("picker")) 11863 { 11864 picker_active_window = g.CurrentWindow; 11865 if (label != label_display_end) 11866 { 11867 TextUnformatted(label, label_display_end); 11868 Separator(); 11869 } 11870 ImGuiColorEditFlags picker_flags_to_forward = ImGuiColorEditFlags__DataTypeMask | ImGuiColorEditFlags__PickerMask | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaBar; 11871 ImGuiColorEditFlags picker_flags = (flags_untouched & picker_flags_to_forward) | ImGuiColorEditFlags__InputsMask | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf; 11872 PushItemWidth(square_sz * 12.0f); // Use 256 + bar sizes? 11873 value_changed |= ColorPicker4("##picker", col, picker_flags, &g.ColorPickerRef.x); 11874 PopItemWidth(); 11875 EndPopup(); 11876 } 11877 } 11878 11879 if (label != label_display_end && !(flags & ImGuiColorEditFlags_NoLabel)) 11880 { 11881 SameLine(0, style.ItemInnerSpacing.x); 11882 TextUnformatted(label, label_display_end); 11883 } 11884 11885 // Convert back 11886 if (picker_active_window == NULL) 11887 { 11888 if (!value_changed_as_float) 11889 for (int n = 0; n < 4; n++) 11890 f[n] = i[n] / 255.0f; 11891 if (flags & ImGuiColorEditFlags_HSV) 11892 ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]); 11893 if (value_changed) 11894 { 11895 col[0] = f[0]; 11896 col[1] = f[1]; 11897 col[2] = f[2]; 11898 if (alpha) 11899 col[3] = f[3]; 11900 } 11901 } 11902 11903 PopID(); 11904 EndGroup(); 11905 11906 // Drag and Drop Target 11907 if ((window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect) && BeginDragDropTarget()) // NB: The flag test is merely an optional micro-optimization, BeginDragDropTarget() does the same test. 11908 { 11909 if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) 11910 { 11911 memcpy((float*)col, payload->Data, sizeof(float) * 3); 11912 value_changed = true; 11913 } 11914 if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) 11915 { 11916 memcpy((float*)col, payload->Data, sizeof(float) * components); 11917 value_changed = true; 11918 } 11919 EndDragDropTarget(); 11920 } 11921 11922 // When picker is being actively used, use its active id so IsItemActive() will function on ColorEdit4(). 11923 if (picker_active_window && g.ActiveId != 0 && g.ActiveIdWindow == picker_active_window) 11924 window->DC.LastItemId = g.ActiveId; 11925 11926 return value_changed; 11927 } 11928 11929 bool ImGui::ColorPicker3(const char* label, float col[3], ImGuiColorEditFlags flags) 11930 { 11931 float col4[4] = { col[0], col[1], col[2], 1.0f }; 11932 if (!ColorPicker4(label, col4, flags | ImGuiColorEditFlags_NoAlpha)) 11933 return false; 11934 col[0] = col4[0]; col[1] = col4[1]; col[2] = col4[2]; 11935 return true; 11936 } 11937 11938 // 'pos' is position of the arrow tip. half_sz.x is length from base to tip. half_sz.y is length on each side. 11939 static void RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col) 11940 { 11941 switch (direction) 11942 { 11943 case ImGuiDir_Left: draw_list->AddTriangleFilled(ImVec2(pos.x + half_sz.x, pos.y - half_sz.y), ImVec2(pos.x + half_sz.x, pos.y + half_sz.y), pos, col); return; 11944 case ImGuiDir_Right: draw_list->AddTriangleFilled(ImVec2(pos.x - half_sz.x, pos.y + half_sz.y), ImVec2(pos.x - half_sz.x, pos.y - half_sz.y), pos, col); return; 11945 case ImGuiDir_Up: draw_list->AddTriangleFilled(ImVec2(pos.x + half_sz.x, pos.y + half_sz.y), ImVec2(pos.x - half_sz.x, pos.y + half_sz.y), pos, col); return; 11946 case ImGuiDir_Down: draw_list->AddTriangleFilled(ImVec2(pos.x - half_sz.x, pos.y - half_sz.y), ImVec2(pos.x + half_sz.x, pos.y - half_sz.y), pos, col); return; 11947 case ImGuiDir_None: case ImGuiDir_COUNT: break; // Fix warnings 11948 } 11949 } 11950 11951 static void RenderArrowsForVerticalBar(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, float bar_w) 11952 { 11953 RenderArrow(draw_list, ImVec2(pos.x + half_sz.x + 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Right, IM_COL32_BLACK); 11954 RenderArrow(draw_list, ImVec2(pos.x + half_sz.x, pos.y), half_sz, ImGuiDir_Right, IM_COL32_WHITE); 11955 RenderArrow(draw_list, ImVec2(pos.x + bar_w - half_sz.x - 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Left, IM_COL32_BLACK); 11956 RenderArrow(draw_list, ImVec2(pos.x + bar_w - half_sz.x, pos.y), half_sz, ImGuiDir_Left, IM_COL32_WHITE); 11957 } 11958 11959 // ColorPicker 11960 // Note: only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set. 11961 // FIXME: we adjust the big color square height based on item width, which may cause a flickering feedback loop (if automatic height makes a vertical scrollbar appears, affecting automatic width..) 11962 bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags flags, const float* ref_col) 11963 { 11964 ImGuiContext& g = *GImGui; 11965 ImGuiWindow* window = GetCurrentWindow(); 11966 ImDrawList* draw_list = window->DrawList; 11967 11968 ImGuiStyle& style = g.Style; 11969 ImGuiIO& io = g.IO; 11970 11971 PushID(label); 11972 BeginGroup(); 11973 11974 if (!(flags & ImGuiColorEditFlags_NoSidePreview)) 11975 flags |= ImGuiColorEditFlags_NoSmallPreview; 11976 11977 // Context menu: display and store options. 11978 if (!(flags & ImGuiColorEditFlags_NoOptions)) 11979 ColorPickerOptionsPopup(flags, col); 11980 11981 // Read stored options 11982 if (!(flags & ImGuiColorEditFlags__PickerMask)) 11983 flags |= ((g.ColorEditOptions & ImGuiColorEditFlags__PickerMask) ? g.ColorEditOptions : ImGuiColorEditFlags__OptionsDefault) & ImGuiColorEditFlags__PickerMask; 11984 IM_ASSERT(ImIsPowerOfTwo((int)(flags & ImGuiColorEditFlags__PickerMask))); // Check that only 1 is selected 11985 if (!(flags & ImGuiColorEditFlags_NoOptions)) 11986 flags |= (g.ColorEditOptions & ImGuiColorEditFlags_AlphaBar); 11987 11988 // Setup 11989 int components = (flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4; 11990 bool alpha_bar = (flags & ImGuiColorEditFlags_AlphaBar) && !(flags & ImGuiColorEditFlags_NoAlpha); 11991 ImVec2 picker_pos = window->DC.CursorPos; 11992 float square_sz = GetFrameHeight(); 11993 float bars_width = square_sz; // Arbitrary smallish width of Hue/Alpha picking bars 11994 float sv_picker_size = ImMax(bars_width * 1, CalcItemWidth() - (alpha_bar ? 2 : 1) * (bars_width + style.ItemInnerSpacing.x)); // Saturation/Value picking box 11995 float bar0_pos_x = picker_pos.x + sv_picker_size + style.ItemInnerSpacing.x; 11996 float bar1_pos_x = bar0_pos_x + bars_width + style.ItemInnerSpacing.x; 11997 float bars_triangles_half_sz = (float)(int)(bars_width * 0.20f); 11998 11999 float backup_initial_col[4]; 12000 memcpy(backup_initial_col, col, components * sizeof(float)); 12001 12002 float wheel_thickness = sv_picker_size * 0.08f; 12003 float wheel_r_outer = sv_picker_size * 0.50f; 12004 float wheel_r_inner = wheel_r_outer - wheel_thickness; 12005 ImVec2 wheel_center(picker_pos.x + (sv_picker_size + bars_width)*0.5f, picker_pos.y + sv_picker_size * 0.5f); 12006 12007 // Note: the triangle is displayed rotated with triangle_pa pointing to Hue, but most coordinates stays unrotated for logic. 12008 float triangle_r = wheel_r_inner - (int)(sv_picker_size * 0.027f); 12009 ImVec2 triangle_pa = ImVec2(triangle_r, 0.0f); // Hue point. 12010 ImVec2 triangle_pb = ImVec2(triangle_r * -0.5f, triangle_r * -0.866025f); // Black point. 12011 ImVec2 triangle_pc = ImVec2(triangle_r * -0.5f, triangle_r * +0.866025f); // White point. 12012 12013 float H, S, V; 12014 ColorConvertRGBtoHSV(col[0], col[1], col[2], H, S, V); 12015 12016 bool value_changed = false, value_changed_h = false, value_changed_sv = false; 12017 12018 PushItemFlag(ImGuiItemFlags_NoNav, true); 12019 if (flags & ImGuiColorEditFlags_PickerHueWheel) 12020 { 12021 // Hue wheel + SV triangle logic 12022 InvisibleButton("hsv", ImVec2(sv_picker_size + style.ItemInnerSpacing.x + bars_width, sv_picker_size)); 12023 if (IsItemActive()) 12024 { 12025 ImVec2 initial_off = g.IO.MouseClickedPos[0] - wheel_center; 12026 ImVec2 current_off = g.IO.MousePos - wheel_center; 12027 float initial_dist2 = ImLengthSqr(initial_off); 12028 if (initial_dist2 >= (wheel_r_inner - 1)*(wheel_r_inner - 1) && initial_dist2 <= (wheel_r_outer + 1)*(wheel_r_outer + 1)) 12029 { 12030 // Interactive with Hue wheel 12031 H = atan2f(current_off.y, current_off.x) / IM_PI * 0.5f; 12032 if (H < 0.0f) 12033 H += 1.0f; 12034 value_changed = value_changed_h = true; 12035 } 12036 float cos_hue_angle = cosf(-H * 2.0f * IM_PI); 12037 float sin_hue_angle = sinf(-H * 2.0f * IM_PI); 12038 if (ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_pc, ImRotate(initial_off, cos_hue_angle, sin_hue_angle))) 12039 { 12040 // Interacting with SV triangle 12041 ImVec2 current_off_unrotated = ImRotate(current_off, cos_hue_angle, sin_hue_angle); 12042 if (!ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated)) 12043 current_off_unrotated = ImTriangleClosestPoint(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated); 12044 float uu, vv, ww; 12045 ImTriangleBarycentricCoords(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated, uu, vv, ww); 12046 V = ImClamp(1.0f - vv, 0.0001f, 1.0f); 12047 S = ImClamp(uu / V, 0.0001f, 1.0f); 12048 value_changed = value_changed_sv = true; 12049 } 12050 } 12051 if (!(flags & ImGuiColorEditFlags_NoOptions)) 12052 OpenPopupOnItemClick("context"); 12053 } 12054 else if (flags & ImGuiColorEditFlags_PickerHueBar) 12055 { 12056 // SV rectangle logic 12057 InvisibleButton("sv", ImVec2(sv_picker_size, sv_picker_size)); 12058 if (IsItemActive()) 12059 { 12060 S = ImSaturate((io.MousePos.x - picker_pos.x) / (sv_picker_size - 1)); 12061 V = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size - 1)); 12062 value_changed = value_changed_sv = true; 12063 } 12064 if (!(flags & ImGuiColorEditFlags_NoOptions)) 12065 OpenPopupOnItemClick("context"); 12066 12067 // Hue bar logic 12068 SetCursorScreenPos(ImVec2(bar0_pos_x, picker_pos.y)); 12069 InvisibleButton("hue", ImVec2(bars_width, sv_picker_size)); 12070 if (IsItemActive()) 12071 { 12072 H = ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size - 1)); 12073 value_changed = value_changed_h = true; 12074 } 12075 } 12076 12077 // Alpha bar logic 12078 if (alpha_bar) 12079 { 12080 SetCursorScreenPos(ImVec2(bar1_pos_x, picker_pos.y)); 12081 InvisibleButton("alpha", ImVec2(bars_width, sv_picker_size)); 12082 if (IsItemActive()) 12083 { 12084 col[3] = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size - 1)); 12085 value_changed = true; 12086 } 12087 } 12088 PopItemFlag(); // ImGuiItemFlags_NoNav 12089 12090 if (!(flags & ImGuiColorEditFlags_NoSidePreview)) 12091 { 12092 SameLine(0, style.ItemInnerSpacing.x); 12093 BeginGroup(); 12094 } 12095 12096 if (!(flags & ImGuiColorEditFlags_NoLabel)) 12097 { 12098 const char* label_display_end = FindRenderedTextEnd(label); 12099 if (label != label_display_end) 12100 { 12101 if ((flags & ImGuiColorEditFlags_NoSidePreview)) 12102 SameLine(0, style.ItemInnerSpacing.x); 12103 TextUnformatted(label, label_display_end); 12104 } 12105 } 12106 12107 if (!(flags & ImGuiColorEditFlags_NoSidePreview)) 12108 { 12109 PushItemFlag(ImGuiItemFlags_NoNavDefaultFocus, true); 12110 ImVec4 col_v4(col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]); 12111 if ((flags & ImGuiColorEditFlags_NoLabel)) 12112 Text("Current"); 12113 ColorButton("##current", col_v4, (flags & (ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf | ImGuiColorEditFlags_NoTooltip)), ImVec2(square_sz * 3, square_sz * 2)); 12114 if (ref_col != NULL) 12115 { 12116 Text("Original"); 12117 ImVec4 ref_col_v4(ref_col[0], ref_col[1], ref_col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : ref_col[3]); 12118 if (ColorButton("##original", ref_col_v4, (flags & (ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf | ImGuiColorEditFlags_NoTooltip)), ImVec2(square_sz * 3, square_sz * 2))) 12119 { 12120 memcpy(col, ref_col, components * sizeof(float)); 12121 value_changed = true; 12122 } 12123 } 12124 PopItemFlag(); 12125 EndGroup(); 12126 } 12127 12128 // Convert back color to RGB 12129 if (value_changed_h || value_changed_sv) 12130 ColorConvertHSVtoRGB(H >= 1.0f ? H - 10 * 1e-6f : H, S > 0.0f ? S : 10 * 1e-6f, V > 0.0f ? V : 1e-6f, col[0], col[1], col[2]); 12131 12132 // R,G,B and H,S,V slider color editor 12133 if ((flags & ImGuiColorEditFlags_NoInputs) == 0) 12134 { 12135 PushItemWidth((alpha_bar ? bar1_pos_x : bar0_pos_x) + bars_width - picker_pos.x); 12136 ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags__DataTypeMask | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoSmallPreview | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf; 12137 ImGuiColorEditFlags sub_flags = (flags & sub_flags_to_forward) | ImGuiColorEditFlags_NoPicker; 12138 if (flags & ImGuiColorEditFlags_RGB || (flags & ImGuiColorEditFlags__InputsMask) == 0) 12139 value_changed |= ColorEdit4("##rgb", col, sub_flags | ImGuiColorEditFlags_RGB); 12140 if (flags & ImGuiColorEditFlags_HSV || (flags & ImGuiColorEditFlags__InputsMask) == 0) 12141 value_changed |= ColorEdit4("##hsv", col, sub_flags | ImGuiColorEditFlags_HSV); 12142 if (flags & ImGuiColorEditFlags_HEX || (flags & ImGuiColorEditFlags__InputsMask) == 0) 12143 value_changed |= ColorEdit4("##hex", col, sub_flags | ImGuiColorEditFlags_HEX); 12144 PopItemWidth(); 12145 } 12146 12147 // Try to cancel hue wrap (after ColorEdit), if any 12148 if (value_changed) 12149 { 12150 float new_H, new_S, new_V; 12151 ColorConvertRGBtoHSV(col[0], col[1], col[2], new_H, new_S, new_V); 12152 if (new_H <= 0 && H > 0) 12153 { 12154 if (new_V <= 0 && V != new_V) 12155 ColorConvertHSVtoRGB(H, S, new_V <= 0 ? V * 0.5f : new_V, col[0], col[1], col[2]); 12156 else if (new_S <= 0) 12157 ColorConvertHSVtoRGB(H, new_S <= 0 ? S * 0.5f : new_S, new_V, col[0], col[1], col[2]); 12158 } 12159 } 12160 12161 ImVec4 hue_color_f(1, 1, 1, 1); ColorConvertHSVtoRGB(H, 1, 1, hue_color_f.x, hue_color_f.y, hue_color_f.z); 12162 ImU32 hue_color32 = ColorConvertFloat4ToU32(hue_color_f); 12163 ImU32 col32_no_alpha = ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 1.0f)); 12164 12165 const ImU32 hue_colors[6 + 1] = { IM_COL32(255,0,0,255), IM_COL32(255,255,0,255), IM_COL32(0,255,0,255), IM_COL32(0,255,255,255), IM_COL32(0,0,255,255), IM_COL32(255,0,255,255), IM_COL32(255,0,0,255) }; 12166 ImVec2 sv_cursor_pos; 12167 12168 if (flags & ImGuiColorEditFlags_PickerHueWheel) 12169 { 12170 // Render Hue Wheel 12171 const float aeps = 1.5f / wheel_r_outer; // Half a pixel arc length in radians (2pi cancels out). 12172 const int segment_per_arc = ImMax(4, (int)wheel_r_outer / 12); 12173 for (int n = 0; n < 6; n++) 12174 { 12175 const float a0 = (n) / 6.0f * 2.0f * IM_PI - aeps; 12176 const float a1 = (n + 1.0f) / 6.0f * 2.0f * IM_PI + aeps; 12177 const int vert_start_idx = draw_list->VtxBuffer.Size; 12178 draw_list->PathArcTo(wheel_center, (wheel_r_inner + wheel_r_outer)*0.5f, a0, a1, segment_per_arc); 12179 draw_list->PathStroke(IM_COL32_WHITE, false, wheel_thickness); 12180 const int vert_end_idx = draw_list->VtxBuffer.Size; 12181 12182 // Paint colors over existing vertices 12183 ImVec2 gradient_p0(wheel_center.x + cosf(a0) * wheel_r_inner, wheel_center.y + sinf(a0) * wheel_r_inner); 12184 ImVec2 gradient_p1(wheel_center.x + cosf(a1) * wheel_r_inner, wheel_center.y + sinf(a1) * wheel_r_inner); 12185 ShadeVertsLinearColorGradientKeepAlpha(draw_list->VtxBuffer.Data + vert_start_idx, draw_list->VtxBuffer.Data + vert_end_idx, gradient_p0, gradient_p1, hue_colors[n], hue_colors[n + 1]); 12186 } 12187 12188 // Render Cursor + preview on Hue Wheel 12189 float cos_hue_angle = cosf(H * 2.0f * IM_PI); 12190 float sin_hue_angle = sinf(H * 2.0f * IM_PI); 12191 ImVec2 hue_cursor_pos(wheel_center.x + cos_hue_angle * (wheel_r_inner + wheel_r_outer)*0.5f, wheel_center.y + sin_hue_angle * (wheel_r_inner + wheel_r_outer)*0.5f); 12192 float hue_cursor_rad = value_changed_h ? wheel_thickness * 0.65f : wheel_thickness * 0.55f; 12193 int hue_cursor_segments = ImClamp((int)(hue_cursor_rad / 1.4f), 9, 32); 12194 draw_list->AddCircleFilled(hue_cursor_pos, hue_cursor_rad, hue_color32, hue_cursor_segments); 12195 draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad + 1, IM_COL32(128, 128, 128, 255), hue_cursor_segments); 12196 draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad, IM_COL32_WHITE, hue_cursor_segments); 12197 12198 // Render SV triangle (rotated according to hue) 12199 ImVec2 tra = wheel_center + ImRotate(triangle_pa, cos_hue_angle, sin_hue_angle); 12200 ImVec2 trb = wheel_center + ImRotate(triangle_pb, cos_hue_angle, sin_hue_angle); 12201 ImVec2 trc = wheel_center + ImRotate(triangle_pc, cos_hue_angle, sin_hue_angle); 12202 ImVec2 uv_white = GetFontTexUvWhitePixel(); 12203 draw_list->PrimReserve(6, 6); 12204 draw_list->PrimVtx(tra, uv_white, hue_color32); 12205 draw_list->PrimVtx(trb, uv_white, hue_color32); 12206 draw_list->PrimVtx(trc, uv_white, IM_COL32_WHITE); 12207 draw_list->PrimVtx(tra, uv_white, IM_COL32_BLACK_TRANS); 12208 draw_list->PrimVtx(trb, uv_white, IM_COL32_BLACK); 12209 draw_list->PrimVtx(trc, uv_white, IM_COL32_BLACK_TRANS); 12210 draw_list->AddTriangle(tra, trb, trc, IM_COL32(128, 128, 128, 255), 1.5f); 12211 sv_cursor_pos = ImLerp(ImLerp(trc, tra, ImSaturate(S)), trb, ImSaturate(1 - V)); 12212 } 12213 else if (flags & ImGuiColorEditFlags_PickerHueBar) 12214 { 12215 // Render SV Square 12216 draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), IM_COL32_WHITE, hue_color32, hue_color32, IM_COL32_WHITE); 12217 draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), IM_COL32_BLACK_TRANS, IM_COL32_BLACK_TRANS, IM_COL32_BLACK, IM_COL32_BLACK); 12218 RenderFrameBorder(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), 0.0f); 12219 sv_cursor_pos.x = ImClamp((float)(int)(picker_pos.x + ImSaturate(S) * sv_picker_size + 0.5f), picker_pos.x + 2, picker_pos.x + sv_picker_size - 2); // Sneakily prevent the circle to stick out too much 12220 sv_cursor_pos.y = ImClamp((float)(int)(picker_pos.y + ImSaturate(1 - V) * sv_picker_size + 0.5f), picker_pos.y + 2, picker_pos.y + sv_picker_size - 2); 12221 12222 // Render Hue Bar 12223 for (int i = 0; i < 6; ++i) 12224 draw_list->AddRectFilledMultiColor(ImVec2(bar0_pos_x, picker_pos.y + i * (sv_picker_size / 6)), ImVec2(bar0_pos_x + bars_width, picker_pos.y + (i + 1) * (sv_picker_size / 6)), hue_colors[i], hue_colors[i], hue_colors[i + 1], hue_colors[i + 1]); 12225 float bar0_line_y = (float)(int)(picker_pos.y + H * sv_picker_size + 0.5f); 12226 RenderFrameBorder(ImVec2(bar0_pos_x, picker_pos.y), ImVec2(bar0_pos_x + bars_width, picker_pos.y + sv_picker_size), 0.0f); 12227 RenderArrowsForVerticalBar(draw_list, ImVec2(bar0_pos_x - 1, bar0_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f); 12228 } 12229 12230 // Render cursor/preview circle (clamp S/V within 0..1 range because floating points colors may lead HSV values to be out of range) 12231 float sv_cursor_rad = value_changed_sv ? 10.0f : 6.0f; 12232 draw_list->AddCircleFilled(sv_cursor_pos, sv_cursor_rad, col32_no_alpha, 12); 12233 draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad + 1, IM_COL32(128, 128, 128, 255), 12); 12234 draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad, IM_COL32_WHITE, 12); 12235 12236 // Render alpha bar 12237 if (alpha_bar) 12238 { 12239 float alpha = ImSaturate(col[3]); 12240 ImRect bar1_bb(bar1_pos_x, picker_pos.y, bar1_pos_x + bars_width, picker_pos.y + sv_picker_size); 12241 RenderColorRectWithAlphaCheckerboard(bar1_bb.Min, bar1_bb.Max, IM_COL32(0, 0, 0, 0), bar1_bb.GetWidth() / 2.0f, ImVec2(0.0f, 0.0f)); 12242 draw_list->AddRectFilledMultiColor(bar1_bb.Min, bar1_bb.Max, col32_no_alpha, col32_no_alpha, col32_no_alpha & ~IM_COL32_A_MASK, col32_no_alpha & ~IM_COL32_A_MASK); 12243 float bar1_line_y = (float)(int)(picker_pos.y + (1.0f - alpha) * sv_picker_size + 0.5f); 12244 RenderFrameBorder(bar1_bb.Min, bar1_bb.Max, 0.0f); 12245 RenderArrowsForVerticalBar(draw_list, ImVec2(bar1_pos_x - 1, bar1_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f); 12246 } 12247 12248 EndGroup(); 12249 PopID(); 12250 12251 return value_changed && memcmp(backup_initial_col, col, components * sizeof(float)); 12252 } 12253 12254 // Horizontal separating line. 12255 void ImGui::Separator() 12256 { 12257 ImGuiWindow* window = GetCurrentWindow(); 12258 if (window->SkipItems) 12259 return; 12260 ImGuiContext& g = *GImGui; 12261 12262 ImGuiSeparatorFlags flags = 0; 12263 if ((flags & (ImGuiSeparatorFlags_Horizontal | ImGuiSeparatorFlags_Vertical)) == 0) 12264 flags |= (window->DC.LayoutType == ImGuiLayoutType_Horizontal) ? ImGuiSeparatorFlags_Vertical : ImGuiSeparatorFlags_Horizontal; 12265 IM_ASSERT(ImIsPowerOfTwo((int)(flags & (ImGuiSeparatorFlags_Horizontal | ImGuiSeparatorFlags_Vertical)))); // Check that only 1 option is selected 12266 if (flags & ImGuiSeparatorFlags_Vertical) 12267 { 12268 VerticalSeparator(); 12269 return; 12270 } 12271 12272 // Horizontal Separator 12273 if (window->DC.ColumnsSet) 12274 PopClipRect(); 12275 12276 float x1 = window->Pos.x; 12277 float x2 = window->Pos.x + window->Size.x; 12278 if (!window->DC.GroupStack.empty()) 12279 x1 += window->DC.IndentX; 12280 12281 const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y + 1.0f)); 12282 ItemSize(ImVec2(0.0f, 0.0f)); // NB: we don't provide our width so that it doesn't get feed back into AutoFit, we don't provide height to not alter layout. 12283 if (!ItemAdd(bb, 0)) 12284 { 12285 if (window->DC.ColumnsSet) 12286 PushColumnClipRect(); 12287 return; 12288 } 12289 12290 window->DrawList->AddLine(bb.Min, ImVec2(bb.Max.x, bb.Min.y), GetColorU32(ImGuiCol_Separator)); 12291 12292 if (g.LogEnabled) 12293 LogRenderedText(NULL, IM_NEWLINE "--------------------------------"); 12294 12295 if (window->DC.ColumnsSet) 12296 { 12297 PushColumnClipRect(); 12298 window->DC.ColumnsSet->LineMinY = window->DC.CursorPos.y; 12299 } 12300 } 12301 12302 void ImGui::VerticalSeparator() 12303 { 12304 ImGuiWindow* window = GetCurrentWindow(); 12305 if (window->SkipItems) 12306 return; 12307 ImGuiContext& g = *GImGui; 12308 12309 float y1 = window->DC.CursorPos.y; 12310 float y2 = window->DC.CursorPos.y + window->DC.CurrentLineHeight; 12311 const ImRect bb(ImVec2(window->DC.CursorPos.x, y1), ImVec2(window->DC.CursorPos.x + 1.0f, y2)); 12312 ItemSize(ImVec2(bb.GetWidth(), 0.0f)); 12313 if (!ItemAdd(bb, 0)) 12314 return; 12315 12316 window->DrawList->AddLine(ImVec2(bb.Min.x, bb.Min.y), ImVec2(bb.Min.x, bb.Max.y), GetColorU32(ImGuiCol_Separator)); 12317 if (g.LogEnabled) 12318 LogText(" |"); 12319 } 12320 12321 bool ImGui::SplitterBehavior(ImGuiID id, const ImRect& bb, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend) 12322 { 12323 ImGuiContext& g = *GImGui; 12324 ImGuiWindow* window = g.CurrentWindow; 12325 12326 const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags; 12327 window->DC.ItemFlags |= ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus; 12328 bool item_add = ItemAdd(bb, id); 12329 window->DC.ItemFlags = item_flags_backup; 12330 if (!item_add) 12331 return false; 12332 12333 bool hovered, held; 12334 ImRect bb_interact = bb; 12335 bb_interact.Expand(axis == ImGuiAxis_Y ? ImVec2(0.0f, hover_extend) : ImVec2(hover_extend, 0.0f)); 12336 ButtonBehavior(bb_interact, id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowItemOverlap); 12337 if (g.ActiveId != id) 12338 SetItemAllowOverlap(); 12339 12340 if (held || (g.HoveredId == id && g.HoveredIdPreviousFrame == id)) 12341 SetMouseCursor(axis == ImGuiAxis_Y ? ImGuiMouseCursor_ResizeNS : ImGuiMouseCursor_ResizeEW); 12342 12343 ImRect bb_render = bb; 12344 if (held) 12345 { 12346 ImVec2 mouse_delta_2d = g.IO.MousePos - g.ActiveIdClickOffset - bb_interact.Min; 12347 float mouse_delta = (axis == ImGuiAxis_Y) ? mouse_delta_2d.y : mouse_delta_2d.x; 12348 12349 // Minimum pane size 12350 if (mouse_delta < min_size1 - *size1) 12351 mouse_delta = min_size1 - *size1; 12352 if (mouse_delta > *size2 - min_size2) 12353 mouse_delta = *size2 - min_size2; 12354 12355 // Apply resize 12356 *size1 += mouse_delta; 12357 *size2 -= mouse_delta; 12358 bb_render.Translate((axis == ImGuiAxis_X) ? ImVec2(mouse_delta, 0.0f) : ImVec2(0.0f, mouse_delta)); 12359 } 12360 12361 // Render 12362 const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : hovered ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator); 12363 window->DrawList->AddRectFilled(bb_render.Min, bb_render.Max, col, g.Style.FrameRounding); 12364 12365 return held; 12366 } 12367 12368 void ImGui::Spacing() 12369 { 12370 ImGuiWindow* window = GetCurrentWindow(); 12371 if (window->SkipItems) 12372 return; 12373 ItemSize(ImVec2(0, 0)); 12374 } 12375 12376 void ImGui::Dummy(const ImVec2& size) 12377 { 12378 ImGuiWindow* window = GetCurrentWindow(); 12379 if (window->SkipItems) 12380 return; 12381 12382 const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); 12383 ItemSize(bb); 12384 ItemAdd(bb, 0); 12385 } 12386 12387 bool ImGui::IsRectVisible(const ImVec2& size) 12388 { 12389 ImGuiWindow* window = GetCurrentWindowRead(); 12390 return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size)); 12391 } 12392 12393 bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max) 12394 { 12395 ImGuiWindow* window = GetCurrentWindowRead(); 12396 return window->ClipRect.Overlaps(ImRect(rect_min, rect_max)); 12397 } 12398 12399 // 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.) 12400 void ImGui::BeginGroup() 12401 { 12402 ImGuiWindow* window = GetCurrentWindow(); 12403 12404 window->DC.GroupStack.resize(window->DC.GroupStack.Size + 1); 12405 ImGuiGroupData& group_data = window->DC.GroupStack.back(); 12406 group_data.BackupCursorPos = window->DC.CursorPos; 12407 group_data.BackupCursorMaxPos = window->DC.CursorMaxPos; 12408 group_data.BackupIndentX = window->DC.IndentX; 12409 group_data.BackupGroupOffsetX = window->DC.GroupOffsetX; 12410 group_data.BackupCurrentLineHeight = window->DC.CurrentLineHeight; 12411 group_data.BackupCurrentLineTextBaseOffset = window->DC.CurrentLineTextBaseOffset; 12412 group_data.BackupLogLinePosY = window->DC.LogLinePosY; 12413 group_data.BackupActiveIdIsAlive = GImGui->ActiveIdIsAlive; 12414 group_data.AdvanceCursor = true; 12415 12416 window->DC.GroupOffsetX = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffsetX; 12417 window->DC.IndentX = window->DC.GroupOffsetX; 12418 window->DC.CursorMaxPos = window->DC.CursorPos; 12419 window->DC.CurrentLineHeight = 0.0f; 12420 window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; 12421 } 12422 12423 void ImGui::EndGroup() 12424 { 12425 ImGuiContext& g = *GImGui; 12426 ImGuiWindow* window = GetCurrentWindow(); 12427 12428 IM_ASSERT(!window->DC.GroupStack.empty()); // Mismatched BeginGroup()/EndGroup() calls 12429 12430 ImGuiGroupData& group_data = window->DC.GroupStack.back(); 12431 12432 ImRect group_bb(group_data.BackupCursorPos, window->DC.CursorMaxPos); 12433 group_bb.Max = ImMax(group_bb.Min, group_bb.Max); 12434 12435 window->DC.CursorPos = group_data.BackupCursorPos; 12436 window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos); 12437 window->DC.CurrentLineHeight = group_data.BackupCurrentLineHeight; 12438 window->DC.CurrentLineTextBaseOffset = group_data.BackupCurrentLineTextBaseOffset; 12439 window->DC.IndentX = group_data.BackupIndentX; 12440 window->DC.GroupOffsetX = group_data.BackupGroupOffsetX; 12441 window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; 12442 12443 if (group_data.AdvanceCursor) 12444 { 12445 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. 12446 ItemSize(group_bb.GetSize(), group_data.BackupCurrentLineTextBaseOffset); 12447 ItemAdd(group_bb, 0); 12448 } 12449 12450 // If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive() will be functional on the entire group. 12451 // It would be be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but if you search for LastItemId you'll notice it is only used in that context. 12452 const bool active_id_within_group = (!group_data.BackupActiveIdIsAlive && g.ActiveIdIsAlive && g.ActiveId && g.ActiveIdWindow->RootWindow == window->RootWindow); 12453 if (active_id_within_group) 12454 window->DC.LastItemId = g.ActiveId; 12455 window->DC.LastItemRect = group_bb; 12456 12457 window->DC.GroupStack.pop_back(); 12458 12459 //window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // [Debug] 12460 } 12461 12462 // Gets back to previous line and continue with horizontal layout 12463 // pos_x == 0 : follow right after previous item 12464 // pos_x != 0 : align to specified x position (relative to window/group left) 12465 // spacing_w < 0 : use default spacing if pos_x == 0, no spacing if pos_x != 0 12466 // spacing_w >= 0 : enforce spacing amount 12467 void ImGui::SameLine(float pos_x, float spacing_w) 12468 { 12469 ImGuiWindow* window = GetCurrentWindow(); 12470 if (window->SkipItems) 12471 return; 12472 12473 ImGuiContext& g = *GImGui; 12474 if (pos_x != 0.0f) 12475 { 12476 if (spacing_w < 0.0f) spacing_w = 0.0f; 12477 window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + pos_x + spacing_w + window->DC.GroupOffsetX + window->DC.ColumnsOffsetX; 12478 window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y; 12479 } 12480 else 12481 { 12482 if (spacing_w < 0.0f) spacing_w = g.Style.ItemSpacing.x; 12483 window->DC.CursorPos.x = window->DC.CursorPosPrevLine.x + spacing_w; 12484 window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y; 12485 } 12486 window->DC.CurrentLineHeight = window->DC.PrevLineHeight; 12487 window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset; 12488 } 12489 12490 void ImGui::NewLine() 12491 { 12492 ImGuiWindow* window = GetCurrentWindow(); 12493 if (window->SkipItems) 12494 return; 12495 12496 ImGuiContext& g = *GImGui; 12497 const ImGuiLayoutType backup_layout_type = window->DC.LayoutType; 12498 window->DC.LayoutType = ImGuiLayoutType_Vertical; 12499 if (window->DC.CurrentLineHeight > 0.0f) // In the event that we are on a line with items that is smaller that FontSize high, we will preserve its height. 12500 ItemSize(ImVec2(0, 0)); 12501 else 12502 ItemSize(ImVec2(0.0f, g.FontSize)); 12503 window->DC.LayoutType = backup_layout_type; 12504 } 12505 12506 void ImGui::NextColumn() 12507 { 12508 ImGuiWindow* window = GetCurrentWindow(); 12509 if (window->SkipItems || window->DC.ColumnsSet == NULL) 12510 return; 12511 12512 ImGuiContext& g = *GImGui; 12513 PopItemWidth(); 12514 PopClipRect(); 12515 12516 ImGuiColumnsSet* columns = window->DC.ColumnsSet; 12517 columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); 12518 if (++columns->Current < columns->Count) 12519 { 12520 // Columns 1+ cancel out IndentX 12521 window->DC.ColumnsOffsetX = GetColumnOffset(columns->Current) - window->DC.IndentX + g.Style.ItemSpacing.x; 12522 window->DrawList->ChannelsSetCurrent(columns->Current); 12523 } 12524 else 12525 { 12526 window->DC.ColumnsOffsetX = 0.0f; 12527 window->DrawList->ChannelsSetCurrent(0); 12528 columns->Current = 0; 12529 columns->LineMinY = columns->LineMaxY; 12530 } 12531 window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX); 12532 window->DC.CursorPos.y = columns->LineMinY; 12533 window->DC.CurrentLineHeight = 0.0f; 12534 window->DC.CurrentLineTextBaseOffset = 0.0f; 12535 12536 PushColumnClipRect(); 12537 PushItemWidth(GetColumnWidth() * 0.65f); // FIXME: Move on columns setup 12538 } 12539 12540 int ImGui::GetColumnIndex() 12541 { 12542 ImGuiWindow* window = GetCurrentWindowRead(); 12543 return window->DC.ColumnsSet ? window->DC.ColumnsSet->Current : 0; 12544 } 12545 12546 int ImGui::GetColumnsCount() 12547 { 12548 ImGuiWindow* window = GetCurrentWindowRead(); 12549 return window->DC.ColumnsSet ? window->DC.ColumnsSet->Count : 1; 12550 } 12551 12552 static float OffsetNormToPixels(const ImGuiColumnsSet* columns, float offset_norm) 12553 { 12554 return offset_norm * (columns->MaxX - columns->MinX); 12555 } 12556 12557 static float PixelsToOffsetNorm(const ImGuiColumnsSet* columns, float offset) 12558 { 12559 return offset / (columns->MaxX - columns->MinX); 12560 } 12561 12562 static inline float GetColumnsRectHalfWidth() { return 4.0f; } 12563 12564 static float GetDraggedColumnOffset(ImGuiColumnsSet* columns, int column_index) 12565 { 12566 // Active (dragged) column always follow mouse. The reason we need this is that dragging a column to the right edge of an auto-resizing 12567 // window creates a feedback loop because we store normalized positions. So while dragging we enforce absolute positioning. 12568 ImGuiContext& g = *GImGui; 12569 ImGuiWindow* window = g.CurrentWindow; 12570 IM_ASSERT(column_index > 0); // We are not supposed to drag column 0. 12571 IM_ASSERT(g.ActiveId == columns->ID + ImGuiID(column_index)); 12572 12573 float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x + GetColumnsRectHalfWidth() - window->Pos.x; 12574 x = ImMax(x, ImGui::GetColumnOffset(column_index - 1) + g.Style.ColumnsMinSpacing); 12575 if ((columns->Flags & ImGuiColumnsFlags_NoPreserveWidths)) 12576 x = ImMin(x, ImGui::GetColumnOffset(column_index + 1) - g.Style.ColumnsMinSpacing); 12577 12578 return x; 12579 } 12580 12581 float ImGui::GetColumnOffset(int column_index) 12582 { 12583 ImGuiWindow* window = GetCurrentWindowRead(); 12584 ImGuiColumnsSet* columns = window->DC.ColumnsSet; 12585 IM_ASSERT(columns != NULL); 12586 12587 if (column_index < 0) 12588 column_index = columns->Current; 12589 IM_ASSERT(column_index < columns->Columns.Size); 12590 12591 const float t = columns->Columns[column_index].OffsetNorm; 12592 const float x_offset = ImLerp(columns->MinX, columns->MaxX, t); 12593 return x_offset; 12594 } 12595 12596 static float GetColumnWidthEx(ImGuiColumnsSet* columns, int column_index, bool before_resize = false) 12597 { 12598 if (column_index < 0) 12599 column_index = columns->Current; 12600 12601 float offset_norm; 12602 if (before_resize) 12603 offset_norm = columns->Columns[column_index + 1].OffsetNormBeforeResize - columns->Columns[column_index].OffsetNormBeforeResize; 12604 else 12605 offset_norm = columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm; 12606 return OffsetNormToPixels(columns, offset_norm); 12607 } 12608 12609 float ImGui::GetColumnWidth(int column_index) 12610 { 12611 ImGuiWindow* window = GetCurrentWindowRead(); 12612 ImGuiColumnsSet* columns = window->DC.ColumnsSet; 12613 IM_ASSERT(columns != NULL); 12614 12615 if (column_index < 0) 12616 column_index = columns->Current; 12617 return OffsetNormToPixels(columns, columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm); 12618 } 12619 12620 void ImGui::SetColumnOffset(int column_index, float offset) 12621 { 12622 ImGuiContext& g = *GImGui; 12623 ImGuiWindow* window = g.CurrentWindow; 12624 ImGuiColumnsSet* columns = window->DC.ColumnsSet; 12625 IM_ASSERT(columns != NULL); 12626 12627 if (column_index < 0) 12628 column_index = columns->Current; 12629 IM_ASSERT(column_index < columns->Columns.Size); 12630 12631 const bool preserve_width = !(columns->Flags & ImGuiColumnsFlags_NoPreserveWidths) && (column_index < columns->Count - 1); 12632 const float width = preserve_width ? GetColumnWidthEx(columns, column_index, columns->IsBeingResized) : 0.0f; 12633 12634 if (!(columns->Flags & ImGuiColumnsFlags_NoForceWithinWindow)) 12635 offset = ImMin(offset, columns->MaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index)); 12636 columns->Columns[column_index].OffsetNorm = PixelsToOffsetNorm(columns, offset - columns->MinX); 12637 12638 if (preserve_width) 12639 SetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width)); 12640 } 12641 12642 void ImGui::SetColumnWidth(int column_index, float width) 12643 { 12644 ImGuiWindow* window = GetCurrentWindowRead(); 12645 ImGuiColumnsSet* columns = window->DC.ColumnsSet; 12646 IM_ASSERT(columns != NULL); 12647 12648 if (column_index < 0) 12649 column_index = columns->Current; 12650 SetColumnOffset(column_index + 1, GetColumnOffset(column_index) + width); 12651 } 12652 12653 void ImGui::PushColumnClipRect(int column_index) 12654 { 12655 ImGuiWindow* window = GetCurrentWindowRead(); 12656 ImGuiColumnsSet* columns = window->DC.ColumnsSet; 12657 if (column_index < 0) 12658 column_index = columns->Current; 12659 12660 PushClipRect(columns->Columns[column_index].ClipRect.Min, columns->Columns[column_index].ClipRect.Max, false); 12661 } 12662 12663 static ImGuiColumnsSet* FindOrAddColumnsSet(ImGuiWindow* window, ImGuiID id) 12664 { 12665 for (int n = 0; n < window->ColumnsStorage.Size; n++) 12666 if (window->ColumnsStorage[n].ID == id) 12667 return &window->ColumnsStorage[n]; 12668 12669 window->ColumnsStorage.push_back(ImGuiColumnsSet()); 12670 ImGuiColumnsSet* columns = &window->ColumnsStorage.back(); 12671 columns->ID = id; 12672 return columns; 12673 } 12674 12675 void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlags flags) 12676 { 12677 ImGuiContext& g = *GImGui; 12678 ImGuiWindow* window = GetCurrentWindow(); 12679 12680 IM_ASSERT(columns_count > 1); 12681 IM_ASSERT(window->DC.ColumnsSet == NULL); // Nested columns are currently not supported 12682 12683 // Differentiate column ID with an arbitrary prefix for cases where users name their columns set the same as another widget. 12684 // In addition, when an identifier isn't explicitly provided we include the number of columns in the hash to make it uniquer. 12685 PushID(0x11223347 + (str_id ? 0 : columns_count)); 12686 ImGuiID id = window->GetID(str_id ? str_id : "columns"); 12687 PopID(); 12688 12689 // Acquire storage for the columns set 12690 ImGuiColumnsSet* columns = FindOrAddColumnsSet(window, id); 12691 IM_ASSERT(columns->ID == id); 12692 columns->Current = 0; 12693 columns->Count = columns_count; 12694 columns->Flags = flags; 12695 window->DC.ColumnsSet = columns; 12696 12697 // Set state for first column 12698 const float content_region_width = (window->SizeContentsExplicit.x != 0.0f) ? (window->SizeContentsExplicit.x) : (window->InnerClipRect.Max.x - window->Pos.x); 12699 columns->MinX = window->DC.IndentX - g.Style.ItemSpacing.x; // Lock our horizontal range 12700 columns->MaxX = ImMax(content_region_width - window->Scroll.x, columns->MinX + 1.0f); 12701 columns->StartPosY = window->DC.CursorPos.y; 12702 columns->StartMaxPosX = window->DC.CursorMaxPos.x; 12703 columns->LineMinY = columns->LineMaxY = window->DC.CursorPos.y; 12704 window->DC.ColumnsOffsetX = 0.0f; 12705 window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX); 12706 12707 // Clear data if columns count changed 12708 if (columns->Columns.Size != 0 && columns->Columns.Size != columns_count + 1) 12709 columns->Columns.resize(0); 12710 12711 // Initialize defaults 12712 columns->IsFirstFrame = (columns->Columns.Size == 0); 12713 if (columns->Columns.Size == 0) 12714 { 12715 columns->Columns.reserve(columns_count + 1); 12716 for (int n = 0; n < columns_count + 1; n++) 12717 { 12718 ImGuiColumnData column; 12719 column.OffsetNorm = n / (float)columns_count; 12720 columns->Columns.push_back(column); 12721 } 12722 } 12723 12724 for (int n = 0; n < columns_count; n++) 12725 { 12726 // Compute clipping rectangle 12727 ImGuiColumnData* column = &columns->Columns[n]; 12728 float clip_x1 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n) - 1.0f); 12729 float clip_x2 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n + 1) - 1.0f); 12730 column->ClipRect = ImRect(clip_x1, -FLT_MAX, clip_x2, +FLT_MAX); 12731 column->ClipRect.ClipWith(window->ClipRect); 12732 } 12733 12734 window->DrawList->ChannelsSplit(columns->Count); 12735 PushColumnClipRect(); 12736 PushItemWidth(GetColumnWidth() * 0.65f); 12737 } 12738 12739 void ImGui::EndColumns() 12740 { 12741 ImGuiContext& g = *GImGui; 12742 ImGuiWindow* window = GetCurrentWindow(); 12743 ImGuiColumnsSet* columns = window->DC.ColumnsSet; 12744 IM_ASSERT(columns != NULL); 12745 12746 PopItemWidth(); 12747 PopClipRect(); 12748 window->DrawList->ChannelsMerge(); 12749 12750 columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); 12751 window->DC.CursorPos.y = columns->LineMaxY; 12752 if (!(columns->Flags & ImGuiColumnsFlags_GrowParentContentsSize)) 12753 window->DC.CursorMaxPos.x = columns->StartMaxPosX; // Restore cursor max pos, as columns don't grow parent 12754 12755 // Draw columns borders and handle resize 12756 bool is_being_resized = false; 12757 if (!(columns->Flags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems) 12758 { 12759 const float y1 = columns->StartPosY; 12760 const float y2 = window->DC.CursorPos.y; 12761 int dragging_column = -1; 12762 for (int n = 1; n < columns->Count; n++) 12763 { 12764 float x = window->Pos.x + GetColumnOffset(n); 12765 const ImGuiID column_id = columns->ID + ImGuiID(n); 12766 const float column_hw = GetColumnsRectHalfWidth(); // Half-width for interaction 12767 const ImRect column_rect(ImVec2(x - column_hw, y1), ImVec2(x + column_hw, y2)); 12768 KeepAliveID(column_id); 12769 if (IsClippedEx(column_rect, column_id, false)) 12770 continue; 12771 12772 bool hovered = false, held = false; 12773 if (!(columns->Flags & ImGuiColumnsFlags_NoResize)) 12774 { 12775 ButtonBehavior(column_rect, column_id, &hovered, &held); 12776 if (hovered || held) 12777 g.MouseCursor = ImGuiMouseCursor_ResizeEW; 12778 if (held && !(columns->Columns[n].Flags & ImGuiColumnsFlags_NoResize)) 12779 dragging_column = n; 12780 } 12781 12782 // Draw column (we clip the Y boundaries CPU side because very long triangles are mishandled by some GPU drivers.) 12783 const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : hovered ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator); 12784 const float xi = (float)(int)x; 12785 window->DrawList->AddLine(ImVec2(xi, ImMax(y1 + 1.0f, window->ClipRect.Min.y)), ImVec2(xi, ImMin(y2, window->ClipRect.Max.y)), col); 12786 } 12787 12788 // Apply dragging after drawing the column lines, so our rendered lines are in sync with how items were displayed during the frame. 12789 if (dragging_column != -1) 12790 { 12791 if (!columns->IsBeingResized) 12792 for (int n = 0; n < columns->Count + 1; n++) 12793 columns->Columns[n].OffsetNormBeforeResize = columns->Columns[n].OffsetNorm; 12794 columns->IsBeingResized = is_being_resized = true; 12795 float x = GetDraggedColumnOffset(columns, dragging_column); 12796 SetColumnOffset(dragging_column, x); 12797 } 12798 } 12799 columns->IsBeingResized = is_being_resized; 12800 12801 window->DC.ColumnsSet = NULL; 12802 window->DC.ColumnsOffsetX = 0.0f; 12803 window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX); 12804 } 12805 12806 // [2018-03: This is currently the only public API, while we are working on making BeginColumns/EndColumns user-facing] 12807 void ImGui::Columns(int columns_count, const char* id, bool border) 12808 { 12809 ImGuiWindow* window = GetCurrentWindow(); 12810 IM_ASSERT(columns_count >= 1); 12811 12812 ImGuiColumnsFlags flags = (border ? 0 : ImGuiColumnsFlags_NoBorder); 12813 //flags |= ImGuiColumnsFlags_NoPreserveWidths; // NB: Legacy behavior 12814 if (window->DC.ColumnsSet != NULL && window->DC.ColumnsSet->Count == columns_count && window->DC.ColumnsSet->Flags == flags) 12815 return; 12816 12817 if (window->DC.ColumnsSet != NULL) 12818 EndColumns(); 12819 12820 if (columns_count != 1) 12821 BeginColumns(id, columns_count, flags); 12822 } 12823 12824 void ImGui::Indent(float indent_w) 12825 { 12826 ImGuiContext& g = *GImGui; 12827 ImGuiWindow* window = GetCurrentWindow(); 12828 window->DC.IndentX += (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing; 12829 window->DC.CursorPos.x = window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX; 12830 } 12831 12832 void ImGui::Unindent(float indent_w) 12833 { 12834 ImGuiContext& g = *GImGui; 12835 ImGuiWindow* window = GetCurrentWindow(); 12836 window->DC.IndentX -= (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing; 12837 window->DC.CursorPos.x = window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX; 12838 } 12839 12840 void ImGui::TreePush(const char* str_id) 12841 { 12842 ImGuiWindow* window = GetCurrentWindow(); 12843 Indent(); 12844 window->DC.TreeDepth++; 12845 PushID(str_id ? str_id : "#TreePush"); 12846 } 12847 12848 void ImGui::TreePush(const void* ptr_id) 12849 { 12850 ImGuiWindow* window = GetCurrentWindow(); 12851 Indent(); 12852 window->DC.TreeDepth++; 12853 PushID(ptr_id ? ptr_id : (const void*)"#TreePush"); 12854 } 12855 12856 void ImGui::TreePushRawID(ImGuiID id) 12857 { 12858 ImGuiWindow* window = GetCurrentWindow(); 12859 Indent(); 12860 window->DC.TreeDepth++; 12861 window->IDStack.push_back(id); 12862 } 12863 12864 void ImGui::TreePop() 12865 { 12866 ImGuiContext& g = *GImGui; 12867 ImGuiWindow* window = g.CurrentWindow; 12868 Unindent(); 12869 12870 window->DC.TreeDepth--; 12871 if (g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet()) 12872 if (g.NavIdIsAlive && (window->DC.TreeDepthMayJumpToParentOnPop & (1 << window->DC.TreeDepth))) 12873 { 12874 SetNavID(window->IDStack.back(), g.NavLayer); 12875 NavMoveRequestCancel(); 12876 } 12877 window->DC.TreeDepthMayJumpToParentOnPop &= (1 << window->DC.TreeDepth) - 1; 12878 12879 PopID(); 12880 } 12881 12882 void ImGui::Value(const char* prefix, bool b) 12883 { 12884 Text("%s: %s", prefix, (b ? "true" : "false")); 12885 } 12886 12887 void ImGui::Value(const char* prefix, int v) 12888 { 12889 Text("%s: %d", prefix, v); 12890 } 12891 12892 void ImGui::Value(const char* prefix, unsigned int v) 12893 { 12894 Text("%s: %d", prefix, v); 12895 } 12896 12897 void ImGui::Value(const char* prefix, float v, const char* float_format) 12898 { 12899 if (float_format) 12900 { 12901 char fmt[64]; 12902 ImFormatString(fmt, IM_ARRAYSIZE(fmt), "%%s: %s", float_format); 12903 Text(fmt, prefix, v); 12904 } 12905 else 12906 { 12907 Text("%s: %.3f", prefix, v); 12908 } 12909 } 9301 const char* label = window->Name; 9302 if (label == FindRenderedTextEnd(label)) 9303 label = GetFallbackWindowNameForWindowingList(window); 9304 Selectable(label, g.NavWindowingTarget == window); 9305 } 9306 End(); 9307 PopStyleVar(); 9308 } 9309 12910 9310 12911 9311 //----------------------------------------------------------------------------- 12912 // DRAG AND DROP9312 // [SECTION] DRAG AND DROP 12913 9313 //----------------------------------------------------------------------------- 12914 9314 12915 9315 void ImGui::ClearDragDrop() 12916 9316 { 12917 ImGuiContext& g = *GImGui; 12918 g.DragDropActive = false; 12919 g.DragDropPayload.Clear(); 12920 g.DragDropAcceptIdCurr = g.DragDropAcceptIdPrev = 0; 12921 g.DragDropAcceptIdCurrRectSurface = FLT_MAX; 12922 g.DragDropAcceptFrameCount = -1; 12923 } 12924 12925 // Call when current ID is active. 9317 ImGuiContext& g = *GImGui; 9318 g.DragDropActive = false; 9319 g.DragDropPayload.Clear(); 9320 g.DragDropAcceptFlags = ImGuiDragDropFlags_None; 9321 g.DragDropAcceptIdCurr = g.DragDropAcceptIdPrev = 0; 9322 g.DragDropAcceptIdCurrRectSurface = FLT_MAX; 9323 g.DragDropAcceptFrameCount = -1; 9324 9325 g.DragDropPayloadBufHeap.clear(); 9326 memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal)); 9327 } 9328 9329 // Call when current ID is active. 12926 9330 // When this returns true you need to: a) call SetDragDropPayload() exactly once, b) you may render the payload visual/description, c) call EndDragDropSource() 12927 9331 bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags) 12928 9332 { 12929 ImGuiContext& g = *GImGui; 12930 ImGuiWindow* window = g.CurrentWindow; 12931 12932 bool source_drag_active = false; 12933 ImGuiID source_id = 0; 12934 ImGuiID source_parent_id = 0; 12935 int mouse_button = 0; 12936 if (!(flags & ImGuiDragDropFlags_SourceExtern)) 12937 { 12938 source_id = window->DC.LastItemId; 12939 if (source_id != 0 && g.ActiveId != source_id) // Early out for most common case 12940 return false; 12941 if (g.IO.MouseDown[mouse_button] == false) 12942 return false; 12943 12944 if (source_id == 0) 12945 { 12946 // If you want to use BeginDragDropSource() on an item with no unique identifier for interaction, such as Text() or Image(), you need to: 12947 // A) Read the explanation below, B) Use the ImGuiDragDropFlags_SourceAllowNullID flag, C) Swallow your programmer pride. 12948 if (!(flags & ImGuiDragDropFlags_SourceAllowNullID)) 12949 { 12950 IM_ASSERT(0); 9333 ImGuiContext& g = *GImGui; 9334 ImGuiWindow* window = g.CurrentWindow; 9335 9336 bool source_drag_active = false; 9337 ImGuiID source_id = 0; 9338 ImGuiID source_parent_id = 0; 9339 ImGuiMouseButton mouse_button = ImGuiMouseButton_Left; 9340 if (!(flags & ImGuiDragDropFlags_SourceExtern)) 9341 { 9342 source_id = window->DC.LastItemId; 9343 if (source_id != 0 && g.ActiveId != source_id) // Early out for most common case 12951 9344 return false; 12952 } 12953 12954 // Magic fallback (=somehow reprehensible) to handle items with no assigned ID, e.g. Text(), Image() 12955 // We build a throwaway ID based on current ID stack + relative AABB of items in window. 12956 // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING OF THE WIDGET, so if your widget moves your dragging operation will be canceled. 12957 // We don't need to maintain/call ClearActiveID() as releasing the button will early out this function and trigger !ActiveIdIsAlive. 12958 bool is_hovered = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect) != 0; 12959 if (!is_hovered && (g.ActiveId == 0 || g.ActiveIdWindow != window)) 9345 if (g.IO.MouseDown[mouse_button] == false) 12960 9346 return false; 12961 source_id = window->DC.LastItemId = window->GetIDFromRectangle(window->DC.LastItemRect); 12962 if (is_hovered) 12963 SetHoveredID(source_id); 12964 if (is_hovered && g.IO.MouseClicked[mouse_button]) 12965 { 12966 SetActiveID(source_id, window); 12967 FocusWindow(window); 12968 } 12969 if (g.ActiveId == source_id) // Allow the underlying widget to display/return hovered during the mouse release frame, else we would get a flicker. 12970 g.ActiveIdAllowOverlap = is_hovered; 12971 } 12972 if (g.ActiveId != source_id) 12973 return false; 12974 source_parent_id = window->IDStack.back(); 12975 source_drag_active = IsMouseDragging(mouse_button); 12976 } 12977 else 12978 { 12979 window = NULL; 12980 source_id = ImHash("#SourceExtern", 0); 12981 source_drag_active = true; 12982 } 12983 12984 if (source_drag_active) 12985 { 12986 if (!g.DragDropActive) 12987 { 12988 IM_ASSERT(source_id != 0); 12989 ClearDragDrop(); 12990 ImGuiPayload& payload = g.DragDropPayload; 12991 payload.SourceId = source_id; 12992 payload.SourceParentId = source_parent_id; 12993 g.DragDropActive = true; 12994 g.DragDropSourceFlags = flags; 12995 g.DragDropMouseButton = mouse_button; 12996 } 12997 12998 if (!(flags & ImGuiDragDropFlags_SourceNoPreviewTooltip)) 12999 { 13000 // FIXME-DRAG 13001 //SetNextWindowPos(g.IO.MousePos - g.ActiveIdClickOffset - g.Style.WindowPadding); 13002 //PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * 0.60f); // This is better but e.g ColorButton with checkboard has issue with transparent colors :( 13003 SetNextWindowPos(g.IO.MousePos); 13004 PushStyleColor(ImGuiCol_PopupBg, GetStyleColorVec4(ImGuiCol_PopupBg) * ImVec4(1.0f, 1.0f, 1.0f, 0.6f)); 13005 BeginTooltip(); 13006 } 13007 13008 if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover) && !(flags & ImGuiDragDropFlags_SourceExtern)) 13009 window->DC.LastItemStatusFlags &= ~ImGuiItemStatusFlags_HoveredRect; 13010 13011 return true; 13012 } 13013 return false; 9347 9348 if (source_id == 0) 9349 { 9350 // If you want to use BeginDragDropSource() on an item with no unique identifier for interaction, such as Text() or Image(), you need to: 9351 // A) Read the explanation below, B) Use the ImGuiDragDropFlags_SourceAllowNullID flag, C) Swallow your programmer pride. 9352 if (!(flags & ImGuiDragDropFlags_SourceAllowNullID)) 9353 { 9354 IM_ASSERT(0); 9355 return false; 9356 } 9357 9358 // Early out 9359 if ((window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect) == 0 && (g.ActiveId == 0 || g.ActiveIdWindow != window)) 9360 return false; 9361 9362 // Magic fallback (=somehow reprehensible) to handle items with no assigned ID, e.g. Text(), Image() 9363 // We build a throwaway ID based on current ID stack + relative AABB of items in window. 9364 // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING OF THE WIDGET, so if your widget moves your dragging operation will be canceled. 9365 // We don't need to maintain/call ClearActiveID() as releasing the button will early out this function and trigger !ActiveIdIsAlive. 9366 source_id = window->DC.LastItemId = window->GetIDFromRectangle(window->DC.LastItemRect); 9367 bool is_hovered = ItemHoverable(window->DC.LastItemRect, source_id); 9368 if (is_hovered && g.IO.MouseClicked[mouse_button]) 9369 { 9370 SetActiveID(source_id, window); 9371 FocusWindow(window); 9372 } 9373 if (g.ActiveId == source_id) // Allow the underlying widget to display/return hovered during the mouse release frame, else we would get a flicker. 9374 g.ActiveIdAllowOverlap = is_hovered; 9375 } 9376 else 9377 { 9378 g.ActiveIdAllowOverlap = false; 9379 } 9380 if (g.ActiveId != source_id) 9381 return false; 9382 source_parent_id = window->IDStack.back(); 9383 source_drag_active = IsMouseDragging(mouse_button); 9384 9385 // Disable navigation and key inputs while dragging 9386 g.ActiveIdUsingNavDirMask = ~(ImU32)0; 9387 g.ActiveIdUsingNavInputMask = ~(ImU32)0; 9388 g.ActiveIdUsingKeyInputMask = ~(ImU64)0; 9389 } 9390 else 9391 { 9392 window = NULL; 9393 source_id = ImHashStr("#SourceExtern"); 9394 source_drag_active = true; 9395 } 9396 9397 if (source_drag_active) 9398 { 9399 if (!g.DragDropActive) 9400 { 9401 IM_ASSERT(source_id != 0); 9402 ClearDragDrop(); 9403 ImGuiPayload& payload = g.DragDropPayload; 9404 payload.SourceId = source_id; 9405 payload.SourceParentId = source_parent_id; 9406 g.DragDropActive = true; 9407 g.DragDropSourceFlags = flags; 9408 g.DragDropMouseButton = mouse_button; 9409 } 9410 g.DragDropSourceFrameCount = g.FrameCount; 9411 g.DragDropWithinSource = true; 9412 9413 if (!(flags & ImGuiDragDropFlags_SourceNoPreviewTooltip)) 9414 { 9415 // Target can request the Source to not display its tooltip (we use a dedicated flag to make this request explicit) 9416 // We unfortunately can't just modify the source flags and skip the call to BeginTooltip, as caller may be emitting contents. 9417 BeginTooltip(); 9418 if (g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip)) 9419 { 9420 ImGuiWindow* tooltip_window = g.CurrentWindow; 9421 tooltip_window->SkipItems = true; 9422 tooltip_window->HiddenFramesCanSkipItems = 1; 9423 } 9424 } 9425 9426 if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover) && !(flags & ImGuiDragDropFlags_SourceExtern)) 9427 window->DC.LastItemStatusFlags &= ~ImGuiItemStatusFlags_HoveredRect; 9428 9429 return true; 9430 } 9431 return false; 13014 9432 } 13015 9433 13016 9434 void ImGui::EndDragDropSource() 13017 9435 { 13018 ImGuiContext& g = *GImGui; 13019 IM_ASSERT(g.DragDropActive); 13020 13021 if (!(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip)) 13022 { 13023 EndTooltip(); 13024 PopStyleColor(); 13025 //PopStyleVar(); 13026 } 13027 13028 // Discard the drag if have not called SetDragDropPayload() 13029 if (g.DragDropPayload.DataFrameCount == -1) 13030 ClearDragDrop(); 9436 ImGuiContext& g = *GImGui; 9437 IM_ASSERT(g.DragDropActive); 9438 IM_ASSERT(g.DragDropWithinSource && "Not after a BeginDragDropSource()?"); 9439 9440 if (!(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip)) 9441 EndTooltip(); 9442 9443 // Discard the drag if have not called SetDragDropPayload() 9444 if (g.DragDropPayload.DataFrameCount == -1) 9445 ClearDragDrop(); 9446 g.DragDropWithinSource = false; 13031 9447 } 13032 9448 … … 13034 9450 bool ImGui::SetDragDropPayload(const char* type, const void* data, size_t data_size, ImGuiCond cond) 13035 9451 { 13036 ImGuiContext& g = *GImGui;13037 ImGuiPayload& payload = g.DragDropPayload;13038 if (cond == 0)13039 cond = ImGuiCond_Always;13040 13041 IM_ASSERT(type != NULL);13042 IM_ASSERT(strlen(type) < IM_ARRAYSIZE(payload.DataType) && "Payload type can be at most 12 characters long");13043 IM_ASSERT((data != NULL && data_size > 0) || (data == NULL && data_size == 0));13044 IM_ASSERT(cond == ImGuiCond_Always || cond == ImGuiCond_Once);13045 IM_ASSERT(payload.SourceId != 0); // Not called between BeginDragDropSource() and EndDragDropSource()13046 13047 if (cond == ImGuiCond_Always || payload.DataFrameCount == -1)13048 {13049 // Copy payload13050 ImStrncpy(payload.DataType, type, IM_ARRAYSIZE(payload.DataType));13051 g.DragDropPayloadBufHeap.resize(0);13052 if (data_size > sizeof(g.DragDropPayloadBufLocal))13053 {13054 // Store in heap13055 g.DragDropPayloadBufHeap.resize((int)data_size);13056 payload.Data = g.DragDropPayloadBufHeap.Data;13057 memcpy(payload.Data, data, data_size);13058 }13059 else if (data_size > 0)13060 {13061 // Store locally13062 memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal));13063 payload.Data = g.DragDropPayloadBufLocal;13064 memcpy(payload.Data, data, data_size);13065 }13066 else13067 {13068 payload.Data = NULL;13069 }13070 payload.DataSize = (int)data_size;13071 }13072 payload.DataFrameCount = g.FrameCount;13073 13074 return (g.DragDropAcceptFrameCount == g.FrameCount) || (g.DragDropAcceptFrameCount == g.FrameCount - 1);9452 ImGuiContext& g = *GImGui; 9453 ImGuiPayload& payload = g.DragDropPayload; 9454 if (cond == 0) 9455 cond = ImGuiCond_Always; 9456 9457 IM_ASSERT(type != NULL); 9458 IM_ASSERT(strlen(type) < IM_ARRAYSIZE(payload.DataType) && "Payload type can be at most 32 characters long"); 9459 IM_ASSERT((data != NULL && data_size > 0) || (data == NULL && data_size == 0)); 9460 IM_ASSERT(cond == ImGuiCond_Always || cond == ImGuiCond_Once); 9461 IM_ASSERT(payload.SourceId != 0); // Not called between BeginDragDropSource() and EndDragDropSource() 9462 9463 if (cond == ImGuiCond_Always || payload.DataFrameCount == -1) 9464 { 9465 // Copy payload 9466 ImStrncpy(payload.DataType, type, IM_ARRAYSIZE(payload.DataType)); 9467 g.DragDropPayloadBufHeap.resize(0); 9468 if (data_size > sizeof(g.DragDropPayloadBufLocal)) 9469 { 9470 // Store in heap 9471 g.DragDropPayloadBufHeap.resize((int)data_size); 9472 payload.Data = g.DragDropPayloadBufHeap.Data; 9473 memcpy(payload.Data, data, data_size); 9474 } 9475 else if (data_size > 0) 9476 { 9477 // Store locally 9478 memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal)); 9479 payload.Data = g.DragDropPayloadBufLocal; 9480 memcpy(payload.Data, data, data_size); 9481 } 9482 else 9483 { 9484 payload.Data = NULL; 9485 } 9486 payload.DataSize = (int)data_size; 9487 } 9488 payload.DataFrameCount = g.FrameCount; 9489 9490 return (g.DragDropAcceptFrameCount == g.FrameCount) || (g.DragDropAcceptFrameCount == g.FrameCount - 1); 13075 9491 } 13076 9492 13077 9493 bool ImGui::BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id) 13078 9494 { 13079 ImGuiContext& g = *GImGui; 13080 if (!g.DragDropActive) 13081 return false; 13082 13083 ImGuiWindow* window = g.CurrentWindow; 13084 if (g.HoveredWindow == NULL || window->RootWindow != g.HoveredWindow->RootWindow) 13085 return false; 13086 IM_ASSERT(id != 0); 13087 if (!IsMouseHoveringRect(bb.Min, bb.Max) || (id == g.DragDropPayload.SourceId)) 13088 return false; 13089 13090 g.DragDropTargetRect = bb; 13091 g.DragDropTargetId = id; 13092 return true; 9495 ImGuiContext& g = *GImGui; 9496 if (!g.DragDropActive) 9497 return false; 9498 9499 ImGuiWindow* window = g.CurrentWindow; 9500 ImGuiWindow* hovered_window = g.HoveredWindowUnderMovingWindow; 9501 if (hovered_window == NULL || window->RootWindow != hovered_window->RootWindow) 9502 return false; 9503 IM_ASSERT(id != 0); 9504 if (!IsMouseHoveringRect(bb.Min, bb.Max) || (id == g.DragDropPayload.SourceId)) 9505 return false; 9506 if (window->SkipItems) 9507 return false; 9508 9509 IM_ASSERT(g.DragDropWithinTarget == false); 9510 g.DragDropTargetRect = bb; 9511 g.DragDropTargetId = id; 9512 g.DragDropWithinTarget = true; 9513 return true; 13093 9514 } 13094 9515 … … 13099 9520 bool ImGui::BeginDragDropTarget() 13100 9521 { 13101 ImGuiContext& g = *GImGui; 13102 if (!g.DragDropActive) 13103 return false; 13104 13105 ImGuiWindow* window = g.CurrentWindow; 13106 if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect)) 13107 return false; 13108 if (g.HoveredWindow == NULL || window->RootWindow != g.HoveredWindow->RootWindow) 13109 return false; 13110 13111 const ImRect& display_rect = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? window->DC.LastItemDisplayRect : window->DC.LastItemRect; 13112 ImGuiID id = window->DC.LastItemId; 13113 if (id == 0) 13114 id = window->GetIDFromRectangle(display_rect); 13115 if (g.DragDropPayload.SourceId == id) 13116 return false; 13117 13118 g.DragDropTargetRect = display_rect; 13119 g.DragDropTargetId = id; 13120 return true; 9522 ImGuiContext& g = *GImGui; 9523 if (!g.DragDropActive) 9524 return false; 9525 9526 ImGuiWindow* window = g.CurrentWindow; 9527 if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect)) 9528 return false; 9529 ImGuiWindow* hovered_window = g.HoveredWindowUnderMovingWindow; 9530 if (hovered_window == NULL || window->RootWindow != hovered_window->RootWindow) 9531 return false; 9532 9533 const ImRect& display_rect = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? window->DC.LastItemDisplayRect : window->DC.LastItemRect; 9534 ImGuiID id = window->DC.LastItemId; 9535 if (id == 0) 9536 id = window->GetIDFromRectangle(display_rect); 9537 if (g.DragDropPayload.SourceId == id) 9538 return false; 9539 9540 IM_ASSERT(g.DragDropWithinTarget == false); 9541 g.DragDropTargetRect = display_rect; 9542 g.DragDropTargetId = id; 9543 g.DragDropWithinTarget = true; 9544 return true; 13121 9545 } 13122 9546 13123 9547 bool ImGui::IsDragDropPayloadBeingAccepted() 13124 9548 { 13125 ImGuiContext& g = *GImGui;13126 return g.DragDropActive && g.DragDropAcceptIdPrev != 0;9549 ImGuiContext& g = *GImGui; 9550 return g.DragDropActive && g.DragDropAcceptIdPrev != 0; 13127 9551 } 13128 9552 13129 9553 const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags) 13130 9554 { 13131 ImGuiContext& g = *GImGui; 13132 ImGuiWindow* window = g.CurrentWindow; 13133 ImGuiPayload& payload = g.DragDropPayload; 13134 IM_ASSERT(g.DragDropActive); // Not called between BeginDragDropTarget() and EndDragDropTarget() ? 13135 IM_ASSERT(payload.DataFrameCount != -1); // Forgot to call EndDragDropTarget() ? 13136 if (type != NULL && !payload.IsDataType(type)) 13137 return NULL; 13138 13139 // Accept smallest drag target bounding box, this allows us to nest drag targets conveniently without ordering constraints. 13140 // NB: We currently accept NULL id as target. However, overlapping targets requires a unique ID to function! 13141 const bool was_accepted_previously = (g.DragDropAcceptIdPrev == g.DragDropTargetId); 13142 ImRect r = g.DragDropTargetRect; 13143 float r_surface = r.GetWidth() * r.GetHeight(); 13144 if (r_surface < g.DragDropAcceptIdCurrRectSurface) 13145 { 13146 g.DragDropAcceptIdCurr = g.DragDropTargetId; 13147 g.DragDropAcceptIdCurrRectSurface = r_surface; 13148 } 13149 13150 // Render default drop visuals 13151 payload.Preview = was_accepted_previously; 13152 flags |= (g.DragDropSourceFlags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect); // Source can also inhibit the preview (useful for external sources that lives for 1 frame) 13153 if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && payload.Preview) 13154 { 13155 // FIXME-DRAG: Settle on a proper default visuals for drop target. 13156 r.Expand(3.5f); 13157 bool push_clip_rect = !window->ClipRect.Contains(r); 13158 if (push_clip_rect) window->DrawList->PushClipRectFullScreen(); 13159 window->DrawList->AddRect(r.Min, r.Max, GetColorU32(ImGuiCol_DragDropTarget), 0.0f, ~0, 2.0f); 13160 if (push_clip_rect) window->DrawList->PopClipRect(); 13161 } 13162 13163 g.DragDropAcceptFrameCount = g.FrameCount; 13164 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() 13165 if (!payload.Delivery && !(flags & ImGuiDragDropFlags_AcceptBeforeDelivery)) 13166 return NULL; 13167 13168 return &payload; 9555 ImGuiContext& g = *GImGui; 9556 ImGuiWindow* window = g.CurrentWindow; 9557 ImGuiPayload& payload = g.DragDropPayload; 9558 IM_ASSERT(g.DragDropActive); // Not called between BeginDragDropTarget() and EndDragDropTarget() ? 9559 IM_ASSERT(payload.DataFrameCount != -1); // Forgot to call EndDragDropTarget() ? 9560 if (type != NULL && !payload.IsDataType(type)) 9561 return NULL; 9562 9563 // Accept smallest drag target bounding box, this allows us to nest drag targets conveniently without ordering constraints. 9564 // NB: We currently accept NULL id as target. However, overlapping targets requires a unique ID to function! 9565 const bool was_accepted_previously = (g.DragDropAcceptIdPrev == g.DragDropTargetId); 9566 ImRect r = g.DragDropTargetRect; 9567 float r_surface = r.GetWidth() * r.GetHeight(); 9568 if (r_surface < g.DragDropAcceptIdCurrRectSurface) 9569 { 9570 g.DragDropAcceptFlags = flags; 9571 g.DragDropAcceptIdCurr = g.DragDropTargetId; 9572 g.DragDropAcceptIdCurrRectSurface = r_surface; 9573 } 9574 9575 // Render default drop visuals 9576 payload.Preview = was_accepted_previously; 9577 flags |= (g.DragDropSourceFlags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect); // Source can also inhibit the preview (useful for external sources that lives for 1 frame) 9578 if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && payload.Preview) 9579 { 9580 // FIXME-DRAG: Settle on a proper default visuals for drop target. 9581 r.Expand(3.5f); 9582 bool push_clip_rect = !window->ClipRect.Contains(r); 9583 if (push_clip_rect) window->DrawList->PushClipRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1)); 9584 window->DrawList->AddRect(r.Min, r.Max, GetColorU32(ImGuiCol_DragDropTarget), 0.0f, ~0, 2.0f); 9585 if (push_clip_rect) window->DrawList->PopClipRect(); 9586 } 9587 9588 g.DragDropAcceptFrameCount = g.FrameCount; 9589 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() 9590 if (!payload.Delivery && !(flags & ImGuiDragDropFlags_AcceptBeforeDelivery)) 9591 return NULL; 9592 9593 return &payload; 9594 } 9595 9596 const ImGuiPayload* ImGui::GetDragDropPayload() 9597 { 9598 ImGuiContext& g = *GImGui; 9599 return g.DragDropActive ? &g.DragDropPayload : NULL; 13169 9600 } 13170 9601 … … 13172 9603 void ImGui::EndDragDropTarget() 13173 9604 { 13174 ImGuiContext& g = *GImGui; (void)g; 13175 IM_ASSERT(g.DragDropActive); 9605 ImGuiContext& g = *GImGui; 9606 IM_ASSERT(g.DragDropActive); 9607 IM_ASSERT(g.DragDropWithinTarget); 9608 g.DragDropWithinTarget = false; 13176 9609 } 13177 9610 13178 9611 //----------------------------------------------------------------------------- 13179 // PLATFORM DEPENDENT HELPERS9612 // [SECTION] LOGGING/CAPTURING 13180 9613 //----------------------------------------------------------------------------- 13181 13182 #if defined(_WIN32) && !defined(_WINDOWS_) && (!defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) || !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)) 13183 #undef WIN32_LEAN_AND_MEAN 13184 #define WIN32_LEAN_AND_MEAN 13185 #ifndef __MINGW32__ 13186 #include <Windows.h> 9614 // All text output from the interface can be captured into tty/file/clipboard. 9615 // By default, tree nodes are automatically opened during logging. 9616 //----------------------------------------------------------------------------- 9617 9618 // Pass text data straight to log (without being displayed) 9619 void ImGui::LogText(const char* fmt, ...) 9620 { 9621 ImGuiContext& g = *GImGui; 9622 if (!g.LogEnabled) 9623 return; 9624 9625 va_list args; 9626 va_start(args, fmt); 9627 if (g.LogFile) 9628 { 9629 g.LogBuffer.Buf.resize(0); 9630 g.LogBuffer.appendfv(fmt, args); 9631 ImFileWrite(g.LogBuffer.c_str(), sizeof(char), (ImU64)g.LogBuffer.size(), g.LogFile); 9632 } 9633 else 9634 { 9635 g.LogBuffer.appendfv(fmt, args); 9636 } 9637 va_end(args); 9638 } 9639 9640 // Internal version that takes a position to decide on newline placement and pad items according to their depth. 9641 // We split text into individual lines to add current tree level padding 9642 void ImGui::LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end) 9643 { 9644 ImGuiContext& g = *GImGui; 9645 ImGuiWindow* window = g.CurrentWindow; 9646 9647 if (!text_end) 9648 text_end = FindRenderedTextEnd(text, text_end); 9649 9650 const bool log_new_line = ref_pos && (ref_pos->y > g.LogLinePosY + 1); 9651 if (ref_pos) 9652 g.LogLinePosY = ref_pos->y; 9653 if (log_new_line) 9654 g.LogLineFirstItem = true; 9655 9656 const char* text_remaining = text; 9657 if (g.LogDepthRef > window->DC.TreeDepth) // Re-adjust padding if we have popped out of our starting depth 9658 g.LogDepthRef = window->DC.TreeDepth; 9659 const int tree_depth = (window->DC.TreeDepth - g.LogDepthRef); 9660 for (;;) 9661 { 9662 // Split the string. Each new line (after a '\n') is followed by spacing corresponding to the current depth of our log entry. 9663 // We don't add a trailing \n to allow a subsequent item on the same line to be captured. 9664 const char* line_start = text_remaining; 9665 const char* line_end = ImStreolRange(line_start, text_end); 9666 const bool is_first_line = (line_start == text); 9667 const bool is_last_line = (line_end == text_end); 9668 if (!is_last_line || (line_start != line_end)) 9669 { 9670 const int char_count = (int)(line_end - line_start); 9671 if (log_new_line || !is_first_line) 9672 LogText(IM_NEWLINE "%*s%.*s", tree_depth * 4, "", char_count, line_start); 9673 else if (g.LogLineFirstItem) 9674 LogText("%*s%.*s", tree_depth * 4, "", char_count, line_start); 9675 else 9676 LogText(" %.*s", char_count, line_start); 9677 g.LogLineFirstItem = false; 9678 } 9679 else if (log_new_line) 9680 { 9681 // An empty "" string at a different Y position should output a carriage return. 9682 LogText(IM_NEWLINE); 9683 break; 9684 } 9685 9686 if (is_last_line) 9687 break; 9688 text_remaining = line_end + 1; 9689 } 9690 } 9691 9692 // Start logging/capturing text output 9693 void ImGui::LogBegin(ImGuiLogType type, int auto_open_depth) 9694 { 9695 ImGuiContext& g = *GImGui; 9696 ImGuiWindow* window = g.CurrentWindow; 9697 IM_ASSERT(g.LogEnabled == false); 9698 IM_ASSERT(g.LogFile == NULL); 9699 IM_ASSERT(g.LogBuffer.empty()); 9700 g.LogEnabled = true; 9701 g.LogType = type; 9702 g.LogDepthRef = window->DC.TreeDepth; 9703 g.LogDepthToExpand = ((auto_open_depth >= 0) ? auto_open_depth : g.LogDepthToExpandDefault); 9704 g.LogLinePosY = FLT_MAX; 9705 g.LogLineFirstItem = true; 9706 } 9707 9708 void ImGui::LogToTTY(int auto_open_depth) 9709 { 9710 ImGuiContext& g = *GImGui; 9711 if (g.LogEnabled) 9712 return; 9713 IM_UNUSED(auto_open_depth); 9714 #ifndef IMGUI_DISABLE_TTY_FUNCTIONS 9715 LogBegin(ImGuiLogType_TTY, auto_open_depth); 9716 g.LogFile = stdout; 9717 #endif 9718 } 9719 9720 // Start logging/capturing text output to given file 9721 void ImGui::LogToFile(int auto_open_depth, const char* filename) 9722 { 9723 ImGuiContext& g = *GImGui; 9724 if (g.LogEnabled) 9725 return; 9726 9727 // FIXME: We could probably open the file in text mode "at", however note that clipboard/buffer logging will still 9728 // be subject to outputting OS-incompatible carriage return if within strings the user doesn't use IM_NEWLINE. 9729 // By opening the file in binary mode "ab" we have consistent output everywhere. 9730 if (!filename) 9731 filename = g.IO.LogFilename; 9732 if (!filename || !filename[0]) 9733 return; 9734 ImFileHandle f = ImFileOpen(filename, "ab"); 9735 if (!f) 9736 { 9737 IM_ASSERT(0); 9738 return; 9739 } 9740 9741 LogBegin(ImGuiLogType_File, auto_open_depth); 9742 g.LogFile = f; 9743 } 9744 9745 // Start logging/capturing text output to clipboard 9746 void ImGui::LogToClipboard(int auto_open_depth) 9747 { 9748 ImGuiContext& g = *GImGui; 9749 if (g.LogEnabled) 9750 return; 9751 LogBegin(ImGuiLogType_Clipboard, auto_open_depth); 9752 } 9753 9754 void ImGui::LogToBuffer(int auto_open_depth) 9755 { 9756 ImGuiContext& g = *GImGui; 9757 if (g.LogEnabled) 9758 return; 9759 LogBegin(ImGuiLogType_Buffer, auto_open_depth); 9760 } 9761 9762 void ImGui::LogFinish() 9763 { 9764 ImGuiContext& g = *GImGui; 9765 if (!g.LogEnabled) 9766 return; 9767 9768 LogText(IM_NEWLINE); 9769 switch (g.LogType) 9770 { 9771 case ImGuiLogType_TTY: 9772 #ifndef IMGUI_DISABLE_TTY_FUNCTIONS 9773 fflush(g.LogFile); 9774 #endif 9775 break; 9776 case ImGuiLogType_File: 9777 ImFileClose(g.LogFile); 9778 break; 9779 case ImGuiLogType_Buffer: 9780 break; 9781 case ImGuiLogType_Clipboard: 9782 if (!g.LogBuffer.empty()) 9783 SetClipboardText(g.LogBuffer.begin()); 9784 break; 9785 case ImGuiLogType_None: 9786 IM_ASSERT(0); 9787 break; 9788 } 9789 9790 g.LogEnabled = false; 9791 g.LogType = ImGuiLogType_None; 9792 g.LogFile = NULL; 9793 g.LogBuffer.clear(); 9794 } 9795 9796 // Helper to display logging buttons 9797 // FIXME-OBSOLETE: We should probably obsolete this and let the user have their own helper (this is one of the oldest function alive!) 9798 void ImGui::LogButtons() 9799 { 9800 ImGuiContext& g = *GImGui; 9801 9802 PushID("LogButtons"); 9803 #ifndef IMGUI_DISABLE_TTY_FUNCTIONS 9804 const bool log_to_tty = Button("Log To TTY"); SameLine(); 13187 9805 #else 13188 #include <windows.h> 9806 const bool log_to_tty = false; 13189 9807 #endif 9808 const bool log_to_file = Button("Log To File"); SameLine(); 9809 const bool log_to_clipboard = Button("Log To Clipboard"); SameLine(); 9810 PushAllowKeyboardFocus(false); 9811 SetNextItemWidth(80.0f); 9812 SliderInt("Default Depth", &g.LogDepthToExpandDefault, 0, 9, NULL); 9813 PopAllowKeyboardFocus(); 9814 PopID(); 9815 9816 // Start logging at the end of the function so that the buttons don't appear in the log 9817 if (log_to_tty) 9818 LogToTTY(); 9819 if (log_to_file) 9820 LogToFile(); 9821 if (log_to_clipboard) 9822 LogToClipboard(); 9823 } 9824 9825 9826 //----------------------------------------------------------------------------- 9827 // [SECTION] SETTINGS 9828 //----------------------------------------------------------------------------- 9829 // - UpdateSettings() [Internal] 9830 // - MarkIniSettingsDirty() [Internal] 9831 // - CreateNewWindowSettings() [Internal] 9832 // - FindWindowSettings() [Internal] 9833 // - FindOrCreateWindowSettings() [Internal] 9834 // - FindSettingsHandler() [Internal] 9835 // - ClearIniSettings() [Internal] 9836 // - LoadIniSettingsFromDisk() 9837 // - LoadIniSettingsFromMemory() 9838 // - SaveIniSettingsToDisk() 9839 // - SaveIniSettingsToMemory() 9840 // - WindowSettingsHandler_***() [Internal] 9841 //----------------------------------------------------------------------------- 9842 9843 // Called by NewFrame() 9844 void ImGui::UpdateSettings() 9845 { 9846 // Load settings on first frame (if not explicitly loaded manually before) 9847 ImGuiContext& g = *GImGui; 9848 if (!g.SettingsLoaded) 9849 { 9850 IM_ASSERT(g.SettingsWindows.empty()); 9851 if (g.IO.IniFilename) 9852 LoadIniSettingsFromDisk(g.IO.IniFilename); 9853 g.SettingsLoaded = true; 9854 } 9855 9856 // Save settings (with a delay after the last modification, so we don't spam disk too much) 9857 if (g.SettingsDirtyTimer > 0.0f) 9858 { 9859 g.SettingsDirtyTimer -= g.IO.DeltaTime; 9860 if (g.SettingsDirtyTimer <= 0.0f) 9861 { 9862 if (g.IO.IniFilename != NULL) 9863 SaveIniSettingsToDisk(g.IO.IniFilename); 9864 else 9865 g.IO.WantSaveIniSettings = true; // Let user know they can call SaveIniSettingsToMemory(). user will need to clear io.WantSaveIniSettings themselves. 9866 g.SettingsDirtyTimer = 0.0f; 9867 } 9868 } 9869 } 9870 9871 void ImGui::MarkIniSettingsDirty() 9872 { 9873 ImGuiContext& g = *GImGui; 9874 if (g.SettingsDirtyTimer <= 0.0f) 9875 g.SettingsDirtyTimer = g.IO.IniSavingRate; 9876 } 9877 9878 void ImGui::MarkIniSettingsDirty(ImGuiWindow* window) 9879 { 9880 ImGuiContext& g = *GImGui; 9881 if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings)) 9882 if (g.SettingsDirtyTimer <= 0.0f) 9883 g.SettingsDirtyTimer = g.IO.IniSavingRate; 9884 } 9885 9886 ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name) 9887 { 9888 ImGuiContext& g = *GImGui; 9889 9890 #if !IMGUI_DEBUG_INI_SETTINGS 9891 // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID() 9892 // Preserve the full string when IMGUI_DEBUG_INI_SETTINGS is set to make .ini inspection easier. 9893 if (const char* p = strstr(name, "###")) 9894 name = p; 13190 9895 #endif 13191 13192 // Win32 API clipboard implementation 13193 #if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) 9896 const size_t name_len = strlen(name); 9897 9898 // Allocate chunk 9899 const size_t chunk_size = sizeof(ImGuiWindowSettings) + name_len + 1; 9900 ImGuiWindowSettings* settings = g.SettingsWindows.alloc_chunk(chunk_size); 9901 IM_PLACEMENT_NEW(settings) ImGuiWindowSettings(); 9902 settings->ID = ImHashStr(name, name_len); 9903 memcpy(settings->GetName(), name, name_len + 1); // Store with zero terminator 9904 9905 return settings; 9906 } 9907 9908 ImGuiWindowSettings* ImGui::FindWindowSettings(ImGuiID id) 9909 { 9910 ImGuiContext& g = *GImGui; 9911 for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) 9912 if (settings->ID == id) 9913 return settings; 9914 return NULL; 9915 } 9916 9917 ImGuiWindowSettings* ImGui::FindOrCreateWindowSettings(const char* name) 9918 { 9919 if (ImGuiWindowSettings* settings = FindWindowSettings(ImHashStr(name))) 9920 return settings; 9921 return CreateNewWindowSettings(name); 9922 } 9923 9924 ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name) 9925 { 9926 ImGuiContext& g = *GImGui; 9927 const ImGuiID type_hash = ImHashStr(type_name); 9928 for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) 9929 if (g.SettingsHandlers[handler_n].TypeHash == type_hash) 9930 return &g.SettingsHandlers[handler_n]; 9931 return NULL; 9932 } 9933 9934 void ImGui::ClearIniSettings() 9935 { 9936 ImGuiContext& g = *GImGui; 9937 g.SettingsIniData.clear(); 9938 for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) 9939 if (g.SettingsHandlers[handler_n].ClearAllFn) 9940 g.SettingsHandlers[handler_n].ClearAllFn(&g, &g.SettingsHandlers[handler_n]); 9941 } 9942 9943 void ImGui::LoadIniSettingsFromDisk(const char* ini_filename) 9944 { 9945 size_t file_data_size = 0; 9946 char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", &file_data_size); 9947 if (!file_data) 9948 return; 9949 LoadIniSettingsFromMemory(file_data, (size_t)file_data_size); 9950 IM_FREE(file_data); 9951 } 9952 9953 // Zero-tolerance, no error reporting, cheap .ini parsing 9954 void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size) 9955 { 9956 ImGuiContext& g = *GImGui; 9957 IM_ASSERT(g.Initialized); 9958 //IM_ASSERT(!g.WithinFrameScope && "Cannot be called between NewFrame() and EndFrame()"); 9959 //IM_ASSERT(g.SettingsLoaded == false && g.FrameCount == 0); 9960 9961 // For user convenience, we allow passing a non zero-terminated string (hence the ini_size parameter). 9962 // 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.. 9963 if (ini_size == 0) 9964 ini_size = strlen(ini_data); 9965 g.SettingsIniData.Buf.resize((int)ini_size + 1); 9966 char* const buf = g.SettingsIniData.Buf.Data; 9967 char* const buf_end = buf + ini_size; 9968 memcpy(buf, ini_data, ini_size); 9969 buf_end[0] = 0; 9970 9971 // Call pre-read handlers 9972 // Some types will clear their data (e.g. dock information) some types will allow merge/override (window) 9973 for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) 9974 if (g.SettingsHandlers[handler_n].ReadInitFn) 9975 g.SettingsHandlers[handler_n].ReadInitFn(&g, &g.SettingsHandlers[handler_n]); 9976 9977 void* entry_data = NULL; 9978 ImGuiSettingsHandler* entry_handler = NULL; 9979 9980 char* line_end = NULL; 9981 for (char* line = buf; line < buf_end; line = line_end + 1) 9982 { 9983 // Skip new lines markers, then find end of the line 9984 while (*line == '\n' || *line == '\r') 9985 line++; 9986 line_end = line; 9987 while (line_end < buf_end && *line_end != '\n' && *line_end != '\r') 9988 line_end++; 9989 line_end[0] = 0; 9990 if (line[0] == ';') 9991 continue; 9992 if (line[0] == '[' && line_end > line && line_end[-1] == ']') 9993 { 9994 // Parse "[Type][Name]". Note that 'Name' can itself contains [] characters, which is acceptable with the current format and parsing code. 9995 line_end[-1] = 0; 9996 const char* name_end = line_end - 1; 9997 const char* type_start = line + 1; 9998 char* type_end = (char*)(void*)ImStrchrRange(type_start, name_end, ']'); 9999 const char* name_start = type_end ? ImStrchrRange(type_end + 1, name_end, '[') : NULL; 10000 if (!type_end || !name_start) 10001 continue; 10002 *type_end = 0; // Overwrite first ']' 10003 name_start++; // Skip second '[' 10004 entry_handler = FindSettingsHandler(type_start); 10005 entry_data = entry_handler ? entry_handler->ReadOpenFn(&g, entry_handler, name_start) : NULL; 10006 } 10007 else if (entry_handler != NULL && entry_data != NULL) 10008 { 10009 // Let type handler parse the line 10010 entry_handler->ReadLineFn(&g, entry_handler, entry_data, line); 10011 } 10012 } 10013 g.SettingsLoaded = true; 10014 10015 // [DEBUG] Restore untouched copy so it can be browsed in Metrics (not strictly necessary) 10016 memcpy(buf, ini_data, ini_size); 10017 10018 // Call post-read handlers 10019 for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) 10020 if (g.SettingsHandlers[handler_n].ApplyAllFn) 10021 g.SettingsHandlers[handler_n].ApplyAllFn(&g, &g.SettingsHandlers[handler_n]); 10022 } 10023 10024 void ImGui::SaveIniSettingsToDisk(const char* ini_filename) 10025 { 10026 ImGuiContext& g = *GImGui; 10027 g.SettingsDirtyTimer = 0.0f; 10028 if (!ini_filename) 10029 return; 10030 10031 size_t ini_data_size = 0; 10032 const char* ini_data = SaveIniSettingsToMemory(&ini_data_size); 10033 ImFileHandle f = ImFileOpen(ini_filename, "wt"); 10034 if (!f) 10035 return; 10036 ImFileWrite(ini_data, sizeof(char), ini_data_size, f); 10037 ImFileClose(f); 10038 } 10039 10040 // Call registered handlers (e.g. SettingsHandlerWindow_WriteAll() + custom handlers) to write their stuff into a text buffer 10041 const char* ImGui::SaveIniSettingsToMemory(size_t* out_size) 10042 { 10043 ImGuiContext& g = *GImGui; 10044 g.SettingsDirtyTimer = 0.0f; 10045 g.SettingsIniData.Buf.resize(0); 10046 g.SettingsIniData.Buf.push_back(0); 10047 for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) 10048 { 10049 ImGuiSettingsHandler* handler = &g.SettingsHandlers[handler_n]; 10050 handler->WriteAllFn(&g, handler, &g.SettingsIniData); 10051 } 10052 if (out_size) 10053 *out_size = (size_t)g.SettingsIniData.size(); 10054 return g.SettingsIniData.c_str(); 10055 } 10056 10057 static void WindowSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*) 10058 { 10059 ImGuiContext& g = *ctx; 10060 for (int i = 0; i != g.Windows.Size; i++) 10061 g.Windows[i]->SettingsOffset = -1; 10062 g.SettingsWindows.clear(); 10063 } 10064 10065 static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name) 10066 { 10067 ImGuiWindowSettings* settings = ImGui::FindOrCreateWindowSettings(name); 10068 ImGuiID id = settings->ID; 10069 *settings = ImGuiWindowSettings(); // Clear existing if recycling previous entry 10070 settings->ID = id; 10071 settings->WantApply = true; 10072 return (void*)settings; 10073 } 10074 10075 static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line) 10076 { 10077 ImGuiWindowSettings* settings = (ImGuiWindowSettings*)entry; 10078 int x, y; 10079 int i; 10080 if (sscanf(line, "Pos=%i,%i", &x, &y) == 2) { settings->Pos = ImVec2ih((short)x, (short)y); } 10081 else if (sscanf(line, "Size=%i,%i", &x, &y) == 2) { settings->Size = ImVec2ih((short)x, (short)y); } 10082 else if (sscanf(line, "Collapsed=%d", &i) == 1) { settings->Collapsed = (i != 0); } 10083 } 10084 10085 // Apply to existing windows (if any) 10086 static void WindowSettingsHandler_ApplyAll(ImGuiContext* ctx, ImGuiSettingsHandler*) 10087 { 10088 ImGuiContext& g = *ctx; 10089 for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) 10090 if (settings->WantApply) 10091 { 10092 if (ImGuiWindow* window = ImGui::FindWindowByID(settings->ID)) 10093 ApplyWindowSettings(window, settings); 10094 settings->WantApply = false; 10095 } 10096 } 10097 10098 static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf) 10099 { 10100 // Gather data from windows that were active during this session 10101 // (if a window wasn't opened in this session we preserve its settings) 10102 ImGuiContext& g = *ctx; 10103 for (int i = 0; i != g.Windows.Size; i++) 10104 { 10105 ImGuiWindow* window = g.Windows[i]; 10106 if (window->Flags & ImGuiWindowFlags_NoSavedSettings) 10107 continue; 10108 10109 ImGuiWindowSettings* settings = (window->SettingsOffset != -1) ? g.SettingsWindows.ptr_from_offset(window->SettingsOffset) : ImGui::FindWindowSettings(window->ID); 10110 if (!settings) 10111 { 10112 settings = ImGui::CreateNewWindowSettings(window->Name); 10113 window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings); 10114 } 10115 IM_ASSERT(settings->ID == window->ID); 10116 settings->Pos = ImVec2ih((short)window->Pos.x, (short)window->Pos.y); 10117 settings->Size = ImVec2ih((short)window->SizeFull.x, (short)window->SizeFull.y); 10118 settings->Collapsed = window->Collapsed; 10119 } 10120 10121 // Write to text buffer 10122 buf->reserve(buf->size() + g.SettingsWindows.size() * 6); // ballpark reserve 10123 for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) 10124 { 10125 const char* settings_name = settings->GetName(); 10126 buf->appendf("[%s][%s]\n", handler->TypeName, settings_name); 10127 buf->appendf("Pos=%d,%d\n", settings->Pos.x, settings->Pos.y); 10128 buf->appendf("Size=%d,%d\n", settings->Size.x, settings->Size.y); 10129 buf->appendf("Collapsed=%d\n", settings->Collapsed); 10130 buf->append("\n"); 10131 } 10132 } 10133 10134 10135 //----------------------------------------------------------------------------- 10136 // [SECTION] VIEWPORTS, PLATFORM WINDOWS 10137 //----------------------------------------------------------------------------- 10138 10139 // (this section is filled in the 'docking' branch) 10140 10141 10142 //----------------------------------------------------------------------------- 10143 // [SECTION] DOCKING 10144 //----------------------------------------------------------------------------- 10145 10146 // (this section is filled in the 'docking' branch) 10147 10148 10149 //----------------------------------------------------------------------------- 10150 // [SECTION] PLATFORM DEPENDENT HELPERS 10151 //----------------------------------------------------------------------------- 10152 10153 #if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) 13194 10154 13195 10155 #ifdef _MSC_VER 13196 10156 #pragma comment(lib, "user32") 10157 #pragma comment(lib, "kernel32") 13197 10158 #endif 13198 10159 10160 // Win32 clipboard implementation 10161 // We use g.ClipboardHandlerData for temporary storage to ensure it is freed on Shutdown() 13199 10162 static const char* GetClipboardTextFn_DefaultImpl(void*) 13200 10163 { 13201 static ImVector<char> buf_local;13202 buf_local.clear();13203 if (!OpenClipboard(NULL))13204 return NULL;13205 HANDLE wbuf_handle =GetClipboardData(CF_UNICODETEXT);13206 if (wbuf_handle == NULL)13207 {13208 CloseClipboard();13209 return NULL;13210 }13211 if (ImWchar* wbuf_global = (ImWchar*)GlobalLock(wbuf_handle))13212 {13213 int buf_len = ImTextCountUtf8BytesFromStr(wbuf_global, NULL) + 1;13214 buf_local.resize(buf_len);13215 ImTextStrToUtf8(buf_local.Data, buf_len, wbuf_global, NULL);13216 }13217 GlobalUnlock(wbuf_handle);13218 CloseClipboard();13219 return buf_local.Data;10164 ImGuiContext& g = *GImGui; 10165 g.ClipboardHandlerData.clear(); 10166 if (!::OpenClipboard(NULL)) 10167 return NULL; 10168 HANDLE wbuf_handle = ::GetClipboardData(CF_UNICODETEXT); 10169 if (wbuf_handle == NULL) 10170 { 10171 ::CloseClipboard(); 10172 return NULL; 10173 } 10174 if (const WCHAR* wbuf_global = (const WCHAR*)::GlobalLock(wbuf_handle)) 10175 { 10176 int buf_len = ::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, NULL, 0, NULL, NULL); 10177 g.ClipboardHandlerData.resize(buf_len); 10178 ::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, g.ClipboardHandlerData.Data, buf_len, NULL, NULL); 10179 } 10180 ::GlobalUnlock(wbuf_handle); 10181 ::CloseClipboard(); 10182 return g.ClipboardHandlerData.Data; 13220 10183 } 13221 10184 13222 10185 static void SetClipboardTextFn_DefaultImpl(void*, const char* text) 13223 10186 { 13224 if (!OpenClipboard(NULL)) 13225 return; 13226 const int wbuf_length = ImTextCountCharsFromUtf8(text, NULL) + 1; 13227 HGLOBAL wbuf_handle = GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(ImWchar)); 13228 if (wbuf_handle == NULL) 13229 { 13230 CloseClipboard(); 13231 return; 13232 } 13233 ImWchar* wbuf_global = (ImWchar*)GlobalLock(wbuf_handle); 13234 ImTextStrFromUtf8(wbuf_global, wbuf_length, text, NULL); 13235 GlobalUnlock(wbuf_handle); 13236 EmptyClipboard(); 13237 SetClipboardData(CF_UNICODETEXT, wbuf_handle); 13238 CloseClipboard(); 10187 if (!::OpenClipboard(NULL)) 10188 return; 10189 const int wbuf_length = ::MultiByteToWideChar(CP_UTF8, 0, text, -1, NULL, 0); 10190 HGLOBAL wbuf_handle = ::GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(WCHAR)); 10191 if (wbuf_handle == NULL) 10192 { 10193 ::CloseClipboard(); 10194 return; 10195 } 10196 WCHAR* wbuf_global = (WCHAR*)::GlobalLock(wbuf_handle); 10197 ::MultiByteToWideChar(CP_UTF8, 0, text, -1, wbuf_global, wbuf_length); 10198 ::GlobalUnlock(wbuf_handle); 10199 ::EmptyClipboard(); 10200 if (::SetClipboardData(CF_UNICODETEXT, wbuf_handle) == NULL) 10201 ::GlobalFree(wbuf_handle); 10202 ::CloseClipboard(); 10203 } 10204 10205 #elif defined(__APPLE__) && TARGET_OS_OSX && defined(IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS) 10206 10207 #include <Carbon/Carbon.h> // Use old API to avoid need for separate .mm file 10208 static PasteboardRef main_clipboard = 0; 10209 10210 // OSX clipboard implementation 10211 // If you enable this you will need to add '-framework ApplicationServices' to your linker command-line! 10212 static void SetClipboardTextFn_DefaultImpl(void*, const char* text) 10213 { 10214 if (!main_clipboard) 10215 PasteboardCreate(kPasteboardClipboard, &main_clipboard); 10216 PasteboardClear(main_clipboard); 10217 CFDataRef cf_data = CFDataCreate(kCFAllocatorDefault, (const UInt8*)text, strlen(text)); 10218 if (cf_data) 10219 { 10220 PasteboardPutItemFlavor(main_clipboard, (PasteboardItemID)1, CFSTR("public.utf8-plain-text"), cf_data, 0); 10221 CFRelease(cf_data); 10222 } 10223 } 10224 10225 static const char* GetClipboardTextFn_DefaultImpl(void*) 10226 { 10227 if (!main_clipboard) 10228 PasteboardCreate(kPasteboardClipboard, &main_clipboard); 10229 PasteboardSynchronize(main_clipboard); 10230 10231 ItemCount item_count = 0; 10232 PasteboardGetItemCount(main_clipboard, &item_count); 10233 for (ItemCount i = 0; i < item_count; i++) 10234 { 10235 PasteboardItemID item_id = 0; 10236 PasteboardGetItemIdentifier(main_clipboard, i + 1, &item_id); 10237 CFArrayRef flavor_type_array = 0; 10238 PasteboardCopyItemFlavors(main_clipboard, item_id, &flavor_type_array); 10239 for (CFIndex j = 0, nj = CFArrayGetCount(flavor_type_array); j < nj; j++) 10240 { 10241 CFDataRef cf_data; 10242 if (PasteboardCopyItemFlavorData(main_clipboard, item_id, CFSTR("public.utf8-plain-text"), &cf_data) == noErr) 10243 { 10244 ImGuiContext& g = *GImGui; 10245 g.ClipboardHandlerData.clear(); 10246 int length = (int)CFDataGetLength(cf_data); 10247 g.ClipboardHandlerData.resize(length + 1); 10248 CFDataGetBytes(cf_data, CFRangeMake(0, length), (UInt8*)g.ClipboardHandlerData.Data); 10249 g.ClipboardHandlerData[length] = 0; 10250 CFRelease(cf_data); 10251 return g.ClipboardHandlerData.Data; 10252 } 10253 } 10254 } 10255 return NULL; 13239 10256 } 13240 10257 13241 10258 #else 13242 10259 13243 // Local ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers10260 // Local Dear ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers. 13244 10261 static const char* GetClipboardTextFn_DefaultImpl(void*) 13245 10262 { 13246 ImGuiContext& g = *GImGui; 13247 return g.PrivateClipboard.empty() ? NULL : g.PrivateClipboard.begin(); 13248 } 13249 13250 // Local ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers 10263 ImGuiContext& g = *GImGui; 10264 return g.ClipboardHandlerData.empty() ? NULL : g.ClipboardHandlerData.begin(); 10265 } 10266 13251 10267 static void SetClipboardTextFn_DefaultImpl(void*, const char* text) 13252 10268 { 13253 ImGuiContext& g = *GImGui;13254 g.PrivateClipboard.clear();13255 const char* text_end = text + strlen(text);13256 g.PrivateClipboard.resize((int)(text_end - text) + 1);13257 memcpy(&g.PrivateClipboard[0], text, (size_t)(text_end - text));13258 g.PrivateClipboard[(int)(text_end - text)] = 0;10269 ImGuiContext& g = *GImGui; 10270 g.ClipboardHandlerData.clear(); 10271 const char* text_end = text + strlen(text); 10272 g.ClipboardHandlerData.resize((int)(text_end - text) + 1); 10273 memcpy(&g.ClipboardHandlerData[0], text, (size_t)(text_end - text)); 10274 g.ClipboardHandlerData[(int)(text_end - text)] = 0; 13259 10275 } 13260 10276 … … 13262 10278 13263 10279 // Win32 API IME support (for Asian languages, etc.) 13264 #if defined(_WIN32) && !defined(__GNUC__) && !defined(IMGUI_DISABLE_WIN32_ DEFAULT_IME_FUNCTIONS)10280 #if defined(_WIN32) && !defined(__GNUC__) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) 13265 10281 13266 10282 #include <imm.h> … … 13271 10287 static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y) 13272 10288 { 13273 // Notify OS Input Method Editor of text input position 13274 if (HWND hwnd = (HWND)GImGui->IO.ImeWindowHandle) 13275 if (HIMC himc = ImmGetContext(hwnd)) 13276 { 13277 COMPOSITIONFORM cf; 13278 cf.ptCurrentPos.x = x; 13279 cf.ptCurrentPos.y = y; 13280 cf.dwStyle = CFS_FORCE_POSITION; 13281 ImmSetCompositionWindow(himc, &cf); 13282 } 10289 // Notify OS Input Method Editor of text input position 10290 ImGuiIO& io = ImGui::GetIO(); 10291 if (HWND hwnd = (HWND)io.ImeWindowHandle) 10292 if (HIMC himc = ::ImmGetContext(hwnd)) 10293 { 10294 COMPOSITIONFORM cf; 10295 cf.ptCurrentPos.x = x; 10296 cf.ptCurrentPos.y = y; 10297 cf.dwStyle = CFS_FORCE_POSITION; 10298 ::ImmSetCompositionWindow(himc, &cf); 10299 ::ImmReleaseContext(hwnd, himc); 10300 } 13283 10301 } 13284 10302 … … 13290 10308 13291 10309 //----------------------------------------------------------------------------- 13292 // HELP, METRICS10310 // [SECTION] METRICS/DEBUG WINDOW 13293 10311 //----------------------------------------------------------------------------- 13294 10312 10313 #ifndef IMGUI_DISABLE_METRICS_WINDOW 10314 // Avoid naming collision with imgui_demo.cpp's HelpMarker() for unity builds. 10315 static void MetricsHelpMarker(const char* desc) 10316 { 10317 ImGui::TextDisabled("(?)"); 10318 if (ImGui::IsItemHovered()) 10319 { 10320 ImGui::BeginTooltip(); 10321 ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); 10322 ImGui::TextUnformatted(desc); 10323 ImGui::PopTextWrapPos(); 10324 ImGui::EndTooltip(); 10325 } 10326 } 10327 13295 10328 void ImGui::ShowMetricsWindow(bool* p_open) 13296 10329 { 13297 if (ImGui::Begin("ImGui Metrics", p_open)) 13298 { 13299 ImGui::Text("Dear ImGui %s", ImGui::GetVersion()); 13300 ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); 13301 ImGui::Text("%d vertices, %d indices (%d triangles)", ImGui::GetIO().MetricsRenderVertices, ImGui::GetIO().MetricsRenderIndices, ImGui::GetIO().MetricsRenderIndices / 3); 13302 ImGui::Text("%d allocations", (int)GImAllocatorActiveAllocationsCount); 13303 static bool show_clip_rects = true; 13304 ImGui::Checkbox("Show clipping rectangles when hovering draw commands", &show_clip_rects); 13305 ImGui::Separator(); 13306 13307 struct Funcs 13308 { 13309 static void NodeDrawList(ImGuiWindow* window, ImDrawList* draw_list, const char* label) 13310 { 10330 if (!ImGui::Begin("Dear ImGui Metrics", p_open)) 10331 { 10332 ImGui::End(); 10333 return; 10334 } 10335 10336 // Debugging enums 10337 enum { WRT_OuterRect, WRT_OuterRectClipped, WRT_InnerRect, WRT_InnerClipRect, WRT_WorkRect, WRT_Content, WRT_ContentRegionRect, WRT_Count }; // Windows Rect Type 10338 const char* wrt_rects_names[WRT_Count] = { "OuterRect", "OuterRectClipped", "InnerRect", "InnerClipRect", "WorkRect", "Content", "ContentRegionRect" }; 10339 enum { TRT_OuterRect, TRT_WorkRect, TRT_HostClipRect, TRT_InnerClipRect, TRT_BackgroundClipRect, TRT_ColumnsRect, TRT_ColumnsClipRect, TRT_ColumnsContentHeadersUsed, TRT_ColumnsContentHeadersIdeal, TRT_ColumnsContentRowsFrozen, TRT_ColumnsContentRowsUnfrozen, TRT_Count }; // Tables Rect Type 10340 const char* trt_rects_names[TRT_Count] = { "OuterRect", "WorkRect", "HostClipRect", "InnerClipRect", "BackgroundClipRect", "ColumnsRect", "ColumnsClipRect", "ColumnsContentHeadersUsed", "ColumnsContentHeadersIdeal", "ColumnsContentRowsFrozen", "ColumnsContentRowsUnfrozen" }; 10341 10342 // State 10343 static bool show_windows_rects = false; 10344 static int show_windows_rect_type = WRT_WorkRect; 10345 static bool show_windows_begin_order = false; 10346 static bool show_tables_rects = false; 10347 static int show_tables_rect_type = TRT_WorkRect; 10348 static bool show_drawcmd_mesh = true; 10349 static bool show_drawcmd_aabb = true; 10350 10351 // Basic info 10352 ImGuiContext& g = *GImGui; 10353 ImGuiIO& io = ImGui::GetIO(); 10354 ImGui::Text("Dear ImGui %s", ImGui::GetVersion()); 10355 ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); 10356 ImGui::Text("%d vertices, %d indices (%d triangles)", io.MetricsRenderVertices, io.MetricsRenderIndices, io.MetricsRenderIndices / 3); 10357 ImGui::Text("%d active windows (%d visible)", io.MetricsActiveWindows, io.MetricsRenderWindows); 10358 ImGui::Text("%d active allocations", io.MetricsActiveAllocations); 10359 ImGui::Separator(); 10360 10361 // Helper functions to display common structures: 10362 // - NodeDrawList() 10363 // - NodeColumns() 10364 // - NodeWindow() 10365 // - NodeWindows() 10366 // - NodeTabBar() 10367 // - NodeStorage() 10368 struct Funcs 10369 { 10370 static ImRect GetWindowRect(ImGuiWindow* window, int rect_type) 10371 { 10372 if (rect_type == WRT_OuterRect) { return window->Rect(); } 10373 else if (rect_type == WRT_OuterRectClipped) { return window->OuterRectClipped; } 10374 else if (rect_type == WRT_InnerRect) { return window->InnerRect; } 10375 else if (rect_type == WRT_InnerClipRect) { return window->InnerClipRect; } 10376 else if (rect_type == WRT_WorkRect) { return window->WorkRect; } 10377 else if (rect_type == WRT_Content) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSize); } 10378 else if (rect_type == WRT_ContentRegionRect) { return window->ContentRegionRect; } 10379 IM_ASSERT(0); 10380 return ImRect(); 10381 } 10382 10383 static void NodeDrawCmdShowMeshAndBoundingBox(ImGuiWindow* window, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, int elem_offset, bool show_mesh, bool show_aabb) 10384 { 10385 IM_ASSERT(show_mesh || show_aabb); 10386 ImDrawList* fg_draw_list = GetForegroundDrawList(window); // Render additional visuals into the top-most draw list 10387 ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; 10388 10389 // Draw wire-frame version of all triangles 10390 ImRect clip_rect = draw_cmd->ClipRect; 10391 ImRect vtxs_rect(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX); 10392 ImDrawListFlags backup_flags = fg_draw_list->Flags; 10393 fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles. 10394 for (unsigned int base_idx = elem_offset; base_idx < (elem_offset + draw_cmd->ElemCount); base_idx += 3) 10395 { 10396 ImVec2 triangle[3]; 10397 for (int n = 0; n < 3; n++) 10398 { 10399 ImVec2 p = draw_list->VtxBuffer[idx_buffer ? idx_buffer[base_idx + n] : (base_idx + n)].pos; 10400 triangle[n] = p; 10401 vtxs_rect.Add(p); 10402 } 10403 if (show_mesh) 10404 fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), true, 1.0f); // In yellow: mesh triangles 10405 } 10406 // Draw bounding boxes 10407 if (show_aabb) 10408 { 10409 fg_draw_list->AddRect(ImFloor(clip_rect.Min), ImFloor(clip_rect.Max), IM_COL32(255, 0, 255, 255)); // In pink: clipping rectangle submitted to GPU 10410 fg_draw_list->AddRect(ImFloor(vtxs_rect.Min), ImFloor(vtxs_rect.Max), IM_COL32(0, 255, 255, 255)); // In cyan: bounding box of triangles 10411 } 10412 fg_draw_list->Flags = backup_flags; 10413 } 10414 10415 static void NodeDrawList(ImGuiWindow* window, ImDrawList* draw_list, const char* label) 10416 { 13311 10417 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); 13312 10418 if (draw_list == ImGui::GetWindowDrawList()) 13313 10419 { 13314 ImGui::SameLine();13315 ImGui::TextColored(ImColor(255, 100, 100), "CURRENTLY APPENDING"); // Can't display stats for active draw list! (we don't have the data double-buffered)13316 if (node_open) ImGui::TreePop();13317 return;10420 ImGui::SameLine(); 10421 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) 10422 if (node_open) ImGui::TreePop(); 10423 return; 13318 10424 } 13319 10425 13320 ImDrawList* overlay_draw_list = GetOverlayDrawList(); // Render additional visuals into the top-most draw list10426 ImDrawList* fg_draw_list = GetForegroundDrawList(window); // Render additional visuals into the top-most draw list 13321 10427 if (window && IsItemHovered()) 13322 overlay_draw_list->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255));10428 fg_draw_list->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255)); 13323 10429 if (!node_open) 13324 return; 13325 13326 int elem_offset = 0; 10430 return; 10431 10432 if (window && !window->WasActive) 10433 ImGui::TextDisabled("Warning: owning Window is inactive. This DrawList is not being rendered!"); 10434 10435 unsigned int elem_offset = 0; 13327 10436 for (const ImDrawCmd* pcmd = draw_list->CmdBuffer.begin(); pcmd < draw_list->CmdBuffer.end(); elem_offset += pcmd->ElemCount, pcmd++) 13328 10437 { 13329 if (pcmd->UserCallback == NULL && pcmd->ElemCount == 0) 13330 continue; 13331 if (pcmd->UserCallback) 13332 { 13333 ImGui::BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData); 13334 continue; 13335 } 13336 ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; 13337 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); 13338 if (show_clip_rects && ImGui::IsItemHovered()) 13339 { 13340 ImRect clip_rect = pcmd->ClipRect; 13341 ImRect vtxs_rect; 13342 for (int i = elem_offset; i < elem_offset + (int)pcmd->ElemCount; i++) 13343 vtxs_rect.Add(draw_list->VtxBuffer[idx_buffer ? idx_buffer[i] : i].pos); 13344 clip_rect.Floor(); overlay_draw_list->AddRect(clip_rect.Min, clip_rect.Max, IM_COL32(255, 255, 0, 255)); 13345 vtxs_rect.Floor(); overlay_draw_list->AddRect(vtxs_rect.Min, vtxs_rect.Max, IM_COL32(255, 0, 255, 255)); 13346 } 13347 if (!pcmd_node_open) 13348 continue; 13349 13350 // Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted. 13351 ImGuiListClipper clipper(pcmd->ElemCount / 3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible. 13352 while (clipper.Step()) 13353 for (int prim = clipper.DisplayStart, vtx_i = elem_offset + clipper.DisplayStart * 3; prim < clipper.DisplayEnd; prim++) 13354 { 13355 char buf[300]; 13356 char *buf_p = buf, *buf_end = buf + IM_ARRAYSIZE(buf); 13357 ImVec2 triangles_pos[3]; 13358 for (int n = 0; n < 3; n++, vtx_i++) 13359 { 13360 ImDrawVert& v = draw_list->VtxBuffer[idx_buffer ? idx_buffer[vtx_i] : vtx_i]; 13361 triangles_pos[n] = v.pos; 13362 buf_p += ImFormatString(buf_p, (int)(buf_end - buf_p), "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n", (n == 0) ? "vtx" : " ", vtx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); 13363 } 13364 ImGui::Selectable(buf, false); 13365 if (ImGui::IsItemHovered()) 13366 { 13367 ImDrawListFlags backup_flags = overlay_draw_list->Flags; 13368 overlay_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines at is more readable for very large and thin triangles. 13369 overlay_draw_list->AddPolyline(triangles_pos, 3, IM_COL32(255, 255, 0, 255), true, 1.0f); 13370 overlay_draw_list->Flags = backup_flags; 13371 } 13372 } 13373 ImGui::TreePop(); 10438 if (pcmd->UserCallback == NULL && pcmd->ElemCount == 0) 10439 continue; 10440 if (pcmd->UserCallback) 10441 { 10442 ImGui::BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData); 10443 continue; 10444 } 10445 10446 ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; 10447 char buf[300]; 10448 ImFormatString(buf, IM_ARRAYSIZE(buf), "DrawCmd:%5d triangles, Tex 0x%p, ClipRect (%4.0f,%4.0f)-(%4.0f,%4.0f)", 10449 pcmd->ElemCount / 3, (void*)(intptr_t)pcmd->TextureId, 10450 pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w); 10451 bool pcmd_node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "%s", buf); 10452 if (ImGui::IsItemHovered() && (show_drawcmd_mesh || show_drawcmd_aabb) && fg_draw_list) 10453 NodeDrawCmdShowMeshAndBoundingBox(window, draw_list, pcmd, elem_offset, show_drawcmd_mesh, show_drawcmd_aabb); 10454 if (!pcmd_node_open) 10455 continue; 10456 10457 // Calculate approximate coverage area (touched pixel count) 10458 // This will be in pixels squared as long there's no post-scaling happening to the renderer output. 10459 float total_area = 0.0f; 10460 for (unsigned int base_idx = elem_offset; base_idx < (elem_offset + pcmd->ElemCount); base_idx += 3) 10461 { 10462 ImVec2 triangle[3]; 10463 for (int n = 0; n < 3; n++) 10464 triangle[n] = draw_list->VtxBuffer[idx_buffer ? idx_buffer[base_idx + n] : (base_idx + n)].pos; 10465 total_area += ImTriangleArea(triangle[0], triangle[1], triangle[2]); 10466 } 10467 10468 // Display vertex information summary. Hover to get all triangles drawn in wire-frame 10469 ImFormatString(buf, IM_ARRAYSIZE(buf), "Mesh: ElemCount: %d, VtxOffset: +%d, IdxOffset: +%d, Area: ~%0.f px", pcmd->ElemCount, pcmd->VtxOffset, pcmd->IdxOffset, total_area); 10470 ImGui::Selectable(buf); 10471 if (ImGui::IsItemHovered() && fg_draw_list) 10472 NodeDrawCmdShowMeshAndBoundingBox(window, draw_list, pcmd, elem_offset, true, false); 10473 10474 // Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted. 10475 ImGuiListClipper clipper; 10476 clipper.Begin(pcmd->ElemCount / 3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible. 10477 while (clipper.Step()) 10478 for (int prim = clipper.DisplayStart, idx_i = elem_offset + clipper.DisplayStart * 3; prim < clipper.DisplayEnd; prim++) 10479 { 10480 char* buf_p = buf, *buf_end = buf + IM_ARRAYSIZE(buf); 10481 ImVec2 triangle[3]; 10482 for (int n = 0; n < 3; n++, idx_i++) 10483 { 10484 ImDrawVert& v = draw_list->VtxBuffer[idx_buffer ? idx_buffer[idx_i] : idx_i]; 10485 triangle[n] = v.pos; 10486 buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n", 10487 (n == 0) ? "Vert:" : " ", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); 10488 } 10489 10490 ImGui::Selectable(buf, false); 10491 if (fg_draw_list && ImGui::IsItemHovered()) 10492 { 10493 ImDrawListFlags backup_flags = fg_draw_list->Flags; 10494 fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles. 10495 fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255,255,0,255), true, 1.0f); 10496 fg_draw_list->Flags = backup_flags; 10497 } 10498 } 10499 ImGui::TreePop(); 13374 10500 } 13375 10501 ImGui::TreePop(); 13376 } 13377 13378 static void NodeWindows(ImVector<ImGuiWindow*>& windows, const char* label) 13379 { 10502 } 10503 10504 static void NodeColumns(const ImGuiColumns* columns) 10505 { 10506 if (!ImGui::TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags)) 10507 return; 10508 ImGui::BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->OffMaxX - columns->OffMinX, columns->OffMinX, columns->OffMaxX); 10509 for (int column_n = 0; column_n < columns->Columns.Size; column_n++) 10510 ImGui::BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, GetColumnOffsetFromNorm(columns, columns->Columns[column_n].OffsetNorm)); 10511 ImGui::TreePop(); 10512 } 10513 10514 static void NodeWindows(ImVector<ImGuiWindow*>& windows, const char* label) 10515 { 13380 10516 if (!ImGui::TreeNode(label, "%s (%d)", label, windows.Size)) 13381 return; 13382 for (int i = 0; i < windows.Size; i++) 13383 Funcs::NodeWindow(windows[i], "Window"); 10517 return; 10518 ImGui::Text("(In front-to-back order:)"); 10519 for (int i = windows.Size - 1; i >= 0; i--) // Iterate front to back 10520 { 10521 ImGui::PushID(windows[i]); 10522 Funcs::NodeWindow(windows[i], "Window"); 10523 ImGui::PopID(); 10524 } 13384 10525 ImGui::TreePop(); 13385 } 13386 13387 static void NodeWindow(ImGuiWindow* window, const char* label) 13388 { 13389 if (!ImGui::TreeNode(window, "%s '%s', %d @ 0x%p", label, window->Name, window->Active || window->WasActive, window)) 13390 return; 10526 } 10527 10528 static void NodeWindow(ImGuiWindow* window, const char* label) 10529 { 10530 if (window == NULL) 10531 { 10532 ImGui::BulletText("%s: NULL", label); 10533 return; 10534 } 10535 10536 ImGuiContext& g = *GImGui; 10537 const bool is_active = window->WasActive; 10538 ImGuiTreeNodeFlags tree_node_flags = (window == g.NavWindow) ? ImGuiTreeNodeFlags_Selected : ImGuiTreeNodeFlags_None; 10539 if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); } 10540 const bool open = ImGui::TreeNodeEx(label, tree_node_flags, "%s '%s'%s", label, window->Name, is_active ? "" : " *Inactive*"); 10541 if (!is_active) { PopStyleColor(); } 10542 if (ImGui::IsItemHovered() && is_active) 10543 ImGui::GetForegroundDrawList(window)->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255)); 10544 if (!open) 10545 return; 10546 10547 if (window->MemoryCompacted) 10548 ImGui::TextDisabled("Note: some memory buffers have been compacted/freed."); 10549 13391 10550 ImGuiWindowFlags flags = window->Flags; 13392 10551 NodeDrawList(window, window->DrawList, "DrawList"); 13393 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); 13394 ImGui::BulletText("Flags: 0x%08X (%s%s%s%s%s%s..)", flags, 13395 (flags & ImGuiWindowFlags_ChildWindow) ? "Child " : "", (flags & ImGuiWindowFlags_Tooltip) ? "Tooltip " : "", (flags & ImGuiWindowFlags_Popup) ? "Popup " : "", 13396 (flags & ImGuiWindowFlags_Modal) ? "Modal " : "", (flags & ImGuiWindowFlags_ChildMenu) ? "ChildMenu " : "", (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : ""); 13397 ImGui::BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f)", window->Scroll.x, GetScrollMaxX(window), window->Scroll.y, GetScrollMaxY(window)); 13398 ImGui::BulletText("Active: %d, WriteAccessed: %d", window->Active, window->WriteAccessed); 10552 ImGui::BulletText("Pos: (%.1f,%.1f), Size: (%.1f,%.1f), ContentSize (%.1f,%.1f)", window->Pos.x, window->Pos.y, window->Size.x, window->Size.y, window->ContentSize.x, window->ContentSize.y); 10553 ImGui::BulletText("Flags: 0x%08X (%s%s%s%s%s%s%s%s%s..)", flags, 10554 (flags & ImGuiWindowFlags_ChildWindow) ? "Child " : "", (flags & ImGuiWindowFlags_Tooltip) ? "Tooltip " : "", (flags & ImGuiWindowFlags_Popup) ? "Popup " : "", 10555 (flags & ImGuiWindowFlags_Modal) ? "Modal " : "", (flags & ImGuiWindowFlags_ChildMenu) ? "ChildMenu " : "", (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : "", 10556 (flags & ImGuiWindowFlags_NoMouseInputs)? "NoMouseInputs":"", (flags & ImGuiWindowFlags_NoNavInputs) ? "NoNavInputs" : "", (flags & ImGuiWindowFlags_AlwaysAutoResize) ? "AlwaysAutoResize" : ""); 10557 ImGui::BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f) Scrollbar:%s%s", window->Scroll.x, window->ScrollMax.x, window->Scroll.y, window->ScrollMax.y, window->ScrollbarX ? "X" : "", window->ScrollbarY ? "Y" : ""); 10558 ImGui::BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1); 10559 ImGui::BulletText("Appearing: %d, Hidden: %d (CanSkip %d Cannot %d), SkipItems: %d", window->Appearing, window->Hidden, window->HiddenFramesCanSkipItems, window->HiddenFramesCannotSkipItems, window->SkipItems); 13399 10560 ImGui::BulletText("NavLastIds: 0x%08X,0x%08X, NavLayerActiveMask: %X", window->NavLastIds[0], window->NavLastIds[1], window->DC.NavLayerActiveMask); 13400 10561 ImGui::BulletText("NavLastChildNavWindow: %s", window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL"); 13401 10562 if (!window->NavRectRel[0].IsInverted()) 13402 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);10563 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); 13403 10564 else 13404 ImGui::BulletText("NavRectRel[0]: <None>");10565 ImGui::BulletText("NavRectRel[0]: <None>"); 13405 10566 if (window->RootWindow != window) NodeWindow(window->RootWindow, "RootWindow"); 13406 10567 if (window->ParentWindow != NULL) NodeWindow(window->ParentWindow, "ParentWindow"); … … 13408 10569 if (window->ColumnsStorage.Size > 0 && ImGui::TreeNode("Columns", "Columns sets (%d)", window->ColumnsStorage.Size)) 13409 10570 { 13410 for (int n = 0; n < window->ColumnsStorage.Size; n++) 13411 { 13412 const ImGuiColumnsSet* columns = &window->ColumnsStorage[n]; 13413 if (ImGui::TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags)) 13414 { 13415 ImGui::BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->MaxX - columns->MinX, columns->MinX, columns->MaxX); 13416 for (int column_n = 0; column_n < columns->Columns.Size; column_n++) 13417 ImGui::BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, OffsetNormToPixels(columns, columns->Columns[column_n].OffsetNorm)); 13418 ImGui::TreePop(); 13419 } 13420 } 13421 ImGui::TreePop(); 10571 for (int n = 0; n < window->ColumnsStorage.Size; n++) 10572 NodeColumns(&window->ColumnsStorage[n]); 10573 ImGui::TreePop(); 13422 10574 } 13423 ImGui::BulletText("Storage: %d bytes", window->StateStorage.Data.Size * (int)sizeof(ImGuiStorage::Pair));10575 NodeStorage(&window->StateStorage, "Storage"); 13424 10576 ImGui::TreePop(); 13425 } 13426 }; 13427 13428 // Access private state, we are going to display the draw lists from last frame 13429 ImGuiContext& g = *GImGui; 13430 Funcs::NodeWindows(g.Windows, "Windows"); 13431 if (ImGui::TreeNode("DrawList", "Active DrawLists (%d)", g.DrawDataBuilder.Layers[0].Size)) 13432 { 13433 for (int i = 0; i < g.DrawDataBuilder.Layers[0].Size; i++) 10577 } 10578 10579 static void NodeWindowSettings(ImGuiWindowSettings* settings) 10580 { 10581 ImGui::Text("0x%08X \"%s\" Pos (%d,%d) Size (%d,%d) Collapsed=%d", 10582 settings->ID, settings->GetName(), settings->Pos.x, settings->Pos.y, settings->Size.x, settings->Size.y, settings->Collapsed); 10583 } 10584 10585 static void NodeTabBar(ImGuiTabBar* tab_bar) 10586 { 10587 // Standalone tab bars (not associated to docking/windows functionality) currently hold no discernible strings. 10588 char buf[256]; 10589 char* p = buf; 10590 const char* buf_end = buf + IM_ARRAYSIZE(buf); 10591 const bool is_active = (tab_bar->PrevFrameVisible >= ImGui::GetFrameCount() - 2); 10592 p += ImFormatString(p, buf_end - p, "Tab Bar 0x%08X (%d tabs)%s", tab_bar->ID, tab_bar->Tabs.Size, is_active ? "" : " *Inactive*"); 10593 IM_UNUSED(p); 10594 if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); } 10595 bool open = ImGui::TreeNode(tab_bar, "%s", buf); 10596 if (!is_active) { PopStyleColor(); } 10597 if (is_active && ImGui::IsItemHovered()) 10598 { 10599 ImDrawList* draw_list = ImGui::GetForegroundDrawList(); 10600 draw_list->AddRect(tab_bar->BarRect.Min, tab_bar->BarRect.Max, IM_COL32(255, 255, 0, 255)); 10601 draw_list->AddLine(ImVec2(tab_bar->ScrollingRectMinX, tab_bar->BarRect.Min.y), ImVec2(tab_bar->ScrollingRectMinX, tab_bar->BarRect.Max.y), IM_COL32(0, 255, 0, 255)); 10602 draw_list->AddLine(ImVec2(tab_bar->ScrollingRectMaxX, tab_bar->BarRect.Min.y), ImVec2(tab_bar->ScrollingRectMaxX, tab_bar->BarRect.Max.y), IM_COL32(0, 255, 0, 255)); 10603 } 10604 if (open) 10605 { 10606 for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) 10607 { 10608 const ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; 10609 ImGui::PushID(tab); 10610 if (ImGui::SmallButton("<")) { TabBarQueueReorder(tab_bar, tab, -1); } ImGui::SameLine(0, 2); 10611 if (ImGui::SmallButton(">")) { TabBarQueueReorder(tab_bar, tab, +1); } ImGui::SameLine(); 10612 ImGui::Text("%02d%c Tab 0x%08X '%s' Offset: %.1f, Width: %.1f/%.1f", tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID, (tab->NameOffset != -1) ? tab_bar->GetTabName(tab) : "", tab->Offset, tab->Width, tab->ContentWidth); 10613 ImGui::PopID(); 10614 } 10615 ImGui::TreePop(); 10616 } 10617 } 10618 10619 static void NodeStorage(ImGuiStorage* storage, const char* label) 10620 { 10621 if (!ImGui::TreeNode(label, "%s: %d entries, %d bytes", label, storage->Data.Size, storage->Data.size_in_bytes())) 10622 return; 10623 for (int n = 0; n < storage->Data.Size; n++) 10624 { 10625 const ImGuiStorage::ImGuiStoragePair& p = storage->Data[n]; 10626 ImGui::BulletText("Key 0x%08X Value { i: %d }", p.key, p.val_i); // Important: we currently don't store a type, real value may not be integer. 10627 } 10628 ImGui::TreePop(); 10629 } 10630 }; 10631 10632 // Tools 10633 if (ImGui::TreeNode("Tools")) 10634 { 10635 // The Item Picker tool is super useful to visually select an item and break into the call-stack of where it was submitted. 10636 if (ImGui::Button("Item Picker..")) 10637 ImGui::DebugStartItemPicker(); 10638 ImGui::SameLine(); 10639 MetricsHelpMarker("Will call the IM_DEBUG_BREAK() macro to break in debugger.\nWarning: If you don't have a debugger attached, this will probably crash."); 10640 10641 ImGui::Checkbox("Show windows begin order", &show_windows_begin_order); 10642 ImGui::Checkbox("Show windows rectangles", &show_windows_rects); 10643 ImGui::SameLine(); 10644 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 12); 10645 show_windows_rects |= ImGui::Combo("##show_windows_rect_type", &show_windows_rect_type, wrt_rects_names, WRT_Count, WRT_Count); 10646 if (show_windows_rects && g.NavWindow) 10647 { 10648 ImGui::BulletText("'%s':", g.NavWindow->Name); 10649 ImGui::Indent(); 10650 for (int rect_n = 0; rect_n < WRT_Count; rect_n++) 10651 { 10652 ImRect r = Funcs::GetWindowRect(g.NavWindow, rect_n); 10653 ImGui::Text("(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), wrt_rects_names[rect_n]); 10654 } 10655 ImGui::Unindent(); 10656 } 10657 ImGui::Checkbox("Show mesh when hovering ImDrawCmd", &show_drawcmd_mesh); 10658 ImGui::Checkbox("Show bounding boxes when hovering ImDrawCmd", &show_drawcmd_aabb); 10659 ImGui::TreePop(); 10660 } 10661 10662 // Contents 10663 Funcs::NodeWindows(g.Windows, "Windows"); 10664 //Funcs::NodeWindows(g.WindowsFocusOrder, "WindowsFocusOrder"); 10665 if (ImGui::TreeNode("DrawLists", "Active DrawLists (%d)", g.DrawDataBuilder.Layers[0].Size)) 10666 { 10667 for (int i = 0; i < g.DrawDataBuilder.Layers[0].Size; i++) 13434 10668 Funcs::NodeDrawList(NULL, g.DrawDataBuilder.Layers[0][i], "DrawList"); 13435 ImGui::TreePop(); 13436 } 13437 if (ImGui::TreeNode("Popups", "Open Popups Stack (%d)", g.OpenPopupStack.Size)) 13438 { 13439 for (int i = 0; i < g.OpenPopupStack.Size; i++) 13440 { 10669 ImGui::TreePop(); 10670 } 10671 10672 // Details for Popups 10673 if (ImGui::TreeNode("Popups", "Popups (%d)", g.OpenPopupStack.Size)) 10674 { 10675 for (int i = 0; i < g.OpenPopupStack.Size; i++) 10676 { 13441 10677 ImGuiWindow* window = g.OpenPopupStack[i].Window; 13442 10678 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" : ""); 13443 } 13444 ImGui::TreePop(); 13445 } 13446 if (ImGui::TreeNode("Internal state")) 13447 { 13448 const char* input_source_names[] = { "None", "Mouse", "Nav", "NavKeyboard", "NavGamepad" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT); 13449 ImGui::Text("HoveredWindow: '%s'", g.HoveredWindow ? g.HoveredWindow->Name : "NULL"); 13450 ImGui::Text("HoveredRootWindow: '%s'", g.HoveredRootWindow ? g.HoveredRootWindow->Name : "NULL"); 13451 ImGui::Text("HoveredId: 0x%08X/0x%08X (%.2f sec)", g.HoveredId, g.HoveredIdPreviousFrame, g.HoveredIdTimer); // Data is "in-flight" so depending on when the Metrics window is called we may see current frame information or not 13452 ImGui::Text("ActiveId: 0x%08X/0x%08X (%.2f sec), ActiveIdSource: %s", g.ActiveId, g.ActiveIdPreviousFrame, g.ActiveIdTimer, input_source_names[g.ActiveIdSource]); 13453 ImGui::Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL"); 13454 ImGui::Text("MovingWindow: '%s'", g.MovingWindow ? g.MovingWindow->Name : "NULL"); 13455 ImGui::Text("NavWindow: '%s'", g.NavWindow ? g.NavWindow->Name : "NULL"); 13456 ImGui::Text("NavId: 0x%08X, NavLayer: %d", g.NavId, g.NavLayer); 13457 ImGui::Text("NavInputSource: %s", input_source_names[g.NavInputSource]); 13458 ImGui::Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible); 13459 ImGui::Text("NavActivateId: 0x%08X, NavInputId: 0x%08X", g.NavActivateId, g.NavInputId); 13460 ImGui::Text("NavDisableHighlight: %d, NavDisableMouseHover: %d", g.NavDisableHighlight, g.NavDisableMouseHover); 13461 ImGui::Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\" (%d bytes)", g.DragDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropPayload.DataSize); 13462 ImGui::TreePop(); 13463 } 13464 } 13465 ImGui::End(); 13466 } 10679 } 10680 ImGui::TreePop(); 10681 } 10682 10683 // Details for TabBars 10684 if (ImGui::TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.GetSize())) 10685 { 10686 for (int n = 0; n < g.TabBars.GetSize(); n++) 10687 Funcs::NodeTabBar(g.TabBars.GetByIndex(n)); 10688 ImGui::TreePop(); 10689 } 10690 10691 // Details for Tables 10692 IM_UNUSED(trt_rects_names); 10693 IM_UNUSED(show_tables_rects); 10694 IM_UNUSED(show_tables_rect_type); 10695 #ifdef IMGUI_HAS_TABLE 10696 if (ImGui::TreeNode("Tables", "Tables (%d)", g.Tables.GetSize())) 10697 { 10698 for (int n = 0; n < g.Tables.GetSize(); n++) 10699 Funcs::NodeTable(g.Tables.GetByIndex(n)); 10700 ImGui::TreePop(); 10701 } 10702 #endif // #ifdef IMGUI_HAS_TABLE 10703 10704 // Details for Docking 10705 #ifdef IMGUI_HAS_DOCK 10706 if (ImGui::TreeNode("Dock nodes")) 10707 { 10708 ImGui::TreePop(); 10709 } 10710 #endif // #ifdef IMGUI_HAS_DOCK 10711 10712 // Settings 10713 if (ImGui::TreeNode("Settings")) 10714 { 10715 if (ImGui::SmallButton("Clear")) 10716 ImGui::ClearIniSettings(); 10717 ImGui::SameLine(); 10718 if (ImGui::SmallButton("Save to memory")) 10719 ImGui::SaveIniSettingsToMemory(); 10720 ImGui::SameLine(); 10721 if (ImGui::SmallButton("Save to disk")) 10722 ImGui::SaveIniSettingsToDisk(g.IO.IniFilename); 10723 ImGui::SameLine(); 10724 if (g.IO.IniFilename) 10725 ImGui::Text("\"%s\"", g.IO.IniFilename); 10726 else 10727 ImGui::TextUnformatted("<NULL>"); 10728 ImGui::Text("SettingsDirtyTimer %.2f", g.SettingsDirtyTimer); 10729 if (ImGui::TreeNode("SettingsHandlers", "Settings handlers: (%d)", g.SettingsHandlers.Size)) 10730 { 10731 for (int n = 0; n < g.SettingsHandlers.Size; n++) 10732 ImGui::BulletText("%s", g.SettingsHandlers[n].TypeName); 10733 ImGui::TreePop(); 10734 } 10735 if (ImGui::TreeNode("SettingsWindows", "Settings packed data: Windows: %d bytes", g.SettingsWindows.size())) 10736 { 10737 for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) 10738 Funcs::NodeWindowSettings(settings); 10739 ImGui::TreePop(); 10740 } 10741 10742 #ifdef IMGUI_HAS_TABLE 10743 if (ImGui::TreeNode("SettingsTables", "Settings packed data: Tables: %d bytes", g.SettingsTables.size())) 10744 { 10745 for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings)) 10746 Funcs::NodeTableSettings(settings); 10747 ImGui::TreePop(); 10748 } 10749 #endif // #ifdef IMGUI_HAS_TABLE 10750 10751 #ifdef IMGUI_HAS_DOCK 10752 #endif // #ifdef IMGUI_HAS_DOCK 10753 10754 if (ImGui::TreeNode("SettingsIniData", "Settings unpacked data (.ini): %d bytes", g.SettingsIniData.size())) 10755 { 10756 ImGui::InputTextMultiline("##Ini", (char*)(void*)g.SettingsIniData.c_str(), g.SettingsIniData.Buf.Size, ImVec2(-FLT_MIN, 0.0f), ImGuiInputTextFlags_ReadOnly); 10757 ImGui::TreePop(); 10758 } 10759 ImGui::TreePop(); 10760 } 10761 10762 // Misc Details 10763 if (ImGui::TreeNode("Internal state")) 10764 { 10765 const char* input_source_names[] = { "None", "Mouse", "Nav", "NavKeyboard", "NavGamepad" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT); 10766 10767 ImGui::Text("WINDOWING"); 10768 ImGui::Indent(); 10769 ImGui::Text("HoveredWindow: '%s'", g.HoveredWindow ? g.HoveredWindow->Name : "NULL"); 10770 ImGui::Text("HoveredRootWindow: '%s'", g.HoveredRootWindow ? g.HoveredRootWindow->Name : "NULL"); 10771 ImGui::Text("HoveredWindowUnderMovingWindow: '%s'", g.HoveredWindowUnderMovingWindow ? g.HoveredWindowUnderMovingWindow->Name : "NULL"); 10772 ImGui::Text("MovingWindow: '%s'", g.MovingWindow ? g.MovingWindow->Name : "NULL"); 10773 ImGui::Unindent(); 10774 10775 ImGui::Text("ITEMS"); 10776 ImGui::Indent(); 10777 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]); 10778 ImGui::Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL"); 10779 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 10780 ImGui::Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\" (%d bytes)", g.DragDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropPayload.DataSize); 10781 ImGui::Unindent(); 10782 10783 ImGui::Text("NAV,FOCUS"); 10784 ImGui::Indent(); 10785 ImGui::Text("NavWindow: '%s'", g.NavWindow ? g.NavWindow->Name : "NULL"); 10786 ImGui::Text("NavId: 0x%08X, NavLayer: %d", g.NavId, g.NavLayer); 10787 ImGui::Text("NavInputSource: %s", input_source_names[g.NavInputSource]); 10788 ImGui::Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible); 10789 ImGui::Text("NavActivateId: 0x%08X, NavInputId: 0x%08X", g.NavActivateId, g.NavInputId); 10790 ImGui::Text("NavDisableHighlight: %d, NavDisableMouseHover: %d", g.NavDisableHighlight, g.NavDisableMouseHover); 10791 ImGui::Text("NavFocusScopeId = 0x%08X", g.NavFocusScopeId); 10792 ImGui::Text("NavWindowingTarget: '%s'", g.NavWindowingTarget ? g.NavWindowingTarget->Name : "NULL"); 10793 ImGui::Unindent(); 10794 10795 ImGui::TreePop(); 10796 } 10797 10798 // Overlay: Display windows Rectangles and Begin Order 10799 if (show_windows_rects || show_windows_begin_order) 10800 { 10801 for (int n = 0; n < g.Windows.Size; n++) 10802 { 10803 ImGuiWindow* window = g.Windows[n]; 10804 if (!window->WasActive) 10805 continue; 10806 ImDrawList* draw_list = GetForegroundDrawList(window); 10807 if (show_windows_rects) 10808 { 10809 ImRect r = Funcs::GetWindowRect(window, show_windows_rect_type); 10810 draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 0, 128, 255)); 10811 } 10812 if (show_windows_begin_order && !(window->Flags & ImGuiWindowFlags_ChildWindow)) 10813 { 10814 char buf[32]; 10815 ImFormatString(buf, IM_ARRAYSIZE(buf), "%d", window->BeginOrderWithinContext); 10816 float font_size = ImGui::GetFontSize(); 10817 draw_list->AddRectFilled(window->Pos, window->Pos + ImVec2(font_size, font_size), IM_COL32(200, 100, 100, 255)); 10818 draw_list->AddText(window->Pos, IM_COL32(255, 255, 255, 255), buf); 10819 } 10820 } 10821 } 10822 10823 #ifdef IMGUI_HAS_TABLE 10824 // Overlay: Display Tables Rectangles 10825 if (show_tables_rects) 10826 { 10827 for (int table_n = 0; table_n < g.Tables.GetSize(); table_n++) 10828 { 10829 ImGuiTable* table = g.Tables.GetByIndex(table_n); 10830 } 10831 } 10832 #endif // #ifdef IMGUI_HAS_TABLE 10833 10834 #ifdef IMGUI_HAS_DOCK 10835 // Overlay: Display Docking info 10836 if (show_docking_nodes && g.IO.KeyCtrl) 10837 { 10838 } 10839 #endif // #ifdef IMGUI_HAS_DOCK 10840 10841 ImGui::End(); 10842 } 10843 10844 #else 10845 10846 void ImGui::ShowMetricsWindow(bool*) { } 10847 10848 #endif 13467 10849 13468 10850 //----------------------------------------------------------------------------- … … 13475 10857 13476 10858 //----------------------------------------------------------------------------- 10859 10860 #endif // #ifndef IMGUI_DISABLE -
IMGUI/imgui.h
r78c3045 re66fd66 1 // dear imgui, v1. 61 WIP1 // dear imgui, v1.79 2 2 // (headers) 3 3 4 // See imgui.cpp file for documentation. 5 // Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp for demo code. 6 // Read 'Programmer guide' in imgui.cpp for notes on how to setup ImGui in your codebase. 7 // Get latest version at https://github.com/ocornut/imgui 4 // Help: 5 // - Read FAQ at http://dearimgui.org/faq 6 // - Newcomers, read 'Programmer guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase. 7 // - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that. 8 // Read imgui.cpp for details, links and comments. 9 10 // Resources: 11 // - FAQ http://dearimgui.org/faq 12 // - Homepage & latest https://github.com/ocornut/imgui 13 // - Releases & changelog https://github.com/ocornut/imgui/releases 14 // - Gallery https://github.com/ocornut/imgui/issues/3488 (please post your screenshots/video there!) 15 // - Glossary https://github.com/ocornut/imgui/wiki/Glossary 16 // - Wiki https://github.com/ocornut/imgui/wiki 17 // - Issues & support https://github.com/ocornut/imgui/issues 18 19 /* 20 21 Index of this file: 22 // Header mess 23 // Forward declarations and basic types 24 // ImGui API (Dear ImGui end-user API) 25 // Flags & Enumerations 26 // Memory allocations macros 27 // ImVector<> 28 // ImGuiStyle 29 // ImGuiIO 30 // Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiPayload) 31 // Obsolete functions 32 // Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, ImColor) 33 // Draw List API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawListFlags, ImDrawList, ImDrawData) 34 // Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFont) 35 36 */ 8 37 9 38 #pragma once 10 39 11 #define IMGUI_DISABLE_INCLUDE_IMCONFIG_H 12 13 // Configuration file (edit imconfig.h or define IMGUI_USER_CONFIG to set your own filename) 40 // Configuration file with compile-time options (edit imconfig.h or #define IMGUI_USER_CONFIG to your own filename) 14 41 #ifdef IMGUI_USER_CONFIG 15 42 #include IMGUI_USER_CONFIG … … 19 46 #endif 20 47 21 #include <float.h> // FLT_MAX 22 #include <stdarg.h> // va_list 48 #ifndef IMGUI_DISABLE 49 50 //----------------------------------------------------------------------------- 51 // Header mess 52 //----------------------------------------------------------------------------- 53 54 // Includes 55 #include <float.h> // FLT_MIN, FLT_MAX 56 #include <stdarg.h> // va_list, va_start, va_end 23 57 #include <stddef.h> // ptrdiff_t, NULL 24 58 #include <string.h> // memset, memmove, memcpy, strlen, strchr, strcpy, strcmp 25 59 26 60 // Version 27 #define IMGUI_VERSION "1.61 WIP" 28 #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert)) 61 // (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens) 62 #define IMGUI_VERSION "1.79" 63 #define IMGUI_VERSION_NUM 17900 64 #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) 29 65 30 66 // Define attributes of all API symbols declarations (e.g. for DLL under Windows) 67 // IMGUI_API is used for core imgui functions, IMGUI_IMPL_API is used for the default bindings files (imgui_impl_xxx.h) 68 // Using dear imgui via a shared library is not recommended, because we don't guarantee backward nor forward ABI compatibility (also function call overhead, as dear imgui is a call-heavy API) 31 69 #ifndef IMGUI_API 32 70 #define IMGUI_API 33 71 #endif 34 35 // Helpers 72 #ifndef IMGUI_IMPL_API 73 #define IMGUI_IMPL_API IMGUI_API 74 #endif 75 76 // Helper Macros 36 77 #ifndef IM_ASSERT 37 78 #include <assert.h> 38 #define IM_ASSERT(_EXPR) assert(_EXPR) 39 #endif 40 #if defined(__clang__) || defined(__GNUC__)41 #define IM_FMTARGS(FMT) __attribute__((format(printf, FMT, FMT+1))) // Apply printf-style warnings to user functions.79 #define IM_ASSERT(_EXPR) assert(_EXPR) // You can override the default assert handler by editing imconfig.h 80 #endif 81 #if !defined(IMGUI_USE_STB_SPRINTF) && (defined(__clang__) || defined(__GNUC__)) 82 #define IM_FMTARGS(FMT) __attribute__((format(printf, FMT, FMT+1))) // To apply printf-style warnings to our functions. 42 83 #define IM_FMTLIST(FMT) __attribute__((format(printf, FMT, 0))) 43 84 #else … … 45 86 #define IM_FMTLIST(FMT) 46 87 #endif 47 #define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR)/sizeof(*_ARR))) // Size of a static C-style array. Don't use on pointers! 48 #define IM_OFFSETOF(_TYPE,_MEMBER) ((size_t)&(((_TYPE*)0)->_MEMBER)) // Offset of _MEMBER within _TYPE. Standardized as offsetof() in modern C++. 49 88 #define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR) / sizeof(*(_ARR)))) // Size of a static C-style array. Don't use on pointers! 89 #define IM_UNUSED(_VAR) ((void)(_VAR)) // Used to silence "unused variable warnings". Often useful as asserts may be stripped out from final builds. 90 #if (__cplusplus >= 201100) 91 #define IM_OFFSETOF(_TYPE,_MEMBER) offsetof(_TYPE, _MEMBER) // Offset of _MEMBER within _TYPE. Standardized as offsetof() in C++11 92 #else 93 #define IM_OFFSETOF(_TYPE,_MEMBER) ((size_t)&(((_TYPE*)0)->_MEMBER)) // Offset of _MEMBER within _TYPE. Old style macro. 94 #endif 95 96 // Warnings 50 97 #if defined(__clang__) 51 98 #pragma clang diagnostic push 52 99 #pragma clang diagnostic ignored "-Wold-style-cast" 53 #endif 100 #if __has_warning("-Wzero-as-null-pointer-constant") 101 #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" 102 #endif 103 #elif defined(__GNUC__) 104 #pragma GCC diagnostic push 105 #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind 106 #pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead 107 #endif 108 109 //----------------------------------------------------------------------------- 110 // Forward declarations and basic types 111 //----------------------------------------------------------------------------- 54 112 55 113 // Forward declarations 56 struct ImDrawChannel; // Temporary storage for outputting drawing commands out of order, used byImDrawList::ChannelsSplit()57 struct ImDrawCmd; // A single draw command within a parent ImDrawList (generally maps to 1 GPU draw call )58 struct ImDrawData; // All draw command lists required to render the frame 59 struct ImDrawList; // A single draw command list (generally one per window )114 struct ImDrawChannel; // Temporary storage to output draw commands out of order, used by ImDrawListSplitter and ImDrawList::ChannelsSplit() 115 struct ImDrawCmd; // A single draw command within a parent ImDrawList (generally maps to 1 GPU draw call, unless it is a callback) 116 struct ImDrawData; // All draw command lists required to render the frame + pos/size coordinates to use for the projection matrix. 117 struct ImDrawList; // A single draw command list (generally one per window, conceptually you may see this as a dynamic "mesh" builder) 60 118 struct ImDrawListSharedData; // Data shared among multiple draw lists (typically owned by parent ImGui context, but you may create one yourself) 61 struct ImDrawVert; // A single vertex (20 bytes by default, override layout with IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT) 119 struct ImDrawListSplitter; // Helper to split a draw list into different layers which can be drawn into out of order, then flattened back. 120 struct ImDrawVert; // A single vertex (pos + uv + col = 20 bytes by default. Override layout with IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT) 62 121 struct ImFont; // Runtime data for a single font within a parent ImFontAtlas 63 122 struct ImFontAtlas; // Runtime data for multiple fonts, bake multiple fonts into a single texture, TTF/OTF font loader 64 123 struct ImFontConfig; // Configuration data when adding a font or merging fonts 65 struct ImColor; // Helper functions to create a color that can be converted to either u32 or float4 (*obsolete* please avoid using) 124 struct ImFontGlyph; // A single font glyph (code point + coordinates within in ImFontAtlas + offset) 125 struct ImFontGlyphRangesBuilder; // Helper to build glyph ranges from text/string data 126 struct ImColor; // Helper functions to create a color that can be converted to either u32 or float4 (*OBSOLETE* please avoid using) 127 struct ImGuiContext; // Dear ImGui context (opaque structure, unless including imgui_internal.h) 66 128 struct ImGuiIO; // Main configuration and I/O between your application and ImGui 67 struct ImGuiOnceUponAFrame; // Simple helper for running a block of code not more than once a frame, used by IMGUI_ONCE_UPON_A_FRAME macro 68 struct ImGuiStorage; // Simple custom key value storage 129 struct ImGuiInputTextCallbackData; // Shared state of InputText() when using custom ImGuiInputTextCallback (rare/advanced use) 130 struct ImGuiListClipper; // Helper to manually clip large list of items 131 struct ImGuiOnceUponAFrame; // Helper for running a block of code not more than once a frame, used by IMGUI_ONCE_UPON_A_FRAME macro 132 struct ImGuiPayload; // User data payload for drag and drop operations 133 struct ImGuiSizeCallbackData; // Callback data when using SetNextWindowSizeConstraints() (rare/advanced use) 134 struct ImGuiStorage; // Helper for key->value storage 69 135 struct ImGuiStyle; // Runtime data for styling/colors 70 struct ImGuiTextFilter; // Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]" 71 struct ImGuiTextBuffer; // Text buffer for logging/accumulating text 72 struct ImGuiTextEditCallbackData; // Shared state of ImGui::InputText() when using custom ImGuiTextEditCallback (rare/advanced use) 73 struct ImGuiSizeCallbackData; // Structure used to constraint window size in custom ways when using custom ImGuiSizeCallback (rare/advanced use) 74 struct ImGuiListClipper; // Helper to manually clip large list of items 75 struct ImGuiPayload; // User data payload for drag and drop operations 76 struct ImGuiContext; // ImGui context (opaque) 77 78 #ifndef ImTextureID 79 typedef void* ImTextureID; // User data to identify a texture (this is whatever to you want it to be! read the FAQ about ImTextureID in imgui.cpp) 80 #endif 81 82 // Typedefs and Enumerations (declared as int for compatibility with old C++ and to not pollute the top of this file) 83 typedef unsigned int ImU32; // 32-bit unsigned integer (typically used to store packed colors) 84 typedef unsigned int ImGuiID; // Unique ID used by widgets (typically hashed from a stack of string) 85 typedef unsigned short ImWchar; // Character for keyboard input/display 86 typedef int ImGuiCol; // enum: a color identifier for styling // enum ImGuiCol_ 87 typedef int ImGuiDir; // enum: a cardinal direction // enum ImGuiDir_ 88 typedef int ImGuiCond; // enum: a condition for Set*() // enum ImGuiCond_ 89 typedef int ImGuiKey; // enum: a key identifier (ImGui-side enum) // enum ImGuiKey_ 90 typedef int ImGuiNavInput; // enum: an input identifier for navigation // enum ImGuiNavInput_ 91 typedef int ImGuiMouseCursor; // enum: a mouse cursor identifier // enum ImGuiMouseCursor_ 92 typedef int ImGuiStyleVar; // enum: a variable identifier for styling // enum ImGuiStyleVar_ 93 typedef int ImDrawCornerFlags; // flags: for ImDrawList::AddRect*() etc. // enum ImDrawCornerFlags_ 94 typedef int ImDrawListFlags; // flags: for ImDrawList // enum ImDrawListFlags_ 95 typedef int ImFontAtlasFlags; // flags: for ImFontAtlas // enum ImFontAtlasFlags_ 96 typedef int ImGuiBackendFlags; // flags: for io.BackendFlags // enum ImGuiBackendFlags_ 97 typedef int ImGuiColorEditFlags; // flags: for ColorEdit*(), ColorPicker*() // enum ImGuiColorEditFlags_ 98 typedef int ImGuiColumnsFlags; // flags: for *Columns*() // enum ImGuiColumnsFlags_ 99 typedef int ImGuiConfigFlags; // flags: for io.ConfigFlags // enum ImGuiConfigFlags_ 100 typedef int ImGuiDragDropFlags; // flags: for *DragDrop*() // enum ImGuiDragDropFlags_ 101 typedef int ImGuiComboFlags; // flags: for BeginCombo() // enum ImGuiComboFlags_ 102 typedef int ImGuiFocusedFlags; // flags: for IsWindowFocused() // enum ImGuiFocusedFlags_ 103 typedef int ImGuiHoveredFlags; // flags: for IsItemHovered() etc. // enum ImGuiHoveredFlags_ 104 typedef int ImGuiInputTextFlags; // flags: for InputText*() // enum ImGuiInputTextFlags_ 105 typedef int ImGuiSelectableFlags; // flags: for Selectable() // enum ImGuiSelectableFlags_ 106 typedef int ImGuiTreeNodeFlags; // flags: for TreeNode*(),CollapsingHeader()// enum ImGuiTreeNodeFlags_ 107 typedef int ImGuiWindowFlags; // flags: for Begin*() // enum ImGuiWindowFlags_ 108 typedef int(*ImGuiTextEditCallback)(ImGuiTextEditCallbackData *data); 109 typedef void(*ImGuiSizeCallback)(ImGuiSizeCallbackData* data); 136 struct ImGuiTextBuffer; // Helper to hold and append into a text buffer (~string builder) 137 struct ImGuiTextFilter; // Helper to parse and apply text filters (e.g. "aaaaa[,bbbbb][,ccccc]") 138 139 // Enums/Flags (declared as int for compatibility with old C++, to allow using as flags and to not pollute the top of this file) 140 // - Tip: Use your programming IDE navigation facilities on the names in the _central column_ below to find the actual flags/enum lists! 141 // In Visual Studio IDE: CTRL+comma ("Edit.NavigateTo") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot. 142 // With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments. 143 typedef int ImGuiCol; // -> enum ImGuiCol_ // Enum: A color identifier for styling 144 typedef int ImGuiCond; // -> enum ImGuiCond_ // Enum: A condition for many Set*() functions 145 typedef int ImGuiDataType; // -> enum ImGuiDataType_ // Enum: A primary data type 146 typedef int ImGuiDir; // -> enum ImGuiDir_ // Enum: A cardinal direction 147 typedef int ImGuiKey; // -> enum ImGuiKey_ // Enum: A key identifier (ImGui-side enum) 148 typedef int ImGuiNavInput; // -> enum ImGuiNavInput_ // Enum: An input identifier for navigation 149 typedef int ImGuiMouseButton; // -> enum ImGuiMouseButton_ // Enum: A mouse button identifier (0=left, 1=right, 2=middle) 150 typedef int ImGuiMouseCursor; // -> enum ImGuiMouseCursor_ // Enum: A mouse cursor identifier 151 typedef int ImGuiStyleVar; // -> enum ImGuiStyleVar_ // Enum: A variable identifier for styling 152 typedef int ImDrawCornerFlags; // -> enum ImDrawCornerFlags_ // Flags: for ImDrawList::AddRect(), AddRectFilled() etc. 153 typedef int ImDrawListFlags; // -> enum ImDrawListFlags_ // Flags: for ImDrawList 154 typedef int ImFontAtlasFlags; // -> enum ImFontAtlasFlags_ // Flags: for ImFontAtlas build 155 typedef int ImGuiBackendFlags; // -> enum ImGuiBackendFlags_ // Flags: for io.BackendFlags 156 typedef int ImGuiButtonFlags; // -> enum ImGuiButtonFlags_ // Flags: for InvisibleButton() 157 typedef int ImGuiColorEditFlags; // -> enum ImGuiColorEditFlags_ // Flags: for ColorEdit4(), ColorPicker4() etc. 158 typedef int ImGuiConfigFlags; // -> enum ImGuiConfigFlags_ // Flags: for io.ConfigFlags 159 typedef int ImGuiComboFlags; // -> enum ImGuiComboFlags_ // Flags: for BeginCombo() 160 typedef int ImGuiDragDropFlags; // -> enum ImGuiDragDropFlags_ // Flags: for BeginDragDropSource(), AcceptDragDropPayload() 161 typedef int ImGuiFocusedFlags; // -> enum ImGuiFocusedFlags_ // Flags: for IsWindowFocused() 162 typedef int ImGuiHoveredFlags; // -> enum ImGuiHoveredFlags_ // Flags: for IsItemHovered(), IsWindowHovered() etc. 163 typedef int ImGuiInputTextFlags; // -> enum ImGuiInputTextFlags_ // Flags: for InputText(), InputTextMultiline() 164 typedef int ImGuiKeyModFlags; // -> enum ImGuiKeyModFlags_ // Flags: for io.KeyMods (Ctrl/Shift/Alt/Super) 165 typedef int ImGuiPopupFlags; // -> enum ImGuiPopupFlags_ // Flags: for OpenPopup*(), BeginPopupContext*(), IsPopupOpen() 166 typedef int ImGuiSelectableFlags; // -> enum ImGuiSelectableFlags_ // Flags: for Selectable() 167 typedef int ImGuiSliderFlags; // -> enum ImGuiSliderFlags_ // Flags: for DragFloat(), DragInt(), SliderFloat(), SliderInt() etc. 168 typedef int ImGuiTabBarFlags; // -> enum ImGuiTabBarFlags_ // Flags: for BeginTabBar() 169 typedef int ImGuiTabItemFlags; // -> enum ImGuiTabItemFlags_ // Flags: for BeginTabItem() 170 typedef int ImGuiTreeNodeFlags; // -> enum ImGuiTreeNodeFlags_ // Flags: for TreeNode(), TreeNodeEx(), CollapsingHeader() 171 typedef int ImGuiWindowFlags; // -> enum ImGuiWindowFlags_ // Flags: for Begin(), BeginChild() 172 173 // Other types 174 #ifndef ImTextureID // ImTextureID [configurable type: override in imconfig.h with '#define ImTextureID xxx'] 175 typedef void* ImTextureID; // User data for rendering back-end to identify a texture. This is whatever to you want it to be! read the FAQ about ImTextureID for details. 176 #endif 177 typedef unsigned int ImGuiID; // A unique ID used by widgets, typically hashed from a stack of string. 178 typedef int (*ImGuiInputTextCallback)(ImGuiInputTextCallbackData* data); 179 typedef void (*ImGuiSizeCallback)(ImGuiSizeCallbackData* data); 180 181 // Decoded character types 182 // (we generally use UTF-8 encoded string in the API. This is storage specifically for a decoded character used for keyboard input and display) 183 typedef unsigned short ImWchar16; // A single decoded U16 character/code point. We encode them as multi bytes UTF-8 when used in strings. 184 typedef unsigned int ImWchar32; // A single decoded U32 character/code point. We encode them as multi bytes UTF-8 when used in strings. 185 #ifdef IMGUI_USE_WCHAR32 // ImWchar [configurable type: override in imconfig.h with '#define IMGUI_USE_WCHAR32' to support Unicode planes 1-16] 186 typedef ImWchar32 ImWchar; 187 #else 188 typedef ImWchar16 ImWchar; 189 #endif 190 191 // Basic scalar data types 192 typedef signed char ImS8; // 8-bit signed integer 193 typedef unsigned char ImU8; // 8-bit unsigned integer 194 typedef signed short ImS16; // 16-bit signed integer 195 typedef unsigned short ImU16; // 16-bit unsigned integer 196 typedef signed int ImS32; // 32-bit signed integer == int 197 typedef unsigned int ImU32; // 32-bit unsigned integer (often used to store packed colors) 110 198 #if defined(_MSC_VER) && !defined(__clang__) 111 typedef unsigned __int64 ImU64; // 64-bit unsigned integer 199 typedef signed __int64 ImS64; // 64-bit signed integer (pre and post C++11 with Visual Studio) 200 typedef unsigned __int64 ImU64; // 64-bit unsigned integer (pre and post C++11 with Visual Studio) 201 #elif (defined(__clang__) || defined(__GNUC__)) && (__cplusplus < 201100) 202 #include <stdint.h> 203 typedef int64_t ImS64; // 64-bit signed integer (pre C++11) 204 typedef uint64_t ImU64; // 64-bit unsigned integer (pre C++11) 112 205 #else 113 typedef unsigned long long ImU64; // 64-bit unsigned integer 114 #endif 115 206 typedef signed long long ImS64; // 64-bit signed integer (post C++11) 207 typedef unsigned long long ImU64; // 64-bit unsigned integer (post C++11) 208 #endif 209 210 // 2D vector (often used to store positions or sizes) 116 211 struct ImVec2 117 212 { 118 float x, y; 119 ImVec2() { x = y = 0.0f; } 120 ImVec2(float _x, float _y) { x = _x; y = _y; } 121 float operator[] (size_t i) const { IM_ASSERT(i <= 1); return (&x)[i]; } // We very rarely use this [] operator, the assert overhead is fine. 213 float x, y; 214 ImVec2() { x = y = 0.0f; } 215 ImVec2(float _x, float _y) { x = _x; y = _y; } 216 float operator[] (size_t idx) const { IM_ASSERT(idx <= 1); return (&x)[idx]; } // We very rarely use this [] operator, the assert overhead is fine. 217 float& operator[] (size_t idx) { IM_ASSERT(idx <= 1); return (&x)[idx]; } // We very rarely use this [] operator, the assert overhead is fine. 122 218 #ifdef IM_VEC2_CLASS_EXTRA 123 IM_VEC2_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec2. 124 #endif 125 }; 126 219 IM_VEC2_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec2. 220 #endif 221 }; 222 223 // 4D vector (often used to store floating-point colors) 127 224 struct ImVec4 128 225 { 129 floatx, y, z, w;130 ImVec4(){ x = y = z = w = 0.0f; }131 ImVec4(float _x, float _y, float _z, float _w){ x = _x; y = _y; z = _z; w = _w; }226 float x, y, z, w; 227 ImVec4() { x = y = z = w = 0.0f; } 228 ImVec4(float _x, float _y, float _z, float _w) { x = _x; y = _y; z = _z; w = _w; } 132 229 #ifdef IM_VEC4_CLASS_EXTRA 133 IM_VEC4_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec4. 134 #endif 135 }; 136 137 // ImGui end-user API 138 // In a namespace so that user can add extra functions in your own separate file (please don't modify imgui.cpp/.h) 230 IM_VEC4_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec4. 231 #endif 232 }; 233 234 //----------------------------------------------------------------------------- 235 // ImGui: Dear ImGui end-user API 236 // (This is a namespace. You can add extra ImGui:: functions in your own separate file. Please don't modify imgui source files!) 237 //----------------------------------------------------------------------------- 238 139 239 namespace ImGui 140 240 { 141 // Context creation and access 142 // All contexts share a same ImFontAtlas by default. If you want different font atlas, you can new() them and overwrite the GetIO().Fonts variable of an ImGui context. 143 // All those functions are not reliant on the current context. 144 IMGUI_API ImGuiContext* CreateContext(ImFontAtlas* shared_font_atlas = NULL); 145 IMGUI_API void DestroyContext(ImGuiContext* ctx = NULL); // NULL = destroy current context 146 IMGUI_API ImGuiContext* GetCurrentContext(); 147 IMGUI_API void SetCurrentContext(ImGuiContext* ctx); 148 IMGUI_API bool DebugCheckVersionAndDataLayout(const char* version_str, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_drawvert); 149 150 // Main 151 IMGUI_API ImGuiIO& GetIO(); 152 IMGUI_API ImGuiStyle& GetStyle(); 153 IMGUI_API void NewFrame(); // start a new ImGui frame, you can submit any command from this point until Render()/EndFrame(). 154 IMGUI_API void Render(); // ends the ImGui frame, finalize the draw data. (Obsolete: optionally call io.RenderDrawListsFn if set. Nowadays, prefer calling your render function yourself.) 155 IMGUI_API ImDrawData* GetDrawData(); // valid after Render() and until the next call to NewFrame(). this is what you have to render. (Obsolete: this used to be passed to your io.RenderDrawListsFn() function.) 156 IMGUI_API void EndFrame(); // ends the ImGui frame. automatically called by Render(), so most likely don't need to ever call that yourself directly. If you don't need to render you may call EndFrame() but you'll have wasted CPU already. If you don't need to render, better to not create any imgui windows instead! 157 158 // Demo, Debug, Information 159 IMGUI_API void ShowDemoWindow(bool* p_open = NULL); // create demo/test window (previously called ShowTestWindow). demonstrate most ImGui features. call this to learn about the library! try to make it always available in your application! 160 IMGUI_API void ShowMetricsWindow(bool* p_open = NULL); // create metrics window. display ImGui internals: draw commands (with individual draw calls and vertices), window list, basic internal state, etc. 161 IMGUI_API void ShowStyleEditor(ImGuiStyle* ref = NULL); // add style editor block (not a window). you can pass in a reference ImGuiStyle structure to compare to, revert to and save to (else it uses the default style) 162 IMGUI_API bool ShowStyleSelector(const char* label); // add style selector block (not a window), essentially a combo listing the default styles. 163 IMGUI_API void ShowFontSelector(const char* label); // add font selector block (not a window), essentially a combo listing the loaded fonts. 164 IMGUI_API void ShowUserGuide(); // add basic help/info block (not a window): how to manipulate ImGui as a end-user (mouse/keyboard controls). 165 IMGUI_API const char* GetVersion(); // get a version string e.g. "1.23" 166 167 // Styles 168 IMGUI_API void StyleColorsDark(ImGuiStyle* dst = NULL); // new, recommended style (default) 169 IMGUI_API void StyleColorsClassic(ImGuiStyle* dst = NULL); // classic imgui style 170 IMGUI_API void StyleColorsLight(ImGuiStyle* dst = NULL); // best used with borders and a custom, thicker font 171 172 // Windows 173 // (Begin = push window to the stack and start appending to it. End = pop window from the stack. You may append multiple times to the same window during the same frame) 174 // Begin()/BeginChild() return false to indicate the window being collapsed or fully clipped, so you may early out and omit submitting anything to the window. 175 // However you need to always call a matching End()/EndChild() for a Begin()/BeginChild() call, regardless of its return value (this is due to legacy reason and is inconsistent with BeginMenu/EndMenu, BeginPopup/EndPopup and other functions where the End call should only be called if the corresponding Begin function returned true.) 176 // Passing 'bool* p_open != NULL' shows a close widget in the upper-right corner of the window, which when clicking will set the boolean to false. 177 // Use child windows to introduce independent scrolling/clipping regions within a host window. Child windows can embed their own child. 178 IMGUI_API bool Begin(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); 179 IMGUI_API void End(); 180 IMGUI_API bool BeginChild(const char* str_id, const ImVec2& size = ImVec2(0, 0), bool border = false, ImGuiWindowFlags flags = 0); // Begin a scrolling region. size==0.0f: use remaining window size, size<0.0f: use remaining window size minus abs(size). size>0.0f: fixed size. each axis can use a different mode, e.g. ImVec2(0,400). 181 IMGUI_API bool BeginChild(ImGuiID id, const ImVec2& size = ImVec2(0, 0), bool border = false, ImGuiWindowFlags flags = 0); 182 IMGUI_API void EndChild(); 183 184 // Windows Utilities 185 IMGUI_API bool IsWindowAppearing(); 186 IMGUI_API bool IsWindowCollapsed(); 187 IMGUI_API bool IsWindowFocused(ImGuiFocusedFlags flags = 0); // is current window focused? or its root/child, depending on flags. see flags for options. 188 IMGUI_API bool IsWindowHovered(ImGuiHoveredFlags flags = 0); // is current window hovered (and typically: not blocked by a popup/modal)? see flags for options. NB: If you are trying to check whether your mouse should be dispatched to imgui or to your app, you should use the 'io.WantCaptureMouse' boolean for that! Please read the FAQ! 189 IMGUI_API ImDrawList* GetWindowDrawList(); // get draw list associated to the window, to append your own drawing primitives 190 IMGUI_API ImVec2 GetWindowPos(); // get current window position in screen space (useful if you want to do your own drawing via the DrawList API) 191 IMGUI_API ImVec2 GetWindowSize(); // get current window size 192 IMGUI_API float GetWindowWidth(); // get current window width (shortcut for GetWindowSize().x) 193 IMGUI_API float GetWindowHeight(); // get current window height (shortcut for GetWindowSize().y) 194 IMGUI_API ImVec2 GetContentRegionMax(); // current content boundaries (typically window boundaries including scrolling, or current column boundaries), in windows coordinates 195 IMGUI_API ImVec2 GetContentRegionAvail(); // == GetContentRegionMax() - GetCursorPos() 196 IMGUI_API float GetContentRegionAvailWidth(); // 197 IMGUI_API ImVec2 GetWindowContentRegionMin(); // content boundaries min (roughly (0,0)-Scroll), in window coordinates 198 IMGUI_API ImVec2 GetWindowContentRegionMax(); // content boundaries max (roughly (0,0)+Size-Scroll) where Size can be override with SetNextWindowContentSize(), in window coordinates 199 IMGUI_API float GetWindowContentRegionWidth(); // 200 201 IMGUI_API void SetNextWindowPos(const ImVec2& pos, ImGuiCond cond = 0, const ImVec2& pivot = ImVec2(0, 0)); // set next window position. call before Begin(). use pivot=(0.5f,0.5f) to center on given point, etc. 202 IMGUI_API void SetNextWindowSize(const ImVec2& size, ImGuiCond cond = 0); // set next window size. set axis to 0.0f to force an auto-fit on this axis. call before Begin() 203 IMGUI_API void SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback = NULL, void* custom_callback_data = NULL); // set next window size limits. use -1,-1 on either X/Y axis to preserve the current size. Use callback to apply non-trivial programmatic constraints. 204 IMGUI_API void SetNextWindowContentSize(const ImVec2& size); // set next window content size (~ enforce the range of scrollbars). not including window decorations (title bar, menu bar, etc.). set an axis to 0.0f to leave it automatic. call before Begin() 205 IMGUI_API void SetNextWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // set next window collapsed state. call before Begin() 206 IMGUI_API void SetNextWindowFocus(); // set next window to be focused / front-most. call before Begin() 207 IMGUI_API void SetNextWindowBgAlpha(float alpha); // set next window background color alpha. helper to easily modify ImGuiCol_WindowBg/ChildBg/PopupBg. 208 IMGUI_API void SetWindowPos(const ImVec2& pos, ImGuiCond cond = 0); // (not recommended) set current window position - call within Begin()/End(). prefer using SetNextWindowPos(), as this may incur tearing and side-effects. 209 IMGUI_API void SetWindowSize(const ImVec2& size, ImGuiCond cond = 0); // (not recommended) set current window size - call within Begin()/End(). set to ImVec2(0,0) to force an auto-fit. prefer using SetNextWindowSize(), as this may incur tearing and minor side-effects. 210 IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // (not recommended) set current window collapsed state. prefer using SetNextWindowCollapsed(). 211 IMGUI_API void SetWindowFocus(); // (not recommended) set current window to be focused / front-most. prefer using SetNextWindowFocus(). 212 IMGUI_API void SetWindowFontScale(float scale); // set font scale. Adjust IO.FontGlobalScale if you want to scale all windows 213 IMGUI_API void SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond = 0); // set named window position. 214 IMGUI_API void SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond = 0); // set named window size. set axis to 0.0f to force an auto-fit on this axis. 215 IMGUI_API void SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond = 0); // set named window collapsed state 216 IMGUI_API void SetWindowFocus(const char* name); // set named window to be focused / front-most. use NULL to remove focus. 217 218 // Windows Scrolling 219 IMGUI_API float GetScrollX(); // get scrolling amount [0..GetScrollMaxX()] 220 IMGUI_API float GetScrollY(); // get scrolling amount [0..GetScrollMaxY()] 221 IMGUI_API float GetScrollMaxX(); // get maximum scrolling amount ~~ ContentSize.X - WindowSize.X 222 IMGUI_API float GetScrollMaxY(); // get maximum scrolling amount ~~ ContentSize.Y - WindowSize.Y 223 IMGUI_API void SetScrollX(float scroll_x); // set scrolling amount [0..GetScrollMaxX()] 224 IMGUI_API void SetScrollY(float scroll_y); // set scrolling amount [0..GetScrollMaxY()] 225 IMGUI_API void SetScrollHere(float center_y_ratio = 0.5f); // adjust scrolling amount to make current cursor position visible. center_y_ratio=0.0: top, 0.5: center, 1.0: bottom. When using to make a "default/current item" visible, consider using SetItemDefaultFocus() instead. 226 IMGUI_API void SetScrollFromPosY(float pos_y, float center_y_ratio = 0.5f); // adjust scrolling amount to make given position valid. use GetCursorPos() or GetCursorStartPos()+offset to get valid positions. 227 228 // Parameters stacks (shared) 229 IMGUI_API void PushFont(ImFont* font); // use NULL as a shortcut to push default font 230 IMGUI_API void PopFont(); 231 IMGUI_API void PushStyleColor(ImGuiCol idx, ImU32 col); 232 IMGUI_API void PushStyleColor(ImGuiCol idx, const ImVec4& col); 233 IMGUI_API void PopStyleColor(int count = 1); 234 IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val); 235 IMGUI_API void PushStyleVar(ImGuiStyleVar idx, const ImVec2& val); 236 IMGUI_API void PopStyleVar(int count = 1); 237 IMGUI_API const ImVec4& GetStyleColorVec4(ImGuiCol idx); // retrieve style color as stored in ImGuiStyle structure. use to feed back into PushStyleColor(), otherwise use GetColorU32() to get style color with style alpha baked in. 238 IMGUI_API ImFont* GetFont(); // get current font 239 IMGUI_API float GetFontSize(); // get current font size (= height in pixels) of current font with current scale applied 240 IMGUI_API ImVec2 GetFontTexUvWhitePixel(); // get UV coordinate for a while pixel, useful to draw custom shapes via the ImDrawList API 241 IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul = 1.0f); // retrieve given style color with style alpha applied and optional extra alpha multiplier 242 IMGUI_API ImU32 GetColorU32(const ImVec4& col); // retrieve given color with style alpha applied 243 IMGUI_API ImU32 GetColorU32(ImU32 col); // retrieve given color with style alpha applied 244 245 // Parameters stacks (current window) 246 IMGUI_API void PushItemWidth(float item_width); // width of items for the common item+label case, pixels. 0.0f = default to ~2/3 of windows width, >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -1.0f always align width to the right side) 247 IMGUI_API void PopItemWidth(); 248 IMGUI_API float CalcItemWidth(); // width of item given pushed settings and current cursor position 249 IMGUI_API void PushTextWrapPos(float wrap_pos_x = 0.0f); // word-wrapping for Text*() commands. < 0.0f: no wrapping; 0.0f: wrap to end of window (or column); > 0.0f: wrap at 'wrap_pos_x' position in window local space 250 IMGUI_API void PopTextWrapPos(); 251 IMGUI_API void PushAllowKeyboardFocus(bool allow_keyboard_focus); // allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets 252 IMGUI_API void PopAllowKeyboardFocus(); 253 IMGUI_API void PushButtonRepeat(bool repeat); // in 'repeat' mode, Button*() functions return repeated true in a typematic manner (using io.KeyRepeatDelay/io.KeyRepeatRate setting). Note that you can call IsItemActive() after any Button() to tell if the button is held in the current frame. 254 IMGUI_API void PopButtonRepeat(); 255 256 // Cursor / Layout 257 IMGUI_API void Separator(); // separator, generally horizontal. inside a menu bar or in horizontal layout mode, this becomes a vertical separator. 258 IMGUI_API void SameLine(float pos_x = 0.0f, float spacing_w = -1.0f); // call between widgets or groups to layout them horizontally 259 IMGUI_API void NewLine(); // undo a SameLine() 260 IMGUI_API void Spacing(); // add vertical spacing 261 IMGUI_API void Dummy(const ImVec2& size); // add a dummy item of given size 262 IMGUI_API void Indent(float indent_w = 0.0f); // move content position toward the right, by style.IndentSpacing or indent_w if != 0 263 IMGUI_API void Unindent(float indent_w = 0.0f); // move content position back to the left, by style.IndentSpacing or indent_w if != 0 264 IMGUI_API void BeginGroup(); // 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.) 265 IMGUI_API void EndGroup(); 266 IMGUI_API ImVec2 GetCursorPos(); // cursor position is relative to window position 267 IMGUI_API float GetCursorPosX(); // " 268 IMGUI_API float GetCursorPosY(); // " 269 IMGUI_API void SetCursorPos(const ImVec2& local_pos); // " 270 IMGUI_API void SetCursorPosX(float x); // " 271 IMGUI_API void SetCursorPosY(float y); // " 272 IMGUI_API ImVec2 GetCursorStartPos(); // initial cursor position 273 IMGUI_API ImVec2 GetCursorScreenPos(); // cursor position in absolute screen coordinates [0..io.DisplaySize] (useful to work with ImDrawList API) 274 IMGUI_API void SetCursorScreenPos(const ImVec2& screen_pos); // cursor position in absolute screen coordinates [0..io.DisplaySize] 275 IMGUI_API void AlignTextToFramePadding(); // vertically align upcoming text baseline to FramePadding.y so that it will align properly to regularly framed items (call if you have text on a line before a framed item) 276 IMGUI_API float GetTextLineHeight(); // ~ FontSize 277 IMGUI_API float GetTextLineHeightWithSpacing(); // ~ FontSize + style.ItemSpacing.y (distance in pixels between 2 consecutive lines of text) 278 IMGUI_API float GetFrameHeight(); // ~ FontSize + style.FramePadding.y * 2 279 IMGUI_API float GetFrameHeightWithSpacing(); // ~ FontSize + style.FramePadding.y * 2 + style.ItemSpacing.y (distance in pixels between 2 consecutive lines of framed widgets) 280 281 // ID stack/scopes 282 // Read the FAQ for more details about how ID are handled in dear imgui. If you are creating widgets in a loop you most 283 // likely want to push a unique identifier (e.g. object pointer, loop index) to uniquely differentiate them. 284 // You can also use the "##foobar" syntax within widget label to distinguish them from each others. 285 // In this header file we use the "label"/"name" terminology to denote a string that will be displayed and used as an ID, 286 // whereas "str_id" denote a string that is only used as an ID and not aimed to be displayed. 287 IMGUI_API void PushID(const char* str_id); // push identifier into the ID stack. IDs are hash of the entire stack! 288 IMGUI_API void PushID(const char* str_id_begin, const char* str_id_end); 289 IMGUI_API void PushID(const void* ptr_id); 290 IMGUI_API void PushID(int int_id); 291 IMGUI_API void PopID(); 292 IMGUI_API ImGuiID GetID(const char* str_id); // calculate unique ID (hash of whole ID stack + given parameter). e.g. if you want to query into ImGuiStorage yourself 293 IMGUI_API ImGuiID GetID(const char* str_id_begin, const char* str_id_end); 294 IMGUI_API ImGuiID GetID(const void* ptr_id); 295 296 // Widgets: Text 297 IMGUI_API void TextUnformatted(const char* text, const char* text_end = NULL); // raw text without formatting. Roughly equivalent to Text("%s", text) but: A) doesn't require null terminated string if 'text_end' is specified, B) it's faster, no memory copy is done, no buffer size limits, recommended for long chunks of text. 298 IMGUI_API void Text(const char* fmt, ...) IM_FMTARGS(1); // simple formatted text 299 IMGUI_API void TextV(const char* fmt, va_list args) IM_FMTLIST(1); 300 IMGUI_API void TextColored(const ImVec4& col, const char* fmt, ...) IM_FMTARGS(2); // shortcut for PushStyleColor(ImGuiCol_Text, col); Text(fmt, ...); PopStyleColor(); 301 IMGUI_API void TextColoredV(const ImVec4& col, const char* fmt, va_list args) IM_FMTLIST(2); 302 IMGUI_API void TextDisabled(const char* fmt, ...) IM_FMTARGS(1); // shortcut for PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]); Text(fmt, ...); PopStyleColor(); 303 IMGUI_API void TextDisabledV(const char* fmt, va_list args) IM_FMTLIST(1); 304 IMGUI_API void TextWrapped(const char* fmt, ...) IM_FMTARGS(1); // shortcut for PushTextWrapPos(0.0f); Text(fmt, ...); PopTextWrapPos();. Note that this won't work on an auto-resizing window if there's no other widgets to extend the window width, yoy may need to set a size using SetNextWindowSize(). 305 IMGUI_API void TextWrappedV(const char* fmt, va_list args) IM_FMTLIST(1); 306 IMGUI_API void LabelText(const char* label, const char* fmt, ...) IM_FMTARGS(2); // display text+label aligned the same way as value+label widgets 307 IMGUI_API void LabelTextV(const char* label, const char* fmt, va_list args) IM_FMTLIST(2); 308 IMGUI_API void BulletText(const char* fmt, ...) IM_FMTARGS(1); // shortcut for Bullet()+Text() 309 IMGUI_API void BulletTextV(const char* fmt, va_list args) IM_FMTLIST(1); 310 311 // Widgets: Main 312 IMGUI_API bool Button(const char* label, const ImVec2& size = ImVec2(0, 0)); // button 313 IMGUI_API bool SmallButton(const char* label); // button with FramePadding=(0,0) to easily embed within text 314 IMGUI_API bool ArrowButton(const char* str_id, ImGuiDir dir); 315 IMGUI_API bool InvisibleButton(const char* str_id, const ImVec2& size); // button behavior without the visuals, useful to build custom behaviors using the public api (along with IsItemActive, IsItemHovered, etc.) 316 IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), const ImVec4& tint_col = ImVec4(1, 1, 1, 1), const ImVec4& border_col = ImVec4(0, 0, 0, 0)); 317 IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); // <0 frame_padding uses default frame padding settings. 0 for no padding 318 IMGUI_API bool Checkbox(const char* label, bool* v); 319 IMGUI_API bool CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value); 320 IMGUI_API bool RadioButton(const char* label, bool active); 321 IMGUI_API bool RadioButton(const char* label, int* v, int v_button); 322 IMGUI_API void PlotLines(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); 323 IMGUI_API void PlotLines(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0)); 324 IMGUI_API void PlotHistogram(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); 325 IMGUI_API void PlotHistogram(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0)); 326 IMGUI_API void ProgressBar(float fraction, const ImVec2& size_arg = ImVec2(-1, 0), const char* overlay = NULL); 327 IMGUI_API void Bullet(); // draw a small circle and keep the cursor on the same line. advance cursor x position by GetTreeNodeToLabelSpacing(), same distance that TreeNode() uses 328 329 // Widgets: Combo Box 330 // The new BeginCombo()/EndCombo() api allows you to manage your contents and selection state however you want it. 331 // The old Combo() api are helpers over BeginCombo()/EndCombo() which are kept available for convenience purpose. 332 IMGUI_API bool BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags = 0); 333 IMGUI_API void EndCombo(); // only call EndCombo() if BeginCombo() returns true! 334 IMGUI_API bool Combo(const char* label, int* current_item, const char* const items[], int items_count, int popup_max_height_in_items = -1); 335 IMGUI_API bool Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int popup_max_height_in_items = -1); // Separate items with \0 within a string, end item-list with \0\0. e.g. "One\0Two\0Three\0" 336 IMGUI_API bool Combo(const char* label, int* current_item, bool(*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int popup_max_height_in_items = -1); 337 338 // Widgets: Drags (tip: ctrl+click on a drag box to input with keyboard. manually input values aren't clamped, can go off-bounds) 339 // For all the Float2/Float3/Float4/Int2/Int3/Int4 versions of every functions, note that a 'float v[X]' function argument is the same as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. You can pass address of your first element out of a contiguous set, e.g. &myvector.x 340 // Speed are per-pixel of mouse movement (v_speed=0.2f: mouse needs to move by 5 pixels to increase value by 1). For gamepad/keyboard navigation, minimum speed is Max(v_speed, minimum_step_at_given_precision). 341 IMGUI_API bool DragFloat(const char* label, float* v, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f); // If v_min >= v_max we have no bound 342 IMGUI_API bool DragFloat2(const char* label, float v[2], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f); 343 IMGUI_API bool DragFloat3(const char* label, float v[3], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f); 344 IMGUI_API bool DragFloat4(const char* label, float v[4], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f); 345 IMGUI_API bool DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", const char* format_max = NULL, float power = 1.0f); 346 IMGUI_API bool DragInt(const char* label, int* v, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%.0f"); // If v_min >= v_max we have no bound 347 IMGUI_API bool DragInt2(const char* label, int v[2], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%.0f"); 348 IMGUI_API bool DragInt3(const char* label, int v[3], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%.0f"); 349 IMGUI_API bool DragInt4(const char* label, int v[4], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%.0f"); 350 IMGUI_API bool DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%.0f", const char* format_max = NULL); 351 352 // Widgets: Input with Keyboard 353 IMGUI_API bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiTextEditCallback callback = NULL, void* user_data = NULL); 354 IMGUI_API bool InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiTextEditCallback callback = NULL, void* user_data = NULL); 355 IMGUI_API bool InputFloat(const char* label, float* v, float step = 0.0f, float step_fast = 0.0f, const char* format = "%.3f", ImGuiInputTextFlags extra_flags = 0); 356 IMGUI_API bool InputFloat2(const char* label, float v[2], const char* format = "%.3f", ImGuiInputTextFlags extra_flags = 0); 357 IMGUI_API bool InputFloat3(const char* label, float v[3], const char* format = "%.3f", ImGuiInputTextFlags extra_flags = 0); 358 IMGUI_API bool InputFloat4(const char* label, float v[4], const char* format = "%.3f", ImGuiInputTextFlags extra_flags = 0); 359 IMGUI_API bool InputInt(const char* label, int* v, int step = 1, int step_fast = 100, ImGuiInputTextFlags extra_flags = 0); 360 IMGUI_API bool InputInt2(const char* label, int v[2], ImGuiInputTextFlags extra_flags = 0); 361 IMGUI_API bool InputInt3(const char* label, int v[3], ImGuiInputTextFlags extra_flags = 0); 362 IMGUI_API bool InputInt4(const char* label, int v[4], ImGuiInputTextFlags extra_flags = 0); 363 IMGUI_API bool InputDouble(const char* label, double* v, double step = 0.0f, double step_fast = 0.0f, const char* format = "%.6f", ImGuiInputTextFlags extra_flags = 0); 364 365 // Widgets: Sliders (tip: ctrl+click on a slider to input with keyboard. manually input values aren't clamped, can go off-bounds) 366 IMGUI_API bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); // adjust format to decorate the value with a prefix or a suffix for in-slider labels or unit display. Use power!=1.0 for logarithmic sliders 367 IMGUI_API bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); 368 IMGUI_API bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); 369 IMGUI_API bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); 370 IMGUI_API bool SliderAngle(const char* label, float* v_rad, float v_degrees_min = -360.0f, float v_degrees_max = +360.0f); 371 IMGUI_API bool SliderInt(const char* label, int* v, int v_min, int v_max, const char* format = "%.0f"); 372 IMGUI_API bool SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format = "%.0f"); 373 IMGUI_API bool SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format = "%.0f"); 374 IMGUI_API bool SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format = "%.0f"); 375 IMGUI_API bool VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); 376 IMGUI_API bool VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format = "%.0f"); 377 378 // Widgets: Color Editor/Picker (tip: the ColorEdit* functions have a little colored preview square that can be left-clicked to open a picker, and right-clicked to open an option menu.) 379 // Note that a 'float v[X]' function argument is the same as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. You can the pass the address of a first float element out of a contiguous structure, e.g. &myvector.x 380 IMGUI_API bool ColorEdit3(const char* label, float col[3], ImGuiColorEditFlags flags = 0); 381 IMGUI_API bool ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0); 382 IMGUI_API bool ColorPicker3(const char* label, float col[3], ImGuiColorEditFlags flags = 0); 383 IMGUI_API bool ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags flags = 0, const float* ref_col = NULL); 384 IMGUI_API bool ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFlags flags = 0, ImVec2 size = ImVec2(0, 0)); // display a colored square/button, hover for details, return true when pressed. 385 IMGUI_API void SetColorEditOptions(ImGuiColorEditFlags flags); // initialize current options (generally on application startup) if you want to select a default format, picker type, etc. User will be able to change many settings, unless you pass the _NoOptions flag to your calls. 386 387 // Widgets: Trees 388 IMGUI_API bool TreeNode(const char* label); // if returning 'true' the node is open and the tree id is pushed into the id stack. user is responsible for calling TreePop(). 389 IMGUI_API bool TreeNode(const char* str_id, const char* fmt, ...) IM_FMTARGS(2); // read the FAQ about why and how to use ID. to align arbitrary text at the same level as a TreeNode() you can use Bullet(). 390 IMGUI_API bool TreeNode(const void* ptr_id, const char* fmt, ...) IM_FMTARGS(2); // " 391 IMGUI_API bool TreeNodeV(const char* str_id, const char* fmt, va_list args) IM_FMTLIST(2); 392 IMGUI_API bool TreeNodeV(const void* ptr_id, const char* fmt, va_list args) IM_FMTLIST(2); 393 IMGUI_API bool TreeNodeEx(const char* label, ImGuiTreeNodeFlags flags = 0); 394 IMGUI_API bool TreeNodeEx(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) IM_FMTARGS(3); 395 IMGUI_API bool TreeNodeEx(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) IM_FMTARGS(3); 396 IMGUI_API bool TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) IM_FMTLIST(3); 397 IMGUI_API bool TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) IM_FMTLIST(3); 398 IMGUI_API void TreePush(const char* str_id); // ~ Indent()+PushId(). Already called by TreeNode() when returning true, but you can call Push/Pop yourself for layout purpose 399 IMGUI_API void TreePush(const void* ptr_id = NULL); // " 400 IMGUI_API void TreePop(); // ~ Unindent()+PopId() 401 IMGUI_API void TreeAdvanceToLabelPos(); // advance cursor x position by GetTreeNodeToLabelSpacing() 402 IMGUI_API float GetTreeNodeToLabelSpacing(); // horizontal distance preceding label when using TreeNode*() or Bullet() == (g.FontSize + style.FramePadding.x*2) for a regular unframed TreeNode 403 IMGUI_API void SetNextTreeNodeOpen(bool is_open, ImGuiCond cond = 0); // set next TreeNode/CollapsingHeader open state. 404 IMGUI_API bool CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags = 0); // if returning 'true' the header is open. doesn't indent nor push on ID stack. user doesn't have to call TreePop(). 405 IMGUI_API bool CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags = 0); // when 'p_open' isn't NULL, display an additional small close button on upper right of the header 406 407 // Widgets: Selectable / Lists 408 IMGUI_API bool Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // "bool selected" carry the selection state (read-only). Selectable() is clicked is returns true so you can modify your selection state. size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height 409 IMGUI_API bool Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // "bool* p_selected" point to the selection state (read-write), as a convenient helper. 410 IMGUI_API bool ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_in_items = -1); 411 IMGUI_API bool ListBox(const char* label, int* current_item, bool(*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items = -1); 412 IMGUI_API bool ListBoxHeader(const char* label, const ImVec2& size = ImVec2(0, 0)); // use if you want to reimplement ListBox() will custom data or interactions. if the function return true, you can output elements then call ListBoxFooter() afterwards. 413 IMGUI_API bool ListBoxHeader(const char* label, int items_count, int height_in_items = -1); // " 414 IMGUI_API void ListBoxFooter(); // terminate the scrolling region. only call ListBoxFooter() if ListBoxHeader() returned true! 415 416 // Widgets: Value() Helpers. Output single value in "name: value" format (tip: freely declare more in your code to handle your types. you can add functions to the ImGui namespace) 417 IMGUI_API void Value(const char* prefix, bool b); 418 IMGUI_API void Value(const char* prefix, int v); 419 IMGUI_API void Value(const char* prefix, unsigned int v); 420 IMGUI_API void Value(const char* prefix, float v, const char* float_format = NULL); 421 422 // Tooltips 423 IMGUI_API void SetTooltip(const char* fmt, ...) IM_FMTARGS(1); // set text tooltip under mouse-cursor, typically use with ImGui::IsItemHovered(). overidde any previous call to SetTooltip(). 424 IMGUI_API void SetTooltipV(const char* fmt, va_list args) IM_FMTLIST(1); 425 IMGUI_API void BeginTooltip(); // begin/append a tooltip window. to create full-featured tooltip (with any kind of contents). 426 IMGUI_API void EndTooltip(); 427 428 // Menus 429 IMGUI_API bool BeginMainMenuBar(); // create and append to a full screen menu-bar. 430 IMGUI_API void EndMainMenuBar(); // only call EndMainMenuBar() if BeginMainMenuBar() returns true! 431 IMGUI_API bool BeginMenuBar(); // append to menu-bar of current window (requires ImGuiWindowFlags_MenuBar flag set on parent window). 432 IMGUI_API void EndMenuBar(); // only call EndMenuBar() if BeginMenuBar() returns true! 433 IMGUI_API bool BeginMenu(const char* label, bool enabled = true); // create a sub-menu entry. only call EndMenu() if this returns true! 434 IMGUI_API void EndMenu(); // only call EndMenu() if BeginMenu() returns true! 435 IMGUI_API bool MenuItem(const char* label, const char* shortcut = NULL, bool selected = false, bool enabled = true); // return true when activated. shortcuts are displayed for convenience but not processed by ImGui at the moment 436 IMGUI_API bool MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled = true); // return true when activated + toggle (*p_selected) if p_selected != NULL 437 438 // Popups 439 IMGUI_API void OpenPopup(const char* str_id); // call to mark popup as open (don't call every frame!). popups are closed when user click outside, or if CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. By default, Selectable()/MenuItem() are calling CloseCurrentPopup(). Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). 440 IMGUI_API bool BeginPopup(const char* str_id, ImGuiWindowFlags flags = 0); // return true if the popup is open, and you can start outputting to it. only call EndPopup() if BeginPopup() returns true! 441 IMGUI_API bool BeginPopupContextItem(const char* str_id = NULL, int mouse_button = 1); // helper to open and begin popup when clicked on last item. if you can pass a NULL str_id only if the previous item had an id. If you want to use that on a non-interactive item such as Text() you need to pass in an explicit ID here. read comments in .cpp! 442 IMGUI_API bool BeginPopupContextWindow(const char* str_id = NULL, int mouse_button = 1, bool also_over_items = true); // helper to open and begin popup when clicked on current window. 443 IMGUI_API bool BeginPopupContextVoid(const char* str_id = NULL, int mouse_button = 1); // helper to open and begin popup when clicked in void (where there are no imgui windows). 444 IMGUI_API bool BeginPopupModal(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); // modal dialog (regular window with title bar, block interactions behind the modal window, can't close the modal window by clicking outside) 445 IMGUI_API void EndPopup(); // only call EndPopup() if BeginPopupXXX() returns true! 446 IMGUI_API bool OpenPopupOnItemClick(const char* str_id = NULL, int mouse_button = 1); // helper to open popup when clicked on last item. return true when just opened. 447 IMGUI_API bool IsPopupOpen(const char* str_id); // return true if the popup is open 448 IMGUI_API void CloseCurrentPopup(); // close the popup we have begin-ed into. clicking on a MenuItem or Selectable automatically close the current popup. 449 450 // Columns 451 // You can also use SameLine(pos_x) for simplified columns. The columns API is still work-in-progress and rather lacking. 452 IMGUI_API void Columns(int count = 1, const char* id = NULL, bool border = true); 453 IMGUI_API void NextColumn(); // next column, defaults to current row or next row if the current row is finished 454 IMGUI_API int GetColumnIndex(); // get current column index 455 IMGUI_API float GetColumnWidth(int column_index = -1); // get column width (in pixels). pass -1 to use current column 456 IMGUI_API void SetColumnWidth(int column_index, float width); // set column width (in pixels). pass -1 to use current column 457 IMGUI_API float GetColumnOffset(int column_index = -1); // get position of column line (in pixels, from the left side of the contents region). pass -1 to use current column, otherwise 0..GetColumnsCount() inclusive. column 0 is typically 0.0f 458 IMGUI_API void SetColumnOffset(int column_index, float offset_x); // set position of column line (in pixels, from the left side of the contents region). pass -1 to use current column 459 IMGUI_API int GetColumnsCount(); 460 461 // Logging/Capture: all text output from interface is captured to tty/file/clipboard. By default, tree nodes are automatically opened during logging. 462 IMGUI_API void LogToTTY(int max_depth = -1); // start logging to tty 463 IMGUI_API void LogToFile(int max_depth = -1, const char* filename = NULL); // start logging to file 464 IMGUI_API void LogToClipboard(int max_depth = -1); // start logging to OS clipboard 465 IMGUI_API void LogFinish(); // stop logging (close file, etc.) 466 IMGUI_API void LogButtons(); // helper to display buttons for logging to tty/file/clipboard 467 IMGUI_API void LogText(const char* fmt, ...) IM_FMTARGS(1); // pass text data straight to log (without being displayed) 468 469 // Drag and Drop 470 // [BETA API] Missing Demo code. API may evolve. 471 IMGUI_API bool BeginDragDropSource(ImGuiDragDropFlags flags = 0); // call when the current item is active. If this return true, you can call SetDragDropPayload() + EndDragDropSource() 472 IMGUI_API bool SetDragDropPayload(const char* type, const void* data, size_t size, ImGuiCond cond = 0);// type is a user defined string of maximum 32 characters. Strings starting with '_' are reserved for dear imgui internal types. Data is copied and held by imgui. 473 IMGUI_API void EndDragDropSource(); // only call EndDragDropSource() if BeginDragDropSource() returns true! 474 IMGUI_API bool BeginDragDropTarget(); // call after submitting an item that may receive an item. If this returns true, you can call AcceptDragDropPayload() + EndDragDropTarget() 475 IMGUI_API const ImGuiPayload* AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags = 0); // accept contents of a given type. If ImGuiDragDropFlags_AcceptBeforeDelivery is set you can peek into the payload before the mouse button is released. 476 IMGUI_API void EndDragDropTarget(); // only call EndDragDropTarget() if BeginDragDropTarget() returns true! 477 478 // Clipping 479 IMGUI_API void PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect); 480 IMGUI_API void PopClipRect(); 481 482 // Focus, Activation 483 // (Prefer using "SetItemDefaultFocus()" over "if (IsWindowAppearing()) SetScrollHere()" when applicable, to make your code more forward compatible when navigation branch is merged) 484 IMGUI_API void SetItemDefaultFocus(); // make last item the default focused item of a window. Please use instead of "if (IsWindowAppearing()) SetScrollHere()" to signify "default item". 485 IMGUI_API void SetKeyboardFocusHere(int offset = 0); // focus keyboard on the next widget. Use positive 'offset' to access sub components of a multiple component widget. Use -1 to access previous widget. 486 487 // Utilities 488 IMGUI_API bool IsItemHovered(ImGuiHoveredFlags flags = 0); // is the last item hovered? (and usable, aka not blocked by a popup, etc.). See ImGuiHoveredFlags for more options. 489 IMGUI_API bool IsItemActive(); // is the last item active? (e.g. button being held, text field being edited- items that don't interact will always return false) 490 IMGUI_API bool IsItemFocused(); // is the last item focused for keyboard/gamepad navigation? 491 IMGUI_API bool IsItemClicked(int mouse_button = 0); // is the last item clicked? (e.g. button/node just clicked on) 492 IMGUI_API bool IsItemVisible(); // is the last item visible? (aka not out of sight due to clipping/scrolling.) 493 IMGUI_API bool IsAnyItemHovered(); 494 IMGUI_API bool IsAnyItemActive(); 495 IMGUI_API bool IsAnyItemFocused(); 496 IMGUI_API ImVec2 GetItemRectMin(); // get bounding rectangle of last item, in screen space 497 IMGUI_API ImVec2 GetItemRectMax(); // " 498 IMGUI_API ImVec2 GetItemRectSize(); // get size of last item, in screen space 499 IMGUI_API void SetItemAllowOverlap(); // allow last item to be overlapped by a subsequent item. sometimes useful with invisible buttons, selectables, etc. to catch unused area. 500 IMGUI_API bool IsRectVisible(const ImVec2& size); // test if rectangle (of given size, starting from cursor position) is visible / not clipped. 501 IMGUI_API bool IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max); // test if rectangle (in screen space) is visible / not clipped. to perform coarse clipping on user's side. 502 IMGUI_API float GetTime(); 503 IMGUI_API int GetFrameCount(); 504 IMGUI_API ImDrawList* GetOverlayDrawList(); // this draw list will be the last rendered one, useful to quickly draw overlays shapes/text 505 IMGUI_API ImDrawListSharedData* GetDrawListSharedData(); // you may use this when creating your own ImDrawList instances 506 IMGUI_API const char* GetStyleColorName(ImGuiCol idx); 507 IMGUI_API void SetStateStorage(ImGuiStorage* storage); // replace current window storage with our own (if you want to manipulate it yourself, typically clear subsection of it) 508 IMGUI_API ImGuiStorage* GetStateStorage(); 509 IMGUI_API ImVec2 CalcTextSize(const char* text, const char* text_end = NULL, bool hide_text_after_double_hash = false, float wrap_width = -1.0f); 510 IMGUI_API void CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end); // calculate coarse clipping for large list of evenly sized items. Prefer using the ImGuiListClipper higher-level helper if you can. 511 512 IMGUI_API bool BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags flags = 0); // helper to create a child window / scrolling region that looks like a normal widget frame 513 IMGUI_API void EndChildFrame(); // always call EndChildFrame() regardless of BeginChildFrame() return values (which indicates a collapsed/clipped window) 514 515 IMGUI_API ImVec4 ColorConvertU32ToFloat4(ImU32 in); 516 IMGUI_API ImU32 ColorConvertFloat4ToU32(const ImVec4& in); 517 IMGUI_API void ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v); 518 IMGUI_API void ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b); 519 520 // Inputs 521 IMGUI_API int GetKeyIndex(ImGuiKey imgui_key); // map ImGuiKey_* values into user's key index. == io.KeyMap[key] 522 IMGUI_API bool IsKeyDown(int user_key_index); // is key being held. == io.KeysDown[user_key_index]. note that imgui doesn't know the semantic of each entry of io.KeysDown[]. Use your own indices/enums according to how your backend/engine stored them into io.KeysDown[]! 523 IMGUI_API bool IsKeyPressed(int user_key_index, bool repeat = true); // was key pressed (went from !Down to Down). if repeat=true, uses io.KeyRepeatDelay / KeyRepeatRate 524 IMGUI_API bool IsKeyReleased(int user_key_index); // was key released (went from Down to !Down).. 525 IMGUI_API int GetKeyPressedAmount(int key_index, float repeat_delay, float rate); // uses provided repeat rate/delay. return a count, most often 0 or 1 but might be >1 if RepeatRate is small enough that DeltaTime > RepeatRate 526 IMGUI_API bool IsMouseDown(int button); // is mouse button held 527 IMGUI_API bool IsAnyMouseDown(); // is any mouse button held 528 IMGUI_API bool IsMouseClicked(int button, bool repeat = false); // did mouse button clicked (went from !Down to Down) 529 IMGUI_API bool IsMouseDoubleClicked(int button); // did mouse button double-clicked. a double-click returns false in IsMouseClicked(). uses io.MouseDoubleClickTime. 530 IMGUI_API bool IsMouseReleased(int button); // did mouse button released (went from Down to !Down) 531 IMGUI_API bool IsMouseDragging(int button = 0, float lock_threshold = -1.0f); // is mouse dragging. if lock_threshold < -1.0f uses io.MouseDraggingThreshold 532 IMGUI_API bool IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip = true); // is mouse hovering given bounding rect (in screen space). clipped by current clipping settings. disregarding of consideration of focus/window ordering/blocked by a popup. 533 IMGUI_API bool IsMousePosValid(const ImVec2* mouse_pos = NULL); // 534 IMGUI_API ImVec2 GetMousePos(); // shortcut to ImGui::GetIO().MousePos provided by user, to be consistent with other calls 535 IMGUI_API ImVec2 GetMousePosOnOpeningCurrentPopup(); // retrieve backup of mouse position at the time of opening popup we have BeginPopup() into 536 IMGUI_API ImVec2 GetMouseDragDelta(int button = 0, float lock_threshold = -1.0f); // dragging amount since clicking. if lock_threshold < -1.0f uses io.MouseDraggingThreshold 537 IMGUI_API void ResetMouseDragDelta(int button = 0); // 538 IMGUI_API ImGuiMouseCursor GetMouseCursor(); // get desired cursor type, reset in ImGui::NewFrame(), this is updated during the frame. valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui will render those for you 539 IMGUI_API void SetMouseCursor(ImGuiMouseCursor type); // set desired cursor type 540 IMGUI_API void CaptureKeyboardFromApp(bool capture = true); // manually override io.WantCaptureKeyboard flag next frame (said flag is entirely left for your application to handle). e.g. force capture keyboard when your widget is being hovered. 541 IMGUI_API void CaptureMouseFromApp(bool capture = true); // manually override io.WantCaptureMouse flag next frame (said flag is entirely left for your application to handle). 542 543 // Clipboard Utilities (also see the LogToClipboard() function to capture or output text data to the clipboard) 544 IMGUI_API const char* GetClipboardText(); 545 IMGUI_API void SetClipboardText(const char* text); 546 547 // Memory Utilities 548 // All those functions are not reliant on the current context. 549 // If you reload the contents of imgui.cpp at runtime, you may need to call SetCurrentContext() + SetAllocatorFunctions() again. 550 IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void(*free_func)(void* ptr, void* user_data), void* user_data = NULL); 551 IMGUI_API void* MemAlloc(size_t size); 552 IMGUI_API void MemFree(void* ptr); 241 // Context creation and access 242 // Each context create its own ImFontAtlas by default. You may instance one yourself and pass it to CreateContext() to share a font atlas between imgui contexts. 243 // None of those functions is reliant on the current context. 244 IMGUI_API ImGuiContext* CreateContext(ImFontAtlas* shared_font_atlas = NULL); 245 IMGUI_API void DestroyContext(ImGuiContext* ctx = NULL); // NULL = destroy current context 246 IMGUI_API ImGuiContext* GetCurrentContext(); 247 IMGUI_API void SetCurrentContext(ImGuiContext* ctx); 248 249 // Main 250 IMGUI_API ImGuiIO& GetIO(); // access the IO structure (mouse/keyboard/gamepad inputs, time, various configuration options/flags) 251 IMGUI_API ImGuiStyle& GetStyle(); // access the Style structure (colors, sizes). Always use PushStyleCol(), PushStyleVar() to modify style mid-frame! 252 IMGUI_API void NewFrame(); // start a new Dear ImGui frame, you can submit any command from this point until Render()/EndFrame(). 253 IMGUI_API void EndFrame(); // ends the Dear ImGui frame. automatically called by Render(). If you don't need to render data (skipping rendering) you may call EndFrame() without Render()... but you'll have wasted CPU already! If you don't need to render, better to not create any windows and not call NewFrame() at all! 254 IMGUI_API void Render(); // ends the Dear ImGui frame, finalize the draw data. You can get call GetDrawData() to obtain it and run your rendering function (up to v1.60, this used to call io.RenderDrawListsFn(). Nowadays, we allow and prefer calling your render function yourself.) 255 IMGUI_API ImDrawData* GetDrawData(); // valid after Render() and until the next call to NewFrame(). this is what you have to render. 256 257 // Demo, Debug, Information 258 IMGUI_API void ShowDemoWindow(bool* p_open = NULL); // create Demo window (previously called ShowTestWindow). demonstrate most ImGui features. call this to learn about the library! try to make it always available in your application! 259 IMGUI_API void ShowAboutWindow(bool* p_open = NULL); // create About window. display Dear ImGui version, credits and build/system information. 260 IMGUI_API void ShowMetricsWindow(bool* p_open = NULL); // create Debug/Metrics window. display Dear ImGui internals: draw commands (with individual draw calls and vertices), window list, basic internal state, etc. 261 IMGUI_API void ShowStyleEditor(ImGuiStyle* ref = NULL); // add style editor block (not a window). you can pass in a reference ImGuiStyle structure to compare to, revert to and save to (else it uses the default style) 262 IMGUI_API bool ShowStyleSelector(const char* label); // add style selector block (not a window), essentially a combo listing the default styles. 263 IMGUI_API void ShowFontSelector(const char* label); // add font selector block (not a window), essentially a combo listing the loaded fonts. 264 IMGUI_API void ShowUserGuide(); // add basic help/info block (not a window): how to manipulate ImGui as a end-user (mouse/keyboard controls). 265 IMGUI_API const char* GetVersion(); // get the compiled version string e.g. "1.23" (essentially the compiled value for IMGUI_VERSION) 266 267 // Styles 268 IMGUI_API void StyleColorsDark(ImGuiStyle* dst = NULL); // new, recommended style (default) 269 IMGUI_API void StyleColorsClassic(ImGuiStyle* dst = NULL); // classic imgui style 270 IMGUI_API void StyleColorsLight(ImGuiStyle* dst = NULL); // best used with borders and a custom, thicker font 271 272 // Windows 273 // - Begin() = push window to the stack and start appending to it. End() = pop window from the stack. 274 // - Passing 'bool* p_open != NULL' shows a window-closing widget in the upper-right corner of the window, 275 // which clicking will set the boolean to false when clicked. 276 // - You may append multiple times to the same window during the same frame by calling Begin()/End() pairs multiple times. 277 // Some information such as 'flags' or 'p_open' will only be considered by the first call to Begin(). 278 // - Begin() return false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting 279 // anything to the window. Always call a matching End() for each Begin() call, regardless of its return value! 280 // [Important: due to legacy reason, this is inconsistent with most other functions such as BeginMenu/EndMenu, 281 // BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding BeginXXX function 282 // returned true. Begin and BeginChild are the only odd ones out. Will be fixed in a future update.] 283 // - Note that the bottom of window stack always contains a window called "Debug". 284 IMGUI_API bool Begin(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); 285 IMGUI_API void End(); 286 287 // Child Windows 288 // - Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window. Child windows can embed their own child. 289 // - For each independent axis of 'size': ==0.0f: use remaining host window size / >0.0f: fixed size / <0.0f: use remaining window size minus abs(size) / Each axis can use a different mode, e.g. ImVec2(0,400). 290 // - BeginChild() returns false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting anything to the window. 291 // Always call a matching EndChild() for each BeginChild() call, regardless of its return value [as with Begin: this is due to legacy reason and inconsistent with most BeginXXX functions apart from the regular Begin() which behaves like BeginChild().] 292 IMGUI_API bool BeginChild(const char* str_id, const ImVec2& size = ImVec2(0, 0), bool border = false, ImGuiWindowFlags flags = 0); 293 IMGUI_API bool BeginChild(ImGuiID id, const ImVec2& size = ImVec2(0, 0), bool border = false, ImGuiWindowFlags flags = 0); 294 IMGUI_API void EndChild(); 295 296 // Windows Utilities 297 // - 'current window' = the window we are appending into while inside a Begin()/End() block. 'next window' = next window we will Begin() into. 298 IMGUI_API bool IsWindowAppearing(); 299 IMGUI_API bool IsWindowCollapsed(); 300 IMGUI_API bool IsWindowFocused(ImGuiFocusedFlags flags=0); // is current window focused? or its root/child, depending on flags. see flags for options. 301 IMGUI_API bool IsWindowHovered(ImGuiHoveredFlags flags=0); // is current window hovered (and typically: not blocked by a popup/modal)? see flags for options. NB: If you are trying to check whether your mouse should be dispatched to imgui or to your app, you should use the 'io.WantCaptureMouse' boolean for that! Please read the FAQ! 302 IMGUI_API ImDrawList* GetWindowDrawList(); // get draw list associated to the current window, to append your own drawing primitives 303 IMGUI_API ImVec2 GetWindowPos(); // get current window position in screen space (useful if you want to do your own drawing via the DrawList API) 304 IMGUI_API ImVec2 GetWindowSize(); // get current window size 305 IMGUI_API float GetWindowWidth(); // get current window width (shortcut for GetWindowSize().x) 306 IMGUI_API float GetWindowHeight(); // get current window height (shortcut for GetWindowSize().y) 307 308 // Prefer using SetNextXXX functions (before Begin) rather that SetXXX functions (after Begin). 309 IMGUI_API void SetNextWindowPos(const ImVec2& pos, ImGuiCond cond = 0, const ImVec2& pivot = ImVec2(0, 0)); // set next window position. call before Begin(). use pivot=(0.5f,0.5f) to center on given point, etc. 310 IMGUI_API void SetNextWindowSize(const ImVec2& size, ImGuiCond cond = 0); // set next window size. set axis to 0.0f to force an auto-fit on this axis. call before Begin() 311 IMGUI_API void SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback = NULL, void* custom_callback_data = NULL); // set next window size limits. use -1,-1 on either X/Y axis to preserve the current size. Sizes will be rounded down. Use callback to apply non-trivial programmatic constraints. 312 IMGUI_API void SetNextWindowContentSize(const ImVec2& size); // set next window content size (~ scrollable client area, which enforce the range of scrollbars). Not including window decorations (title bar, menu bar, etc.) nor WindowPadding. set an axis to 0.0f to leave it automatic. call before Begin() 313 IMGUI_API void SetNextWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // set next window collapsed state. call before Begin() 314 IMGUI_API void SetNextWindowFocus(); // set next window to be focused / top-most. call before Begin() 315 IMGUI_API void SetNextWindowBgAlpha(float alpha); // set next window background color alpha. helper to easily override the Alpha component of ImGuiCol_WindowBg/ChildBg/PopupBg. you may also use ImGuiWindowFlags_NoBackground. 316 IMGUI_API void SetWindowPos(const ImVec2& pos, ImGuiCond cond = 0); // (not recommended) set current window position - call within Begin()/End(). prefer using SetNextWindowPos(), as this may incur tearing and side-effects. 317 IMGUI_API void SetWindowSize(const ImVec2& size, ImGuiCond cond = 0); // (not recommended) set current window size - call within Begin()/End(). set to ImVec2(0, 0) to force an auto-fit. prefer using SetNextWindowSize(), as this may incur tearing and minor side-effects. 318 IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // (not recommended) set current window collapsed state. prefer using SetNextWindowCollapsed(). 319 IMGUI_API void SetWindowFocus(); // (not recommended) set current window to be focused / top-most. prefer using SetNextWindowFocus(). 320 IMGUI_API void SetWindowFontScale(float scale); // set font scale. Adjust IO.FontGlobalScale if you want to scale all windows. This is an old API! For correct scaling, prefer to reload font + rebuild ImFontAtlas + call style.ScaleAllSizes(). 321 IMGUI_API void SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond = 0); // set named window position. 322 IMGUI_API void SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond = 0); // set named window size. set axis to 0.0f to force an auto-fit on this axis. 323 IMGUI_API void SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond = 0); // set named window collapsed state 324 IMGUI_API void SetWindowFocus(const char* name); // set named window to be focused / top-most. use NULL to remove focus. 325 326 // Content region 327 // - Those functions are bound to be redesigned soon (they are confusing, incomplete and return values in local window coordinates which increases confusion) 328 IMGUI_API ImVec2 GetContentRegionMax(); // current content boundaries (typically window boundaries including scrolling, or current column boundaries), in windows coordinates 329 IMGUI_API ImVec2 GetContentRegionAvail(); // == GetContentRegionMax() - GetCursorPos() 330 IMGUI_API ImVec2 GetWindowContentRegionMin(); // content boundaries min (roughly (0,0)-Scroll), in window coordinates 331 IMGUI_API ImVec2 GetWindowContentRegionMax(); // content boundaries max (roughly (0,0)+Size-Scroll) where Size can be override with SetNextWindowContentSize(), in window coordinates 332 IMGUI_API float GetWindowContentRegionWidth(); // 333 334 // Windows Scrolling 335 IMGUI_API float GetScrollX(); // get scrolling amount [0..GetScrollMaxX()] 336 IMGUI_API float GetScrollY(); // get scrolling amount [0..GetScrollMaxY()] 337 IMGUI_API float GetScrollMaxX(); // get maximum scrolling amount ~~ ContentSize.x - WindowSize.x 338 IMGUI_API float GetScrollMaxY(); // get maximum scrolling amount ~~ ContentSize.y - WindowSize.y 339 IMGUI_API void SetScrollX(float scroll_x); // set scrolling amount [0..GetScrollMaxX()] 340 IMGUI_API void SetScrollY(float scroll_y); // set scrolling amount [0..GetScrollMaxY()] 341 IMGUI_API void SetScrollHereX(float center_x_ratio = 0.5f); // adjust scrolling amount to make current cursor position visible. center_x_ratio=0.0: left, 0.5: center, 1.0: right. When using to make a "default/current item" visible, consider using SetItemDefaultFocus() instead. 342 IMGUI_API void SetScrollHereY(float center_y_ratio = 0.5f); // adjust scrolling amount to make current cursor position visible. center_y_ratio=0.0: top, 0.5: center, 1.0: bottom. When using to make a "default/current item" visible, consider using SetItemDefaultFocus() instead. 343 IMGUI_API void SetScrollFromPosX(float local_x, float center_x_ratio = 0.5f); // adjust scrolling amount to make given position visible. Generally GetCursorStartPos() + offset to compute a valid position. 344 IMGUI_API void SetScrollFromPosY(float local_y, float center_y_ratio = 0.5f); // adjust scrolling amount to make given position visible. Generally GetCursorStartPos() + offset to compute a valid position. 345 346 // Parameters stacks (shared) 347 IMGUI_API void PushFont(ImFont* font); // use NULL as a shortcut to push default font 348 IMGUI_API void PopFont(); 349 IMGUI_API void PushStyleColor(ImGuiCol idx, ImU32 col); 350 IMGUI_API void PushStyleColor(ImGuiCol idx, const ImVec4& col); 351 IMGUI_API void PopStyleColor(int count = 1); 352 IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val); 353 IMGUI_API void PushStyleVar(ImGuiStyleVar idx, const ImVec2& val); 354 IMGUI_API void PopStyleVar(int count = 1); 355 IMGUI_API const ImVec4& GetStyleColorVec4(ImGuiCol idx); // retrieve style color as stored in ImGuiStyle structure. use to feed back into PushStyleColor(), otherwise use GetColorU32() to get style color with style alpha baked in. 356 IMGUI_API ImFont* GetFont(); // get current font 357 IMGUI_API float GetFontSize(); // get current font size (= height in pixels) of current font with current scale applied 358 IMGUI_API ImVec2 GetFontTexUvWhitePixel(); // get UV coordinate for a while pixel, useful to draw custom shapes via the ImDrawList API 359 IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul = 1.0f); // retrieve given style color with style alpha applied and optional extra alpha multiplier 360 IMGUI_API ImU32 GetColorU32(const ImVec4& col); // retrieve given color with style alpha applied 361 IMGUI_API ImU32 GetColorU32(ImU32 col); // retrieve given color with style alpha applied 362 363 // Parameters stacks (current window) 364 IMGUI_API void PushItemWidth(float item_width); // push width of items for common large "item+label" widgets. >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -1.0f always align width to the right side). 0.0f = default to ~2/3 of windows width, 365 IMGUI_API void PopItemWidth(); 366 IMGUI_API void SetNextItemWidth(float item_width); // set width of the _next_ common large "item+label" widget. >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -1.0f always align width to the right side) 367 IMGUI_API float CalcItemWidth(); // width of item given pushed settings and current cursor position. NOT necessarily the width of last item unlike most 'Item' functions. 368 IMGUI_API void PushTextWrapPos(float wrap_local_pos_x = 0.0f); // push word-wrapping position for Text*() commands. < 0.0f: no wrapping; 0.0f: wrap to end of window (or column); > 0.0f: wrap at 'wrap_pos_x' position in window local space 369 IMGUI_API void PopTextWrapPos(); 370 IMGUI_API void PushAllowKeyboardFocus(bool allow_keyboard_focus); // allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets 371 IMGUI_API void PopAllowKeyboardFocus(); 372 IMGUI_API void PushButtonRepeat(bool repeat); // in 'repeat' mode, Button*() functions return repeated true in a typematic manner (using io.KeyRepeatDelay/io.KeyRepeatRate setting). Note that you can call IsItemActive() after any Button() to tell if the button is held in the current frame. 373 IMGUI_API void PopButtonRepeat(); 374 375 // Cursor / Layout 376 // - By "cursor" we mean the current output position. 377 // - The typical widget behavior is to output themselves at the current cursor position, then move the cursor one line down. 378 // - You can call SameLine() between widgets to undo the last carriage return and output at the right of the preceding widget. 379 // - Attention! We currently have inconsistencies between window-local and absolute positions we will aim to fix with future API: 380 // Window-local coordinates: SameLine(), GetCursorPos(), SetCursorPos(), GetCursorStartPos(), GetContentRegionMax(), GetWindowContentRegion*(), PushTextWrapPos() 381 // Absolute coordinate: GetCursorScreenPos(), SetCursorScreenPos(), all ImDrawList:: functions. 382 IMGUI_API void Separator(); // separator, generally horizontal. inside a menu bar or in horizontal layout mode, this becomes a vertical separator. 383 IMGUI_API void SameLine(float offset_from_start_x=0.0f, float spacing=-1.0f); // call between widgets or groups to layout them horizontally. X position given in window coordinates. 384 IMGUI_API void NewLine(); // undo a SameLine() or force a new line when in an horizontal-layout context. 385 IMGUI_API void Spacing(); // add vertical spacing. 386 IMGUI_API void Dummy(const ImVec2& size); // add a dummy item of given size. unlike InvisibleButton(), Dummy() won't take the mouse click or be navigable into. 387 IMGUI_API void Indent(float indent_w = 0.0f); // move content position toward the right, by style.IndentSpacing or indent_w if != 0 388 IMGUI_API void Unindent(float indent_w = 0.0f); // move content position back to the left, by style.IndentSpacing or indent_w if != 0 389 IMGUI_API void BeginGroup(); // lock horizontal starting position 390 IMGUI_API void EndGroup(); // unlock horizontal starting position + capture the whole group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.) 391 IMGUI_API ImVec2 GetCursorPos(); // cursor position in window coordinates (relative to window position) 392 IMGUI_API float GetCursorPosX(); // (some functions are using window-relative coordinates, such as: GetCursorPos, GetCursorStartPos, GetContentRegionMax, GetWindowContentRegion* etc. 393 IMGUI_API float GetCursorPosY(); // other functions such as GetCursorScreenPos or everything in ImDrawList:: 394 IMGUI_API void SetCursorPos(const ImVec2& local_pos); // are using the main, absolute coordinate system. 395 IMGUI_API void SetCursorPosX(float local_x); // GetWindowPos() + GetCursorPos() == GetCursorScreenPos() etc.) 396 IMGUI_API void SetCursorPosY(float local_y); // 397 IMGUI_API ImVec2 GetCursorStartPos(); // initial cursor position in window coordinates 398 IMGUI_API ImVec2 GetCursorScreenPos(); // cursor position in absolute screen coordinates [0..io.DisplaySize] (useful to work with ImDrawList API) 399 IMGUI_API void SetCursorScreenPos(const ImVec2& pos); // cursor position in absolute screen coordinates [0..io.DisplaySize] 400 IMGUI_API void AlignTextToFramePadding(); // vertically align upcoming text baseline to FramePadding.y so that it will align properly to regularly framed items (call if you have text on a line before a framed item) 401 IMGUI_API float GetTextLineHeight(); // ~ FontSize 402 IMGUI_API float GetTextLineHeightWithSpacing(); // ~ FontSize + style.ItemSpacing.y (distance in pixels between 2 consecutive lines of text) 403 IMGUI_API float GetFrameHeight(); // ~ FontSize + style.FramePadding.y * 2 404 IMGUI_API float GetFrameHeightWithSpacing(); // ~ FontSize + style.FramePadding.y * 2 + style.ItemSpacing.y (distance in pixels between 2 consecutive lines of framed widgets) 405 406 // ID stack/scopes 407 // - Read the FAQ for more details about how ID are handled in dear imgui. If you are creating widgets in a loop you most 408 // likely want to push a unique identifier (e.g. object pointer, loop index) to uniquely differentiate them. 409 // - The resulting ID are hashes of the entire stack. 410 // - You can also use the "Label##foobar" syntax within widget label to distinguish them from each others. 411 // - In this header file we use the "label"/"name" terminology to denote a string that will be displayed and used as an ID, 412 // whereas "str_id" denote a string that is only used as an ID and not normally displayed. 413 IMGUI_API void PushID(const char* str_id); // push string into the ID stack (will hash string). 414 IMGUI_API void PushID(const char* str_id_begin, const char* str_id_end); // push string into the ID stack (will hash string). 415 IMGUI_API void PushID(const void* ptr_id); // push pointer into the ID stack (will hash pointer). 416 IMGUI_API void PushID(int int_id); // push integer into the ID stack (will hash integer). 417 IMGUI_API void PopID(); // pop from the ID stack. 418 IMGUI_API ImGuiID GetID(const char* str_id); // calculate unique ID (hash of whole ID stack + given parameter). e.g. if you want to query into ImGuiStorage yourself 419 IMGUI_API ImGuiID GetID(const char* str_id_begin, const char* str_id_end); 420 IMGUI_API ImGuiID GetID(const void* ptr_id); 421 422 // Widgets: Text 423 IMGUI_API void TextUnformatted(const char* text, const char* text_end = NULL); // raw text without formatting. Roughly equivalent to Text("%s", text) but: A) doesn't require null terminated string if 'text_end' is specified, B) it's faster, no memory copy is done, no buffer size limits, recommended for long chunks of text. 424 IMGUI_API void Text(const char* fmt, ...) IM_FMTARGS(1); // formatted text 425 IMGUI_API void TextV(const char* fmt, va_list args) IM_FMTLIST(1); 426 IMGUI_API void TextColored(const ImVec4& col, const char* fmt, ...) IM_FMTARGS(2); // shortcut for PushStyleColor(ImGuiCol_Text, col); Text(fmt, ...); PopStyleColor(); 427 IMGUI_API void TextColoredV(const ImVec4& col, const char* fmt, va_list args) IM_FMTLIST(2); 428 IMGUI_API void TextDisabled(const char* fmt, ...) IM_FMTARGS(1); // shortcut for PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]); Text(fmt, ...); PopStyleColor(); 429 IMGUI_API void TextDisabledV(const char* fmt, va_list args) IM_FMTLIST(1); 430 IMGUI_API void TextWrapped(const char* fmt, ...) IM_FMTARGS(1); // shortcut for PushTextWrapPos(0.0f); Text(fmt, ...); PopTextWrapPos();. Note that this won't work on an auto-resizing window if there's no other widgets to extend the window width, yoy may need to set a size using SetNextWindowSize(). 431 IMGUI_API void TextWrappedV(const char* fmt, va_list args) IM_FMTLIST(1); 432 IMGUI_API void LabelText(const char* label, const char* fmt, ...) IM_FMTARGS(2); // display text+label aligned the same way as value+label widgets 433 IMGUI_API void LabelTextV(const char* label, const char* fmt, va_list args) IM_FMTLIST(2); 434 IMGUI_API void BulletText(const char* fmt, ...) IM_FMTARGS(1); // shortcut for Bullet()+Text() 435 IMGUI_API void BulletTextV(const char* fmt, va_list args) IM_FMTLIST(1); 436 437 // Widgets: Main 438 // - Most widgets return true when the value has been changed or when pressed/selected 439 // - You may also use one of the many IsItemXXX functions (e.g. IsItemActive, IsItemHovered, etc.) to query widget state. 440 IMGUI_API bool Button(const char* label, const ImVec2& size = ImVec2(0, 0)); // button 441 IMGUI_API bool SmallButton(const char* label); // button with FramePadding=(0,0) to easily embed within text 442 IMGUI_API bool InvisibleButton(const char* str_id, const ImVec2& size, ImGuiButtonFlags flags = 0); // flexible button behavior without the visuals, frequently useful to build custom behaviors using the public api (along with IsItemActive, IsItemHovered, etc.) 443 IMGUI_API bool ArrowButton(const char* str_id, ImGuiDir dir); // square button with an arrow shape 444 IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1,1), const ImVec4& tint_col = ImVec4(1,1,1,1), const ImVec4& border_col = ImVec4(0,0,0,0)); 445 IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1,1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0,0,0,0), const ImVec4& tint_col = ImVec4(1,1,1,1)); // <0 frame_padding uses default frame padding settings. 0 for no padding 446 IMGUI_API bool Checkbox(const char* label, bool* v); 447 IMGUI_API bool CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value); 448 IMGUI_API bool RadioButton(const char* label, bool active); // use with e.g. if (RadioButton("one", my_value==1)) { my_value = 1; } 449 IMGUI_API bool RadioButton(const char* label, int* v, int v_button); // shortcut to handle the above pattern when value is an integer 450 IMGUI_API void ProgressBar(float fraction, const ImVec2& size_arg = ImVec2(-1, 0), const char* overlay = NULL); 451 IMGUI_API void Bullet(); // draw a small circle + keep the cursor on the same line. advance cursor x position by GetTreeNodeToLabelSpacing(), same distance that TreeNode() uses 452 453 // Widgets: Combo Box 454 // - The BeginCombo()/EndCombo() api allows you to manage your contents and selection state however you want it, by creating e.g. Selectable() items. 455 // - The old Combo() api are helpers over BeginCombo()/EndCombo() which are kept available for convenience purpose. 456 IMGUI_API bool BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags = 0); 457 IMGUI_API void EndCombo(); // only call EndCombo() if BeginCombo() returns true! 458 IMGUI_API bool Combo(const char* label, int* current_item, const char* const items[], int items_count, int popup_max_height_in_items = -1); 459 IMGUI_API bool Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int popup_max_height_in_items = -1); // Separate items with \0 within a string, end item-list with \0\0. e.g. "One\0Two\0Three\0" 460 IMGUI_API bool Combo(const char* label, int* current_item, bool(*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int popup_max_height_in_items = -1); 461 462 // Widgets: Drag Sliders 463 // - CTRL+Click on any drag box to turn them into an input box. Manually input values aren't clamped and can go off-bounds. 464 // - For all the Float2/Float3/Float4/Int2/Int3/Int4 versions of every functions, note that a 'float v[X]' function argument is the same as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. You can pass address of your first element out of a contiguous set, e.g. &myvector.x 465 // - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. 466 // - Format string may also be set to NULL or use the default format ("%f" or "%d"). 467 // - Speed are per-pixel of mouse movement (v_speed=0.2f: mouse needs to move by 5 pixels to increase value by 1). For gamepad/keyboard navigation, minimum speed is Max(v_speed, minimum_step_at_given_precision). 468 // - Use v_min < v_max to clamp edits to given limits. Note that CTRL+Click manual input can override those limits. 469 // - Use v_max = FLT_MAX / INT_MAX etc to avoid clamping to a maximum, same with v_min = -FLT_MAX / INT_MIN to avoid clamping to a minimum. 470 // - We use the same sets of flags for DragXXX() and SliderXXX() functions as the features are the same and it makes it easier to swap them. 471 // - Legacy: Pre-1.78 there are DragXXX() function signatures that takes a final `float power=1.0f' argument instead of the `ImGuiSliderFlags flags=0' argument. 472 // If you get a warning converting a float to ImGuiSliderFlags, read https://github.com/ocornut/imgui/issues/3361 473 IMGUI_API bool DragFloat(const char* label, float* v, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", ImGuiSliderFlags flags = 0); // If v_min >= v_max we have no bound 474 IMGUI_API bool DragFloat2(const char* label, float v[2], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", ImGuiSliderFlags flags = 0); 475 IMGUI_API bool DragFloat3(const char* label, float v[3], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", ImGuiSliderFlags flags = 0); 476 IMGUI_API bool DragFloat4(const char* label, float v[4], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", ImGuiSliderFlags flags = 0); 477 IMGUI_API bool DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", const char* format_max = NULL, ImGuiSliderFlags flags = 0); 478 IMGUI_API bool DragInt(const char* label, int* v, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiSliderFlags flags = 0); // If v_min >= v_max we have no bound 479 IMGUI_API bool DragInt2(const char* label, int v[2], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiSliderFlags flags = 0); 480 IMGUI_API bool DragInt3(const char* label, int v[3], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiSliderFlags flags = 0); 481 IMGUI_API bool DragInt4(const char* label, int v[4], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiSliderFlags flags = 0); 482 IMGUI_API bool DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", const char* format_max = NULL, ImGuiSliderFlags flags = 0); 483 IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, ImGuiSliderFlags flags = 0); 484 IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, ImGuiSliderFlags flags = 0); 485 486 // Widgets: Regular Sliders 487 // - CTRL+Click on any slider to turn them into an input box. Manually input values aren't clamped and can go off-bounds. 488 // - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. 489 // - Format string may also be set to NULL or use the default format ("%f" or "%d"). 490 // - Legacy: Pre-1.78 there are SliderXXX() function signatures that takes a final `float power=1.0f' argument instead of the `ImGuiSliderFlags flags=0' argument. 491 // If you get a warning converting a float to ImGuiSliderFlags, read https://github.com/ocornut/imgui/issues/3361 492 IMGUI_API bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); // adjust format to decorate the value with a prefix or a suffix for in-slider labels or unit display. 493 IMGUI_API bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); 494 IMGUI_API bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); 495 IMGUI_API bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); 496 IMGUI_API bool SliderAngle(const char* label, float* v_rad, float v_degrees_min = -360.0f, float v_degrees_max = +360.0f, const char* format = "%.0f deg", ImGuiSliderFlags flags = 0); 497 IMGUI_API bool SliderInt(const char* label, int* v, int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0); 498 IMGUI_API bool SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0); 499 IMGUI_API bool SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0); 500 IMGUI_API bool SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0); 501 IMGUI_API bool SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format = NULL, ImGuiSliderFlags flags = 0); 502 IMGUI_API bool SliderScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_min, const void* p_max, const char* format = NULL, ImGuiSliderFlags flags = 0); 503 IMGUI_API bool VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); 504 IMGUI_API bool VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0); 505 IMGUI_API bool VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format = NULL, ImGuiSliderFlags flags = 0); 506 507 // Widgets: Input with Keyboard 508 // - If you want to use InputText() with std::string or any custom dynamic string type, see misc/cpp/imgui_stdlib.h and comments in imgui_demo.cpp. 509 // - Most of the ImGuiInputTextFlags flags are only useful for InputText() and not for InputFloatX, InputIntX, InputDouble etc. 510 IMGUI_API bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); 511 IMGUI_API bool InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); 512 IMGUI_API bool InputTextWithHint(const char* label, const char* hint, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); 513 IMGUI_API bool InputFloat(const char* label, float* v, float step = 0.0f, float step_fast = 0.0f, const char* format = "%.3f", ImGuiInputTextFlags flags = 0); 514 IMGUI_API bool InputFloat2(const char* label, float v[2], const char* format = "%.3f", ImGuiInputTextFlags flags = 0); 515 IMGUI_API bool InputFloat3(const char* label, float v[3], const char* format = "%.3f", ImGuiInputTextFlags flags = 0); 516 IMGUI_API bool InputFloat4(const char* label, float v[4], const char* format = "%.3f", ImGuiInputTextFlags flags = 0); 517 IMGUI_API bool InputInt(const char* label, int* v, int step = 1, int step_fast = 100, ImGuiInputTextFlags flags = 0); 518 IMGUI_API bool InputInt2(const char* label, int v[2], ImGuiInputTextFlags flags = 0); 519 IMGUI_API bool InputInt3(const char* label, int v[3], ImGuiInputTextFlags flags = 0); 520 IMGUI_API bool InputInt4(const char* label, int v[4], ImGuiInputTextFlags flags = 0); 521 IMGUI_API bool InputDouble(const char* label, double* v, double step = 0.0, double step_fast = 0.0, const char* format = "%.6f", ImGuiInputTextFlags flags = 0); 522 IMGUI_API bool InputScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_step = NULL, const void* p_step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags flags = 0); 523 IMGUI_API bool InputScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_step = NULL, const void* p_step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags flags = 0); 524 525 // Widgets: Color Editor/Picker (tip: the ColorEdit* functions have a little colored preview square that can be left-clicked to open a picker, and right-clicked to open an option menu.) 526 // - Note that in C++ a 'float v[X]' function argument is the _same_ as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. 527 // - You can pass the address of a first float element out of a contiguous structure, e.g. &myvector.x 528 IMGUI_API bool ColorEdit3(const char* label, float col[3], ImGuiColorEditFlags flags = 0); 529 IMGUI_API bool ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0); 530 IMGUI_API bool ColorPicker3(const char* label, float col[3], ImGuiColorEditFlags flags = 0); 531 IMGUI_API bool ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags flags = 0, const float* ref_col = NULL); 532 IMGUI_API bool ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFlags flags = 0, ImVec2 size = ImVec2(0, 0)); // display a colored square/button, hover for details, return true when pressed. 533 IMGUI_API void SetColorEditOptions(ImGuiColorEditFlags flags); // initialize current options (generally on application startup) if you want to select a default format, picker type, etc. User will be able to change many settings, unless you pass the _NoOptions flag to your calls. 534 535 // Widgets: Trees 536 // - TreeNode functions return true when the node is open, in which case you need to also call TreePop() when you are finished displaying the tree node contents. 537 IMGUI_API bool TreeNode(const char* label); 538 IMGUI_API bool TreeNode(const char* str_id, const char* fmt, ...) IM_FMTARGS(2); // helper variation to easily decorelate the id from the displayed string. Read the FAQ about why and how to use ID. to align arbitrary text at the same level as a TreeNode() you can use Bullet(). 539 IMGUI_API bool TreeNode(const void* ptr_id, const char* fmt, ...) IM_FMTARGS(2); // " 540 IMGUI_API bool TreeNodeV(const char* str_id, const char* fmt, va_list args) IM_FMTLIST(2); 541 IMGUI_API bool TreeNodeV(const void* ptr_id, const char* fmt, va_list args) IM_FMTLIST(2); 542 IMGUI_API bool TreeNodeEx(const char* label, ImGuiTreeNodeFlags flags = 0); 543 IMGUI_API bool TreeNodeEx(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) IM_FMTARGS(3); 544 IMGUI_API bool TreeNodeEx(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) IM_FMTARGS(3); 545 IMGUI_API bool TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) IM_FMTLIST(3); 546 IMGUI_API bool TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) IM_FMTLIST(3); 547 IMGUI_API void TreePush(const char* str_id); // ~ Indent()+PushId(). Already called by TreeNode() when returning true, but you can call TreePush/TreePop yourself if desired. 548 IMGUI_API void TreePush(const void* ptr_id = NULL); // " 549 IMGUI_API void TreePop(); // ~ Unindent()+PopId() 550 IMGUI_API float GetTreeNodeToLabelSpacing(); // horizontal distance preceding label when using TreeNode*() or Bullet() == (g.FontSize + style.FramePadding.x*2) for a regular unframed TreeNode 551 IMGUI_API bool CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags = 0); // if returning 'true' the header is open. doesn't indent nor push on ID stack. user doesn't have to call TreePop(). 552 IMGUI_API bool CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags = 0); // when 'p_open' isn't NULL, display an additional small close button on upper right of the header 553 IMGUI_API void SetNextItemOpen(bool is_open, ImGuiCond cond = 0); // set next TreeNode/CollapsingHeader open state. 554 555 // Widgets: Selectables 556 // - A selectable highlights when hovered, and can display another color when selected. 557 // - Neighbors selectable extend their highlight bounds in order to leave no gap between them. This is so a series of selected Selectable appear contiguous. 558 IMGUI_API bool Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // "bool selected" carry the selection state (read-only). Selectable() is clicked is returns true so you can modify your selection state. size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height 559 IMGUI_API bool Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // "bool* p_selected" point to the selection state (read-write), as a convenient helper. 560 561 // Widgets: List Boxes 562 // - FIXME: To be consistent with all the newer API, ListBoxHeader/ListBoxFooter should in reality be called BeginListBox/EndListBox. Will rename them. 563 IMGUI_API bool ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_in_items = -1); 564 IMGUI_API bool ListBox(const char* label, int* current_item, bool (*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items = -1); 565 IMGUI_API bool ListBoxHeader(const char* label, const ImVec2& size = ImVec2(0, 0)); // use if you want to reimplement ListBox() will custom data or interactions. if the function return true, you can output elements then call ListBoxFooter() afterwards. 566 IMGUI_API bool ListBoxHeader(const char* label, int items_count, int height_in_items = -1); // " 567 IMGUI_API void ListBoxFooter(); // terminate the scrolling region. only call ListBoxFooter() if ListBoxHeader() returned true! 568 569 // Widgets: Data Plotting 570 IMGUI_API void PlotLines(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); 571 IMGUI_API void PlotLines(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0)); 572 IMGUI_API void PlotHistogram(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); 573 IMGUI_API void PlotHistogram(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0)); 574 575 // Widgets: Value() Helpers. 576 // - Those are merely shortcut to calling Text() with a format string. Output single value in "name: value" format (tip: freely declare more in your code to handle your types. you can add functions to the ImGui namespace) 577 IMGUI_API void Value(const char* prefix, bool b); 578 IMGUI_API void Value(const char* prefix, int v); 579 IMGUI_API void Value(const char* prefix, unsigned int v); 580 IMGUI_API void Value(const char* prefix, float v, const char* float_format = NULL); 581 582 // Widgets: Menus 583 // - Use BeginMenuBar() on a window ImGuiWindowFlags_MenuBar to append to its menu bar. 584 // - Use BeginMainMenuBar() to create a menu bar at the top of the screen and append to it. 585 // - Use BeginMenu() to create a menu. You can call BeginMenu() multiple time with the same identifier to append more items to it. 586 IMGUI_API bool BeginMenuBar(); // append to menu-bar of current window (requires ImGuiWindowFlags_MenuBar flag set on parent window). 587 IMGUI_API void EndMenuBar(); // only call EndMenuBar() if BeginMenuBar() returns true! 588 IMGUI_API bool BeginMainMenuBar(); // create and append to a full screen menu-bar. 589 IMGUI_API void EndMainMenuBar(); // only call EndMainMenuBar() if BeginMainMenuBar() returns true! 590 IMGUI_API bool BeginMenu(const char* label, bool enabled = true); // create a sub-menu entry. only call EndMenu() if this returns true! 591 IMGUI_API void EndMenu(); // only call EndMenu() if BeginMenu() returns true! 592 IMGUI_API bool MenuItem(const char* label, const char* shortcut = NULL, bool selected = false, bool enabled = true); // return true when activated. shortcuts are displayed for convenience but not processed by ImGui at the moment 593 IMGUI_API bool MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled = true); // return true when activated + toggle (*p_selected) if p_selected != NULL 594 595 // Tooltips 596 // - Tooltip are windows following the mouse which do not take focus away. 597 IMGUI_API void BeginTooltip(); // begin/append a tooltip window. to create full-featured tooltip (with any kind of items). 598 IMGUI_API void EndTooltip(); 599 IMGUI_API void SetTooltip(const char* fmt, ...) IM_FMTARGS(1); // set a text-only tooltip, typically use with ImGui::IsItemHovered(). override any previous call to SetTooltip(). 600 IMGUI_API void SetTooltipV(const char* fmt, va_list args) IM_FMTLIST(1); 601 602 // Popups, Modals 603 // - They block normal mouse hovering detection (and therefore most mouse interactions) behind them. 604 // - If not modal: they can be closed by clicking anywhere outside them, or by pressing ESCAPE. 605 // - Their visibility state (~bool) is held internally instead of being held by the programmer as we are used to with regular Begin*() calls. 606 // - The 3 properties above are related: we need to retain popup visibility state in the library because popups may be closed as any time. 607 // - You can bypass the hovering restriction by using ImGuiHoveredFlags_AllowWhenBlockedByPopup when calling IsItemHovered() or IsWindowHovered(). 608 // - IMPORTANT: Popup identifiers are relative to the current ID stack, so OpenPopup and BeginPopup generally needs to be at the same level of the stack. 609 // This is sometimes leading to confusing mistakes. May rework this in the future. 610 // Popups: begin/end functions 611 // - BeginPopup(): query popup state, if open start appending into the window. Call EndPopup() afterwards. ImGuiWindowFlags are forwarded to the window. 612 // - BeginPopupModal(): block every interactions behind the window, cannot be closed by user, add a dimming background, has a title bar. 613 IMGUI_API bool BeginPopup(const char* str_id, ImGuiWindowFlags flags = 0); // return true if the popup is open, and you can start outputting to it. 614 IMGUI_API bool BeginPopupModal(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); // return true if the modal is open, and you can start outputting to it. 615 IMGUI_API void EndPopup(); // only call EndPopup() if BeginPopupXXX() returns true! 616 // Popups: open/close functions 617 // - OpenPopup(): set popup state to open. ImGuiPopupFlags are available for opening options. 618 // - If not modal: they can be closed by clicking anywhere outside them, or by pressing ESCAPE. 619 // - CloseCurrentPopup(): use inside the BeginPopup()/EndPopup() scope to close manually. 620 // - CloseCurrentPopup() is called by default by Selectable()/MenuItem() when activated (FIXME: need some options). 621 // - Use ImGuiPopupFlags_NoOpenOverExistingPopup to avoid opening a popup if there's already one at the same level. This is equivalent to e.g. testing for !IsAnyPopupOpen() prior to OpenPopup(). 622 IMGUI_API void OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags = 0); // call to mark popup as open (don't call every frame!). 623 IMGUI_API void OpenPopupOnItemClick(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // helper to open popup when clicked on last item. return true when just opened. (note: actually triggers on the mouse _released_ event to be consistent with popup behaviors) 624 IMGUI_API void CloseCurrentPopup(); // manually close the popup we have begin-ed into. 625 // Popups: open+begin combined functions helpers 626 // - Helpers to do OpenPopup+BeginPopup where the Open action is triggered by e.g. hovering an item and right-clicking. 627 // - They are convenient to easily create context menus, hence the name. 628 // - IMPORTANT: Notice that BeginPopupContextXXX takes ImGuiPopupFlags just like OpenPopup() and unlike BeginPopup(). For full consistency, we may add ImGuiWindowFlags to the BeginPopupContextXXX functions in the future. 629 // - IMPORTANT: we exceptionally default their flags to 1 (== ImGuiPopupFlags_MouseButtonRight) for backward compatibility with older API taking 'int mouse_button = 1' parameter, so if you add other flags remember to re-add the ImGuiPopupFlags_MouseButtonRight. 630 IMGUI_API bool BeginPopupContextItem(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // open+begin popup when clicked on last item. if you can pass a NULL str_id only if the previous item had an id. If you want to use that on a non-interactive item such as Text() you need to pass in an explicit ID here. read comments in .cpp! 631 IMGUI_API bool BeginPopupContextWindow(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1);// open+begin popup when clicked on current window. 632 IMGUI_API bool BeginPopupContextVoid(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // open+begin popup when clicked in void (where there are no windows). 633 // Popups: test function 634 // - IsPopupOpen(): return true if the popup is open at the current BeginPopup() level of the popup stack. 635 // - IsPopupOpen() with ImGuiPopupFlags_AnyPopupId: return true if any popup is open at the current BeginPopup() level of the popup stack. 636 // - IsPopupOpen() with ImGuiPopupFlags_AnyPopupId + ImGuiPopupFlags_AnyPopupLevel: return true if any popup is open. 637 IMGUI_API bool IsPopupOpen(const char* str_id, ImGuiPopupFlags flags = 0); // return true if the popup is open. 638 639 // Columns 640 // - You can also use SameLine(pos_x) to mimic simplified columns. 641 // - The columns API is work-in-progress and rather lacking (columns are arguably the worst part of dear imgui at the moment!) 642 // - There is a maximum of 64 columns. 643 // - Currently working on new 'Tables' api which will replace columns around Q2 2020 (see GitHub #2957). 644 IMGUI_API void Columns(int count = 1, const char* id = NULL, bool border = true); 645 IMGUI_API void NextColumn(); // next column, defaults to current row or next row if the current row is finished 646 IMGUI_API int GetColumnIndex(); // get current column index 647 IMGUI_API float GetColumnWidth(int column_index = -1); // get column width (in pixels). pass -1 to use current column 648 IMGUI_API void SetColumnWidth(int column_index, float width); // set column width (in pixels). pass -1 to use current column 649 IMGUI_API float GetColumnOffset(int column_index = -1); // get position of column line (in pixels, from the left side of the contents region). pass -1 to use current column, otherwise 0..GetColumnsCount() inclusive. column 0 is typically 0.0f 650 IMGUI_API void SetColumnOffset(int column_index, float offset_x); // set position of column line (in pixels, from the left side of the contents region). pass -1 to use current column 651 IMGUI_API int GetColumnsCount(); 652 653 // Tab Bars, Tabs 654 IMGUI_API bool BeginTabBar(const char* str_id, ImGuiTabBarFlags flags = 0); // create and append into a TabBar 655 IMGUI_API void EndTabBar(); // only call EndTabBar() if BeginTabBar() returns true! 656 IMGUI_API bool BeginTabItem(const char* label, bool* p_open = NULL, ImGuiTabItemFlags flags = 0); // create a Tab. Returns true if the Tab is selected. 657 IMGUI_API void EndTabItem(); // only call EndTabItem() if BeginTabItem() returns true! 658 IMGUI_API bool TabItemButton(const char* label, ImGuiTabItemFlags flags = 0); // create a Tab behaving like a button. return true when clicked. cannot be selected in the tab bar. 659 IMGUI_API void SetTabItemClosed(const char* tab_or_docked_window_label); // notify TabBar or Docking system of a closed tab/window ahead (useful to reduce visual flicker on reorderable tab bars). For tab-bar: call after BeginTabBar() and before Tab submissions. Otherwise call with a window name. 660 661 // Logging/Capture 662 // - All text output from the interface can be captured into tty/file/clipboard. By default, tree nodes are automatically opened during logging. 663 IMGUI_API void LogToTTY(int auto_open_depth = -1); // start logging to tty (stdout) 664 IMGUI_API void LogToFile(int auto_open_depth = -1, const char* filename = NULL); // start logging to file 665 IMGUI_API void LogToClipboard(int auto_open_depth = -1); // start logging to OS clipboard 666 IMGUI_API void LogFinish(); // stop logging (close file, etc.) 667 IMGUI_API void LogButtons(); // helper to display buttons for logging to tty/file/clipboard 668 IMGUI_API void LogText(const char* fmt, ...) IM_FMTARGS(1); // pass text data straight to log (without being displayed) 669 670 // Drag and Drop 671 // - [BETA API] API may evolve! 672 // - If you stop calling BeginDragDropSource() the payload is preserved however it won't have a preview tooltip (we currently display a fallback "..." tooltip as replacement) 673 IMGUI_API bool BeginDragDropSource(ImGuiDragDropFlags flags = 0); // call when the current item is active. If this return true, you can call SetDragDropPayload() + EndDragDropSource() 674 IMGUI_API bool SetDragDropPayload(const char* type, const void* data, size_t sz, ImGuiCond cond = 0); // type is a user defined string of maximum 32 characters. Strings starting with '_' are reserved for dear imgui internal types. Data is copied and held by imgui. 675 IMGUI_API void EndDragDropSource(); // only call EndDragDropSource() if BeginDragDropSource() returns true! 676 IMGUI_API bool BeginDragDropTarget(); // call after submitting an item that may receive a payload. If this returns true, you can call AcceptDragDropPayload() + EndDragDropTarget() 677 IMGUI_API const ImGuiPayload* AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags = 0); // accept contents of a given type. If ImGuiDragDropFlags_AcceptBeforeDelivery is set you can peek into the payload before the mouse button is released. 678 IMGUI_API void EndDragDropTarget(); // only call EndDragDropTarget() if BeginDragDropTarget() returns true! 679 IMGUI_API const ImGuiPayload* GetDragDropPayload(); // peek directly into the current payload from anywhere. may return NULL. use ImGuiPayload::IsDataType() to test for the payload type. 680 681 // Clipping 682 IMGUI_API void PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect); 683 IMGUI_API void PopClipRect(); 684 685 // Focus, Activation 686 // - Prefer using "SetItemDefaultFocus()" over "if (IsWindowAppearing()) SetScrollHereY()" when applicable to signify "this is the default item" 687 IMGUI_API void SetItemDefaultFocus(); // make last item the default focused item of a window. 688 IMGUI_API void SetKeyboardFocusHere(int offset = 0); // focus keyboard on the next widget. Use positive 'offset' to access sub components of a multiple component widget. Use -1 to access previous widget. 689 690 // Item/Widgets Utilities 691 // - Most of the functions are referring to the last/previous item we submitted. 692 // - See Demo Window under "Widgets->Querying Status" for an interactive visualization of most of those functions. 693 IMGUI_API bool IsItemHovered(ImGuiHoveredFlags flags = 0); // is the last item hovered? (and usable, aka not blocked by a popup, etc.). See ImGuiHoveredFlags for more options. 694 IMGUI_API bool IsItemActive(); // is the last item active? (e.g. button being held, text field being edited. This will continuously return true while holding mouse button on an item. Items that don't interact will always return false) 695 IMGUI_API bool IsItemFocused(); // is the last item focused for keyboard/gamepad navigation? 696 IMGUI_API bool IsItemClicked(ImGuiMouseButton mouse_button = 0); // is the last item clicked? (e.g. button/node just clicked on) == IsMouseClicked(mouse_button) && IsItemHovered() 697 IMGUI_API bool IsItemVisible(); // is the last item visible? (items may be out of sight because of clipping/scrolling) 698 IMGUI_API bool IsItemEdited(); // did the last item modify its underlying value this frame? or was pressed? This is generally the same as the "bool" return value of many widgets. 699 IMGUI_API bool IsItemActivated(); // was the last item just made active (item was previously inactive). 700 IMGUI_API bool IsItemDeactivated(); // was the last item just made inactive (item was previously active). Useful for Undo/Redo patterns with widgets that requires continuous editing. 701 IMGUI_API bool IsItemDeactivatedAfterEdit(); // was the last item just made inactive and made a value change when it was active? (e.g. Slider/Drag moved). Useful for Undo/Redo patterns with widgets that requires continuous editing. Note that you may get false positives (some widgets such as Combo()/ListBox()/Selectable() will return true even when clicking an already selected item). 702 IMGUI_API bool IsItemToggledOpen(); // was the last item open state toggled? set by TreeNode(). 703 IMGUI_API bool IsAnyItemHovered(); // is any item hovered? 704 IMGUI_API bool IsAnyItemActive(); // is any item active? 705 IMGUI_API bool IsAnyItemFocused(); // is any item focused? 706 IMGUI_API ImVec2 GetItemRectMin(); // get upper-left bounding rectangle of the last item (screen space) 707 IMGUI_API ImVec2 GetItemRectMax(); // get lower-right bounding rectangle of the last item (screen space) 708 IMGUI_API ImVec2 GetItemRectSize(); // get size of last item 709 IMGUI_API void SetItemAllowOverlap(); // allow last item to be overlapped by a subsequent item. sometimes useful with invisible buttons, selectables, etc. to catch unused area. 710 711 // Miscellaneous Utilities 712 IMGUI_API bool IsRectVisible(const ImVec2& size); // test if rectangle (of given size, starting from cursor position) is visible / not clipped. 713 IMGUI_API bool IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max); // test if rectangle (in screen space) is visible / not clipped. to perform coarse clipping on user's side. 714 IMGUI_API double GetTime(); // get global imgui time. incremented by io.DeltaTime every frame. 715 IMGUI_API int GetFrameCount(); // get global imgui frame count. incremented by 1 every frame. 716 IMGUI_API ImDrawList* GetBackgroundDrawList(); // this draw list will be the first rendering one. Useful to quickly draw shapes/text behind dear imgui contents. 717 IMGUI_API ImDrawList* GetForegroundDrawList(); // this draw list will be the last rendered one. Useful to quickly draw shapes/text over dear imgui contents. 718 IMGUI_API ImDrawListSharedData* GetDrawListSharedData(); // you may use this when creating your own ImDrawList instances. 719 IMGUI_API const char* GetStyleColorName(ImGuiCol idx); // get a string corresponding to the enum value (for display, saving, etc.). 720 IMGUI_API void SetStateStorage(ImGuiStorage* storage); // replace current window storage with our own (if you want to manipulate it yourself, typically clear subsection of it) 721 IMGUI_API ImGuiStorage* GetStateStorage(); 722 IMGUI_API void CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end); // calculate coarse clipping for large list of evenly sized items. Prefer using the ImGuiListClipper higher-level helper if you can. 723 IMGUI_API bool BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags flags = 0); // helper to create a child window / scrolling region that looks like a normal widget frame 724 IMGUI_API void EndChildFrame(); // always call EndChildFrame() regardless of BeginChildFrame() return values (which indicates a collapsed/clipped window) 725 726 // Text Utilities 727 IMGUI_API ImVec2 CalcTextSize(const char* text, const char* text_end = NULL, bool hide_text_after_double_hash = false, float wrap_width = -1.0f); 728 729 // Color Utilities 730 IMGUI_API ImVec4 ColorConvertU32ToFloat4(ImU32 in); 731 IMGUI_API ImU32 ColorConvertFloat4ToU32(const ImVec4& in); 732 IMGUI_API void ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v); 733 IMGUI_API void ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b); 734 735 // Inputs Utilities: Keyboard 736 // - For 'int user_key_index' you can use your own indices/enums according to how your back-end/engine stored them in io.KeysDown[]. 737 // - We don't know the meaning of those value. You can use GetKeyIndex() to map a ImGuiKey_ value into the user index. 738 IMGUI_API int GetKeyIndex(ImGuiKey imgui_key); // map ImGuiKey_* values into user's key index. == io.KeyMap[key] 739 IMGUI_API bool IsKeyDown(int user_key_index); // is key being held. == io.KeysDown[user_key_index]. 740 IMGUI_API bool IsKeyPressed(int user_key_index, bool repeat = true); // was key pressed (went from !Down to Down)? if repeat=true, uses io.KeyRepeatDelay / KeyRepeatRate 741 IMGUI_API bool IsKeyReleased(int user_key_index); // was key released (went from Down to !Down)? 742 IMGUI_API int GetKeyPressedAmount(int key_index, float repeat_delay, float rate); // uses provided repeat rate/delay. return a count, most often 0 or 1 but might be >1 if RepeatRate is small enough that DeltaTime > RepeatRate 743 IMGUI_API void CaptureKeyboardFromApp(bool want_capture_keyboard_value = true); // attention: misleading name! manually override io.WantCaptureKeyboard flag next frame (said flag is entirely left for your application to handle). e.g. force capture keyboard when your widget is being hovered. This is equivalent to setting "io.WantCaptureKeyboard = want_capture_keyboard_value"; after the next NewFrame() call. 744 745 // Inputs Utilities: Mouse 746 // - To refer to a mouse button, you may use named enums in your code e.g. ImGuiMouseButton_Left, ImGuiMouseButton_Right. 747 // - You can also use regular integer: it is forever guaranteed that 0=Left, 1=Right, 2=Middle. 748 // - Dragging operations are only reported after mouse has moved a certain distance away from the initial clicking position (see 'lock_threshold' and 'io.MouseDraggingThreshold') 749 IMGUI_API bool IsMouseDown(ImGuiMouseButton button); // is mouse button held? 750 IMGUI_API bool IsMouseClicked(ImGuiMouseButton button, bool repeat = false); // did mouse button clicked? (went from !Down to Down) 751 IMGUI_API bool IsMouseReleased(ImGuiMouseButton button); // did mouse button released? (went from Down to !Down) 752 IMGUI_API bool IsMouseDoubleClicked(ImGuiMouseButton button); // did mouse button double-clicked? (note that a double-click will also report IsMouseClicked() == true) 753 IMGUI_API bool IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip = true);// is mouse hovering given bounding rect (in screen space). clipped by current clipping settings, but disregarding of other consideration of focus/window ordering/popup-block. 754 IMGUI_API bool IsMousePosValid(const ImVec2* mouse_pos = NULL); // by convention we use (-FLT_MAX,-FLT_MAX) to denote that there is no mouse available 755 IMGUI_API bool IsAnyMouseDown(); // is any mouse button held? 756 IMGUI_API ImVec2 GetMousePos(); // shortcut to ImGui::GetIO().MousePos provided by user, to be consistent with other calls 757 IMGUI_API ImVec2 GetMousePosOnOpeningCurrentPopup(); // retrieve mouse position at the time of opening popup we have BeginPopup() into (helper to avoid user backing that value themselves) 758 IMGUI_API bool IsMouseDragging(ImGuiMouseButton button, float lock_threshold = -1.0f); // is mouse dragging? (if lock_threshold < -1.0f, uses io.MouseDraggingThreshold) 759 IMGUI_API ImVec2 GetMouseDragDelta(ImGuiMouseButton button = 0, float lock_threshold = -1.0f); // return the delta from the initial clicking position while the mouse button is pressed or was just released. This is locked and return 0.0f until the mouse moves past a distance threshold at least once (if lock_threshold < -1.0f, uses io.MouseDraggingThreshold) 760 IMGUI_API void ResetMouseDragDelta(ImGuiMouseButton button = 0); // 761 IMGUI_API ImGuiMouseCursor GetMouseCursor(); // get desired cursor type, reset in ImGui::NewFrame(), this is updated during the frame. valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui will render those for you 762 IMGUI_API void SetMouseCursor(ImGuiMouseCursor cursor_type); // set desired cursor type 763 IMGUI_API void CaptureMouseFromApp(bool want_capture_mouse_value = true); // attention: misleading name! manually override io.WantCaptureMouse flag next frame (said flag is entirely left for your application to handle). This is equivalent to setting "io.WantCaptureMouse = want_capture_mouse_value;" after the next NewFrame() call. 764 765 // Clipboard Utilities 766 // - Also see the LogToClipboard() function to capture GUI into clipboard, or easily output text data to the clipboard. 767 IMGUI_API const char* GetClipboardText(); 768 IMGUI_API void SetClipboardText(const char* text); 769 770 // Settings/.Ini Utilities 771 // - The disk functions are automatically called if io.IniFilename != NULL (default is "imgui.ini"). 772 // - Set io.IniFilename to NULL to load/save manually. Read io.WantSaveIniSettings description about handling .ini saving manually. 773 IMGUI_API void LoadIniSettingsFromDisk(const char* ini_filename); // call after CreateContext() and before the first call to NewFrame(). NewFrame() automatically calls LoadIniSettingsFromDisk(io.IniFilename). 774 IMGUI_API void LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size=0); // call after CreateContext() and before the first call to NewFrame() to provide .ini data from your own data source. 775 IMGUI_API void SaveIniSettingsToDisk(const char* ini_filename); // this is automatically called (if io.IniFilename is not empty) a few seconds after any modification that should be reflected in the .ini file (and also by DestroyContext). 776 IMGUI_API const char* SaveIniSettingsToMemory(size_t* out_ini_size = NULL); // return a zero-terminated string with the .ini data which you can save by your own mean. call when io.WantSaveIniSettings is set, then save data by your own mean and clear io.WantSaveIniSettings. 777 778 // Debug Utilities 779 IMGUI_API bool DebugCheckVersionAndDataLayout(const char* version_str, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_drawvert, size_t sz_drawidx); // This is called by IMGUI_CHECKVERSION() macro. 780 781 // Memory Allocators 782 // - All those functions are not reliant on the current context. 783 // - If you reload the contents of imgui.cpp at runtime, you may need to call SetCurrentContext() + SetAllocatorFunctions() again because we use global storage for those. 784 IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data = NULL); 785 IMGUI_API void* MemAlloc(size_t size); 786 IMGUI_API void MemFree(void* ptr); 553 787 554 788 } // namespace ImGui 555 789 556 // Flags for ImGui::Begin() 790 //----------------------------------------------------------------------------- 791 // Flags & Enumerations 792 //----------------------------------------------------------------------------- 793 794 // Flags for ImGui::Begin() 557 795 enum ImGuiWindowFlags_ 558 796 { 559 ImGuiWindowFlags_NoTitleBar = 1 << 0, // Disable title-bar 560 ImGuiWindowFlags_NoResize = 1 << 1, // Disable user resizing with the lower-right grip 561 ImGuiWindowFlags_NoMove = 1 << 2, // Disable user moving the window 562 ImGuiWindowFlags_NoScrollbar = 1 << 3, // Disable scrollbars (window can still scroll with mouse or programatically) 563 ImGuiWindowFlags_NoScrollWithMouse = 1 << 4, // Disable user vertically scrolling with mouse wheel. On child window, mouse wheel will be forwarded to the parent unless NoScrollbar is also set. 564 ImGuiWindowFlags_NoCollapse = 1 << 5, // Disable user collapsing window by double-clicking on it 565 ImGuiWindowFlags_AlwaysAutoResize = 1 << 6, // Resize every window to its content every frame 566 //ImGuiWindowFlags_ShowBorders = 1 << 7, // Show borders around windows and items (OBSOLETE! Use e.g. style.FrameBorderSize=1.0f to enable borders). 567 ImGuiWindowFlags_NoSavedSettings = 1 << 8, // Never load/save settings in .ini file 568 ImGuiWindowFlags_NoInputs = 1 << 9, // Disable catching mouse or keyboard inputs, hovering test with pass through. 569 ImGuiWindowFlags_MenuBar = 1 << 10, // Has a menu-bar 570 ImGuiWindowFlags_HorizontalScrollbar = 1 << 11, // Allow horizontal scrollbar to appear (off by default). You may use SetNextWindowContentSize(ImVec2(width,0.0f)); prior to calling Begin() to specify width. Read code in imgui_demo in the "Horizontal Scrolling" section. 571 ImGuiWindowFlags_NoFocusOnAppearing = 1 << 12, // Disable taking focus when transitioning from hidden to visible state 572 ImGuiWindowFlags_NoBringToFrontOnFocus = 1 << 13, // Disable bringing window to front when taking focus (e.g. clicking on it or programatically giving it focus) 573 ImGuiWindowFlags_AlwaysVerticalScrollbar = 1 << 14, // Always show vertical scrollbar (even if ContentSize.y < Size.y) 574 ImGuiWindowFlags_AlwaysHorizontalScrollbar = 1 << 15, // Always show horizontal scrollbar (even if ContentSize.x < Size.x) 575 ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 16, // Ensure child windows without border uses style.WindowPadding (ignored by default for non-bordered child windows, because more convenient) 576 ImGuiWindowFlags_ResizeFromAnySide = 1 << 17, // [BETA] Enable resize from any corners and borders. Your back-end needs to honor the different values of io.MouseCursor set by imgui. 577 ImGuiWindowFlags_NoNavInputs = 1 << 18, // No gamepad/keyboard navigation within the window 578 ImGuiWindowFlags_NoNavFocus = 1 << 19, // No focusing toward this window with gamepad/keyboard navigation (e.g. skipped by CTRL+TAB) 579 ImGuiWindowFlags_NoNav = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, 580 581 // [Internal] 582 ImGuiWindowFlags_NavFlattened = 1 << 23, // [BETA] Allow gamepad/keyboard navigation to cross over parent border to this child (only use on child that have no scrolling!) 583 ImGuiWindowFlags_ChildWindow = 1 << 24, // Don't use! For internal use by BeginChild() 584 ImGuiWindowFlags_Tooltip = 1 << 25, // Don't use! For internal use by BeginTooltip() 585 ImGuiWindowFlags_Popup = 1 << 26, // Don't use! For internal use by BeginPopup() 586 ImGuiWindowFlags_Modal = 1 << 27, // Don't use! For internal use by BeginPopupModal() 587 ImGuiWindowFlags_ChildMenu = 1 << 28 // Don't use! For internal use by BeginMenu() 797 ImGuiWindowFlags_None = 0, 798 ImGuiWindowFlags_NoTitleBar = 1 << 0, // Disable title-bar 799 ImGuiWindowFlags_NoResize = 1 << 1, // Disable user resizing with the lower-right grip 800 ImGuiWindowFlags_NoMove = 1 << 2, // Disable user moving the window 801 ImGuiWindowFlags_NoScrollbar = 1 << 3, // Disable scrollbars (window can still scroll with mouse or programmatically) 802 ImGuiWindowFlags_NoScrollWithMouse = 1 << 4, // Disable user vertically scrolling with mouse wheel. On child window, mouse wheel will be forwarded to the parent unless NoScrollbar is also set. 803 ImGuiWindowFlags_NoCollapse = 1 << 5, // Disable user collapsing window by double-clicking on it 804 ImGuiWindowFlags_AlwaysAutoResize = 1 << 6, // Resize every window to its content every frame 805 ImGuiWindowFlags_NoBackground = 1 << 7, // Disable drawing background color (WindowBg, etc.) and outside border. Similar as using SetNextWindowBgAlpha(0.0f). 806 ImGuiWindowFlags_NoSavedSettings = 1 << 8, // Never load/save settings in .ini file 807 ImGuiWindowFlags_NoMouseInputs = 1 << 9, // Disable catching mouse, hovering test with pass through. 808 ImGuiWindowFlags_MenuBar = 1 << 10, // Has a menu-bar 809 ImGuiWindowFlags_HorizontalScrollbar = 1 << 11, // Allow horizontal scrollbar to appear (off by default). You may use SetNextWindowContentSize(ImVec2(width,0.0f)); prior to calling Begin() to specify width. Read code in imgui_demo in the "Horizontal Scrolling" section. 810 ImGuiWindowFlags_NoFocusOnAppearing = 1 << 12, // Disable taking focus when transitioning from hidden to visible state 811 ImGuiWindowFlags_NoBringToFrontOnFocus = 1 << 13, // Disable bringing window to front when taking focus (e.g. clicking on it or programmatically giving it focus) 812 ImGuiWindowFlags_AlwaysVerticalScrollbar= 1 << 14, // Always show vertical scrollbar (even if ContentSize.y < Size.y) 813 ImGuiWindowFlags_AlwaysHorizontalScrollbar=1<< 15, // Always show horizontal scrollbar (even if ContentSize.x < Size.x) 814 ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 16, // Ensure child windows without border uses style.WindowPadding (ignored by default for non-bordered child windows, because more convenient) 815 ImGuiWindowFlags_NoNavInputs = 1 << 18, // No gamepad/keyboard navigation within the window 816 ImGuiWindowFlags_NoNavFocus = 1 << 19, // No focusing toward this window with gamepad/keyboard navigation (e.g. skipped by CTRL+TAB) 817 ImGuiWindowFlags_UnsavedDocument = 1 << 20, // Append '*' to title without affecting the ID, as a convenience to avoid using the ### operator. When used in a tab/docking context, tab is selected on closure and closure is deferred by one frame to allow code to cancel the closure (with a confirmation popup, etc.) without flicker. 818 ImGuiWindowFlags_NoNav = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, 819 ImGuiWindowFlags_NoDecoration = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse, 820 ImGuiWindowFlags_NoInputs = ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, 821 822 // [Internal] 823 ImGuiWindowFlags_NavFlattened = 1 << 23, // [BETA] Allow gamepad/keyboard navigation to cross over parent border to this child (only use on child that have no scrolling!) 824 ImGuiWindowFlags_ChildWindow = 1 << 24, // Don't use! For internal use by BeginChild() 825 ImGuiWindowFlags_Tooltip = 1 << 25, // Don't use! For internal use by BeginTooltip() 826 ImGuiWindowFlags_Popup = 1 << 26, // Don't use! For internal use by BeginPopup() 827 ImGuiWindowFlags_Modal = 1 << 27, // Don't use! For internal use by BeginPopupModal() 828 ImGuiWindowFlags_ChildMenu = 1 << 28 // Don't use! For internal use by BeginMenu() 829 830 // [Obsolete] 831 //ImGuiWindowFlags_ShowBorders = 1 << 7, // --> Set style.FrameBorderSize=1.0f or style.WindowBorderSize=1.0f to enable borders around items or windows. 832 //ImGuiWindowFlags_ResizeFromAnySide = 1 << 17, // --> Set io.ConfigWindowsResizeFromEdges=true and make sure mouse cursors are supported by back-end (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) 588 833 }; 589 834 … … 591 836 enum ImGuiInputTextFlags_ 592 837 { 593 ImGuiInputTextFlags_CharsDecimal = 1 << 0, // Allow 0123456789.+-*/ 594 ImGuiInputTextFlags_CharsHexadecimal = 1 << 1, // Allow 0123456789ABCDEFabcdef 595 ImGuiInputTextFlags_CharsUppercase = 1 << 2, // Turn a..z into A..Z 596 ImGuiInputTextFlags_CharsNoBlank = 1 << 3, // Filter out spaces, tabs 597 ImGuiInputTextFlags_AutoSelectAll = 1 << 4, // Select entire text when first taking mouse focus 598 ImGuiInputTextFlags_EnterReturnsTrue = 1 << 5, // Return 'true' when Enter is pressed (as opposed to when the value was modified) 599 ImGuiInputTextFlags_CallbackCompletion = 1 << 6, // Call user function on pressing TAB (for completion handling) 600 ImGuiInputTextFlags_CallbackHistory = 1 << 7, // Call user function on pressing Up/Down arrows (for history handling) 601 ImGuiInputTextFlags_CallbackAlways = 1 << 8, // Call user function every time. User code may query cursor position, modify text buffer. 602 ImGuiInputTextFlags_CallbackCharFilter = 1 << 9, // Call user function to filter character. Modify data->EventChar to replace/filter input, or return 1 to discard character. 603 ImGuiInputTextFlags_AllowTabInput = 1 << 10, // Pressing TAB input a '\t' character into the text field 604 ImGuiInputTextFlags_CtrlEnterForNewLine = 1 << 11, // In multi-line mode, unfocus with Enter, add new line with Ctrl+Enter (default is opposite: unfocus with Ctrl+Enter, add line with Enter). 605 ImGuiInputTextFlags_NoHorizontalScroll = 1 << 12, // Disable following the cursor horizontally 606 ImGuiInputTextFlags_AlwaysInsertMode = 1 << 13, // Insert mode 607 ImGuiInputTextFlags_ReadOnly = 1 << 14, // Read-only mode 608 ImGuiInputTextFlags_Password = 1 << 15, // Password mode, display all characters as '*' 609 ImGuiInputTextFlags_NoUndoRedo = 1 << 16, // Disable undo/redo. Note that input text owns the text data while active, if you want to provide your own undo/redo stack you need e.g. to call ClearActiveID(). 610 ImGuiInputTextFlags_CharsScientific = 1 << 17, // Allow 0123456789.+-*/eE (Scientific notation input) 611 // [Internal] 612 ImGuiInputTextFlags_Multiline = 1 << 20 // For internal use by InputTextMultiline() 838 ImGuiInputTextFlags_None = 0, 839 ImGuiInputTextFlags_CharsDecimal = 1 << 0, // Allow 0123456789.+-*/ 840 ImGuiInputTextFlags_CharsHexadecimal = 1 << 1, // Allow 0123456789ABCDEFabcdef 841 ImGuiInputTextFlags_CharsUppercase = 1 << 2, // Turn a..z into A..Z 842 ImGuiInputTextFlags_CharsNoBlank = 1 << 3, // Filter out spaces, tabs 843 ImGuiInputTextFlags_AutoSelectAll = 1 << 4, // Select entire text when first taking mouse focus 844 ImGuiInputTextFlags_EnterReturnsTrue = 1 << 5, // Return 'true' when Enter is pressed (as opposed to every time the value was modified). Consider looking at the IsItemDeactivatedAfterEdit() function. 845 ImGuiInputTextFlags_CallbackCompletion = 1 << 6, // Callback on pressing TAB (for completion handling) 846 ImGuiInputTextFlags_CallbackHistory = 1 << 7, // Callback on pressing Up/Down arrows (for history handling) 847 ImGuiInputTextFlags_CallbackAlways = 1 << 8, // Callback on each iteration. User code may query cursor position, modify text buffer. 848 ImGuiInputTextFlags_CallbackCharFilter = 1 << 9, // Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard. 849 ImGuiInputTextFlags_AllowTabInput = 1 << 10, // Pressing TAB input a '\t' character into the text field 850 ImGuiInputTextFlags_CtrlEnterForNewLine = 1 << 11, // In multi-line mode, unfocus with Enter, add new line with Ctrl+Enter (default is opposite: unfocus with Ctrl+Enter, add line with Enter). 851 ImGuiInputTextFlags_NoHorizontalScroll = 1 << 12, // Disable following the cursor horizontally 852 ImGuiInputTextFlags_AlwaysInsertMode = 1 << 13, // Insert mode 853 ImGuiInputTextFlags_ReadOnly = 1 << 14, // Read-only mode 854 ImGuiInputTextFlags_Password = 1 << 15, // Password mode, display all characters as '*' 855 ImGuiInputTextFlags_NoUndoRedo = 1 << 16, // Disable undo/redo. Note that input text owns the text data while active, if you want to provide your own undo/redo stack you need e.g. to call ClearActiveID(). 856 ImGuiInputTextFlags_CharsScientific = 1 << 17, // Allow 0123456789.+-*/eE (Scientific notation input) 857 ImGuiInputTextFlags_CallbackResize = 1 << 18, // Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. Notify when the string wants to be resized (for string types which hold a cache of their Size). You will be provided a new BufSize in the callback and NEED to honor it. (see misc/cpp/imgui_stdlib.h for an example of using this) 858 ImGuiInputTextFlags_CallbackEdit = 1 << 19, // Callback on any edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active) 859 // [Internal] 860 ImGuiInputTextFlags_Multiline = 1 << 20, // For internal use by InputTextMultiline() 861 ImGuiInputTextFlags_NoMarkEdited = 1 << 21 // For internal use by functions using InputText() before reformatting data 613 862 }; 614 863 … … 616 865 enum ImGuiTreeNodeFlags_ 617 866 { 618 ImGuiTreeNodeFlags_Selected = 1 << 0, // Draw as selected 619 ImGuiTreeNodeFlags_Framed = 1 << 1, // Full colored frame (e.g. for CollapsingHeader) 620 ImGuiTreeNodeFlags_AllowItemOverlap = 1 << 2, // Hit testing to allow subsequent widgets to overlap this one 621 ImGuiTreeNodeFlags_NoTreePushOnOpen = 1 << 3, // Don't do a TreePush() when open (e.g. for CollapsingHeader) = no extra indent nor pushing on ID stack 622 ImGuiTreeNodeFlags_NoAutoOpenOnLog = 1 << 4, // Don't automatically and temporarily open node when Logging is active (by default logging will automatically open tree nodes) 623 ImGuiTreeNodeFlags_DefaultOpen = 1 << 5, // Default node to be open 624 ImGuiTreeNodeFlags_OpenOnDoubleClick = 1 << 6, // Need double-click to open node 625 ImGuiTreeNodeFlags_OpenOnArrow = 1 << 7, // Only open when clicking on the arrow part. If ImGuiTreeNodeFlags_OpenOnDoubleClick is also set, single-click arrow or double-click all box to open. 626 ImGuiTreeNodeFlags_Leaf = 1 << 8, // No collapsing, no arrow (use as a convenience for leaf nodes). 627 ImGuiTreeNodeFlags_Bullet = 1 << 9, // Display a bullet instead of arrow 628 ImGuiTreeNodeFlags_FramePadding = 1 << 10, // Use FramePadding (even for an unframed text node) to vertically align text baseline to regular widget height. Equivalent to calling AlignTextToFramePadding(). 629 //ImGuITreeNodeFlags_SpanAllAvailWidth = 1 << 11, // FIXME: TODO: Extend hit box horizontally even if not framed 630 //ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 12, // FIXME: TODO: Disable automatic scroll on TreePop() if node got just open and contents is not visible 631 ImGuiTreeNodeFlags_NavLeftJumpsBackHere = 1 << 13, // (WIP) Nav: left direction may move to this TreeNode() from any of its child (items submitted between TreeNode and TreePop) 632 ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoAutoOpenOnLog 633 634 // Obsolete names (will be removed) 635 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS 636 , ImGuiTreeNodeFlags_AllowOverlapMode = ImGuiTreeNodeFlags_AllowItemOverlap 637 #endif 867 ImGuiTreeNodeFlags_None = 0, 868 ImGuiTreeNodeFlags_Selected = 1 << 0, // Draw as selected 869 ImGuiTreeNodeFlags_Framed = 1 << 1, // Full colored frame (e.g. for CollapsingHeader) 870 ImGuiTreeNodeFlags_AllowItemOverlap = 1 << 2, // Hit testing to allow subsequent widgets to overlap this one 871 ImGuiTreeNodeFlags_NoTreePushOnOpen = 1 << 3, // Don't do a TreePush() when open (e.g. for CollapsingHeader) = no extra indent nor pushing on ID stack 872 ImGuiTreeNodeFlags_NoAutoOpenOnLog = 1 << 4, // Don't automatically and temporarily open node when Logging is active (by default logging will automatically open tree nodes) 873 ImGuiTreeNodeFlags_DefaultOpen = 1 << 5, // Default node to be open 874 ImGuiTreeNodeFlags_OpenOnDoubleClick = 1 << 6, // Need double-click to open node 875 ImGuiTreeNodeFlags_OpenOnArrow = 1 << 7, // Only open when clicking on the arrow part. If ImGuiTreeNodeFlags_OpenOnDoubleClick is also set, single-click arrow or double-click all box to open. 876 ImGuiTreeNodeFlags_Leaf = 1 << 8, // No collapsing, no arrow (use as a convenience for leaf nodes). 877 ImGuiTreeNodeFlags_Bullet = 1 << 9, // Display a bullet instead of arrow 878 ImGuiTreeNodeFlags_FramePadding = 1 << 10, // Use FramePadding (even for an unframed text node) to vertically align text baseline to regular widget height. Equivalent to calling AlignTextToFramePadding(). 879 ImGuiTreeNodeFlags_SpanAvailWidth = 1 << 11, // Extend hit box to the right-most edge, even if not framed. This is not the default in order to allow adding other items on the same line. In the future we may refactor the hit system to be front-to-back, allowing natural overlaps and then this can become the default. 880 ImGuiTreeNodeFlags_SpanFullWidth = 1 << 12, // Extend hit box to the left-most and right-most edges (bypass the indented area). 881 ImGuiTreeNodeFlags_NavLeftJumpsBackHere = 1 << 13, // (WIP) Nav: left direction may move to this TreeNode() from any of its child (items submitted between TreeNode and TreePop) 882 //ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 14, // FIXME: TODO: Disable automatic scroll on TreePop() if node got just open and contents is not visible 883 ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_NoAutoOpenOnLog 884 }; 885 886 // Flags for OpenPopup*(), BeginPopupContext*(), IsPopupOpen() functions. 887 // - To be backward compatible with older API which took an 'int mouse_button = 1' argument, we need to treat 888 // small flags values as a mouse button index, so we encode the mouse button in the first few bits of the flags. 889 // It is therefore guaranteed to be legal to pass a mouse button index in ImGuiPopupFlags. 890 // - For the same reason, we exceptionally default the ImGuiPopupFlags argument of BeginPopupContextXXX functions to 1 instead of 0. 891 // IMPORTANT: because the default parameter is 1 (==ImGuiPopupFlags_MouseButtonRight), if you rely on the default parameter 892 // and want to another another flag, you need to pass in the ImGuiPopupFlags_MouseButtonRight flag. 893 // - Multiple buttons currently cannot be combined/or-ed in those functions (we could allow it later). 894 enum ImGuiPopupFlags_ 895 { 896 ImGuiPopupFlags_None = 0, 897 ImGuiPopupFlags_MouseButtonLeft = 0, // For BeginPopupContext*(): open on Left Mouse release. Guaranteed to always be == 0 (same as ImGuiMouseButton_Left) 898 ImGuiPopupFlags_MouseButtonRight = 1, // For BeginPopupContext*(): open on Right Mouse release. Guaranteed to always be == 1 (same as ImGuiMouseButton_Right) 899 ImGuiPopupFlags_MouseButtonMiddle = 2, // For BeginPopupContext*(): open on Middle Mouse release. Guaranteed to always be == 2 (same as ImGuiMouseButton_Middle) 900 ImGuiPopupFlags_MouseButtonMask_ = 0x1F, 901 ImGuiPopupFlags_MouseButtonDefault_ = 1, 902 ImGuiPopupFlags_NoOpenOverExistingPopup = 1 << 5, // For OpenPopup*(), BeginPopupContext*(): don't open if there's already a popup at the same level of the popup stack 903 ImGuiPopupFlags_NoOpenOverItems = 1 << 6, // For BeginPopupContextWindow(): don't return true when hovering items, only when hovering empty space 904 ImGuiPopupFlags_AnyPopupId = 1 << 7, // For IsPopupOpen(): ignore the ImGuiID parameter and test for any popup. 905 ImGuiPopupFlags_AnyPopupLevel = 1 << 8, // For IsPopupOpen(): search/test at any level of the popup stack (default test in the current level) 906 ImGuiPopupFlags_AnyPopup = ImGuiPopupFlags_AnyPopupId | ImGuiPopupFlags_AnyPopupLevel 638 907 }; 639 908 … … 641 910 enum ImGuiSelectableFlags_ 642 911 { 643 ImGuiSelectableFlags_DontClosePopups = 1 << 0, // Clicking this don't close parent popup window 644 ImGuiSelectableFlags_SpanAllColumns = 1 << 1, // Selectable frame can span all columns (text will still fit in current column) 645 ImGuiSelectableFlags_AllowDoubleClick = 1 << 2 // Generate press events on double clicks too 912 ImGuiSelectableFlags_None = 0, 913 ImGuiSelectableFlags_DontClosePopups = 1 << 0, // Clicking this don't close parent popup window 914 ImGuiSelectableFlags_SpanAllColumns = 1 << 1, // Selectable frame can span all columns (text will still fit in current column) 915 ImGuiSelectableFlags_AllowDoubleClick = 1 << 2, // Generate press events on double clicks too 916 ImGuiSelectableFlags_Disabled = 1 << 3, // Cannot be selected, display grayed out text 917 ImGuiSelectableFlags_AllowItemOverlap = 1 << 4 // (WIP) Hit testing to allow subsequent widgets to overlap this one 646 918 }; 647 919 … … 649 921 enum ImGuiComboFlags_ 650 922 { 651 ImGuiComboFlags_PopupAlignLeft = 1 << 0, // Align the popup toward the left by default 652 ImGuiComboFlags_HeightSmall = 1 << 1, // Max ~4 items visible. Tip: If you want your combo popup to be a specific size you can use SetNextWindowSizeConstraints() prior to calling BeginCombo() 653 ImGuiComboFlags_HeightRegular = 1 << 2, // Max ~8 items visible (default) 654 ImGuiComboFlags_HeightLarge = 1 << 3, // Max ~20 items visible 655 ImGuiComboFlags_HeightLargest = 1 << 4, // As many fitting items as possible 656 ImGuiComboFlags_NoArrowButton = 1 << 5, // Display on the preview box without the square arrow button 657 ImGuiComboFlags_NoPreview = 1 << 6, // Display only a square arrow button 658 ImGuiComboFlags_HeightMask_ = ImGuiComboFlags_HeightSmall | ImGuiComboFlags_HeightRegular | ImGuiComboFlags_HeightLarge | ImGuiComboFlags_HeightLargest 923 ImGuiComboFlags_None = 0, 924 ImGuiComboFlags_PopupAlignLeft = 1 << 0, // Align the popup toward the left by default 925 ImGuiComboFlags_HeightSmall = 1 << 1, // Max ~4 items visible. Tip: If you want your combo popup to be a specific size you can use SetNextWindowSizeConstraints() prior to calling BeginCombo() 926 ImGuiComboFlags_HeightRegular = 1 << 2, // Max ~8 items visible (default) 927 ImGuiComboFlags_HeightLarge = 1 << 3, // Max ~20 items visible 928 ImGuiComboFlags_HeightLargest = 1 << 4, // As many fitting items as possible 929 ImGuiComboFlags_NoArrowButton = 1 << 5, // Display on the preview box without the square arrow button 930 ImGuiComboFlags_NoPreview = 1 << 6, // Display only a square arrow button 931 ImGuiComboFlags_HeightMask_ = ImGuiComboFlags_HeightSmall | ImGuiComboFlags_HeightRegular | ImGuiComboFlags_HeightLarge | ImGuiComboFlags_HeightLargest 932 }; 933 934 // Flags for ImGui::BeginTabBar() 935 enum ImGuiTabBarFlags_ 936 { 937 ImGuiTabBarFlags_None = 0, 938 ImGuiTabBarFlags_Reorderable = 1 << 0, // Allow manually dragging tabs to re-order them + New tabs are appended at the end of list 939 ImGuiTabBarFlags_AutoSelectNewTabs = 1 << 1, // Automatically select new tabs when they appear 940 ImGuiTabBarFlags_TabListPopupButton = 1 << 2, // Disable buttons to open the tab list popup 941 ImGuiTabBarFlags_NoCloseWithMiddleMouseButton = 1 << 3, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false. 942 ImGuiTabBarFlags_NoTabListScrollingButtons = 1 << 4, // Disable scrolling buttons (apply when fitting policy is ImGuiTabBarFlags_FittingPolicyScroll) 943 ImGuiTabBarFlags_NoTooltip = 1 << 5, // Disable tooltips when hovering a tab 944 ImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 6, // Resize tabs when they don't fit 945 ImGuiTabBarFlags_FittingPolicyScroll = 1 << 7, // Add scroll buttons when tabs don't fit 946 ImGuiTabBarFlags_FittingPolicyMask_ = ImGuiTabBarFlags_FittingPolicyResizeDown | ImGuiTabBarFlags_FittingPolicyScroll, 947 ImGuiTabBarFlags_FittingPolicyDefault_ = ImGuiTabBarFlags_FittingPolicyResizeDown 948 }; 949 950 // Flags for ImGui::BeginTabItem() 951 enum ImGuiTabItemFlags_ 952 { 953 ImGuiTabItemFlags_None = 0, 954 ImGuiTabItemFlags_UnsavedDocument = 1 << 0, // Append '*' to title without affecting the ID, as a convenience to avoid using the ### operator. Also: tab is selected on closure and closure is deferred by one frame to allow code to undo it without flicker. 955 ImGuiTabItemFlags_SetSelected = 1 << 1, // Trigger flag to programmatically make the tab selected when calling BeginTabItem() 956 ImGuiTabItemFlags_NoCloseWithMiddleMouseButton = 1 << 2, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false. 957 ImGuiTabItemFlags_NoPushId = 1 << 3, // Don't call PushID(tab->ID)/PopID() on BeginTabItem()/EndTabItem() 958 ImGuiTabItemFlags_NoTooltip = 1 << 4, // Disable tooltip for the given tab 959 ImGuiTabItemFlags_NoReorder = 1 << 5, // Disable reordering this tab or having another tab cross over this tab 960 ImGuiTabItemFlags_Leading = 1 << 6, // Enforce the tab position to the left of the tab bar (after the tab list popup button) 961 ImGuiTabItemFlags_Trailing = 1 << 7 // Enforce the tab position to the right of the tab bar (before the scrolling buttons) 659 962 }; 660 963 … … 662 965 enum ImGuiFocusedFlags_ 663 966 { 664 ImGuiFocusedFlags_ChildWindows = 1 << 0, // IsWindowFocused(): Return true if any children of the window is focused 665 ImGuiFocusedFlags_RootWindow = 1 << 1, // IsWindowFocused(): Test from root window (top most parent of the current hierarchy) 666 ImGuiFocusedFlags_AnyWindow = 1 << 2, // IsWindowFocused(): Return true if any window is focused 667 ImGuiFocusedFlags_RootAndChildWindows = ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows 967 ImGuiFocusedFlags_None = 0, 968 ImGuiFocusedFlags_ChildWindows = 1 << 0, // IsWindowFocused(): Return true if any children of the window is focused 969 ImGuiFocusedFlags_RootWindow = 1 << 1, // IsWindowFocused(): Test from root window (top most parent of the current hierarchy) 970 ImGuiFocusedFlags_AnyWindow = 1 << 2, // IsWindowFocused(): Return true if any window is focused. Important: If you are trying to tell how to dispatch your low-level inputs, do NOT use this. Use 'io.WantCaptureMouse' instead! Please read the FAQ! 971 ImGuiFocusedFlags_RootAndChildWindows = ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows 668 972 }; 669 973 670 974 // Flags for ImGui::IsItemHovered(), ImGui::IsWindowHovered() 671 // Note: If you are trying to check whether your mouse should be dispatched to imgui or to your app, you should use the 'io.WantCaptureMouse' boolean for that. Please read the FAQ! 975 // Note: if you are trying to check whether your mouse should be dispatched to Dear ImGui or to your app, you should use 'io.WantCaptureMouse' instead! Please read the FAQ! 976 // Note: windows with the ImGuiWindowFlags_NoInputs flag are ignored by IsWindowHovered() calls. 672 977 enum ImGuiHoveredFlags_ 673 978 { 674 ImGuiHoveredFlags_Default = 0, // Return true if directly over the item/window, not obstructed by another window, not obstructed by an active popup or modal blocking inputs under them. 675 ImGuiHoveredFlags_ChildWindows = 1 << 0, // IsWindowHovered() only: Return true if any children of the window is hovered 676 ImGuiHoveredFlags_RootWindow = 1 << 1, // IsWindowHovered() only: Test from root window (top most parent of the current hierarchy) 677 ImGuiHoveredFlags_AnyWindow = 1 << 2, // IsWindowHovered() only: Return true if any window is hovered 678 ImGuiHoveredFlags_AllowWhenBlockedByPopup = 1 << 3, // Return true even if a popup window is normally blocking access to this item/window 679 //ImGuiHoveredFlags_AllowWhenBlockedByModal = 1 << 4, // Return true even if a modal popup window is normally blocking access to this item/window. FIXME-TODO: Unavailable yet. 680 ImGuiHoveredFlags_AllowWhenBlockedByActiveItem = 1 << 5, // Return true even if an active item is blocking access to this item/window. Useful for Drag and Drop patterns. 681 ImGuiHoveredFlags_AllowWhenOverlapped = 1 << 6, // Return true even if the position is overlapped by another window 682 ImGuiHoveredFlags_RectOnly = ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped, 683 ImGuiHoveredFlags_RootAndChildWindows = ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows 979 ImGuiHoveredFlags_None = 0, // Return true if directly over the item/window, not obstructed by another window, not obstructed by an active popup or modal blocking inputs under them. 980 ImGuiHoveredFlags_ChildWindows = 1 << 0, // IsWindowHovered() only: Return true if any children of the window is hovered 981 ImGuiHoveredFlags_RootWindow = 1 << 1, // IsWindowHovered() only: Test from root window (top most parent of the current hierarchy) 982 ImGuiHoveredFlags_AnyWindow = 1 << 2, // IsWindowHovered() only: Return true if any window is hovered 983 ImGuiHoveredFlags_AllowWhenBlockedByPopup = 1 << 3, // Return true even if a popup window is normally blocking access to this item/window 984 //ImGuiHoveredFlags_AllowWhenBlockedByModal = 1 << 4, // Return true even if a modal popup window is normally blocking access to this item/window. FIXME-TODO: Unavailable yet. 985 ImGuiHoveredFlags_AllowWhenBlockedByActiveItem = 1 << 5, // Return true even if an active item is blocking access to this item/window. Useful for Drag and Drop patterns. 986 ImGuiHoveredFlags_AllowWhenOverlapped = 1 << 6, // Return true even if the position is obstructed or overlapped by another window 987 ImGuiHoveredFlags_AllowWhenDisabled = 1 << 7, // Return true even if the item is disabled 988 ImGuiHoveredFlags_RectOnly = ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped, 989 ImGuiHoveredFlags_RootAndChildWindows = ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows 684 990 }; 685 991 … … 687 993 enum ImGuiDragDropFlags_ 688 994 { 689 // BeginDragDropSource() flags 690 ImGuiDragDropFlags_SourceNoPreviewTooltip = 1 << 0, // By default, a successful call to BeginDragDropSource opens a tooltip so you can display a preview or description of the source contents. This flag disable this behavior. 691 ImGuiDragDropFlags_SourceNoDisableHover = 1 << 1, // By default, when dragging we clear data so that IsItemHovered() will return true, to avoid subsequent user code submitting tooltips. This flag disable this behavior so you can still call IsItemHovered() on the source item. 692 ImGuiDragDropFlags_SourceNoHoldToOpenOthers = 1 << 2, // Disable the behavior that allows to open tree nodes and collapsing header by holding over them while dragging a source item. 693 ImGuiDragDropFlags_SourceAllowNullID = 1 << 3, // Allow items such as Text(), Image() that have no unique identifier to be used as drag source, by manufacturing a temporary identifier based on their window-relative position. This is extremely unusual within the dear imgui ecosystem and so we made it explicit. 694 ImGuiDragDropFlags_SourceExtern = 1 << 4, // External source (from outside of imgui), won't attempt to read current item/window info. Will always return true. Only one Extern source can be active simultaneously. 695 // AcceptDragDropPayload() flags 696 ImGuiDragDropFlags_AcceptBeforeDelivery = 1 << 10, // AcceptDragDropPayload() will returns true even before the mouse button is released. You can then call IsDelivery() to test if the payload needs to be delivered. 697 ImGuiDragDropFlags_AcceptNoDrawDefaultRect = 1 << 11, // Do not draw the default highlight rectangle when hovering over target. 698 ImGuiDragDropFlags_AcceptPeekOnly = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoDrawDefaultRect // For peeking ahead and inspecting the payload before delivery. 995 ImGuiDragDropFlags_None = 0, 996 // BeginDragDropSource() flags 997 ImGuiDragDropFlags_SourceNoPreviewTooltip = 1 << 0, // By default, a successful call to BeginDragDropSource opens a tooltip so you can display a preview or description of the source contents. This flag disable this behavior. 998 ImGuiDragDropFlags_SourceNoDisableHover = 1 << 1, // By default, when dragging we clear data so that IsItemHovered() will return false, to avoid subsequent user code submitting tooltips. This flag disable this behavior so you can still call IsItemHovered() on the source item. 999 ImGuiDragDropFlags_SourceNoHoldToOpenOthers = 1 << 2, // Disable the behavior that allows to open tree nodes and collapsing header by holding over them while dragging a source item. 1000 ImGuiDragDropFlags_SourceAllowNullID = 1 << 3, // Allow items such as Text(), Image() that have no unique identifier to be used as drag source, by manufacturing a temporary identifier based on their window-relative position. This is extremely unusual within the dear imgui ecosystem and so we made it explicit. 1001 ImGuiDragDropFlags_SourceExtern = 1 << 4, // External source (from outside of dear imgui), won't attempt to read current item/window info. Will always return true. Only one Extern source can be active simultaneously. 1002 ImGuiDragDropFlags_SourceAutoExpirePayload = 1 << 5, // Automatically expire the payload if the source cease to be submitted (otherwise payloads are persisting while being dragged) 1003 // AcceptDragDropPayload() flags 1004 ImGuiDragDropFlags_AcceptBeforeDelivery = 1 << 10, // AcceptDragDropPayload() will returns true even before the mouse button is released. You can then call IsDelivery() to test if the payload needs to be delivered. 1005 ImGuiDragDropFlags_AcceptNoDrawDefaultRect = 1 << 11, // Do not draw the default highlight rectangle when hovering over target. 1006 ImGuiDragDropFlags_AcceptNoPreviewTooltip = 1 << 12, // Request hiding the BeginDragDropSource tooltip from the BeginDragDropTarget site. 1007 ImGuiDragDropFlags_AcceptPeekOnly = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoDrawDefaultRect // For peeking ahead and inspecting the payload before delivery. 699 1008 }; 700 1009 701 1010 // Standard Drag and Drop payload types. You can define you own payload types using short strings. Types starting with '_' are defined by Dear ImGui. 702 #define IMGUI_PAYLOAD_TYPE_COLOR_3F "_COL3F" // float[3]: Standard type for colors, without alpha. User code may use this type. 1011 #define IMGUI_PAYLOAD_TYPE_COLOR_3F "_COL3F" // float[3]: Standard type for colors, without alpha. User code may use this type. 703 1012 #define IMGUI_PAYLOAD_TYPE_COLOR_4F "_COL4F" // float[4]: Standard type for colors. User code may use this type. 1013 1014 // A primary data type 1015 enum ImGuiDataType_ 1016 { 1017 ImGuiDataType_S8, // signed char / char (with sensible compilers) 1018 ImGuiDataType_U8, // unsigned char 1019 ImGuiDataType_S16, // short 1020 ImGuiDataType_U16, // unsigned short 1021 ImGuiDataType_S32, // int 1022 ImGuiDataType_U32, // unsigned int 1023 ImGuiDataType_S64, // long long / __int64 1024 ImGuiDataType_U64, // unsigned long long / unsigned __int64 1025 ImGuiDataType_Float, // float 1026 ImGuiDataType_Double, // double 1027 ImGuiDataType_COUNT 1028 }; 704 1029 705 1030 // A cardinal direction 706 1031 enum ImGuiDir_ 707 1032 { 708 ImGuiDir_None= -1,709 ImGuiDir_Left= 0,710 ImGuiDir_Right= 1,711 ImGuiDir_Up= 2,712 ImGuiDir_Down= 3,713 ImGuiDir_COUNT1033 ImGuiDir_None = -1, 1034 ImGuiDir_Left = 0, 1035 ImGuiDir_Right = 1, 1036 ImGuiDir_Up = 2, 1037 ImGuiDir_Down = 3, 1038 ImGuiDir_COUNT 714 1039 }; 715 1040 … … 717 1042 enum ImGuiKey_ 718 1043 { 719 ImGuiKey_Tab, 720 ImGuiKey_LeftArrow, 721 ImGuiKey_RightArrow, 722 ImGuiKey_UpArrow, 723 ImGuiKey_DownArrow, 724 ImGuiKey_PageUp, 725 ImGuiKey_PageDown, 726 ImGuiKey_Home, 727 ImGuiKey_End, 728 ImGuiKey_Insert, 729 ImGuiKey_Delete, 730 ImGuiKey_Backspace, 731 ImGuiKey_Space, 732 ImGuiKey_Enter, 733 ImGuiKey_Escape, 734 ImGuiKey_A, // for text edit CTRL+A: select all 735 ImGuiKey_C, // for text edit CTRL+C: copy 736 ImGuiKey_V, // for text edit CTRL+V: paste 737 ImGuiKey_X, // for text edit CTRL+X: cut 738 ImGuiKey_Y, // for text edit CTRL+Y: redo 739 ImGuiKey_Z, // for text edit CTRL+Z: undo 740 ImGuiKey_COUNT 741 }; 742 743 // [BETA] Gamepad/Keyboard directional navigation 1044 ImGuiKey_Tab, 1045 ImGuiKey_LeftArrow, 1046 ImGuiKey_RightArrow, 1047 ImGuiKey_UpArrow, 1048 ImGuiKey_DownArrow, 1049 ImGuiKey_PageUp, 1050 ImGuiKey_PageDown, 1051 ImGuiKey_Home, 1052 ImGuiKey_End, 1053 ImGuiKey_Insert, 1054 ImGuiKey_Delete, 1055 ImGuiKey_Backspace, 1056 ImGuiKey_Space, 1057 ImGuiKey_Enter, 1058 ImGuiKey_Escape, 1059 ImGuiKey_KeyPadEnter, 1060 ImGuiKey_A, // for text edit CTRL+A: select all 1061 ImGuiKey_C, // for text edit CTRL+C: copy 1062 ImGuiKey_V, // for text edit CTRL+V: paste 1063 ImGuiKey_X, // for text edit CTRL+X: cut 1064 ImGuiKey_Y, // for text edit CTRL+Y: redo 1065 ImGuiKey_Z, // for text edit CTRL+Z: undo 1066 ImGuiKey_COUNT 1067 }; 1068 1069 // To test io.KeyMods (which is a combination of individual fields io.KeyCtrl, io.KeyShift, io.KeyAlt set by user/back-end) 1070 enum ImGuiKeyModFlags_ 1071 { 1072 ImGuiKeyModFlags_None = 0, 1073 ImGuiKeyModFlags_Ctrl = 1 << 0, 1074 ImGuiKeyModFlags_Shift = 1 << 1, 1075 ImGuiKeyModFlags_Alt = 1 << 2, 1076 ImGuiKeyModFlags_Super = 1 << 3 1077 }; 1078 1079 // Gamepad/Keyboard navigation 744 1080 // Keyboard: Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays. 745 1081 // Gamepad: Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable. Back-end: set ImGuiBackendFlags_HasGamepad and fill the io.NavInputs[] fields before calling NewFrame(). Note that io.NavInputs[] is cleared by EndFrame(). 746 // Read instructions in imgui.cpp for more details. Download PNG/PSD at goo.gl/9LgVZW.1082 // Read instructions in imgui.cpp for more details. Download PNG/PSD at http://goo.gl/9LgVZW. 747 1083 enum ImGuiNavInput_ 748 1084 { 749 // Gamepad Mapping750 ImGuiNavInput_Activate, // activate / open / toggle / tweak value // e.g. Cross (PS4), A (Xbox), A (Switch), Space (Keyboard)751 ImGuiNavInput_Cancel, // cancel / close / exit // e.g. Circle (PS4), B (Xbox), B (Switch), Escape (Keyboard)752 ImGuiNavInput_Input, // text input / on-screen keyboard // e.g. Triang.(PS4), Y (Xbox), X (Switch), Return (Keyboard)753 ImGuiNavInput_Menu, // tap: toggle menu / hold: focus, move, resize // e.g. Square (PS4), X (Xbox), Y (Switch), Alt (Keyboard)754 ImGuiNavInput_DpadLeft, // move / tweak / resize window (w/ PadMenu) // e.g. D-pad Left/Right/Up/Down (Gamepads), Arrow keys (Keyboard)755 ImGuiNavInput_DpadRight, //756 ImGuiNavInput_DpadUp, //757 ImGuiNavInput_DpadDown, //758 ImGuiNavInput_LStickLeft, // scroll / move window (w/ PadMenu) // e.g. Left Analog Stick Left/Right/Up/Down759 ImGuiNavInput_LStickRight, //760 ImGuiNavInput_LStickUp, //761 ImGuiNavInput_LStickDown, //762 ImGuiNavInput_FocusPrev, // next window (w/ PadMenu) // e.g. L1 or L2 (PS4), LB or LT (Xbox), L or ZL (Switch)763 ImGuiNavInput_FocusNext, // prev window (w/ PadMenu) // e.g. R1 or R2 (PS4), RB or RT (Xbox), R or ZL (Switch)764 ImGuiNavInput_TweakSlow, // slower tweaks // e.g. L1 or L2 (PS4), LB or LT (Xbox), L or ZL (Switch)765 ImGuiNavInput_TweakFast, // faster tweaks // e.g. R1 or R2 (PS4), RB or RT (Xbox), R or ZL (Switch)766 767 768 769 770 771 772 773 774 775 1085 // Gamepad Mapping 1086 ImGuiNavInput_Activate, // activate / open / toggle / tweak value // e.g. Cross (PS4), A (Xbox), A (Switch), Space (Keyboard) 1087 ImGuiNavInput_Cancel, // cancel / close / exit // e.g. Circle (PS4), B (Xbox), B (Switch), Escape (Keyboard) 1088 ImGuiNavInput_Input, // text input / on-screen keyboard // e.g. Triang.(PS4), Y (Xbox), X (Switch), Return (Keyboard) 1089 ImGuiNavInput_Menu, // tap: toggle menu / hold: focus, move, resize // e.g. Square (PS4), X (Xbox), Y (Switch), Alt (Keyboard) 1090 ImGuiNavInput_DpadLeft, // move / tweak / resize window (w/ PadMenu) // e.g. D-pad Left/Right/Up/Down (Gamepads), Arrow keys (Keyboard) 1091 ImGuiNavInput_DpadRight, // 1092 ImGuiNavInput_DpadUp, // 1093 ImGuiNavInput_DpadDown, // 1094 ImGuiNavInput_LStickLeft, // scroll / move window (w/ PadMenu) // e.g. Left Analog Stick Left/Right/Up/Down 1095 ImGuiNavInput_LStickRight, // 1096 ImGuiNavInput_LStickUp, // 1097 ImGuiNavInput_LStickDown, // 1098 ImGuiNavInput_FocusPrev, // next window (w/ PadMenu) // e.g. L1 or L2 (PS4), LB or LT (Xbox), L or ZL (Switch) 1099 ImGuiNavInput_FocusNext, // prev window (w/ PadMenu) // e.g. R1 or R2 (PS4), RB or RT (Xbox), R or ZL (Switch) 1100 ImGuiNavInput_TweakSlow, // slower tweaks // e.g. L1 or L2 (PS4), LB or LT (Xbox), L or ZL (Switch) 1101 ImGuiNavInput_TweakFast, // faster tweaks // e.g. R1 or R2 (PS4), RB or RT (Xbox), R or ZL (Switch) 1102 1103 // [Internal] Don't use directly! This is used internally to differentiate keyboard from gamepad inputs for behaviors that require to differentiate them. 1104 // Keyboard behavior that have no corresponding gamepad mapping (e.g. CTRL+TAB) will be directly reading from io.KeysDown[] instead of io.NavInputs[]. 1105 ImGuiNavInput_KeyMenu_, // toggle menu // = io.KeyAlt 1106 ImGuiNavInput_KeyLeft_, // move left // = Arrow keys 1107 ImGuiNavInput_KeyRight_, // move right 1108 ImGuiNavInput_KeyUp_, // move up 1109 ImGuiNavInput_KeyDown_, // move down 1110 ImGuiNavInput_COUNT, 1111 ImGuiNavInput_InternalStart_ = ImGuiNavInput_KeyMenu_ 776 1112 }; 777 1113 … … 779 1115 enum ImGuiConfigFlags_ 780 1116 { 781 ImGuiConfigFlags_NavEnableKeyboard = 1 << 0, // Master keyboard navigation enable flag. NewFrame() will automatically fill io.NavInputs[] based on io.KeysDown[]. 782 ImGuiConfigFlags_NavEnableGamepad = 1 << 1, // Master gamepad navigation enable flag. This is mostly to instruct your imgui back-end to fill io.NavInputs[]. Back-end also needs to set ImGuiBackendFlags_HasGamepad. 783 ImGuiConfigFlags_NavEnableSetMousePos = 1 << 2, // Instruct navigation to move the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is awkward. Will update io.MousePos and set io.WantSetMousePos=true. If enabled you MUST honor io.WantSetMousePos requests in your binding, otherwise ImGui will react as if the mouse is jumping around back and forth. 784 ImGuiConfigFlags_NavNoCaptureKeyboard = 1 << 3, // Instruct navigation to not set the io.WantCaptureKeyboard flag with io.NavActive is set. 785 ImGuiConfigFlags_NoMouse = 1 << 4, // Instruct imgui to clear mouse position/buttons in NewFrame(). This allows ignoring the mouse information back-end 786 ImGuiConfigFlags_NoMouseCursorChange = 1 << 5, // Instruct back-end to not alter mouse cursor shape and visibility. 787 788 // User storage (to allow your back-end/engine to communicate to code that may be shared between multiple projects. Those flags are not used by core ImGui) 789 ImGuiConfigFlags_IsSRGB = 1 << 20, // Application is SRGB-aware. 790 ImGuiConfigFlags_IsTouchScreen = 1 << 21 // Application is using a touch screen instead of a mouse. 1117 ImGuiConfigFlags_None = 0, 1118 ImGuiConfigFlags_NavEnableKeyboard = 1 << 0, // Master keyboard navigation enable flag. NewFrame() will automatically fill io.NavInputs[] based on io.KeysDown[]. 1119 ImGuiConfigFlags_NavEnableGamepad = 1 << 1, // Master gamepad navigation enable flag. This is mostly to instruct your imgui back-end to fill io.NavInputs[]. Back-end also needs to set ImGuiBackendFlags_HasGamepad. 1120 ImGuiConfigFlags_NavEnableSetMousePos = 1 << 2, // Instruct navigation to move the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is awkward. Will update io.MousePos and set io.WantSetMousePos=true. If enabled you MUST honor io.WantSetMousePos requests in your binding, otherwise ImGui will react as if the mouse is jumping around back and forth. 1121 ImGuiConfigFlags_NavNoCaptureKeyboard = 1 << 3, // Instruct navigation to not set the io.WantCaptureKeyboard flag when io.NavActive is set. 1122 ImGuiConfigFlags_NoMouse = 1 << 4, // Instruct imgui to clear mouse position/buttons in NewFrame(). This allows ignoring the mouse information set by the back-end. 1123 ImGuiConfigFlags_NoMouseCursorChange = 1 << 5, // Instruct back-end to not alter mouse cursor shape and visibility. Use if the back-end cursor changes are interfering with yours and you don't want to use SetMouseCursor() to change mouse cursor. You may want to honor requests from imgui by reading GetMouseCursor() yourself instead. 1124 1125 // User storage (to allow your back-end/engine to communicate to code that may be shared between multiple projects. Those flags are not used by core Dear ImGui) 1126 ImGuiConfigFlags_IsSRGB = 1 << 20, // Application is SRGB-aware. 1127 ImGuiConfigFlags_IsTouchScreen = 1 << 21 // Application is using a touch screen instead of a mouse. 791 1128 }; 792 1129 … … 794 1131 enum ImGuiBackendFlags_ 795 1132 { 796 ImGuiBackendFlags_HasGamepad = 1 << 0, // Back-end supports and has a connected gamepad. 797 ImGuiBackendFlags_HasMouseCursors = 1 << 1, // Back-end supports reading GetMouseCursor() to change the OS cursor shape. 798 ImGuiBackendFlags_HasSetMousePos = 1 << 2 // Back-end supports io.WantSetMousePos requests to reposition the OS mouse position (only used if ImGuiConfigFlags_NavEnableSetMousePos is set). 1133 ImGuiBackendFlags_None = 0, 1134 ImGuiBackendFlags_HasGamepad = 1 << 0, // Back-end Platform supports gamepad and currently has one connected. 1135 ImGuiBackendFlags_HasMouseCursors = 1 << 1, // Back-end Platform supports honoring GetMouseCursor() value to change the OS cursor shape. 1136 ImGuiBackendFlags_HasSetMousePos = 1 << 2, // Back-end Platform supports io.WantSetMousePos requests to reposition the OS mouse position (only used if ImGuiConfigFlags_NavEnableSetMousePos is set). 1137 ImGuiBackendFlags_RendererHasVtxOffset = 1 << 3 // Back-end Renderer supports ImDrawCmd::VtxOffset. This enables output of large meshes (64K+ vertices) while still using 16-bit indices. 799 1138 }; 800 1139 … … 802 1141 enum ImGuiCol_ 803 1142 { 804 ImGuiCol_Text, 805 ImGuiCol_TextDisabled, 806 ImGuiCol_WindowBg, // Background of normal windows 807 ImGuiCol_ChildBg, // Background of child windows 808 ImGuiCol_PopupBg, // Background of popups, menus, tooltips windows 809 ImGuiCol_Border, 810 ImGuiCol_BorderShadow, 811 ImGuiCol_FrameBg, // Background of checkbox, radio button, plot, slider, text input 812 ImGuiCol_FrameBgHovered, 813 ImGuiCol_FrameBgActive, 814 ImGuiCol_TitleBg, 815 ImGuiCol_TitleBgActive, 816 ImGuiCol_TitleBgCollapsed, 817 ImGuiCol_MenuBarBg, 818 ImGuiCol_ScrollbarBg, 819 ImGuiCol_ScrollbarGrab, 820 ImGuiCol_ScrollbarGrabHovered, 821 ImGuiCol_ScrollbarGrabActive, 822 ImGuiCol_CheckMark, 823 ImGuiCol_SliderGrab, 824 ImGuiCol_SliderGrabActive, 825 ImGuiCol_Button, 826 ImGuiCol_ButtonHovered, 827 ImGuiCol_ButtonActive, 828 ImGuiCol_Header, 829 ImGuiCol_HeaderHovered, 830 ImGuiCol_HeaderActive, 831 ImGuiCol_Separator, 832 ImGuiCol_SeparatorHovered, 833 ImGuiCol_SeparatorActive, 834 ImGuiCol_ResizeGrip, 835 ImGuiCol_ResizeGripHovered, 836 ImGuiCol_ResizeGripActive, 837 ImGuiCol_PlotLines, 838 ImGuiCol_PlotLinesHovered, 839 ImGuiCol_PlotHistogram, 840 ImGuiCol_PlotHistogramHovered, 841 ImGuiCol_TextSelectedBg, 842 ImGuiCol_ModalWindowDarkening, // Darken/colorize entire screen behind a modal window, when one is active 843 ImGuiCol_DragDropTarget, 844 ImGuiCol_NavHighlight, // Gamepad/keyboard: current highlighted item 845 ImGuiCol_NavWindowingHighlight, // Gamepad/keyboard: when holding NavMenu to focus/move/resize windows 846 ImGuiCol_COUNT 847 848 // Obsolete names (will be removed) 1143 ImGuiCol_Text, 1144 ImGuiCol_TextDisabled, 1145 ImGuiCol_WindowBg, // Background of normal windows 1146 ImGuiCol_ChildBg, // Background of child windows 1147 ImGuiCol_PopupBg, // Background of popups, menus, tooltips windows 1148 ImGuiCol_Border, 1149 ImGuiCol_BorderShadow, 1150 ImGuiCol_FrameBg, // Background of checkbox, radio button, plot, slider, text input 1151 ImGuiCol_FrameBgHovered, 1152 ImGuiCol_FrameBgActive, 1153 ImGuiCol_TitleBg, 1154 ImGuiCol_TitleBgActive, 1155 ImGuiCol_TitleBgCollapsed, 1156 ImGuiCol_MenuBarBg, 1157 ImGuiCol_ScrollbarBg, 1158 ImGuiCol_ScrollbarGrab, 1159 ImGuiCol_ScrollbarGrabHovered, 1160 ImGuiCol_ScrollbarGrabActive, 1161 ImGuiCol_CheckMark, 1162 ImGuiCol_SliderGrab, 1163 ImGuiCol_SliderGrabActive, 1164 ImGuiCol_Button, 1165 ImGuiCol_ButtonHovered, 1166 ImGuiCol_ButtonActive, 1167 ImGuiCol_Header, // Header* colors are used for CollapsingHeader, TreeNode, Selectable, MenuItem 1168 ImGuiCol_HeaderHovered, 1169 ImGuiCol_HeaderActive, 1170 ImGuiCol_Separator, 1171 ImGuiCol_SeparatorHovered, 1172 ImGuiCol_SeparatorActive, 1173 ImGuiCol_ResizeGrip, 1174 ImGuiCol_ResizeGripHovered, 1175 ImGuiCol_ResizeGripActive, 1176 ImGuiCol_Tab, 1177 ImGuiCol_TabHovered, 1178 ImGuiCol_TabActive, 1179 ImGuiCol_TabUnfocused, 1180 ImGuiCol_TabUnfocusedActive, 1181 ImGuiCol_PlotLines, 1182 ImGuiCol_PlotLinesHovered, 1183 ImGuiCol_PlotHistogram, 1184 ImGuiCol_PlotHistogramHovered, 1185 ImGuiCol_TextSelectedBg, 1186 ImGuiCol_DragDropTarget, 1187 ImGuiCol_NavHighlight, // Gamepad/keyboard: current highlighted item 1188 ImGuiCol_NavWindowingHighlight, // Highlight window when using CTRL+TAB 1189 ImGuiCol_NavWindowingDimBg, // Darken/colorize entire screen behind the CTRL+TAB window list, when active 1190 ImGuiCol_ModalWindowDimBg, // Darken/colorize entire screen behind a modal window, when one is active 1191 ImGuiCol_COUNT 1192 1193 // Obsolete names (will be removed) 849 1194 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS 850 , ImGuiCol_ChildWindowBg = ImGuiCol_ChildBg, ImGuiCol_Column = ImGuiCol_Separator, ImGuiCol_ColumnHovered = ImGuiCol_SeparatorHovered, ImGuiCol_ColumnActive = ImGuiCol_SeparatorActive 851 //ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered, // [unused since 1.60+] the close button now uses regular button colors. 852 //ImGuiCol_ComboBg, // [unused since 1.53+] ComboBg has been merged with PopupBg, so a redirect isn't accurate. 1195 , ImGuiCol_ModalWindowDarkening = ImGuiCol_ModalWindowDimBg // [renamed in 1.63] 1196 //, ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered// [unused since 1.60+] the close button now uses regular button colors. 853 1197 #endif 854 1198 }; 855 1199 856 1200 // Enumeration for PushStyleVar() / PopStyleVar() to temporarily modify the ImGuiStyle structure. 857 // NB: the enum only refers to fields of ImGuiStyle which makes sense to be pushed/popped inside UI code. During initialization, feel free to just poke into ImGuiStyle directly. 858 // NB: if changing this enum, you need to update the associated internal table GStyleVarInfo[] accordingly. This is where we link enum values to members offset/type. 1201 // - The enum only refers to fields of ImGuiStyle which makes sense to be pushed/popped inside UI code. 1202 // During initialization or between frames, feel free to just poke into ImGuiStyle directly. 1203 // - Tip: Use your programming IDE navigation facilities on the names in the _second column_ below to find the actual members and their description. 1204 // In Visual Studio IDE: CTRL+comma ("Edit.NavigateTo") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot. 1205 // With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments. 1206 // - When changing this enum, you need to update the associated internal table GStyleVarInfo[] accordingly. This is where we link enum values to members offset/type. 859 1207 enum ImGuiStyleVar_ 860 1208 { 861 // Enum name ......................// Member in ImGuiStyle structure (see ImGuiStyle for descriptions) 862 ImGuiStyleVar_Alpha, // float Alpha 863 ImGuiStyleVar_WindowPadding, // ImVec2 WindowPadding 864 ImGuiStyleVar_WindowRounding, // float WindowRounding 865 ImGuiStyleVar_WindowBorderSize, // float WindowBorderSize 866 ImGuiStyleVar_WindowMinSize, // ImVec2 WindowMinSize 867 ImGuiStyleVar_WindowTitleAlign, // ImVec2 WindowTitleAlign 868 ImGuiStyleVar_ChildRounding, // float ChildRounding 869 ImGuiStyleVar_ChildBorderSize, // float ChildBorderSize 870 ImGuiStyleVar_PopupRounding, // float PopupRounding 871 ImGuiStyleVar_PopupBorderSize, // float PopupBorderSize 872 ImGuiStyleVar_FramePadding, // ImVec2 FramePadding 873 ImGuiStyleVar_FrameRounding, // float FrameRounding 874 ImGuiStyleVar_FrameBorderSize, // float FrameBorderSize 875 ImGuiStyleVar_ItemSpacing, // ImVec2 ItemSpacing 876 ImGuiStyleVar_ItemInnerSpacing, // ImVec2 ItemInnerSpacing 877 ImGuiStyleVar_IndentSpacing, // float IndentSpacing 878 ImGuiStyleVar_ScrollbarSize, // float ScrollbarSize 879 ImGuiStyleVar_ScrollbarRounding, // float ScrollbarRounding 880 ImGuiStyleVar_GrabMinSize, // float GrabMinSize 881 ImGuiStyleVar_GrabRounding, // float GrabRounding 882 ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign 883 ImGuiStyleVar_COUNT 884 885 // Obsolete names (will be removed) 1209 // Enum name --------------------- // Member in ImGuiStyle structure (see ImGuiStyle for descriptions) 1210 ImGuiStyleVar_Alpha, // float Alpha 1211 ImGuiStyleVar_WindowPadding, // ImVec2 WindowPadding 1212 ImGuiStyleVar_WindowRounding, // float WindowRounding 1213 ImGuiStyleVar_WindowBorderSize, // float WindowBorderSize 1214 ImGuiStyleVar_WindowMinSize, // ImVec2 WindowMinSize 1215 ImGuiStyleVar_WindowTitleAlign, // ImVec2 WindowTitleAlign 1216 ImGuiStyleVar_ChildRounding, // float ChildRounding 1217 ImGuiStyleVar_ChildBorderSize, // float ChildBorderSize 1218 ImGuiStyleVar_PopupRounding, // float PopupRounding 1219 ImGuiStyleVar_PopupBorderSize, // float PopupBorderSize 1220 ImGuiStyleVar_FramePadding, // ImVec2 FramePadding 1221 ImGuiStyleVar_FrameRounding, // float FrameRounding 1222 ImGuiStyleVar_FrameBorderSize, // float FrameBorderSize 1223 ImGuiStyleVar_ItemSpacing, // ImVec2 ItemSpacing 1224 ImGuiStyleVar_ItemInnerSpacing, // ImVec2 ItemInnerSpacing 1225 ImGuiStyleVar_IndentSpacing, // float IndentSpacing 1226 ImGuiStyleVar_ScrollbarSize, // float ScrollbarSize 1227 ImGuiStyleVar_ScrollbarRounding, // float ScrollbarRounding 1228 ImGuiStyleVar_GrabMinSize, // float GrabMinSize 1229 ImGuiStyleVar_GrabRounding, // float GrabRounding 1230 ImGuiStyleVar_TabRounding, // float TabRounding 1231 ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign 1232 ImGuiStyleVar_SelectableTextAlign, // ImVec2 SelectableTextAlign 1233 ImGuiStyleVar_COUNT 1234 1235 // Obsolete names (will be removed) 886 1236 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS 887 , ImGuiStyleVar_Count_ = ImGuiStyleVar_COUNT, ImGuiStyleVar_ChildWindowRounding = ImGuiStyleVar_ChildRounding 888 #endif 889 }; 890 891 // Enumeration for ColorEdit3() / ColorEdit4() / ColorPicker3() / ColorPicker4() / ColorButton() 1237 , ImGuiStyleVar_Count_ = ImGuiStyleVar_COUNT // [renamed in 1.60] 1238 #endif 1239 }; 1240 1241 // Flags for InvisibleButton() [extended in imgui_internal.h] 1242 enum ImGuiButtonFlags_ 1243 { 1244 ImGuiButtonFlags_None = 0, 1245 ImGuiButtonFlags_MouseButtonLeft = 1 << 0, // React on left mouse button (default) 1246 ImGuiButtonFlags_MouseButtonRight = 1 << 1, // React on right mouse button 1247 ImGuiButtonFlags_MouseButtonMiddle = 1 << 2, // React on center mouse button 1248 1249 // [Internal] 1250 ImGuiButtonFlags_MouseButtonMask_ = ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight | ImGuiButtonFlags_MouseButtonMiddle, 1251 ImGuiButtonFlags_MouseButtonDefault_ = ImGuiButtonFlags_MouseButtonLeft 1252 }; 1253 1254 // Flags for ColorEdit3() / ColorEdit4() / ColorPicker3() / ColorPicker4() / ColorButton() 892 1255 enum ImGuiColorEditFlags_ 893 1256 { 894 ImGuiColorEditFlags_NoAlpha = 1 << 1, // // ColorEdit, ColorPicker, ColorButton: ignore Alpha component (read 3 components from the input pointer). 895 ImGuiColorEditFlags_NoPicker = 1 << 2, // // ColorEdit: disable picker when clicking on colored square. 896 ImGuiColorEditFlags_NoOptions = 1 << 3, // // ColorEdit: disable toggling options menu when right-clicking on inputs/small preview. 897 ImGuiColorEditFlags_NoSmallPreview = 1 << 4, // // ColorEdit, ColorPicker: disable colored square preview next to the inputs. (e.g. to show only the inputs) 898 ImGuiColorEditFlags_NoInputs = 1 << 5, // // ColorEdit, ColorPicker: disable inputs sliders/text widgets (e.g. to show only the small preview colored square). 899 ImGuiColorEditFlags_NoTooltip = 1 << 6, // // ColorEdit, ColorPicker, ColorButton: disable tooltip when hovering the preview. 900 ImGuiColorEditFlags_NoLabel = 1 << 7, // // ColorEdit, ColorPicker: disable display of inline text label (the label is still forwarded to the tooltip and picker). 901 ImGuiColorEditFlags_NoSidePreview = 1 << 8, // // ColorPicker: disable bigger color preview on right side of the picker, use small colored square preview instead. 902 903 // User Options (right-click on widget to change some of them). You can set application defaults using SetColorEditOptions(). The idea is that you probably don't want to override them in most of your calls, let the user choose and/or call SetColorEditOptions() during startup. 904 ImGuiColorEditFlags_AlphaBar = 1 << 9, // // ColorEdit, ColorPicker: show vertical alpha bar/gradient in picker. 905 ImGuiColorEditFlags_AlphaPreview = 1 << 10, // // ColorEdit, ColorPicker, ColorButton: display preview as a transparent color over a checkerboard, instead of opaque. 906 ImGuiColorEditFlags_AlphaPreviewHalf = 1 << 11, // // ColorEdit, ColorPicker, ColorButton: display half opaque / half checkerboard, instead of opaque. 907 ImGuiColorEditFlags_HDR = 1 << 12, // // (WIP) ColorEdit: Currently only disable 0.0f..1.0f limits in RGBA edition (note: you probably want to use ImGuiColorEditFlags_Float flag as well). 908 ImGuiColorEditFlags_RGB = 1 << 13, // [Inputs] // ColorEdit: choose one among RGB/HSV/HEX. ColorPicker: choose any combination using RGB/HSV/HEX. 909 ImGuiColorEditFlags_HSV = 1 << 14, // [Inputs] // " 910 ImGuiColorEditFlags_HEX = 1 << 15, // [Inputs] // " 911 ImGuiColorEditFlags_Uint8 = 1 << 16, // [DataType] // ColorEdit, ColorPicker, ColorButton: _display_ values formatted as 0..255. 912 ImGuiColorEditFlags_Float = 1 << 17, // [DataType] // ColorEdit, ColorPicker, ColorButton: _display_ values formatted as 0.0f..1.0f floats instead of 0..255 integers. No round-trip of value via integers. 913 ImGuiColorEditFlags_PickerHueBar = 1 << 18, // [PickerMode] // ColorPicker: bar for Hue, rectangle for Sat/Value. 914 ImGuiColorEditFlags_PickerHueWheel = 1 << 19, // [PickerMode] // ColorPicker: wheel for Hue, triangle for Sat/Value. 915 916 // [Internal] Masks 917 ImGuiColorEditFlags__InputsMask = ImGuiColorEditFlags_RGB | ImGuiColorEditFlags_HSV | ImGuiColorEditFlags_HEX, 918 ImGuiColorEditFlags__DataTypeMask = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_Float, 919 ImGuiColorEditFlags__PickerMask = ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_PickerHueBar, 920 ImGuiColorEditFlags__OptionsDefault = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_RGB | ImGuiColorEditFlags_PickerHueBar // Change application default using SetColorEditOptions() 1257 ImGuiColorEditFlags_None = 0, 1258 ImGuiColorEditFlags_NoAlpha = 1 << 1, // // ColorEdit, ColorPicker, ColorButton: ignore Alpha component (will only read 3 components from the input pointer). 1259 ImGuiColorEditFlags_NoPicker = 1 << 2, // // ColorEdit: disable picker when clicking on colored square. 1260 ImGuiColorEditFlags_NoOptions = 1 << 3, // // ColorEdit: disable toggling options menu when right-clicking on inputs/small preview. 1261 ImGuiColorEditFlags_NoSmallPreview = 1 << 4, // // ColorEdit, ColorPicker: disable colored square preview next to the inputs. (e.g. to show only the inputs) 1262 ImGuiColorEditFlags_NoInputs = 1 << 5, // // ColorEdit, ColorPicker: disable inputs sliders/text widgets (e.g. to show only the small preview colored square). 1263 ImGuiColorEditFlags_NoTooltip = 1 << 6, // // ColorEdit, ColorPicker, ColorButton: disable tooltip when hovering the preview. 1264 ImGuiColorEditFlags_NoLabel = 1 << 7, // // ColorEdit, ColorPicker: disable display of inline text label (the label is still forwarded to the tooltip and picker). 1265 ImGuiColorEditFlags_NoSidePreview = 1 << 8, // // ColorPicker: disable bigger color preview on right side of the picker, use small colored square preview instead. 1266 ImGuiColorEditFlags_NoDragDrop = 1 << 9, // // ColorEdit: disable drag and drop target. ColorButton: disable drag and drop source. 1267 ImGuiColorEditFlags_NoBorder = 1 << 10, // // ColorButton: disable border (which is enforced by default) 1268 1269 // User Options (right-click on widget to change some of them). 1270 ImGuiColorEditFlags_AlphaBar = 1 << 16, // // ColorEdit, ColorPicker: show vertical alpha bar/gradient in picker. 1271 ImGuiColorEditFlags_AlphaPreview = 1 << 17, // // ColorEdit, ColorPicker, ColorButton: display preview as a transparent color over a checkerboard, instead of opaque. 1272 ImGuiColorEditFlags_AlphaPreviewHalf= 1 << 18, // // ColorEdit, ColorPicker, ColorButton: display half opaque / half checkerboard, instead of opaque. 1273 ImGuiColorEditFlags_HDR = 1 << 19, // // (WIP) ColorEdit: Currently only disable 0.0f..1.0f limits in RGBA edition (note: you probably want to use ImGuiColorEditFlags_Float flag as well). 1274 ImGuiColorEditFlags_DisplayRGB = 1 << 20, // [Display] // ColorEdit: override _display_ type among RGB/HSV/Hex. ColorPicker: select any combination using one or more of RGB/HSV/Hex. 1275 ImGuiColorEditFlags_DisplayHSV = 1 << 21, // [Display] // " 1276 ImGuiColorEditFlags_DisplayHex = 1 << 22, // [Display] // " 1277 ImGuiColorEditFlags_Uint8 = 1 << 23, // [DataType] // ColorEdit, ColorPicker, ColorButton: _display_ values formatted as 0..255. 1278 ImGuiColorEditFlags_Float = 1 << 24, // [DataType] // ColorEdit, ColorPicker, ColorButton: _display_ values formatted as 0.0f..1.0f floats instead of 0..255 integers. No round-trip of value via integers. 1279 ImGuiColorEditFlags_PickerHueBar = 1 << 25, // [Picker] // ColorPicker: bar for Hue, rectangle for Sat/Value. 1280 ImGuiColorEditFlags_PickerHueWheel = 1 << 26, // [Picker] // ColorPicker: wheel for Hue, triangle for Sat/Value. 1281 ImGuiColorEditFlags_InputRGB = 1 << 27, // [Input] // ColorEdit, ColorPicker: input and output data in RGB format. 1282 ImGuiColorEditFlags_InputHSV = 1 << 28, // [Input] // ColorEdit, ColorPicker: input and output data in HSV format. 1283 1284 // Defaults Options. You can set application defaults using SetColorEditOptions(). The intent is that you probably don't want to 1285 // override them in most of your calls. Let the user choose via the option menu and/or call SetColorEditOptions() once during startup. 1286 ImGuiColorEditFlags__OptionsDefault = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_PickerHueBar, 1287 1288 // [Internal] Masks 1289 ImGuiColorEditFlags__DisplayMask = ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_DisplayHex, 1290 ImGuiColorEditFlags__DataTypeMask = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_Float, 1291 ImGuiColorEditFlags__PickerMask = ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_PickerHueBar, 1292 ImGuiColorEditFlags__InputMask = ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_InputHSV 1293 1294 // Obsolete names (will be removed) 1295 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS 1296 , ImGuiColorEditFlags_RGB = ImGuiColorEditFlags_DisplayRGB, ImGuiColorEditFlags_HSV = ImGuiColorEditFlags_DisplayHSV, ImGuiColorEditFlags_HEX = ImGuiColorEditFlags_DisplayHex // [renamed in 1.69] 1297 #endif 1298 }; 1299 1300 // Flags for DragFloat(), DragInt(), SliderFloat(), SliderInt() etc. 1301 // We use the same sets of flags for DragXXX() and SliderXXX() functions as the features are the same and it makes it easier to swap them. 1302 enum ImGuiSliderFlags_ 1303 { 1304 ImGuiSliderFlags_None = 0, 1305 ImGuiSliderFlags_AlwaysClamp = 1 << 4, // Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds. 1306 ImGuiSliderFlags_Logarithmic = 1 << 5, // Make the widget logarithmic (linear otherwise). Consider using ImGuiSliderFlags_NoRoundToFormat with this if using a format-string with small amount of digits. 1307 ImGuiSliderFlags_NoRoundToFormat = 1 << 6, // Disable rounding underlying value to match precision of the display format string (e.g. %.3f values are rounded to those 3 digits) 1308 ImGuiSliderFlags_NoInput = 1 << 7, // Disable CTRL+Click or Enter key allowing to input text directly into the widget 1309 ImGuiSliderFlags_InvalidMask_ = 0x7000000F // [Internal] We treat using those bits as being potentially a 'float power' argument from the previous API that has got miscast to this enum, and will trigger an assert if needed. 1310 1311 // Obsolete names (will be removed) 1312 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS 1313 , ImGuiSliderFlags_ClampOnInput = ImGuiSliderFlags_AlwaysClamp // [renamed in 1.79] 1314 #endif 1315 }; 1316 1317 // Identify a mouse button. 1318 // Those values are guaranteed to be stable and we frequently use 0/1 directly. Named enums provided for convenience. 1319 enum ImGuiMouseButton_ 1320 { 1321 ImGuiMouseButton_Left = 0, 1322 ImGuiMouseButton_Right = 1, 1323 ImGuiMouseButton_Middle = 2, 1324 ImGuiMouseButton_COUNT = 5 921 1325 }; 922 1326 … … 925 1329 enum ImGuiMouseCursor_ 926 1330 { 927 ImGuiMouseCursor_None = -1, 928 ImGuiMouseCursor_Arrow = 0, 929 ImGuiMouseCursor_TextInput, // When hovering over InputText, etc. 930 ImGuiMouseCursor_ResizeAll, // Unused by imgui functions 931 ImGuiMouseCursor_ResizeNS, // When hovering over an horizontal border 932 ImGuiMouseCursor_ResizeEW, // When hovering over a vertical border or a column 933 ImGuiMouseCursor_ResizeNESW, // When hovering over the bottom-left corner of a window 934 ImGuiMouseCursor_ResizeNWSE, // When hovering over the bottom-right corner of a window 935 ImGuiMouseCursor_COUNT 936 937 // Obsolete names (will be removed) 1331 ImGuiMouseCursor_None = -1, 1332 ImGuiMouseCursor_Arrow = 0, 1333 ImGuiMouseCursor_TextInput, // When hovering over InputText, etc. 1334 ImGuiMouseCursor_ResizeAll, // (Unused by Dear ImGui functions) 1335 ImGuiMouseCursor_ResizeNS, // When hovering over an horizontal border 1336 ImGuiMouseCursor_ResizeEW, // When hovering over a vertical border or a column 1337 ImGuiMouseCursor_ResizeNESW, // When hovering over the bottom-left corner of a window 1338 ImGuiMouseCursor_ResizeNWSE, // When hovering over the bottom-right corner of a window 1339 ImGuiMouseCursor_Hand, // (Unused by Dear ImGui functions. Use for e.g. hyperlinks) 1340 ImGuiMouseCursor_NotAllowed, // When hovering something with disallowed interaction. Usually a crossed circle. 1341 ImGuiMouseCursor_COUNT 1342 1343 // Obsolete names (will be removed) 938 1344 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS 939 , ImGuiMouseCursor_Count_ = ImGuiMouseCursor_COUNT 940 #endif 941 }; 942 943 // Condition for ImGui::SetWindow***(), SetNextWindow***(), SetNextTreeNode***() functions 944 // Important: Treat as a regular enum! Do NOT combine multiple values using binary operators! All the functions above treat 0 as a shortcut to ImGuiCond_Always. 1345 , ImGuiMouseCursor_Count_ = ImGuiMouseCursor_COUNT // [renamed in 1.60] 1346 #endif 1347 }; 1348 1349 // Enumeration for ImGui::SetWindow***(), SetNextWindow***(), SetNextItem***() functions 1350 // Represent a condition. 1351 // Important: Treat as a regular enum! Do NOT combine multiple values using binary operators! All the functions above treat 0 as a shortcut to ImGuiCond_Always. 945 1352 enum ImGuiCond_ 946 1353 { 947 ImGuiCond_Always = 1 << 0, // Set the variable 948 ImGuiCond_Once = 1 << 1, // Set the variable once per runtime session (only the first call with succeed) 949 ImGuiCond_FirstUseEver = 1 << 2, // Set the variable if the object/window has no persistently saved data (no entry in .ini file) 950 ImGuiCond_Appearing = 1 << 3 // Set the variable if the object/window is appearing after being hidden/inactive (or the first time) 951 952 // Obsolete names (will be removed) 1354 ImGuiCond_None = 0, // No condition (always set the variable), same as _Always 1355 ImGuiCond_Always = 1 << 0, // No condition (always set the variable) 1356 ImGuiCond_Once = 1 << 1, // Set the variable once per runtime session (only the first call will succeed) 1357 ImGuiCond_FirstUseEver = 1 << 2, // Set the variable if the object/window has no persistently saved data (no entry in .ini file) 1358 ImGuiCond_Appearing = 1 << 3 // Set the variable if the object/window is appearing after being hidden/inactive (or the first time) 1359 }; 1360 1361 //----------------------------------------------------------------------------- 1362 // Helpers: Memory allocations macros 1363 // IM_MALLOC(), IM_FREE(), IM_NEW(), IM_PLACEMENT_NEW(), IM_DELETE() 1364 // We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax. 1365 // Defining a custom placement new() with a custom parameter allows us to bypass including <new> which on some platforms complains when user has disabled exceptions. 1366 //----------------------------------------------------------------------------- 1367 1368 struct ImNewWrapper {}; 1369 inline void* operator new(size_t, ImNewWrapper, void* ptr) { return ptr; } 1370 inline void operator delete(void*, ImNewWrapper, void*) {} // This is only required so we can use the symmetrical new() 1371 #define IM_ALLOC(_SIZE) ImGui::MemAlloc(_SIZE) 1372 #define IM_FREE(_PTR) ImGui::MemFree(_PTR) 1373 #define IM_PLACEMENT_NEW(_PTR) new(ImNewWrapper(), _PTR) 1374 #define IM_NEW(_TYPE) new(ImNewWrapper(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE 1375 template<typename T> void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p); } } 1376 1377 //----------------------------------------------------------------------------- 1378 // Helper: ImVector<> 1379 // Lightweight std::vector<>-like class to avoid dragging dependencies (also, some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug). 1380 //----------------------------------------------------------------------------- 1381 // - You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our public structures are relying on it. 1382 // - We use std-like naming convention here, which is a little unusual for this codebase. 1383 // - Important: clear() frees memory, resize(0) keep the allocated buffer. We use resize(0) a lot to intentionally recycle allocated buffers across frames and amortize our costs. 1384 // - Important: our implementation does NOT call C++ constructors/destructors, we treat everything as raw data! This is intentional but be extra mindful of that, 1385 // Do NOT use this class as a std::vector replacement in your own code! Many of the structures used by dear imgui can be safely initialized by a zero-memset. 1386 //----------------------------------------------------------------------------- 1387 1388 template<typename T> 1389 struct ImVector 1390 { 1391 int Size; 1392 int Capacity; 1393 T* Data; 1394 1395 // Provide standard typedefs but we don't use them ourselves. 1396 typedef T value_type; 1397 typedef value_type* iterator; 1398 typedef const value_type* const_iterator; 1399 1400 // Constructors, destructor 1401 inline ImVector() { Size = Capacity = 0; Data = NULL; } 1402 inline ImVector(const ImVector<T>& src) { Size = Capacity = 0; Data = NULL; operator=(src); } 1403 inline ImVector<T>& operator=(const ImVector<T>& src) { clear(); resize(src.Size); memcpy(Data, src.Data, (size_t)Size * sizeof(T)); return *this; } 1404 inline ~ImVector() { if (Data) IM_FREE(Data); } 1405 1406 inline bool empty() const { return Size == 0; } 1407 inline int size() const { return Size; } 1408 inline int size_in_bytes() const { return Size * (int)sizeof(T); } 1409 inline int max_size() const { return 0x7FFFFFFF / (int)sizeof(T); } 1410 inline int capacity() const { return Capacity; } 1411 inline T& operator[](int i) { IM_ASSERT(i >= 0 && i < Size); return Data[i]; } 1412 inline const T& operator[](int i) const { IM_ASSERT(i >= 0 && i < Size); return Data[i]; } 1413 1414 inline void clear() { if (Data) { Size = Capacity = 0; IM_FREE(Data); Data = NULL; } } 1415 inline T* begin() { return Data; } 1416 inline const T* begin() const { return Data; } 1417 inline T* end() { return Data + Size; } 1418 inline const T* end() const { return Data + Size; } 1419 inline T& front() { IM_ASSERT(Size > 0); return Data[0]; } 1420 inline const T& front() const { IM_ASSERT(Size > 0); return Data[0]; } 1421 inline T& back() { IM_ASSERT(Size > 0); return Data[Size - 1]; } 1422 inline const T& back() const { IM_ASSERT(Size > 0); return Data[Size - 1]; } 1423 inline void swap(ImVector<T>& rhs) { int rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; int rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; T* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; } 1424 1425 inline int _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity / 2) : 8; return new_capacity > sz ? new_capacity : sz; } 1426 inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; } 1427 inline void resize(int new_size, const T& v) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; } 1428 inline void shrink(int new_size) { IM_ASSERT(new_size <= Size); Size = new_size; } // Resize a vector to a smaller size, guaranteed not to cause a reallocation 1429 inline void reserve(int new_capacity) { if (new_capacity <= Capacity) return; T* new_data = (T*)IM_ALLOC((size_t)new_capacity * sizeof(T)); if (Data) { memcpy(new_data, Data, (size_t)Size * sizeof(T)); IM_FREE(Data); } Data = new_data; Capacity = new_capacity; } 1430 1431 // NB: It is illegal to call push_back/push_front/insert with a reference pointing inside the ImVector data itself! e.g. v.push_back(v[10]) is forbidden. 1432 inline void push_back(const T& v) { if (Size == Capacity) reserve(_grow_capacity(Size + 1)); memcpy(&Data[Size], &v, sizeof(v)); Size++; } 1433 inline void pop_back() { IM_ASSERT(Size > 0); Size--; } 1434 inline void push_front(const T& v) { if (Size == 0) push_back(v); else insert(Data, v); } 1435 inline T* erase(const T* it) { IM_ASSERT(it >= Data && it < Data + Size); const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + 1, ((size_t)Size - (size_t)off - 1) * sizeof(T)); Size--; return Data + off; } 1436 inline T* erase(const T* it, const T* it_last){ IM_ASSERT(it >= Data && it < Data + Size && it_last > it && it_last <= Data + Size); const ptrdiff_t count = it_last - it; const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + count, ((size_t)Size - (size_t)off - count) * sizeof(T)); Size -= (int)count; return Data + off; } 1437 inline T* erase_unsorted(const T* it) { IM_ASSERT(it >= Data && it < Data + Size); const ptrdiff_t off = it - Data; if (it < Data + Size - 1) memcpy(Data + off, Data + Size - 1, sizeof(T)); Size--; return Data + off; } 1438 inline T* insert(const T* it, const T& v) { IM_ASSERT(it >= Data && it <= Data + Size); const ptrdiff_t off = it - Data; if (Size == Capacity) reserve(_grow_capacity(Size + 1)); if (off < (int)Size) memmove(Data + off + 1, Data + off, ((size_t)Size - (size_t)off) * sizeof(T)); memcpy(&Data[off], &v, sizeof(v)); Size++; return Data + off; } 1439 inline bool contains(const T& v) const { const T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data++ == v) return true; return false; } 1440 inline T* find(const T& v) { T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data == v) break; else ++data; return data; } 1441 inline const T* find(const T& v) const { const T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data == v) break; else ++data; return data; } 1442 inline bool find_erase(const T& v) { const T* it = find(v); if (it < Data + Size) { erase(it); return true; } return false; } 1443 inline bool find_erase_unsorted(const T& v) { const T* it = find(v); if (it < Data + Size) { erase_unsorted(it); return true; } return false; } 1444 inline int index_from_ptr(const T* it) const { IM_ASSERT(it >= Data && it < Data + Size); const ptrdiff_t off = it - Data; return (int)off; } 1445 }; 1446 1447 //----------------------------------------------------------------------------- 1448 // ImGuiStyle 1449 // You may modify the ImGui::GetStyle() main instance during initialization and before NewFrame(). 1450 // During the frame, use ImGui::PushStyleVar(ImGuiStyleVar_XXXX)/PopStyleVar() to alter the main style values, 1451 // and ImGui::PushStyleColor(ImGuiCol_XXX)/PopStyleColor() for colors. 1452 //----------------------------------------------------------------------------- 1453 1454 struct ImGuiStyle 1455 { 1456 float Alpha; // Global alpha applies to everything in Dear ImGui. 1457 ImVec2 WindowPadding; // Padding within a window. 1458 float WindowRounding; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended. 1459 float WindowBorderSize; // Thickness of border around windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). 1460 ImVec2 WindowMinSize; // Minimum window size. This is a global setting. If you want to constraint individual windows, use SetNextWindowSizeConstraints(). 1461 ImVec2 WindowTitleAlign; // Alignment for title bar text. Defaults to (0.0f,0.5f) for left-aligned,vertically centered. 1462 ImGuiDir WindowMenuButtonPosition; // Side of the collapsing/docking button in the title bar (None/Left/Right). Defaults to ImGuiDir_Left. 1463 float ChildRounding; // Radius of child window corners rounding. Set to 0.0f to have rectangular windows. 1464 float ChildBorderSize; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). 1465 float PopupRounding; // Radius of popup window corners rounding. (Note that tooltip windows use WindowRounding) 1466 float PopupBorderSize; // Thickness of border around popup/tooltip windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). 1467 ImVec2 FramePadding; // Padding within a framed rectangle (used by most widgets). 1468 float FrameRounding; // Radius of frame corners rounding. Set to 0.0f to have rectangular frame (used by most widgets). 1469 float FrameBorderSize; // Thickness of border around frames. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). 1470 ImVec2 ItemSpacing; // Horizontal and vertical spacing between widgets/lines. 1471 ImVec2 ItemInnerSpacing; // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label). 1472 ImVec2 TouchExtraPadding; // 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! 1473 float IndentSpacing; // Horizontal indentation when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). 1474 float ColumnsMinSpacing; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1). 1475 float ScrollbarSize; // Width of the vertical scrollbar, Height of the horizontal scrollbar. 1476 float ScrollbarRounding; // Radius of grab corners for scrollbar. 1477 float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar. 1478 float GrabRounding; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. 1479 float LogSliderDeadzone; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero. 1480 float TabRounding; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. 1481 float TabBorderSize; // Thickness of border around tabs. 1482 float TabMinWidthForCloseButton; // Minimum width for close button to appears on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected. 1483 ImGuiDir ColorButtonPosition; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. 1484 ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered). 1485 ImVec2 SelectableTextAlign; // Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. 1486 ImVec2 DisplayWindowPadding; // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows. 1487 ImVec2 DisplaySafeAreaPadding; // If you cannot see the edges of your screen (e.g. on a TV) increase the safe area padding. Apply to popups/tooltips as well regular windows. NB: Prefer configuring your TV sets correctly! 1488 float MouseCursorScale; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later. 1489 bool AntiAliasedLines; // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU. Latched at the beginning of the frame (copied to ImDrawList). 1490 bool AntiAliasedLinesUseTex; // Enable anti-aliased lines/borders using textures where possible. Require back-end to render with bilinear filtering. Latched at the beginning of the frame (copied to ImDrawList). 1491 bool AntiAliasedFill; // Enable anti-aliased edges around filled shapes (rounded rectangles, circles, etc.). Disable if you are really tight on CPU/GPU. Latched at the beginning of the frame (copied to ImDrawList). 1492 float CurveTessellationTol; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality. 1493 float CircleSegmentMaxError; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry. 1494 ImVec4 Colors[ImGuiCol_COUNT]; 1495 1496 IMGUI_API ImGuiStyle(); 1497 IMGUI_API void ScaleAllSizes(float scale_factor); 1498 }; 1499 1500 //----------------------------------------------------------------------------- 1501 // ImGuiIO 1502 // Communicate most settings and inputs/outputs to Dear ImGui using this structure. 1503 // Access via ImGui::GetIO(). Read 'Programmer guide' section in .cpp file for general usage. 1504 //----------------------------------------------------------------------------- 1505 1506 struct ImGuiIO 1507 { 1508 //------------------------------------------------------------------ 1509 // Configuration (fill once) // Default value 1510 //------------------------------------------------------------------ 1511 1512 ImGuiConfigFlags ConfigFlags; // = 0 // See ImGuiConfigFlags_ enum. Set by user/application. Gamepad/keyboard navigation options, etc. 1513 ImGuiBackendFlags BackendFlags; // = 0 // See ImGuiBackendFlags_ enum. Set by back-end (imgui_impl_xxx files or custom back-end) to communicate features supported by the back-end. 1514 ImVec2 DisplaySize; // <unset> // Main display size, in pixels. 1515 float DeltaTime; // = 1.0f/60.0f // Time elapsed since last frame, in seconds. 1516 float IniSavingRate; // = 5.0f // Minimum time between saving positions/sizes to .ini file, in seconds. 1517 const char* IniFilename; // = "imgui.ini" // Path to .ini file. Set NULL to disable automatic .ini loading/saving, if e.g. you want to manually load/save from memory. 1518 const char* LogFilename; // = "imgui_log.txt"// Path to .log file (default parameter to ImGui::LogToFile when no file is specified). 1519 float MouseDoubleClickTime; // = 0.30f // Time for a double-click, in seconds. 1520 float MouseDoubleClickMaxDist; // = 6.0f // Distance threshold to stay in to validate a double-click, in pixels. 1521 float MouseDragThreshold; // = 6.0f // Distance threshold before considering we are dragging. 1522 int KeyMap[ImGuiKey_COUNT]; // <unset> // Map of indices into the KeysDown[512] entries array which represent your "native" keyboard state. 1523 float KeyRepeatDelay; // = 0.250f // When holding a key/button, time before it starts repeating, in seconds (for buttons in Repeat mode, etc.). 1524 float KeyRepeatRate; // = 0.050f // When holding a key/button, rate at which it repeats, in seconds. 1525 void* UserData; // = NULL // Store your own data for retrieval by callbacks. 1526 1527 ImFontAtlas*Fonts; // <auto> // Font atlas: load, rasterize and pack one or more fonts into a single texture. 1528 float FontGlobalScale; // = 1.0f // Global scale all fonts 1529 bool FontAllowUserScaling; // = false // Allow user scaling text of individual window with CTRL+Wheel. 1530 ImFont* FontDefault; // = NULL // Font to use on NewFrame(). Use NULL to uses Fonts->Fonts[0]. 1531 ImVec2 DisplayFramebufferScale; // = (1, 1) // For retina display or other situations where window coordinates are different from framebuffer coordinates. This generally ends up in ImDrawData::FramebufferScale. 1532 1533 // Miscellaneous options 1534 bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by back-end implementations. 1535 bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl (was called io.OptMacOSXBehaviors prior to 1.63) 1536 bool ConfigInputTextCursorBlink; // = true // Set to false to disable blinking cursor, for users who consider it distracting. (was called: io.OptCursorBlink prior to 1.63) 1537 bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback. (This used to be a per-window ImGuiWindowFlags_ResizeFromAnySide flag) 1538 bool ConfigWindowsMoveFromTitleBarOnly; // = false // [BETA] Set to true to only allow moving windows when clicked+dragged from the title bar. Windows without a title bar are not affected. 1539 float ConfigWindowsMemoryCompactTimer;// = 60.0f // [BETA] Compact window memory usage when unused. Set to -1.0f to disable. 1540 1541 //------------------------------------------------------------------ 1542 // Platform Functions 1543 // (the imgui_impl_xxxx back-end files are setting those up for you) 1544 //------------------------------------------------------------------ 1545 1546 // Optional: Platform/Renderer back-end name (informational only! will be displayed in About Window) + User data for back-end/wrappers to store their own stuff. 1547 const char* BackendPlatformName; // = NULL 1548 const char* BackendRendererName; // = NULL 1549 void* BackendPlatformUserData; // = NULL // User data for platform back-end 1550 void* BackendRendererUserData; // = NULL // User data for renderer back-end 1551 void* BackendLanguageUserData; // = NULL // User data for non C++ programming language back-end 1552 1553 // Optional: Access OS clipboard 1554 // (default to use native Win32 clipboard on Windows, otherwise uses a private clipboard. Override to access OS clipboard on other architectures) 1555 const char* (*GetClipboardTextFn)(void* user_data); 1556 void (*SetClipboardTextFn)(void* user_data, const char* text); 1557 void* ClipboardUserData; 1558 1559 // Optional: Notify OS Input Method Editor of the screen position of your cursor for text input position (e.g. when using Japanese/Chinese IME on Windows) 1560 // (default to use native imm32 api on Windows) 1561 void (*ImeSetInputScreenPosFn)(int x, int y); 1562 void* ImeWindowHandle; // = NULL // (Windows) Set this to your HWND to get automatic IME cursor positioning. 1563 953 1564 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS 954 , ImGuiSetCond_Always = ImGuiCond_Always, ImGuiSetCond_Once = ImGuiCond_Once, ImGuiSetCond_FirstUseEver = ImGuiCond_FirstUseEver, ImGuiSetCond_Appearing = ImGuiCond_Appearing 955 #endif 956 }; 957 958 // You may modify the ImGui::GetStyle() main instance during initialization and before NewFrame(). 959 // During the frame, use ImGui::PushStyleVar(ImGuiStyleVar_XXXX)/PopStyleVar() to alter the main style values, and ImGui::PushStyleColor(ImGuiCol_XXX)/PopStyleColor() for colors. 960 struct ImGuiStyle 961 { 962 float Alpha; // Global alpha applies to everything in ImGui. 963 ImVec2 WindowPadding; // Padding within a window. 964 float WindowRounding; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. 965 float WindowBorderSize; // Thickness of border around windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). 966 ImVec2 WindowMinSize; // Minimum window size. This is a global setting. If you want to constraint individual windows, use SetNextWindowSizeConstraints(). 967 ImVec2 WindowTitleAlign; // Alignment for title bar text. Defaults to (0.0f,0.5f) for left-aligned,vertically centered. 968 float ChildRounding; // Radius of child window corners rounding. Set to 0.0f to have rectangular windows. 969 float ChildBorderSize; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). 970 float PopupRounding; // Radius of popup window corners rounding. (Note that tooltip windows use WindowRounding) 971 float PopupBorderSize; // Thickness of border around popup/tooltip windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). 972 ImVec2 FramePadding; // Padding within a framed rectangle (used by most widgets). 973 float FrameRounding; // Radius of frame corners rounding. Set to 0.0f to have rectangular frame (used by most widgets). 974 float FrameBorderSize; // Thickness of border around frames. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). 975 ImVec2 ItemSpacing; // Horizontal and vertical spacing between widgets/lines. 976 ImVec2 ItemInnerSpacing; // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label). 977 ImVec2 TouchExtraPadding; // 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! 978 float IndentSpacing; // Horizontal indentation when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). 979 float ColumnsMinSpacing; // Minimum horizontal spacing between two columns. 980 float ScrollbarSize; // Width of the vertical scrollbar, Height of the horizontal scrollbar. 981 float ScrollbarRounding; // Radius of grab corners for scrollbar. 982 float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar. 983 float GrabRounding; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. 984 ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f,0.5f) for horizontally+vertically centered. 985 ImVec2 DisplayWindowPadding; // Window positions are clamped to be visible within the display area by at least this amount. Only covers regular windows. 986 ImVec2 DisplaySafeAreaPadding; // If you cannot see the edges of your screen (e.g. on a TV) increase the safe area padding. Apply to popups/tooltips as well regular windows. NB: Prefer configuring your TV sets correctly! 987 float MouseCursorScale; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later. 988 bool AntiAliasedLines; // Enable anti-aliasing on lines/borders. Disable if you are really tight on CPU/GPU. 989 bool AntiAliasedFill; // Enable anti-aliasing on filled shapes (rounded rectangles, circles, etc.) 990 float CurveTessellationTol; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality. 991 ImVec4 Colors[ImGuiCol_COUNT]; 992 993 IMGUI_API ImGuiStyle(); 994 IMGUI_API void ScaleAllSizes(float scale_factor); 995 }; 996 997 // This is where your app communicate with ImGui. Access via ImGui::GetIO(). 998 // Read 'Programmer guide' section in .cpp file for general usage. 999 struct ImGuiIO 1000 { 1001 //------------------------------------------------------------------ 1002 // Settings (fill once) // Default value: 1003 //------------------------------------------------------------------ 1004 1005 ImGuiConfigFlags ConfigFlags; // = 0 // See ImGuiConfigFlags_ enum. Set by user/application. Gamepad/keyboard navigation options, etc. 1006 ImGuiBackendFlags BackendFlags; // = 0 // Set ImGuiBackendFlags_ enum. Set by imgui_impl_xxx files or custom back-end. 1007 ImVec2 DisplaySize; // <unset> // Display size, in pixels. For clamping windows positions. 1008 float DeltaTime; // = 1.0f/60.0f // Time elapsed since last frame, in seconds. 1009 float IniSavingRate; // = 5.0f // Maximum time between saving positions/sizes to .ini file, in seconds. 1010 const char* IniFilename; // = "imgui.ini" // Path to .ini file. NULL to disable .ini saving. 1011 const char* LogFilename; // = "imgui_log.txt" // Path to .log file (default parameter to ImGui::LogToFile when no file is specified). 1012 float MouseDoubleClickTime; // = 0.30f // Time for a double-click, in seconds. 1013 float MouseDoubleClickMaxDist; // = 6.0f // Distance threshold to stay in to validate a double-click, in pixels. 1014 float MouseDragThreshold; // = 6.0f // Distance threshold before considering we are dragging. 1015 int KeyMap[ImGuiKey_COUNT]; // <unset> // Map of indices into the KeysDown[512] entries array which represent your "native" keyboard state. 1016 float KeyRepeatDelay; // = 0.250f // When holding a key/button, time before it starts repeating, in seconds (for buttons in Repeat mode, etc.). 1017 float KeyRepeatRate; // = 0.050f // When holding a key/button, rate at which it repeats, in seconds. 1018 void* UserData; // = NULL // Store your own data for retrieval by callbacks. 1019 1020 ImFontAtlas* Fonts; // <auto> // Load and assemble one or more fonts into a single tightly packed texture. Output to Fonts array. 1021 float FontGlobalScale; // = 1.0f // Global scale all fonts 1022 bool FontAllowUserScaling; // = false // Allow user scaling text of individual window with CTRL+Wheel. 1023 ImFont* FontDefault; // = NULL // Font to use on NewFrame(). Use NULL to uses Fonts->Fonts[0]. 1024 ImVec2 DisplayFramebufferScale; // = (1.0f,1.0f) // For retina display or other situations where window coordinates are different from framebuffer coordinates. User storage only, presently not used by ImGui. 1025 ImVec2 DisplayVisibleMin; // <unset> (0.0f,0.0f) // If you use DisplaySize as a virtual space larger than your screen, set DisplayVisibleMin/Max to the visible area. 1026 ImVec2 DisplayVisibleMax; // <unset> (0.0f,0.0f) // If the values are the same, we defaults to Min=(0.0f) and Max=DisplaySize 1027 1028 // Advanced/subtle behaviors 1029 bool OptMacOSXBehaviors; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl 1030 bool OptCursorBlink; // = true // Enable blinking cursor, for users who consider it annoying. 1031 1032 //------------------------------------------------------------------ 1033 // Settings (User Functions) 1034 //------------------------------------------------------------------ 1035 1036 // Optional: access OS clipboard 1037 // (default to use native Win32 clipboard on Windows, otherwise uses a private clipboard. Override to access OS clipboard on other architectures) 1038 const char* (*GetClipboardTextFn)(void* user_data); 1039 void(*SetClipboardTextFn)(void* user_data, const char* text); 1040 void* ClipboardUserData; 1041 1042 // Optional: notify OS Input Method Editor of the screen position of your cursor for text input position (e.g. when using Japanese/Chinese IME in Windows) 1043 // (default to use native imm32 api on Windows) 1044 void(*ImeSetInputScreenPosFn)(int x, int y); 1045 void* ImeWindowHandle; // (Windows) Set this to your HWND to get automatic IME cursor positioning. 1046 1047 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS 1048 // [OBSOLETE] Rendering function, will be automatically called in Render(). Please call your rendering function yourself now! You can obtain the ImDrawData* by calling ImGui::GetDrawData() after Render(). 1049 // See example applications if you are unsure of how to implement this. 1050 void(*RenderDrawListsFn)(ImDrawData* data); 1051 #endif 1052 1053 //------------------------------------------------------------------ 1054 // Input - Fill before calling NewFrame() 1055 //------------------------------------------------------------------ 1056 1057 ImVec2 MousePos; // Mouse position, in pixels. Set to ImVec2(-FLT_MAX,-FLT_MAX) if mouse is unavailable (on another screen, etc.) 1058 bool MouseDown[5]; // Mouse buttons: left, right, middle + extras. ImGui itself mostly only uses left button (BeginPopupContext** are using right button). Others buttons allows us to track if the mouse is being used by your application + available to user as a convenience via IsMouse** API. 1059 float MouseWheel; // Mouse wheel Vertical: 1 unit scrolls about 5 lines text. 1060 float MouseWheelH; // Mouse wheel Horizontal. Most users don't have a mouse with an horizontal wheel, may not be filled by all back-ends. 1061 bool MouseDrawCursor; // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). 1062 bool KeyCtrl; // Keyboard modifier pressed: Control 1063 bool KeyShift; // Keyboard modifier pressed: Shift 1064 bool KeyAlt; // Keyboard modifier pressed: Alt 1065 bool KeySuper; // Keyboard modifier pressed: Cmd/Super/Windows 1066 bool KeysDown[512]; // Keyboard keys that are pressed (ideally left in the "native" order your engine has access to keyboard keys, so you can use your own defines/enums for keys). 1067 ImWchar InputCharacters[16 + 1]; // List of characters input (translated by user from keypress+keyboard state). Fill using AddInputCharacter() helper. 1068 float NavInputs[ImGuiNavInput_COUNT]; // Gamepad inputs (keyboard keys will be auto-mapped and be written here by ImGui::NewFrame, all values will be cleared back to zero in ImGui::EndFrame) 1069 1070 // Functions 1071 IMGUI_API void AddInputCharacter(ImWchar c); // Add new character into InputCharacters[] 1072 IMGUI_API void AddInputCharactersUTF8(const char* utf8_chars); // Add new characters into InputCharacters[] from an UTF-8 string 1073 inline void ClearInputCharacters() { InputCharacters[0] = 0; } // Clear the text input buffer manually 1074 1075 //------------------------------------------------------------------ 1076 // Output - Retrieve after calling NewFrame() 1077 //------------------------------------------------------------------ 1078 1079 bool WantCaptureMouse; // When io.WantCaptureMouse is true, imgui will use the mouse inputs, do not dispatch them to your main game/application (in both cases, always pass on mouse inputs to imgui). (e.g. unclicked mouse is hovering over an imgui window, widget is active, mouse was clicked over an imgui window, etc.). 1080 bool WantCaptureKeyboard; // When io.WantCaptureKeyboard is true, imgui will use the keyboard inputs, do not dispatch them to your main game/application (in both cases, always pass keyboard inputs to imgui). (e.g. InputText active, or an imgui window is focused and navigation is enabled, etc.). 1081 bool WantTextInput; // Mobile/console: when io.WantTextInput is true, you may display an on-screen keyboard. This is set by ImGui when it wants textual keyboard input to happen (e.g. when a InputText widget is active). 1082 bool WantSetMousePos; // MousePos has been altered, back-end should reposition mouse on next frame. Set only when ImGuiConfigFlags_NavEnableSetMousePos flag is enabled. 1083 bool NavActive; // Directional navigation is currently allowed (will handle ImGuiKey_NavXXX events) = a window is focused and it doesn't use the ImGuiWindowFlags_NoNavInputs flag. 1084 bool NavVisible; // Directional navigation is visible and allowed (will handle ImGuiKey_NavXXX events). 1085 float Framerate; // Application framerate estimation, in frame per second. Solely for convenience. Rolling average estimation based on IO.DeltaTime over 120 frames 1086 int MetricsRenderVertices; // Vertices output during last call to Render() 1087 int MetricsRenderIndices; // Indices output during last call to Render() = number of triangles * 3 1088 int MetricsActiveWindows; // Number of visible root windows (exclude child windows) 1089 ImVec2 MouseDelta; // Mouse delta. Note that this is zero if either current or previous position are invalid (-FLT_MAX,-FLT_MAX), so a disappearing/reappearing mouse won't have a huge delta. 1090 1091 //------------------------------------------------------------------ 1092 // [Internal] ImGui will maintain those fields. Forward compatibility not guaranteed! 1093 //------------------------------------------------------------------ 1094 1095 ImVec2 MousePosPrev; // Previous mouse position temporary storage (nb: not for public use, set to MousePos in NewFrame()) 1096 ImVec2 MouseClickedPos[5]; // Position at time of clicking 1097 float MouseClickedTime[5]; // Time of last click (used to figure out double-click) 1098 bool MouseClicked[5]; // Mouse button went from !Down to Down 1099 bool MouseDoubleClicked[5]; // Has mouse button been double-clicked? 1100 bool MouseReleased[5]; // Mouse button went from Down to !Down 1101 bool MouseDownOwned[5]; // Track if button was clicked inside a window. We don't request mouse capture from the application if click started outside ImGui bounds. 1102 float MouseDownDuration[5]; // Duration the mouse button has been down (0.0f == just clicked) 1103 float MouseDownDurationPrev[5]; // Previous time the mouse button has been down 1104 ImVec2 MouseDragMaxDistanceAbs[5]; // Maximum distance, absolute, on each axis, of how much mouse has traveled from the clicking point 1105 float MouseDragMaxDistanceSqr[5]; // Squared maximum distance of how much mouse has traveled from the clicking point 1106 float KeysDownDuration[512]; // Duration the keyboard key has been down (0.0f == just pressed) 1107 float KeysDownDurationPrev[512]; // Previous duration the key has been down 1108 float NavInputsDownDuration[ImGuiNavInput_COUNT]; 1109 float NavInputsDownDurationPrev[ImGuiNavInput_COUNT]; 1110 1111 IMGUI_API ImGuiIO(); 1565 // [OBSOLETE since 1.60+] Rendering function, will be automatically called in Render(). Please call your rendering function yourself now! 1566 // You can obtain the ImDrawData* by calling ImGui::GetDrawData() after Render(). See example applications if you are unsure of how to implement this. 1567 void (*RenderDrawListsFn)(ImDrawData* data); 1568 #else 1569 // This is only here to keep ImGuiIO the same size/layout, so that IMGUI_DISABLE_OBSOLETE_FUNCTIONS can exceptionally be used outside of imconfig.h. 1570 void* RenderDrawListsFnUnused; 1571 #endif 1572 1573 //------------------------------------------------------------------ 1574 // Input - Fill before calling NewFrame() 1575 //------------------------------------------------------------------ 1576 1577 ImVec2 MousePos; // Mouse position, in pixels. Set to ImVec2(-FLT_MAX, -FLT_MAX) if mouse is unavailable (on another screen, etc.) 1578 bool MouseDown[5]; // Mouse buttons: 0=left, 1=right, 2=middle + extras (ImGuiMouseButton_COUNT == 5). Dear ImGui mostly uses left and right buttons. Others buttons allows us to track if the mouse is being used by your application + available to user as a convenience via IsMouse** API. 1579 float MouseWheel; // Mouse wheel Vertical: 1 unit scrolls about 5 lines text. 1580 float MouseWheelH; // Mouse wheel Horizontal. Most users don't have a mouse with an horizontal wheel, may not be filled by all back-ends. 1581 bool KeyCtrl; // Keyboard modifier pressed: Control 1582 bool KeyShift; // Keyboard modifier pressed: Shift 1583 bool KeyAlt; // Keyboard modifier pressed: Alt 1584 bool KeySuper; // Keyboard modifier pressed: Cmd/Super/Windows 1585 bool KeysDown[512]; // Keyboard keys that are pressed (ideally left in the "native" order your engine has access to keyboard keys, so you can use your own defines/enums for keys). 1586 float NavInputs[ImGuiNavInput_COUNT]; // Gamepad inputs. Cleared back to zero by EndFrame(). Keyboard keys will be auto-mapped and be written here by NewFrame(). 1587 1588 // Functions 1589 IMGUI_API void AddInputCharacter(unsigned int c); // Queue new character input 1590 IMGUI_API void AddInputCharacterUTF16(ImWchar16 c); // Queue new character input from an UTF-16 character, it can be a surrogate 1591 IMGUI_API void AddInputCharactersUTF8(const char* str); // Queue new characters input from an UTF-8 string 1592 IMGUI_API void ClearInputCharacters(); // Clear the text input buffer manually 1593 1594 //------------------------------------------------------------------ 1595 // Output - Updated by NewFrame() or EndFrame()/Render() 1596 // (when reading from the io.WantCaptureMouse, io.WantCaptureKeyboard flags to dispatch your inputs, it is 1597 // generally easier and more correct to use their state BEFORE calling NewFrame(). See FAQ for details!) 1598 //------------------------------------------------------------------ 1599 1600 bool WantCaptureMouse; // Set when Dear ImGui will use mouse inputs, in this case do not dispatch them to your main game/application (either way, always pass on mouse inputs to imgui). (e.g. unclicked mouse is hovering over an imgui window, widget is active, mouse was clicked over an imgui window, etc.). 1601 bool WantCaptureKeyboard; // Set when Dear ImGui will use keyboard inputs, in this case do not dispatch them to your main game/application (either way, always pass keyboard inputs to imgui). (e.g. InputText active, or an imgui window is focused and navigation is enabled, etc.). 1602 bool WantTextInput; // Mobile/console: when set, you may display an on-screen keyboard. This is set by Dear ImGui when it wants textual keyboard input to happen (e.g. when a InputText widget is active). 1603 bool WantSetMousePos; // MousePos has been altered, back-end should reposition mouse on next frame. Rarely used! Set only when ImGuiConfigFlags_NavEnableSetMousePos flag is enabled. 1604 bool WantSaveIniSettings; // When manual .ini load/save is active (io.IniFilename == NULL), this will be set to notify your application that you can call SaveIniSettingsToMemory() and save yourself. Important: clear io.WantSaveIniSettings yourself after saving! 1605 bool NavActive; // Keyboard/Gamepad navigation is currently allowed (will handle ImGuiKey_NavXXX events) = a window is focused and it doesn't use the ImGuiWindowFlags_NoNavInputs flag. 1606 bool NavVisible; // Keyboard/Gamepad navigation is visible and allowed (will handle ImGuiKey_NavXXX events). 1607 float Framerate; // Application framerate estimate, in frame per second. Solely for convenience. Rolling average estimation based on io.DeltaTime over 120 frames. 1608 int MetricsRenderVertices; // Vertices output during last call to Render() 1609 int MetricsRenderIndices; // Indices output during last call to Render() = number of triangles * 3 1610 int MetricsRenderWindows; // Number of visible windows 1611 int MetricsActiveWindows; // Number of active windows 1612 int MetricsActiveAllocations; // Number of active allocations, updated by MemAlloc/MemFree based on current context. May be off if you have multiple imgui contexts. 1613 ImVec2 MouseDelta; // Mouse delta. Note that this is zero if either current or previous position are invalid (-FLT_MAX,-FLT_MAX), so a disappearing/reappearing mouse won't have a huge delta. 1614 1615 //------------------------------------------------------------------ 1616 // [Internal] Dear ImGui will maintain those fields. Forward compatibility not guaranteed! 1617 //------------------------------------------------------------------ 1618 1619 ImGuiKeyModFlags KeyMods; // Key mods flags (same as io.KeyCtrl/KeyShift/KeyAlt/KeySuper but merged into flags), updated by NewFrame() 1620 ImVec2 MousePosPrev; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid) 1621 ImVec2 MouseClickedPos[5]; // Position at time of clicking 1622 double MouseClickedTime[5]; // Time of last click (used to figure out double-click) 1623 bool MouseClicked[5]; // Mouse button went from !Down to Down 1624 bool MouseDoubleClicked[5]; // Has mouse button been double-clicked? 1625 bool MouseReleased[5]; // Mouse button went from Down to !Down 1626 bool MouseDownOwned[5]; // Track if button was clicked inside a dear imgui window. We don't request mouse capture from the application if click started outside ImGui bounds. 1627 bool MouseDownWasDoubleClick[5]; // Track if button down was a double-click 1628 float MouseDownDuration[5]; // Duration the mouse button has been down (0.0f == just clicked) 1629 float MouseDownDurationPrev[5]; // Previous time the mouse button has been down 1630 ImVec2 MouseDragMaxDistanceAbs[5]; // Maximum distance, absolute, on each axis, of how much mouse has traveled from the clicking point 1631 float MouseDragMaxDistanceSqr[5]; // Squared maximum distance of how much mouse has traveled from the clicking point 1632 float KeysDownDuration[512]; // Duration the keyboard key has been down (0.0f == just pressed) 1633 float KeysDownDurationPrev[512]; // Previous duration the key has been down 1634 float NavInputsDownDuration[ImGuiNavInput_COUNT]; 1635 float NavInputsDownDurationPrev[ImGuiNavInput_COUNT]; 1636 float PenPressure; // Touch/Pen pressure (0.0f to 1.0f, should be >0.0f only when MouseDown[0] == true). Helper storage currently unused by Dear ImGui. 1637 ImWchar16 InputQueueSurrogate; // For AddInputCharacterUTF16 1638 ImVector<ImWchar> InputQueueCharacters; // Queue of _characters_ input (obtained by platform back-end). Fill using AddInputCharacter() helper. 1639 1640 IMGUI_API ImGuiIO(); 1641 }; 1642 1643 //----------------------------------------------------------------------------- 1644 // Misc data structures 1645 //----------------------------------------------------------------------------- 1646 1647 // Shared state of InputText(), passed as an argument to your callback when a ImGuiInputTextFlags_Callback* flag is used. 1648 // The callback function should return 0 by default. 1649 // Callbacks (follow a flag name and see comments in ImGuiInputTextFlags_ declarations for more details) 1650 // - ImGuiInputTextFlags_CallbackEdit: Callback on buffer edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active) 1651 // - ImGuiInputTextFlags_CallbackAlways: Callback on each iteration 1652 // - ImGuiInputTextFlags_CallbackCompletion: Callback on pressing TAB 1653 // - ImGuiInputTextFlags_CallbackHistory: Callback on pressing Up/Down arrows 1654 // - ImGuiInputTextFlags_CallbackCharFilter: Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard. 1655 // - ImGuiInputTextFlags_CallbackResize: Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. 1656 struct ImGuiInputTextCallbackData 1657 { 1658 ImGuiInputTextFlags EventFlag; // One ImGuiInputTextFlags_Callback* // Read-only 1659 ImGuiInputTextFlags Flags; // What user passed to InputText() // Read-only 1660 void* UserData; // What user passed to InputText() // Read-only 1661 1662 // Arguments for the different callback events 1663 // - To modify the text buffer in a callback, prefer using the InsertChars() / DeleteChars() function. InsertChars() will take care of calling the resize callback if necessary. 1664 // - If you know your edits are not going to resize the underlying buffer allocation, you may modify the contents of 'Buf[]' directly. You need to update 'BufTextLen' accordingly (0 <= BufTextLen < BufSize) and set 'BufDirty'' to true so InputText can update its internal state. 1665 ImWchar EventChar; // Character input // Read-write // [CharFilter] Replace character with another one, or set to zero to drop. return 1 is equivalent to setting EventChar=0; 1666 ImGuiKey EventKey; // Key pressed (Up/Down/TAB) // Read-only // [Completion,History] 1667 char* Buf; // Text buffer // Read-write // [Resize] Can replace pointer / [Completion,History,Always] Only write to pointed data, don't replace the actual pointer! 1668 int BufTextLen; // Text length (in bytes) // Read-write // [Resize,Completion,History,Always] Exclude zero-terminator storage. In C land: == strlen(some_text), in C++ land: string.length() 1669 int BufSize; // Buffer size (in bytes) = capacity+1 // Read-only // [Resize,Completion,History,Always] Include zero-terminator storage. In C land == ARRAYSIZE(my_char_array), in C++ land: string.capacity()+1 1670 bool BufDirty; // Set if you modify Buf/BufTextLen! // Write // [Completion,History,Always] 1671 int CursorPos; // // Read-write // [Completion,History,Always] 1672 int SelectionStart; // // Read-write // [Completion,History,Always] == to SelectionEnd when no selection) 1673 int SelectionEnd; // // Read-write // [Completion,History,Always] 1674 1675 // Helper functions for text manipulation. 1676 // Use those function to benefit from the CallbackResize behaviors. Calling those function reset the selection. 1677 IMGUI_API ImGuiInputTextCallbackData(); 1678 IMGUI_API void DeleteChars(int pos, int bytes_count); 1679 IMGUI_API void InsertChars(int pos, const char* text, const char* text_end = NULL); 1680 void SelectAll() { SelectionStart = 0; SelectionEnd = BufTextLen; } 1681 void ClearSelection() { SelectionStart = SelectionEnd = BufTextLen; } 1682 bool HasSelection() const { return SelectionStart != SelectionEnd; } 1683 }; 1684 1685 // Resizing callback data to apply custom constraint. As enabled by SetNextWindowSizeConstraints(). Callback is called during the next Begin(). 1686 // NB: For basic min/max size constraint on each axis you don't need to use the callback! The SetNextWindowSizeConstraints() parameters are enough. 1687 struct ImGuiSizeCallbackData 1688 { 1689 void* UserData; // Read-only. What user passed to SetNextWindowSizeConstraints() 1690 ImVec2 Pos; // Read-only. Window position, for reference. 1691 ImVec2 CurrentSize; // Read-only. Current window size. 1692 ImVec2 DesiredSize; // Read-write. Desired size, based on user's mouse position. Write to this field to restrain resizing. 1693 }; 1694 1695 // Data payload for Drag and Drop operations: AcceptDragDropPayload(), GetDragDropPayload() 1696 struct ImGuiPayload 1697 { 1698 // Members 1699 void* Data; // Data (copied and owned by dear imgui) 1700 int DataSize; // Data size 1701 1702 // [Internal] 1703 ImGuiID SourceId; // Source item id 1704 ImGuiID SourceParentId; // Source parent id (if available) 1705 int DataFrameCount; // Data timestamp 1706 char DataType[32 + 1]; // Data type tag (short user-supplied string, 32 characters max) 1707 bool Preview; // Set when AcceptDragDropPayload() was called and mouse has been hovering the target item (nb: handle overlapping drag targets) 1708 bool Delivery; // Set when AcceptDragDropPayload() was called and mouse button is released over the target item. 1709 1710 ImGuiPayload() { Clear(); } 1711 void Clear() { SourceId = SourceParentId = 0; Data = NULL; DataSize = 0; memset(DataType, 0, sizeof(DataType)); DataFrameCount = -1; Preview = Delivery = false; } 1712 bool IsDataType(const char* type) const { return DataFrameCount != -1 && strcmp(type, DataType) == 0; } 1713 bool IsPreview() const { return Preview; } 1714 bool IsDelivery() const { return Delivery; } 1112 1715 }; 1113 1716 1114 1717 //----------------------------------------------------------------------------- 1115 1718 // Obsolete functions (Will be removed! Read 'API BREAKING CHANGES' section in imgui.cpp for details) 1719 // Please keep your copy of dear imgui up to date! Occasionally set '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' in imconfig.h to stay ahead. 1116 1720 //----------------------------------------------------------------------------- 1117 1721 … … 1119 1723 namespace ImGui 1120 1724 { 1121 // OBSOLETED in 1.61 (from Apr 2018) 1122 bool InputFloat(const char* label, float* v, float step, float step_fast, int decimal_precision, ImGuiInputTextFlags extra_flags = 0); // Use the 'const char* format' version instead of 'decimal_precision'! 1123 bool InputFloat2(const char* label, float v[2], int decimal_precision, ImGuiInputTextFlags extra_flags = 0); 1124 bool InputFloat3(const char* label, float v[3], int decimal_precision, ImGuiInputTextFlags extra_flags = 0); 1125 bool InputFloat4(const char* label, float v[4], int decimal_precision, ImGuiInputTextFlags extra_flags = 0); 1126 // OBSOLETED in 1.60 (from Dec 2017) 1127 static inline bool IsAnyWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_AnyWindow); } 1128 static inline bool IsAnyWindowHovered() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); } 1129 static inline ImVec2 CalcItemRectClosestPoint(const ImVec2& pos, bool on_edge = false, float outward = 0.f) { (void)on_edge; (void)outward; IM_ASSERT(0); return pos; } 1130 // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) 1131 static inline void ShowTestWindow() { return ShowDemoWindow(); } 1132 static inline bool IsRootWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootWindow); } 1133 static inline bool IsRootWindowOrAnyChildFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows); } 1134 static inline void SetNextWindowContentWidth(float w) { SetNextWindowContentSize(ImVec2(w, 0.0f)); } 1135 static inline float GetItemsLineHeightWithSpacing() { return GetFrameHeightWithSpacing(); } 1136 // OBSOLETED in 1.52 (between Aug 2017 and Oct 2017) 1137 bool Begin(const char* name, bool* p_open, const ImVec2& size_on_first_use, float bg_alpha_override = -1.0f, ImGuiWindowFlags flags = 0); // Use SetNextWindowSize(size, ImGuiCond_FirstUseEver) + SetNextWindowBgAlpha() instead. 1138 static inline bool IsRootWindowOrAnyChildHovered() { return IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows); } 1139 static inline void AlignFirstTextHeightToWidgets() { AlignTextToFramePadding(); } 1140 static inline void SetNextWindowPosCenter(ImGuiCond c = 0) { ImGuiIO& io = GetIO(); SetNextWindowPos(ImVec2(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f), c, ImVec2(0.5f, 0.5f)); } 1141 // OBSOLETED in 1.51 (between Jun 2017 and Aug 2017) 1142 static inline bool IsItemHoveredRect() { return IsItemHovered(ImGuiHoveredFlags_RectOnly); } 1143 static inline bool IsPosHoveringAnyWindow(const ImVec2&) { IM_ASSERT(0); return false; } // This was misleading and partly broken. You probably want to use the ImGui::GetIO().WantCaptureMouse flag instead. 1144 static inline bool IsMouseHoveringAnyWindow() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); } 1145 static inline bool IsMouseHoveringWindow() { return IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem); } 1146 // OBSOLETED IN 1.49 (between Apr 2016 and May 2016) 1147 static inline bool CollapsingHeader(const char* label, const char* str_id, bool framed = true, bool default_open = false) { (void)str_id; (void)framed; ImGuiTreeNodeFlags default_open_flags = 1 << 5; return CollapsingHeader(label, (default_open ? default_open_flags : 0)); } 1725 // OBSOLETED in 1.79 (from August 2020) 1726 static inline void OpenPopupContextItem(const char* str_id = NULL, ImGuiMouseButton mb = 1) { OpenPopupOnItemClick(str_id, mb); } // Bool return value removed. Use IsWindowAppearing() in BeginPopup() instead. Renamed in 1.77, renamed back in 1.79. Sorry! 1727 // OBSOLETED in 1.78 (from June 2020) 1728 // Old drag/sliders functions that took a 'float power = 1.0' argument instead of flags. 1729 // For shared code, you can version check at compile-time with `#if IMGUI_VERSION_NUM >= 17704`. 1730 IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, float power); 1731 IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min, const void* p_max, const char* format, float power); 1732 static inline bool DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, format, power); } 1733 static inline bool DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalarN(label, ImGuiDataType_Float, v, 2, v_speed, &v_min, &v_max, format, power); } 1734 static inline bool DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalarN(label, ImGuiDataType_Float, v, 3, v_speed, &v_min, &v_max, format, power); } 1735 static inline bool DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalarN(label, ImGuiDataType_Float, v, 4, v_speed, &v_min, &v_max, format, power); } 1736 IMGUI_API bool SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, float power); 1737 IMGUI_API bool SliderScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_min, const void* p_max, const char* format, float power); 1738 static inline bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, float power) { return SliderScalar(label, ImGuiDataType_Float, v, &v_min, &v_max, format, power); } 1739 static inline bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format, float power) { return SliderScalarN(label, ImGuiDataType_Float, v, 2, &v_min, &v_max, format, power); } 1740 static inline bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format, float power) { return SliderScalarN(label, ImGuiDataType_Float, v, 3, &v_min, &v_max, format, power); } 1741 static inline bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format, float power) { return SliderScalarN(label, ImGuiDataType_Float, v, 4, &v_min, &v_max, format, power); } 1742 // OBSOLETED in 1.77 (from June 2020) 1743 static inline bool BeginPopupContextWindow(const char* str_id, ImGuiMouseButton mb, bool over_items) { return BeginPopupContextWindow(str_id, mb | (over_items ? 0 : ImGuiPopupFlags_NoOpenOverItems)); } 1744 // OBSOLETED in 1.72 (from April 2019) 1745 static inline void TreeAdvanceToLabelPos() { SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()); } 1746 // OBSOLETED in 1.71 (from June 2019) 1747 static inline void SetNextTreeNodeOpen(bool open, ImGuiCond cond = 0) { SetNextItemOpen(open, cond); } 1748 // OBSOLETED in 1.70 (from May 2019) 1749 static inline float GetContentRegionAvailWidth() { return GetContentRegionAvail().x; } 1750 // OBSOLETED in 1.69 (from Mar 2019) 1751 static inline ImDrawList* GetOverlayDrawList() { return GetForegroundDrawList(); } 1752 // OBSOLETED in 1.66 (from Sep 2018) 1753 static inline void SetScrollHere(float center_ratio=0.5f){ SetScrollHereY(center_ratio); } 1754 // OBSOLETED in 1.63 (between Aug 2018 and Sept 2018) 1755 static inline bool IsItemDeactivatedAfterChange() { return IsItemDeactivatedAfterEdit(); } 1756 // OBSOLETED in 1.61 (between Apr 2018 and Aug 2018) 1757 IMGUI_API bool InputFloat(const char* label, float* v, float step, float step_fast, int decimal_precision, ImGuiInputTextFlags flags = 0); // Use the 'const char* format' version instead of 'decimal_precision'! 1758 IMGUI_API bool InputFloat2(const char* label, float v[2], int decimal_precision, ImGuiInputTextFlags flags = 0); 1759 IMGUI_API bool InputFloat3(const char* label, float v[3], int decimal_precision, ImGuiInputTextFlags flags = 0); 1760 IMGUI_API bool InputFloat4(const char* label, float v[4], int decimal_precision, ImGuiInputTextFlags flags = 0); 1761 // OBSOLETED in 1.60 (between Dec 2017 and Apr 2018) 1762 static inline bool IsAnyWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_AnyWindow); } 1763 static inline bool IsAnyWindowHovered() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); } 1148 1764 } 1765 typedef ImGuiInputTextCallback ImGuiTextEditCallback; // OBSOLETED in 1.63 (from Aug 2018): made the names consistent 1766 typedef ImGuiInputTextCallbackData ImGuiTextEditCallbackData; 1149 1767 #endif 1150 1768 … … 1153 1771 //----------------------------------------------------------------------------- 1154 1772 1155 // Helper: Lightweight std::vector<> like class to avoid dragging dependencies (also: Windows implementation of STL with debug enabled is absurdly slow, so let's bypass it so our code runs fast in debug). 1156 // *Important* Our implementation does NOT call C++ constructors/destructors. This is intentional, we do not require it but you have to be mindful of that. Do not use this class as a straight std::vector replacement in your code! 1157 template<typename T> 1158 class ImVector 1159 { 1160 public: 1161 int Size; 1162 int Capacity; 1163 T* Data; 1164 1165 typedef T value_type; 1166 typedef value_type* iterator; 1167 typedef const value_type* const_iterator; 1168 1169 inline ImVector() { Size = Capacity = 0; Data = NULL; } 1170 inline ~ImVector() { if (Data) ImGui::MemFree(Data); } 1171 inline ImVector(const ImVector<T>& src) { Size = Capacity = 0; Data = NULL; operator=(src); } 1172 inline ImVector& operator=(const ImVector<T>& src) { clear(); resize(src.Size); memcpy(Data, src.Data, (size_t)Size * sizeof(value_type)); return *this; } 1173 1174 inline bool empty() const { return Size == 0; } 1175 inline int size() const { return Size; } 1176 inline int capacity() const { return Capacity; } 1177 inline value_type& operator[](int i) { IM_ASSERT(i < Size); return Data[i]; } 1178 inline const value_type& operator[](int i) const { IM_ASSERT(i < Size); return Data[i]; } 1179 1180 inline void clear() { if (Data) { Size = Capacity = 0; ImGui::MemFree(Data); Data = NULL; } } 1181 inline iterator begin() { return Data; } 1182 inline const_iterator begin() const { return Data; } 1183 inline iterator end() { return Data + Size; } 1184 inline const_iterator end() const { return Data + Size; } 1185 inline value_type& front() { IM_ASSERT(Size > 0); return Data[0]; } 1186 inline const value_type& front() const { IM_ASSERT(Size > 0); return Data[0]; } 1187 inline value_type& back() { IM_ASSERT(Size > 0); return Data[Size - 1]; } 1188 inline const value_type& back() const { IM_ASSERT(Size > 0); return Data[Size - 1]; } 1189 inline void swap(ImVector<value_type>& rhs) { int rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; int rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; value_type* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; } 1190 1191 inline int _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity / 2) : 8; return new_capacity > sz ? new_capacity : sz; } 1192 inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; } 1193 inline void resize(int new_size, const value_type& v) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; } 1194 inline void reserve(int new_capacity) 1195 { 1196 if (new_capacity <= Capacity) 1197 return; 1198 value_type* new_data = (value_type*)ImGui::MemAlloc((size_t)new_capacity * sizeof(value_type)); 1199 if (Data) 1200 memcpy(new_data, Data, (size_t)Size * sizeof(value_type)); 1201 ImGui::MemFree(Data); 1202 Data = new_data; 1203 Capacity = new_capacity; 1204 } 1205 1206 // NB: &v cannot be pointing inside the ImVector Data itself! e.g. v.push_back(v[10]) is forbidden. 1207 inline void push_back(const value_type& v) { if (Size == Capacity) reserve(_grow_capacity(Size + 1)); memcpy(&Data[Size], &v, sizeof(v)); Size++; } 1208 inline void pop_back() { IM_ASSERT(Size > 0); Size--; } 1209 inline void push_front(const value_type& v) { if (Size == 0) push_back(v); else insert(Data, v); } 1210 inline iterator erase(const_iterator it) { IM_ASSERT(it >= Data && it < Data + Size); const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + 1, ((size_t)Size - (size_t)off - 1) * sizeof(value_type)); Size--; return Data + off; } 1211 inline iterator insert(const_iterator it, const value_type& v) { IM_ASSERT(it >= Data && it <= Data + Size); const ptrdiff_t off = it - Data; if (Size == Capacity) reserve(_grow_capacity(Size + 1)); if (off < (int)Size) memmove(Data + off + 1, Data + off, ((size_t)Size - (size_t)off) * sizeof(value_type)); memcpy(&Data[off], &v, sizeof(v)); Size++; return Data + off; } 1212 inline bool contains(const value_type& v) const { const T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data++ == v) return true; return false; } 1213 }; 1214 1215 // Helper: IM_NEW(), IM_PLACEMENT_NEW(), IM_DELETE() macros to call MemAlloc + Placement New, Placement Delete + MemFree 1216 // We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax. 1217 // Defining a custom placement new() with a dummy parameter allows us to bypass including <new> which on some platforms complains when user has disabled exceptions. 1218 struct ImNewDummy {}; 1219 inline void* operator new(size_t, ImNewDummy, void* ptr) { return ptr; } 1220 inline void operator delete(void*, ImNewDummy, void*) {} // This is only required so we can use the symetrical new() 1221 #define IM_PLACEMENT_NEW(_PTR) new(ImNewDummy(), _PTR) 1222 #define IM_NEW(_TYPE) new(ImNewDummy(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE 1223 template<typename T> void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p); } } 1773 // Helper: Unicode defines 1774 #define IM_UNICODE_CODEPOINT_INVALID 0xFFFD // Invalid Unicode code point (standard value). 1775 #ifdef IMGUI_USE_WCHAR32 1776 #define IM_UNICODE_CODEPOINT_MAX 0x10FFFF // Maximum Unicode code point supported by this build. 1777 #else 1778 #define IM_UNICODE_CODEPOINT_MAX 0xFFFF // Maximum Unicode code point supported by this build. 1779 #endif 1224 1780 1225 1781 // Helper: Execute a block of code at maximum once a frame. Convenient if you want to quickly create an UI within deep-nested code that runs multiple times every frame. … … 1227 1783 struct ImGuiOnceUponAFrame 1228 1784 { 1229 ImGuiOnceUponAFrame() { RefFrame = -1; } 1230 mutable int RefFrame; 1231 operator bool() const { int current_frame = ImGui::GetFrameCount(); if (RefFrame == current_frame) return false; RefFrame = current_frame; return true; } 1232 }; 1233 1234 // Helper: Macro for ImGuiOnceUponAFrame. Attention: The macro expands into 2 statement so make sure you don't use it within e.g. an if() statement without curly braces. 1235 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // Will obsolete 1236 #define IMGUI_ONCE_UPON_A_FRAME static ImGuiOnceUponAFrame imgui_oaf; if (imgui_oaf) 1237 #endif 1785 ImGuiOnceUponAFrame() { RefFrame = -1; } 1786 mutable int RefFrame; 1787 operator bool() const { int current_frame = ImGui::GetFrameCount(); if (RefFrame == current_frame) return false; RefFrame = current_frame; return true; } 1788 }; 1238 1789 1239 1790 // Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]" 1240 1791 struct ImGuiTextFilter 1241 1792 { 1242 struct TextRange 1243 { 1244 const char* b; 1245 const char* e; 1246 1247 TextRange() { b = e = NULL; } 1248 TextRange(const char* _b, const char* _e) { b = _b; e = _e; } 1249 const char* begin() const { return b; } 1250 const char* end() const { return e; } 1251 bool empty() const { return b == e; } 1252 char front() const { return *b; } 1253 static bool is_blank(char c) { return c == ' ' || c == '\t'; } 1254 void trim_blanks() { while (b < e && is_blank(*b)) b++; while (e > b && is_blank(*(e - 1))) e--; } 1255 IMGUI_API void split(char separator, ImVector<TextRange>& out); 1256 }; 1257 1258 char InputBuf[256]; 1259 ImVector<TextRange> Filters; 1260 int CountGrep; 1261 1262 IMGUI_API ImGuiTextFilter(const char* default_filter = ""); 1263 IMGUI_API bool Draw(const char* label = "Filter (inc,-exc)", float width = 0.0f); // Helper calling InputText+Build 1264 IMGUI_API bool PassFilter(const char* text, const char* text_end = NULL) const; 1265 IMGUI_API void Build(); 1266 void Clear() { InputBuf[0] = 0; Build(); } 1267 bool IsActive() const { return !Filters.empty(); } 1268 }; 1269 1270 // Helper: Text buffer for logging/accumulating text 1793 IMGUI_API ImGuiTextFilter(const char* default_filter = ""); 1794 IMGUI_API bool Draw(const char* label = "Filter (inc,-exc)", float width = 0.0f); // Helper calling InputText+Build 1795 IMGUI_API bool PassFilter(const char* text, const char* text_end = NULL) const; 1796 IMGUI_API void Build(); 1797 void Clear() { InputBuf[0] = 0; Build(); } 1798 bool IsActive() const { return !Filters.empty(); } 1799 1800 // [Internal] 1801 struct ImGuiTextRange 1802 { 1803 const char* b; 1804 const char* e; 1805 1806 ImGuiTextRange() { b = e = NULL; } 1807 ImGuiTextRange(const char* _b, const char* _e) { b = _b; e = _e; } 1808 bool empty() const { return b == e; } 1809 IMGUI_API void split(char separator, ImVector<ImGuiTextRange>* out) const; 1810 }; 1811 char InputBuf[256]; 1812 ImVector<ImGuiTextRange>Filters; 1813 int CountGrep; 1814 }; 1815 1816 // Helper: Growable text buffer for logging/accumulating text 1817 // (this could be called 'ImGuiTextBuilder' / 'ImGuiStringBuilder') 1271 1818 struct ImGuiTextBuffer 1272 1819 { 1273 ImVector<char> Buf; 1274 1275 ImGuiTextBuffer() { Buf.push_back(0); } 1276 inline char operator[](int i) { return Buf.Data[i]; } 1277 const char* begin() const { return &Buf.front(); } 1278 const char* end() const { return &Buf.back(); } // Buf is zero-terminated, so end() will point on the zero-terminator 1279 int size() const { return Buf.Size - 1; } 1280 bool empty() { return Buf.Size <= 1; } 1281 void clear() { Buf.clear(); Buf.push_back(0); } 1282 void reserve(int capacity) { Buf.reserve(capacity); } 1283 const char* c_str() const { return Buf.Data; } 1284 IMGUI_API void appendf(const char* fmt, ...) IM_FMTARGS(2); 1285 IMGUI_API void appendfv(const char* fmt, va_list args) IM_FMTLIST(2); 1286 }; 1287 1288 // Helper: Simple Key->value storage 1820 ImVector<char> Buf; 1821 IMGUI_API static char EmptyString[1]; 1822 1823 ImGuiTextBuffer() { } 1824 inline char operator[](int i) const { IM_ASSERT(Buf.Data != NULL); return Buf.Data[i]; } 1825 const char* begin() const { return Buf.Data ? &Buf.front() : EmptyString; } 1826 const char* end() const { return Buf.Data ? &Buf.back() : EmptyString; } // Buf is zero-terminated, so end() will point on the zero-terminator 1827 int size() const { return Buf.Size ? Buf.Size - 1 : 0; } 1828 bool empty() const { return Buf.Size <= 1; } 1829 void clear() { Buf.clear(); } 1830 void reserve(int capacity) { Buf.reserve(capacity); } 1831 const char* c_str() const { return Buf.Data ? Buf.Data : EmptyString; } 1832 IMGUI_API void append(const char* str, const char* str_end = NULL); 1833 IMGUI_API void appendf(const char* fmt, ...) IM_FMTARGS(2); 1834 IMGUI_API void appendfv(const char* fmt, va_list args) IM_FMTLIST(2); 1835 }; 1836 1837 // Helper: Key->Value storage 1289 1838 // Typically you don't have to worry about this since a storage is held within each Window. 1290 1839 // We use it to e.g. store collapse state for a tree (Int 0/1) … … 1296 1845 struct ImGuiStorage 1297 1846 { 1298 struct Pair 1299 { 1300 ImGuiID key; 1301 union { int val_i; float val_f; void* val_p; }; 1302 Pair(ImGuiID _key, int _val_i) { key = _key; val_i = _val_i; } 1303 Pair(ImGuiID _key, float _val_f) { key = _key; val_f = _val_f; } 1304 Pair(ImGuiID _key, void* _val_p) { key = _key; val_p = _val_p; } 1305 }; 1306 ImVector<Pair> Data; 1307 1308 // - Get***() functions find pair, never add/allocate. Pairs are sorted so a query is O(log N) 1309 // - Set***() functions find pair, insertion on demand if missing. 1310 // - Sorted insertion is costly, paid once. A typical frame shouldn't need to insert any new pair. 1311 void Clear() { Data.clear(); } 1312 IMGUI_API int GetInt(ImGuiID key, int default_val = 0) const; 1313 IMGUI_API void SetInt(ImGuiID key, int val); 1314 IMGUI_API bool GetBool(ImGuiID key, bool default_val = false) const; 1315 IMGUI_API void SetBool(ImGuiID key, bool val); 1316 IMGUI_API float GetFloat(ImGuiID key, float default_val = 0.0f) const; 1317 IMGUI_API void SetFloat(ImGuiID key, float val); 1318 IMGUI_API void* GetVoidPtr(ImGuiID key) const; // default_val is NULL 1319 IMGUI_API void SetVoidPtr(ImGuiID key, void* val); 1320 1321 // - Get***Ref() functions finds pair, insert on demand if missing, return pointer. Useful if you intend to do Get+Set. 1322 // - 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. 1323 // - A typical use case where this is convenient for quick hacking (e.g. add storage during a live Edit&Continue session if you can't modify existing struct) 1324 // float* pvar = ImGui::GetFloatRef(key); ImGui::SliderFloat("var", pvar, 0, 100.0f); some_var += *pvar; 1325 IMGUI_API int* GetIntRef(ImGuiID key, int default_val = 0); 1326 IMGUI_API bool* GetBoolRef(ImGuiID key, bool default_val = false); 1327 IMGUI_API float* GetFloatRef(ImGuiID key, float default_val = 0.0f); 1328 IMGUI_API void** GetVoidPtrRef(ImGuiID key, void* default_val = NULL); 1329 1330 // Use on your own storage if you know only integer are being stored (open/close all tree nodes) 1331 IMGUI_API void SetAllInt(int val); 1332 1333 // For quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once. 1334 IMGUI_API void BuildSortByKey(); 1335 }; 1336 1337 // Shared state of InputText(), passed to callback when a ImGuiInputTextFlags_Callback* flag is used and the corresponding callback is triggered. 1338 struct ImGuiTextEditCallbackData 1339 { 1340 ImGuiInputTextFlags EventFlag; // One of ImGuiInputTextFlags_Callback* // Read-only 1341 ImGuiInputTextFlags Flags; // What user passed to InputText() // Read-only 1342 void* UserData; // What user passed to InputText() // Read-only 1343 bool ReadOnly; // Read-only mode // Read-only 1344 1345 // CharFilter event: 1346 ImWchar EventChar; // Character input // Read-write (replace character or set to zero) 1347 1348 // Completion,History,Always events: 1349 // If you modify the buffer contents make sure you update 'BufTextLen' and set 'BufDirty' to true. 1350 ImGuiKey EventKey; // Key pressed (Up/Down/TAB) // Read-only 1351 char* Buf; // Current text buffer // Read-write (pointed data only, can't replace the actual pointer) 1352 int BufTextLen; // Current text length in bytes // Read-write 1353 int BufSize; // Maximum text length in bytes // Read-only 1354 bool BufDirty; // Set if you modify Buf/BufTextLen!! // Write 1355 int CursorPos; // // Read-write 1356 int SelectionStart; // // Read-write (== to SelectionEnd when no selection) 1357 int SelectionEnd; // // Read-write 1358 1359 // NB: Helper functions for text manipulation. Calling those function loses selection. 1360 IMGUI_API void DeleteChars(int pos, int bytes_count); 1361 IMGUI_API void InsertChars(int pos, const char* text, const char* text_end = NULL); 1362 bool HasSelection() const { return SelectionStart != SelectionEnd; } 1363 }; 1364 1365 // Resizing callback data to apply custom constraint. As enabled by SetNextWindowSizeConstraints(). Callback is called during the next Begin(). 1366 // NB: For basic min/max size constraint on each axis you don't need to use the callback! The SetNextWindowSizeConstraints() parameters are enough. 1367 struct ImGuiSizeCallbackData 1368 { 1369 void* UserData; // Read-only. What user passed to SetNextWindowSizeConstraints() 1370 ImVec2 Pos; // Read-only. Window position, for reference. 1371 ImVec2 CurrentSize; // Read-only. Current window size. 1372 ImVec2 DesiredSize; // Read-write. Desired size, based on user's mouse position. Write to this field to restrain resizing. 1373 }; 1374 1375 // Data payload for Drag and Drop operations 1376 struct ImGuiPayload 1377 { 1378 // Members 1379 void* Data; // Data (copied and owned by dear imgui) 1380 int DataSize; // Data size 1381 1382 // [Internal] 1383 ImGuiID SourceId; // Source item id 1384 ImGuiID SourceParentId; // Source parent id (if available) 1385 int DataFrameCount; // Data timestamp 1386 char DataType[32 + 1]; // Data type tag (short user-supplied string, 32 characters max) 1387 bool Preview; // Set when AcceptDragDropPayload() was called and mouse has been hovering the target item (nb: handle overlapping drag targets) 1388 bool Delivery; // Set when AcceptDragDropPayload() was called and mouse button is released over the target item. 1389 1390 ImGuiPayload() { Clear(); } 1391 void Clear() { SourceId = SourceParentId = 0; Data = NULL; DataSize = 0; memset(DataType, 0, sizeof(DataType)); DataFrameCount = -1; Preview = Delivery = false; } 1392 bool IsDataType(const char* type) const { return DataFrameCount != -1 && strcmp(type, DataType) == 0; } 1393 bool IsPreview() const { return Preview; } 1394 bool IsDelivery() const { return Delivery; } 1395 }; 1396 1397 // Helpers macros to generate 32-bits encoded colors 1847 // [Internal] 1848 struct ImGuiStoragePair 1849 { 1850 ImGuiID key; 1851 union { int val_i; float val_f; void* val_p; }; 1852 ImGuiStoragePair(ImGuiID _key, int _val_i) { key = _key; val_i = _val_i; } 1853 ImGuiStoragePair(ImGuiID _key, float _val_f) { key = _key; val_f = _val_f; } 1854 ImGuiStoragePair(ImGuiID _key, void* _val_p) { key = _key; val_p = _val_p; } 1855 }; 1856 1857 ImVector<ImGuiStoragePair> Data; 1858 1859 // - Get***() functions find pair, never add/allocate. Pairs are sorted so a query is O(log N) 1860 // - Set***() functions find pair, insertion on demand if missing. 1861 // - Sorted insertion is costly, paid once. A typical frame shouldn't need to insert any new pair. 1862 void Clear() { Data.clear(); } 1863 IMGUI_API int GetInt(ImGuiID key, int default_val = 0) const; 1864 IMGUI_API void SetInt(ImGuiID key, int val); 1865 IMGUI_API bool GetBool(ImGuiID key, bool default_val = false) const; 1866 IMGUI_API void SetBool(ImGuiID key, bool val); 1867 IMGUI_API float GetFloat(ImGuiID key, float default_val = 0.0f) const; 1868 IMGUI_API void SetFloat(ImGuiID key, float val); 1869 IMGUI_API void* GetVoidPtr(ImGuiID key) const; // default_val is NULL 1870 IMGUI_API void SetVoidPtr(ImGuiID key, void* val); 1871 1872 // - Get***Ref() functions finds pair, insert on demand if missing, return pointer. Useful if you intend to do Get+Set. 1873 // - 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. 1874 // - A typical use case where this is convenient for quick hacking (e.g. add storage during a live Edit&Continue session if you can't modify existing struct) 1875 // float* pvar = ImGui::GetFloatRef(key); ImGui::SliderFloat("var", pvar, 0, 100.0f); some_var += *pvar; 1876 IMGUI_API int* GetIntRef(ImGuiID key, int default_val = 0); 1877 IMGUI_API bool* GetBoolRef(ImGuiID key, bool default_val = false); 1878 IMGUI_API float* GetFloatRef(ImGuiID key, float default_val = 0.0f); 1879 IMGUI_API void** GetVoidPtrRef(ImGuiID key, void* default_val = NULL); 1880 1881 // Use on your own storage if you know only integer are being stored (open/close all tree nodes) 1882 IMGUI_API void SetAllInt(int val); 1883 1884 // For quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once. 1885 IMGUI_API void BuildSortByKey(); 1886 }; 1887 1888 // Helper: Manually clip large list of items. 1889 // If you are submitting lots of evenly spaced items and you have a random access to the list, you can perform coarse 1890 // clipping based on visibility to save yourself from processing those items at all. 1891 // The clipper calculates the range of visible items and advance the cursor to compensate for the non-visible items we have skipped. 1892 // (Dear ImGui already clip items based on their bounds but it needs to measure text size to do so, whereas manual coarse clipping before submission makes this cost and your own data fetching/submission cost almost null) 1893 // Usage: 1894 // ImGuiListClipper clipper; 1895 // clipper.Begin(1000); // We have 1000 elements, evenly spaced. 1896 // while (clipper.Step()) 1897 // for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) 1898 // ImGui::Text("line number %d", i); 1899 // Generally what happens is: 1900 // - Clipper lets you process the first element (DisplayStart = 0, DisplayEnd = 1) regardless of it being visible or not. 1901 // - User code submit one element. 1902 // - Clipper can measure the height of the first element 1903 // - Clipper calculate the actual range of elements to display based on the current clipping rectangle, position the cursor before the first visible element. 1904 // - User code submit visible elements. 1905 struct ImGuiListClipper 1906 { 1907 int DisplayStart; 1908 int DisplayEnd; 1909 1910 // [Internal] 1911 int ItemsCount; 1912 int StepNo; 1913 float ItemsHeight; 1914 float StartPosY; 1915 1916 IMGUI_API ImGuiListClipper(); 1917 IMGUI_API ~ImGuiListClipper(); 1918 1919 // items_count: Use INT_MAX if you don't know how many items you have (in which case the cursor won't be advanced in the final step) 1920 // items_height: Use -1.0f to be calculated automatically on first step. Otherwise pass in the distance between your items, typically GetTextLineHeightWithSpacing() or GetFrameHeightWithSpacing(). 1921 IMGUI_API void Begin(int items_count, float items_height = -1.0f); // Automatically called by constructor if you passed 'items_count' or by Step() in Step 1. 1922 IMGUI_API void End(); // Automatically called on the last call of Step() that returns false. 1923 IMGUI_API bool Step(); // Call until it returns false. The DisplayStart/DisplayEnd fields will be set and you can process/draw those items. 1924 1925 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS 1926 inline ImGuiListClipper(int items_count, float items_height = -1.0f) { memset(this, 0, sizeof(*this)); ItemsCount = -1; Begin(items_count, items_height); } // [removed in 1.79] 1927 #endif 1928 }; 1929 1930 // Helpers macros to generate 32-bit encoded colors 1398 1931 #ifdef IMGUI_USE_BGRA_PACKED_COLOR 1399 1932 #define IM_COL32_R_SHIFT 16 … … 1414 1947 #define IM_COL32_BLACK_TRANS IM_COL32(0,0,0,0) // Transparent black = 0x00000000 1415 1948 1416 // Helper: ImColor() implicit y converts colors to either ImU32 (packed 4x1 byte) or ImVec4 (4x1 float)1949 // Helper: ImColor() implicitly converts colors to either ImU32 (packed 4x1 byte) or ImVec4 (4x1 float) 1417 1950 // Prefer using IM_COL32() macros if you want a guaranteed compile-time ImU32 for usage with ImDrawList API. 1418 1951 // **Avoid storing ImColor! Store either u32 of ImVec4. This is not a full-featured color class. MAY OBSOLETE. … … 1420 1953 struct ImColor 1421 1954 { 1422 ImVec4 Value; 1423 1424 ImColor() { Value.x = Value.y = Value.z = Value.w = 0.0f; } 1425 ImColor(int r, int g, int b, int a = 255) { float sc = 1.0f / 255.0f; Value.x = (float)r * sc; Value.y = (float)g * sc; Value.z = (float)b * sc; Value.w = (float)a * sc; } 1426 ImColor(ImU32 rgba) { float sc = 1.0f / 255.0f; Value.x = (float)((rgba >> IM_COL32_R_SHIFT) & 0xFF) * sc; Value.y = (float)((rgba >> IM_COL32_G_SHIFT) & 0xFF) * sc; Value.z = (float)((rgba >> IM_COL32_B_SHIFT) & 0xFF) * sc; Value.w = (float)((rgba >> IM_COL32_A_SHIFT) & 0xFF) * sc; } 1427 ImColor(float r, float g, float b, float a = 1.0f) { Value.x = r; Value.y = g; Value.z = b; Value.w = a; } 1428 ImColor(const ImVec4& col) { Value = col; } 1429 inline operator ImU32() const { return ImGui::ColorConvertFloat4ToU32(Value); } 1430 inline operator ImVec4() const { return Value; } 1431 1432 // FIXME-OBSOLETE: May need to obsolete/cleanup those helpers. 1433 inline void SetHSV(float h, float s, float v, float a = 1.0f) { ImGui::ColorConvertHSVtoRGB(h, s, v, Value.x, Value.y, Value.z); Value.w = a; } 1434 static ImColor HSV(float h, float s, float v, float a = 1.0f) { float r, g, b; ImGui::ColorConvertHSVtoRGB(h, s, v, r, g, b); return ImColor(r, g, b, a); } 1435 }; 1436 1437 // Helper: Manually clip large list of items. 1438 // If you are submitting lots of evenly spaced items and you have a random access to the list, you can perform coarse clipping based on visibility to save yourself from processing those items at all. 1439 // The clipper calculates the range of visible items and advance the cursor to compensate for the non-visible items we have skipped. 1440 // ImGui already clip items based on their bounds but it needs to measure text size to do so. Coarse clipping before submission makes this cost and your own data fetching/submission cost null. 1441 // Usage: 1442 // ImGuiListClipper clipper(1000); // we have 1000 elements, evenly spaced. 1443 // while (clipper.Step()) 1444 // for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) 1445 // ImGui::Text("line number %d", i); 1446 // - Step 0: the clipper let you process the first element, regardless of it being visible or not, so we can measure the element height (step skipped if we passed a known height as second arg to constructor). 1447 // - 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. 1448 // - (Step 2: dummy step only required if an explicit items_height was passed to constructor or Begin() and user call Step(). Does nothing and switch to Step 3.) 1449 // - 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. 1450 struct ImGuiListClipper 1451 { 1452 float StartPosY; 1453 float ItemsHeight; 1454 int ItemsCount, StepNo, DisplayStart, DisplayEnd; 1455 1456 // items_count: Use -1 to ignore (you can call Begin later). Use INT_MAX if you don't know how many items you have (in which case the cursor won't be advanced in the final step). 1457 // items_height: Use -1.0f to be calculated automatically on first step. Otherwise pass in the distance between your items, typically GetTextLineHeightWithSpacing() or GetFrameHeightWithSpacing(). 1458 // If you don't specify an items_height, you NEED to call Step(). If you specify items_height you may call the old Begin()/End() api directly, but prefer calling Step(). 1459 ImGuiListClipper(int items_count = -1, float items_height = -1.0f) { Begin(items_count, items_height); } // NB: Begin() initialize every fields (as we allow user to call Begin/End multiple times on a same instance if they want). 1460 ~ImGuiListClipper() { IM_ASSERT(ItemsCount == -1); } // Assert if user forgot to call End() or Step() until false. 1461 1462 IMGUI_API bool Step(); // Call until it returns false. The DisplayStart/DisplayEnd fields will be set and you can process/draw those items. 1463 IMGUI_API void Begin(int items_count, float items_height = -1.0f); // Automatically called by constructor if you passed 'items_count' or by Step() in Step 1. 1464 IMGUI_API void End(); // Automatically called on the last call of Step() that returns false. 1465 }; 1466 1467 //----------------------------------------------------------------------------- 1468 // Draw List 1955 ImVec4 Value; 1956 1957 ImColor() { Value.x = Value.y = Value.z = Value.w = 0.0f; } 1958 ImColor(int r, int g, int b, int a = 255) { float sc = 1.0f / 255.0f; Value.x = (float)r * sc; Value.y = (float)g * sc; Value.z = (float)b * sc; Value.w = (float)a * sc; } 1959 ImColor(ImU32 rgba) { float sc = 1.0f / 255.0f; Value.x = (float)((rgba >> IM_COL32_R_SHIFT) & 0xFF) * sc; Value.y = (float)((rgba >> IM_COL32_G_SHIFT) & 0xFF) * sc; Value.z = (float)((rgba >> IM_COL32_B_SHIFT) & 0xFF) * sc; Value.w = (float)((rgba >> IM_COL32_A_SHIFT) & 0xFF) * sc; } 1960 ImColor(float r, float g, float b, float a = 1.0f) { Value.x = r; Value.y = g; Value.z = b; Value.w = a; } 1961 ImColor(const ImVec4& col) { Value = col; } 1962 inline operator ImU32() const { return ImGui::ColorConvertFloat4ToU32(Value); } 1963 inline operator ImVec4() const { return Value; } 1964 1965 // FIXME-OBSOLETE: May need to obsolete/cleanup those helpers. 1966 inline void SetHSV(float h, float s, float v, float a = 1.0f){ ImGui::ColorConvertHSVtoRGB(h, s, v, Value.x, Value.y, Value.z); Value.w = a; } 1967 static ImColor HSV(float h, float s, float v, float a = 1.0f) { float r, g, b; ImGui::ColorConvertHSVtoRGB(h, s, v, r, g, b); return ImColor(r, g, b, a); } 1968 }; 1969 1970 //----------------------------------------------------------------------------- 1971 // Draw List API (ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawListFlags, ImDrawList, ImDrawData) 1469 1972 // Hold a series of drawing commands. The user provides a renderer for ImDrawData which essentially contains an array of ImDrawList. 1470 1973 //----------------------------------------------------------------------------- 1471 1974 1472 // Draw callbacks for advanced uses. 1473 // NB- You most likely do NOT need to use draw callbacks just to create your own widget or customized UI rendering (you can poke into the draw list for that) 1474 // Draw callback may be useful for example, A) Change your GPU render state, B) render a complex 3D scene inside a UI element (without an intermediate texture/render target), etc. 1475 // The expected behavior from your rendering function is 'if (cmd.UserCallback != NULL) cmd.UserCallback(parent_list, cmd); else RenderTriangles()' 1476 typedef void(*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* cmd); 1975 // The maximum line width to bake anti-aliased textures for. Build atlas with ImFontAtlasFlags_NoBakedLines to disable baking. 1976 #ifndef IM_DRAWLIST_TEX_LINES_WIDTH_MAX 1977 #define IM_DRAWLIST_TEX_LINES_WIDTH_MAX (63) 1978 #endif 1979 1980 // ImDrawCallback: Draw callbacks for advanced uses [configurable type: override in imconfig.h] 1981 // NB: You most likely do NOT need to use draw callbacks just to create your own widget or customized UI rendering, 1982 // you can poke into the draw list for that! Draw callback may be useful for example to: 1983 // A) Change your GPU render state, 1984 // B) render a complex 3D scene inside a UI element without an intermediate texture/render target, etc. 1985 // The expected behavior from your rendering function is 'if (cmd.UserCallback != NULL) { cmd.UserCallback(parent_list, cmd); } else { RenderTriangles() }' 1986 // If you want to override the signature of ImDrawCallback, you can simply use e.g. '#define ImDrawCallback MyDrawCallback' (in imconfig.h) + update rendering back-end accordingly. 1987 #ifndef ImDrawCallback 1988 typedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* cmd); 1989 #endif 1990 1991 // Special Draw callback value to request renderer back-end to reset the graphics/render state. 1992 // The renderer back-end needs to handle this special value, otherwise it will crash trying to call a function at this address. 1993 // This is useful for example if you submitted callbacks which you know have altered the render state and you want it to be restored. 1994 // It is not done by default because they are many perfectly useful way of altering render state for imgui contents (e.g. changing shader/blending settings before an Image call). 1995 #define ImDrawCallback_ResetRenderState (ImDrawCallback)(-1) 1477 1996 1478 1997 // Typically, 1 command = 1 GPU draw call (unless command is a callback) 1998 // - VtxOffset/IdxOffset: When 'io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset' is enabled, 1999 // those fields allow us to render meshes larger than 64K vertices while keeping 16-bit indices. 2000 // Pre-1.71 back-ends will typically ignore the VtxOffset/IdxOffset fields. 2001 // - The ClipRect/TextureId/VtxOffset fields must be contiguous as we memcmp() them together (this is asserted for). 1479 2002 struct ImDrawCmd 1480 2003 { 1481 unsigned int ElemCount; // Number of indices (multiple of 3) to be rendered as triangles. Vertices are stored in the callee ImDrawList's vtx_buffer[] array, indices in idx_buffer[]. 1482 ImVec4 ClipRect; // Clipping rectangle (x1, y1, x2, y2) 1483 ImTextureID TextureId; // User-provided texture ID. Set by user in ImfontAtlas::SetTexID() for fonts or passed to Image*() functions. Ignore if never using images or multiple fonts atlas. 1484 ImDrawCallback UserCallback; // If != NULL, call the function instead of rendering the vertices. clip_rect and texture_id will be set normally. 1485 void* UserCallbackData; // The draw callback code can access this. 1486 1487 ImDrawCmd() { ElemCount = 0; ClipRect.x = ClipRect.y = ClipRect.z = ClipRect.w = 0.0f; TextureId = NULL; UserCallback = NULL; UserCallbackData = NULL; } 1488 }; 1489 1490 // Vertex index (override with '#define ImDrawIdx unsigned int' inside in imconfig.h) 2004 ImVec4 ClipRect; // 4*4 // Clipping rectangle (x1, y1, x2, y2). Subtract ImDrawData->DisplayPos to get clipping rectangle in "viewport" coordinates 2005 ImTextureID TextureId; // 4-8 // User-provided texture ID. Set by user in ImfontAtlas::SetTexID() for fonts or passed to Image*() functions. Ignore if never using images or multiple fonts atlas. 2006 unsigned int VtxOffset; // 4 // Start offset in vertex buffer. ImGuiBackendFlags_RendererHasVtxOffset: always 0, otherwise may be >0 to support meshes larger than 64K vertices with 16-bit indices. 2007 unsigned int IdxOffset; // 4 // Start offset in index buffer. Always equal to sum of ElemCount drawn so far. 2008 unsigned int ElemCount; // 4 // Number of indices (multiple of 3) to be rendered as triangles. Vertices are stored in the callee ImDrawList's vtx_buffer[] array, indices in idx_buffer[]. 2009 ImDrawCallback UserCallback; // 4-8 // If != NULL, call the function instead of rendering the vertices. clip_rect and texture_id will be set normally. 2010 void* UserCallbackData; // 4-8 // The draw callback code can access this. 2011 2012 ImDrawCmd() { memset(this, 0, sizeof(*this)); } // Also ensure our padding fields are zeroed 2013 }; 2014 2015 // Vertex index, default to 16-bit 2016 // To allow large meshes with 16-bit indices: set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset' and handle ImDrawCmd::VtxOffset in the renderer back-end (recommended). 2017 // To use 32-bit indices: override with '#define ImDrawIdx unsigned int' in imconfig.h. 1491 2018 #ifndef ImDrawIdx 1492 2019 typedef unsigned short ImDrawIdx; … … 1497 2024 struct ImDrawVert 1498 2025 { 1499 ImVec2 pos;1500 ImVec2 uv;1501 ImU32 col;2026 ImVec2 pos; 2027 ImVec2 uv; 2028 ImU32 col; 1502 2029 }; 1503 2030 #else 1504 2031 // You can override the vertex format layout by defining IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT in imconfig.h 1505 2032 // The code expect ImVec2 pos (8 bytes), ImVec2 uv (8 bytes), ImU32 col (4 bytes), but you can re-order them or add other fields as needed to simplify integration in your engine. 1506 // The type has to be described within the macro (you can either declare the struct or use a typedef) 1507 // NOTE: IMGUI DOESN'T CLEAR THE STRUCTURE AND DOESN'T CALL A CONSTRUCTOR SO ANY CUSTOM FIELD WILL BE UNINITIALIZED. IF YOU ADD EXTRA FIELDS (SUCH AS A 'Z' COORDINATES) YOU WILL NEED TO CLEAR THEM DURING RENDER OR TO IGNORE THEM. 2033 // The type has to be described within the macro (you can either declare the struct or use a typedef). This is because ImVec2/ImU32 are likely not declared a the time you'd want to set your type up. 2034 // NOTE: IMGUI DOESN'T CLEAR THE STRUCTURE AND DOESN'T CALL A CONSTRUCTOR SO ANY CUSTOM FIELD WILL BE UNINITIALIZED. IF YOU ADD EXTRA FIELDS (SUCH AS A 'Z' COORDINATES) YOU WILL NEED TO CLEAR THEM DURING RENDER OR TO IGNORE THEM. 1508 2035 IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT; 1509 2036 #endif 1510 2037 1511 // Draw channels are used by the Columns API to "split" the render list into different channels while building, so items of each column can be batched together. 1512 // You can also use them to simulate drawing layers and submit primitives in a different order than how they will be rendered. 2038 // For use by ImDrawListSplitter. 1513 2039 struct ImDrawChannel 1514 2040 { 1515 ImVector<ImDrawCmd> CmdBuffer; 1516 ImVector<ImDrawIdx> IdxBuffer; 2041 ImVector<ImDrawCmd> _CmdBuffer; 2042 ImVector<ImDrawIdx> _IdxBuffer; 2043 }; 2044 2045 // Split/Merge functions are used to split the draw list into different layers which can be drawn into out of order. 2046 // This is used by the Columns api, so items of each column can be batched together in a same draw call. 2047 struct ImDrawListSplitter 2048 { 2049 int _Current; // Current channel number (0) 2050 int _Count; // Number of active channels (1+) 2051 ImVector<ImDrawChannel> _Channels; // Draw channels (not resized down so _Count might be < Channels.Size) 2052 2053 inline ImDrawListSplitter() { Clear(); } 2054 inline ~ImDrawListSplitter() { ClearFreeMemory(); } 2055 inline void Clear() { _Current = 0; _Count = 1; } // Do not clear Channels[] so our allocations are reused next frame 2056 IMGUI_API void ClearFreeMemory(); 2057 IMGUI_API void Split(ImDrawList* draw_list, int count); 2058 IMGUI_API void Merge(ImDrawList* draw_list); 2059 IMGUI_API void SetCurrentChannel(ImDrawList* draw_list, int channel_idx); 1517 2060 }; 1518 2061 1519 2062 enum ImDrawCornerFlags_ 1520 2063 { 1521 ImDrawCornerFlags_TopLeft = 1 << 0, // 0x1 1522 ImDrawCornerFlags_TopRight = 1 << 1, // 0x2 1523 ImDrawCornerFlags_BotLeft = 1 << 2, // 0x4 1524 ImDrawCornerFlags_BotRight = 1 << 3, // 0x8 1525 ImDrawCornerFlags_Top = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_TopRight, // 0x3 1526 ImDrawCornerFlags_Bot = ImDrawCornerFlags_BotLeft | ImDrawCornerFlags_BotRight, // 0xC 1527 ImDrawCornerFlags_Left = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotLeft, // 0x5 1528 ImDrawCornerFlags_Right = ImDrawCornerFlags_TopRight | ImDrawCornerFlags_BotRight, // 0xA 1529 ImDrawCornerFlags_All = 0xF // In your function calls you may use ~0 (= all bits sets) instead of ImDrawCornerFlags_All, as a convenience 1530 }; 1531 2064 ImDrawCornerFlags_None = 0, 2065 ImDrawCornerFlags_TopLeft = 1 << 0, // 0x1 2066 ImDrawCornerFlags_TopRight = 1 << 1, // 0x2 2067 ImDrawCornerFlags_BotLeft = 1 << 2, // 0x4 2068 ImDrawCornerFlags_BotRight = 1 << 3, // 0x8 2069 ImDrawCornerFlags_Top = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_TopRight, // 0x3 2070 ImDrawCornerFlags_Bot = ImDrawCornerFlags_BotLeft | ImDrawCornerFlags_BotRight, // 0xC 2071 ImDrawCornerFlags_Left = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotLeft, // 0x5 2072 ImDrawCornerFlags_Right = ImDrawCornerFlags_TopRight | ImDrawCornerFlags_BotRight, // 0xA 2073 ImDrawCornerFlags_All = 0xF // In your function calls you may use ~0 (= all bits sets) instead of ImDrawCornerFlags_All, as a convenience 2074 }; 2075 2076 // Flags for ImDrawList. Those are set automatically by ImGui:: functions from ImGuiIO settings, and generally not manipulated directly. 2077 // It is however possible to temporarily alter flags between calls to ImDrawList:: functions. 1532 2078 enum ImDrawListFlags_ 1533 2079 { 1534 ImDrawListFlags_AntiAliasedLines = 1 << 0, 1535 ImDrawListFlags_AntiAliasedFill = 1 << 1 2080 ImDrawListFlags_None = 0, 2081 ImDrawListFlags_AntiAliasedLines = 1 << 0, // Enable anti-aliased lines/borders (*2 the number of triangles for 1.0f wide line or lines thin enough to be drawn using textures, otherwise *3 the number of triangles) 2082 ImDrawListFlags_AntiAliasedLinesUseTex = 1 << 1, // Enable anti-aliased lines/borders using textures when possible. Require back-end to render with bilinear filtering. 2083 ImDrawListFlags_AntiAliasedFill = 1 << 2, // Enable anti-aliased edge around filled shapes (rounded rectangles, circles). 2084 ImDrawListFlags_AllowVtxOffset = 1 << 3 // Can emit 'VtxOffset > 0' to allow large meshes. Set when 'ImGuiBackendFlags_RendererHasVtxOffset' is enabled. 1536 2085 }; 1537 2086 1538 2087 // Draw command list 1539 // This is the low-level list of polygons that ImGui functions are filling. At the end of the frame, all command lists are passed to your ImGuiIO::RenderDrawListFn function for rendering. 1540 // Each ImGui window contains its own ImDrawList. You can use ImGui::GetWindowDrawList() to access the current window draw list and draw custom primitives. 2088 // This is the low-level list of polygons that ImGui:: functions are filling. At the end of the frame, 2089 // all command lists are passed to your ImGuiIO::RenderDrawListFn function for rendering. 2090 // Each dear imgui window contains its own ImDrawList. You can use ImGui::GetWindowDrawList() to 2091 // access the current window draw list and draw custom primitives. 1541 2092 // You can interleave normal ImGui:: calls and adding primitives to the current draw list. 1542 // All positions are generally in pixel coordinates (top-left at (0,0), bottom-right at io.DisplaySize), howeveryou are totally free to apply whatever transformation matrix to want to the data (if you apply such transformation you'll want to apply it to ClipRect as well)2093 // All positions are generally in pixel coordinates (top-left at (0,0), bottom-right at io.DisplaySize), but you are totally free to apply whatever transformation matrix to want to the data (if you apply such transformation you'll want to apply it to ClipRect as well) 1543 2094 // Important: Primitives are always added to the list and not culled (culling is done at higher-level by ImGui:: functions), if you use this API a lot consider coarse culling your drawn objects. 1544 2095 struct ImDrawList 1545 2096 { 1546 // This is what you have to render 1547 ImVector<ImDrawCmd> CmdBuffer; // Draw commands. Typically 1 command = 1 GPU draw call, unless the command is a callback. 1548 ImVector<ImDrawIdx> IdxBuffer; // Index buffer. Each command consume ImDrawCmd::ElemCount of those 1549 ImVector<ImDrawVert> VtxBuffer; // Vertex buffer. 1550 ImDrawListFlags Flags; // Flags, you may poke into these to adjust anti-aliasing settings per-primitive. 1551 1552 // [Internal, used while building lists] 1553 const ImDrawListSharedData* _Data; // Pointer to shared draw data (you can use ImGui::GetDrawListSharedData() to get the one from current ImGui context) 1554 const char* _OwnerName; // Pointer to owner window's name for debugging 1555 unsigned int _VtxCurrentIdx; // [Internal] == VtxBuffer.Size 1556 ImDrawVert* _VtxWritePtr; // [Internal] point within VtxBuffer.Data after each add command (to avoid using the ImVector<> operators too much) 1557 ImDrawIdx* _IdxWritePtr; // [Internal] point within IdxBuffer.Data after each add command (to avoid using the ImVector<> operators too much) 1558 ImVector<ImVec4> _ClipRectStack; // [Internal] 1559 ImVector<ImTextureID> _TextureIdStack; // [Internal] 1560 ImVector<ImVec2> _Path; // [Internal] current path building 1561 int _ChannelsCurrent; // [Internal] current channel number (0) 1562 int _ChannelsCount; // [Internal] number of active channels (1+) 1563 ImVector<ImDrawChannel> _Channels; // [Internal] draw channels for columns API (not resized down so _ChannelsCount may be smaller than _Channels.Size) 1564 1565 // If you want to create ImDrawList instances, pass them ImGui::GetDrawListSharedData() or create and use your own ImDrawListSharedData (so you can use ImDrawList without ImGui) 1566 ImDrawList(const ImDrawListSharedData* shared_data) { _Data = shared_data; _OwnerName = NULL; Clear(); } 1567 ~ImDrawList() { ClearFreeMemory(); } 1568 IMGUI_API void PushClipRect(ImVec2 clip_rect_min, ImVec2 clip_rect_max, bool intersect_with_current_clip_rect = false); // Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling) 1569 IMGUI_API void PushClipRectFullScreen(); 1570 IMGUI_API void PopClipRect(); 1571 IMGUI_API void PushTextureID(ImTextureID texture_id); 1572 IMGUI_API void PopTextureID(); 1573 inline ImVec2 GetClipRectMin() const { const ImVec4& cr = _ClipRectStack.back(); return ImVec2(cr.x, cr.y); } 1574 inline ImVec2 GetClipRectMax() const { const ImVec4& cr = _ClipRectStack.back(); return ImVec2(cr.z, cr.w); } 1575 1576 // Primitives 1577 IMGUI_API void AddLine(const ImVec2& a, const ImVec2& b, ImU32 col, float thickness = 1.0f); 1578 IMGUI_API void AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, int rounding_corners_flags = ImDrawCornerFlags_All, float thickness = 1.0f); // a: upper-left, b: lower-right, rounding_corners_flags: 4-bits corresponding to which corner to round 1579 IMGUI_API void AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, int rounding_corners_flags = ImDrawCornerFlags_All); // a: upper-left, b: lower-right 1580 IMGUI_API void AddRectFilledMultiColor(const ImVec2& a, const ImVec2& b, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left); 1581 IMGUI_API void AddQuad(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col, float thickness = 1.0f); 1582 IMGUI_API void AddQuadFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col); 1583 IMGUI_API void AddTriangle(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col, float thickness = 1.0f); 1584 IMGUI_API void AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col); 1585 IMGUI_API void AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments = 12, float thickness = 1.0f); 1586 IMGUI_API void AddCircleFilled(const ImVec2& centre, float radius, ImU32 col, int num_segments = 12); 1587 IMGUI_API void AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL); 1588 IMGUI_API void AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL, float wrap_width = 0.0f, const ImVec4* cpu_fine_clip_rect = NULL); 1589 IMGUI_API void AddImage(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a = ImVec2(0, 0), const ImVec2& uv_b = ImVec2(1, 1), ImU32 col = 0xFFFFFFFF); 1590 IMGUI_API void AddImageQuad(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a = ImVec2(0, 0), const ImVec2& uv_b = ImVec2(1, 0), const ImVec2& uv_c = ImVec2(1, 1), const ImVec2& uv_d = ImVec2(0, 1), ImU32 col = 0xFFFFFFFF); 1591 IMGUI_API void AddImageRounded(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col, float rounding, int rounding_corners = ImDrawCornerFlags_All); 1592 IMGUI_API void AddPolyline(const ImVec2* points, const int num_points, ImU32 col, bool closed, float thickness); 1593 IMGUI_API void AddConvexPolyFilled(const ImVec2* points, const int num_points, ImU32 col); 1594 IMGUI_API void AddBezierCurve(const ImVec2& pos0, const ImVec2& cp0, const ImVec2& cp1, const ImVec2& pos1, ImU32 col, float thickness, int num_segments = 0); 1595 1596 // Stateful path API, add points then finish with PathFill() or PathStroke() 1597 inline void PathClear() { _Path.resize(0); } 1598 inline void PathLineTo(const ImVec2& pos) { _Path.push_back(pos); } 1599 inline void PathLineToMergeDuplicate(const ImVec2& pos) { if (_Path.Size == 0 || memcmp(&_Path[_Path.Size - 1], &pos, 8) != 0) _Path.push_back(pos); } 1600 inline void PathFillConvex(ImU32 col) { AddConvexPolyFilled(_Path.Data, _Path.Size, col); PathClear(); } 1601 inline void PathStroke(ImU32 col, bool closed, float thickness = 1.0f) { AddPolyline(_Path.Data, _Path.Size, col, closed, thickness); PathClear(); } 1602 IMGUI_API void PathArcTo(const ImVec2& centre, float radius, float a_min, float a_max, int num_segments = 10); 1603 IMGUI_API void PathArcToFast(const ImVec2& centre, float radius, int a_min_of_12, int a_max_of_12); // Use precomputed angles for a 12 steps circle 1604 IMGUI_API void PathBezierCurveTo(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, int num_segments = 0); 1605 IMGUI_API void PathRect(const ImVec2& rect_min, const ImVec2& rect_max, float rounding = 0.0f, int rounding_corners_flags = ImDrawCornerFlags_All); 1606 1607 // Channels 1608 // - Use to simulate layers. By switching channels to can render out-of-order (e.g. submit foreground primitives before background primitives) 1609 // - Use to minimize draw calls (e.g. if going back-and-forth between multiple non-overlapping clipping rectangles, prefer to append into separate channels then merge at the end) 1610 IMGUI_API void ChannelsSplit(int channels_count); 1611 IMGUI_API void ChannelsMerge(); 1612 IMGUI_API void ChannelsSetCurrent(int channel_index); 1613 1614 // Advanced 1615 IMGUI_API void AddCallback(ImDrawCallback callback, void* callback_data); // Your rendering function must check for 'UserCallback' in ImDrawCmd and call the function instead of rendering triangles. 1616 IMGUI_API void AddDrawCmd(); // This is useful if you need to forcefully create a new draw call (to allow for dependent rendering / blending). Otherwise primitives are merged into the same draw-call as much as possible 1617 IMGUI_API ImDrawList* CloneOutput() const; // Create a clone of the CmdBuffer/IdxBuffer/VtxBuffer. 1618 1619 // Internal helpers 1620 // NB: all primitives needs to be reserved via PrimReserve() beforehand! 1621 IMGUI_API void Clear(); 1622 IMGUI_API void ClearFreeMemory(); 1623 IMGUI_API void PrimReserve(int idx_count, int vtx_count); 1624 IMGUI_API void PrimRect(const ImVec2& a, const ImVec2& b, ImU32 col); // Axis aligned rectangle (composed of two triangles) 1625 IMGUI_API void PrimRectUV(const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col); 1626 IMGUI_API void PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a, const ImVec2& uv_b, const ImVec2& uv_c, const ImVec2& uv_d, ImU32 col); 1627 inline void PrimWriteVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { _VtxWritePtr->pos = pos; _VtxWritePtr->uv = uv; _VtxWritePtr->col = col; _VtxWritePtr++; _VtxCurrentIdx++; } 1628 inline void PrimWriteIdx(ImDrawIdx idx) { *_IdxWritePtr = idx; _IdxWritePtr++; } 1629 inline void PrimVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { PrimWriteIdx((ImDrawIdx)_VtxCurrentIdx); PrimWriteVtx(pos, uv, col); } 1630 IMGUI_API void UpdateClipRect(); 1631 IMGUI_API void UpdateTextureID(); 1632 }; 1633 1634 // All draw data to render an ImGui frame 1635 // (NB: the style and the naming convention here is a little inconsistent but we preserve them for backward compatibility purpose) 2097 // This is what you have to render 2098 ImVector<ImDrawCmd> CmdBuffer; // Draw commands. Typically 1 command = 1 GPU draw call, unless the command is a callback. 2099 ImVector<ImDrawIdx> IdxBuffer; // Index buffer. Each command consume ImDrawCmd::ElemCount of those 2100 ImVector<ImDrawVert> VtxBuffer; // Vertex buffer. 2101 ImDrawListFlags Flags; // Flags, you may poke into these to adjust anti-aliasing settings per-primitive. 2102 2103 // [Internal, used while building lists] 2104 const ImDrawListSharedData* _Data; // Pointer to shared draw data (you can use ImGui::GetDrawListSharedData() to get the one from current ImGui context) 2105 const char* _OwnerName; // Pointer to owner window's name for debugging 2106 unsigned int _VtxCurrentIdx; // [Internal] Generally == VtxBuffer.Size unless we are past 64K vertices, in which case this gets reset to 0. 2107 ImDrawVert* _VtxWritePtr; // [Internal] point within VtxBuffer.Data after each add command (to avoid using the ImVector<> operators too much) 2108 ImDrawIdx* _IdxWritePtr; // [Internal] point within IdxBuffer.Data after each add command (to avoid using the ImVector<> operators too much) 2109 ImVector<ImVec4> _ClipRectStack; // [Internal] 2110 ImVector<ImTextureID> _TextureIdStack; // [Internal] 2111 ImVector<ImVec2> _Path; // [Internal] current path building 2112 ImDrawCmd _CmdHeader; // [Internal] Template of active commands. Fields should match those of CmdBuffer.back(). 2113 ImDrawListSplitter _Splitter; // [Internal] for channels api (note: prefer using your own persistent instance of ImDrawListSplitter!) 2114 2115 // If you want to create ImDrawList instances, pass them ImGui::GetDrawListSharedData() or create and use your own ImDrawListSharedData (so you can use ImDrawList without ImGui) 2116 ImDrawList(const ImDrawListSharedData* shared_data) { _Data = shared_data; Flags = ImDrawListFlags_None; _VtxCurrentIdx = 0; _VtxWritePtr = NULL; _IdxWritePtr = NULL; _OwnerName = NULL; } 2117 2118 ~ImDrawList() { _ClearFreeMemory(); } 2119 IMGUI_API void PushClipRect(ImVec2 clip_rect_min, ImVec2 clip_rect_max, bool intersect_with_current_clip_rect = false); // Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling) 2120 IMGUI_API void PushClipRectFullScreen(); 2121 IMGUI_API void PopClipRect(); 2122 IMGUI_API void PushTextureID(ImTextureID texture_id); 2123 IMGUI_API void PopTextureID(); 2124 inline ImVec2 GetClipRectMin() const { const ImVec4& cr = _ClipRectStack.back(); return ImVec2(cr.x, cr.y); } 2125 inline ImVec2 GetClipRectMax() const { const ImVec4& cr = _ClipRectStack.back(); return ImVec2(cr.z, cr.w); } 2126 2127 // Primitives 2128 // - For rectangular primitives, "p_min" and "p_max" represent the upper-left and lower-right corners. 2129 // - For circle primitives, use "num_segments == 0" to automatically calculate tessellation (preferred). 2130 // In older versions (until Dear ImGui 1.77) the AddCircle functions defaulted to num_segments == 12. 2131 // In future versions we will use textures to provide cheaper and higher-quality circles. 2132 // Use AddNgon() and AddNgonFilled() functions if you need to guaranteed a specific number of sides. 2133 IMGUI_API void AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float thickness = 1.0f); 2134 IMGUI_API void AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding = 0.0f, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All, float thickness = 1.0f); // a: upper-left, b: lower-right (== upper-left + size), rounding_corners_flags: 4 bits corresponding to which corner to round 2135 IMGUI_API void AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding = 0.0f, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All); // a: upper-left, b: lower-right (== upper-left + size) 2136 IMGUI_API void AddRectFilledMultiColor(const ImVec2& p_min, const ImVec2& p_max, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left); 2137 IMGUI_API void AddQuad(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness = 1.0f); 2138 IMGUI_API void AddQuadFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col); 2139 IMGUI_API void AddTriangle(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness = 1.0f); 2140 IMGUI_API void AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col); 2141 IMGUI_API void AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments = 0, float thickness = 1.0f); 2142 IMGUI_API void AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments = 0); 2143 IMGUI_API void AddNgon(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness = 1.0f); 2144 IMGUI_API void AddNgonFilled(const ImVec2& center, float radius, ImU32 col, int num_segments); 2145 IMGUI_API void AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL); 2146 IMGUI_API void AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL, float wrap_width = 0.0f, const ImVec4* cpu_fine_clip_rect = NULL); 2147 IMGUI_API void AddPolyline(const ImVec2* points, int num_points, ImU32 col, bool closed, float thickness); 2148 IMGUI_API void AddConvexPolyFilled(const ImVec2* points, int num_points, ImU32 col); // Note: Anti-aliased filling requires points to be in clockwise order. 2149 IMGUI_API void AddBezierCurve(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0); 2150 2151 // Image primitives 2152 // - Read FAQ to understand what ImTextureID is. 2153 // - "p_min" and "p_max" represent the upper-left and lower-right corners of the rectangle. 2154 // - "uv_min" and "uv_max" represent the normalized texture coordinates to use for those corners. Using (0,0)->(1,1) texture coordinates will generally display the entire texture. 2155 IMGUI_API void AddImage(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min = ImVec2(0, 0), const ImVec2& uv_max = ImVec2(1, 1), ImU32 col = IM_COL32_WHITE); 2156 IMGUI_API void AddImageQuad(ImTextureID user_texture_id, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& uv1 = ImVec2(0, 0), const ImVec2& uv2 = ImVec2(1, 0), const ImVec2& uv3 = ImVec2(1, 1), const ImVec2& uv4 = ImVec2(0, 1), ImU32 col = IM_COL32_WHITE); 2157 IMGUI_API void AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All); 2158 2159 // Stateful path API, add points then finish with PathFillConvex() or PathStroke() 2160 inline void PathClear() { _Path.Size = 0; } 2161 inline void PathLineTo(const ImVec2& pos) { _Path.push_back(pos); } 2162 inline void PathLineToMergeDuplicate(const ImVec2& pos) { if (_Path.Size == 0 || memcmp(&_Path.Data[_Path.Size - 1], &pos, 8) != 0) _Path.push_back(pos); } 2163 inline void PathFillConvex(ImU32 col) { AddConvexPolyFilled(_Path.Data, _Path.Size, col); _Path.Size = 0; } // Note: Anti-aliased filling requires points to be in clockwise order. 2164 inline void PathStroke(ImU32 col, bool closed, float thickness = 1.0f) { AddPolyline(_Path.Data, _Path.Size, col, closed, thickness); _Path.Size = 0; } 2165 IMGUI_API void PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments = 10); 2166 IMGUI_API void PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12); // Use precomputed angles for a 12 steps circle 2167 IMGUI_API void PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0); 2168 IMGUI_API void PathRect(const ImVec2& rect_min, const ImVec2& rect_max, float rounding = 0.0f, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All); 2169 2170 // Advanced 2171 IMGUI_API void AddCallback(ImDrawCallback callback, void* callback_data); // Your rendering function must check for 'UserCallback' in ImDrawCmd and call the function instead of rendering triangles. 2172 IMGUI_API void AddDrawCmd(); // This is useful if you need to forcefully create a new draw call (to allow for dependent rendering / blending). Otherwise primitives are merged into the same draw-call as much as possible 2173 IMGUI_API ImDrawList* CloneOutput() const; // Create a clone of the CmdBuffer/IdxBuffer/VtxBuffer. 2174 2175 // Advanced: Channels 2176 // - Use to split render into layers. By switching channels to can render out-of-order (e.g. submit FG primitives before BG primitives) 2177 // - Use to minimize draw calls (e.g. if going back-and-forth between multiple clipping rectangles, prefer to append into separate channels then merge at the end) 2178 // - FIXME-OBSOLETE: This API shouldn't have been in ImDrawList in the first place! 2179 // Prefer using your own persistent instance of ImDrawListSplitter as you can stack them. 2180 // Using the ImDrawList::ChannelsXXXX you cannot stack a split over another. 2181 inline void ChannelsSplit(int count) { _Splitter.Split(this, count); } 2182 inline void ChannelsMerge() { _Splitter.Merge(this); } 2183 inline void ChannelsSetCurrent(int n) { _Splitter.SetCurrentChannel(this, n); } 2184 2185 // Advanced: Primitives allocations 2186 // - We render triangles (three vertices) 2187 // - All primitives needs to be reserved via PrimReserve() beforehand. 2188 IMGUI_API void PrimReserve(int idx_count, int vtx_count); 2189 IMGUI_API void PrimUnreserve(int idx_count, int vtx_count); 2190 IMGUI_API void PrimRect(const ImVec2& a, const ImVec2& b, ImU32 col); // Axis aligned rectangle (composed of two triangles) 2191 IMGUI_API void PrimRectUV(const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col); 2192 IMGUI_API void PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a, const ImVec2& uv_b, const ImVec2& uv_c, const ImVec2& uv_d, ImU32 col); 2193 inline void PrimWriteVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { _VtxWritePtr->pos = pos; _VtxWritePtr->uv = uv; _VtxWritePtr->col = col; _VtxWritePtr++; _VtxCurrentIdx++; } 2194 inline void PrimWriteIdx(ImDrawIdx idx) { *_IdxWritePtr = idx; _IdxWritePtr++; } 2195 inline void PrimVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { PrimWriteIdx((ImDrawIdx)_VtxCurrentIdx); PrimWriteVtx(pos, uv, col); } // Write vertex with unique index 2196 2197 // [Internal helpers] 2198 IMGUI_API void _ResetForNewFrame(); 2199 IMGUI_API void _ClearFreeMemory(); 2200 IMGUI_API void _PopUnusedDrawCmd(); 2201 IMGUI_API void _OnChangedClipRect(); 2202 IMGUI_API void _OnChangedTextureID(); 2203 IMGUI_API void _OnChangedVtxOffset(); 2204 }; 2205 2206 // All draw data to render a Dear ImGui frame 2207 // (NB: the style and the naming convention here is a little inconsistent, we currently preserve them for backward compatibility purpose, 2208 // as this is one of the oldest structure exposed by the library! Basically, ImDrawList == CmdList) 1636 2209 struct ImDrawData 1637 2210 { 1638 bool Valid; // Only valid after Render() is called and before the next NewFrame() is called. 1639 ImDrawList** CmdLists; // Array of ImDrawList* to render. The ImDrawList are owned by ImGuiContext and only pointed to from here. 1640 int CmdListsCount; // Number of ImDrawList* to render 1641 int TotalIdxCount; // For convenience, sum of all ImDrawList's IdxBuffer.Size 1642 int TotalVtxCount; // For convenience, sum of all ImDrawList's VtxBuffer.Size 1643 1644 // Functions 1645 ImDrawData() { Valid = false; Clear(); } 1646 ~ImDrawData() { Clear(); } 1647 void Clear() { Valid = false; CmdLists = NULL; CmdListsCount = TotalVtxCount = TotalIdxCount = 0; } // The ImDrawList are owned by ImGuiContext! 1648 IMGUI_API void DeIndexAllBuffers(); // Helper to convert all buffers from indexed to non-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering! 1649 IMGUI_API void ScaleClipRects(const ImVec2& sc); // Helper to scale the ClipRect field of each ImDrawCmd. Use if your final output buffer is at a different scale than ImGui expects, or if there is a difference between your window resolution and framebuffer resolution. 1650 }; 2211 bool Valid; // Only valid after Render() is called and before the next NewFrame() is called. 2212 ImDrawList** CmdLists; // Array of ImDrawList* to render. The ImDrawList are owned by ImGuiContext and only pointed to from here. 2213 int CmdListsCount; // Number of ImDrawList* to render 2214 int TotalIdxCount; // For convenience, sum of all ImDrawList's IdxBuffer.Size 2215 int TotalVtxCount; // For convenience, sum of all ImDrawList's VtxBuffer.Size 2216 ImVec2 DisplayPos; // Upper-left position of the viewport to render (== upper-left of the orthogonal projection matrix to use) 2217 ImVec2 DisplaySize; // Size of the viewport to render (== io.DisplaySize for the main viewport) (DisplayPos + DisplaySize == lower-right of the orthogonal projection matrix to use) 2218 ImVec2 FramebufferScale; // Amount of pixels for each unit of DisplaySize. Based on io.DisplayFramebufferScale. Generally (1,1) on normal display, (2,2) on OSX with Retina display. 2219 2220 // Functions 2221 ImDrawData() { Valid = false; Clear(); } 2222 ~ImDrawData() { Clear(); } 2223 void Clear() { Valid = false; CmdLists = NULL; CmdListsCount = TotalVtxCount = TotalIdxCount = 0; DisplayPos = DisplaySize = FramebufferScale = ImVec2(0.f, 0.f); } // The ImDrawList are owned by ImGuiContext! 2224 IMGUI_API void DeIndexAllBuffers(); // Helper to convert all buffers from indexed to non-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering! 2225 IMGUI_API void ScaleClipRects(const ImVec2& fb_scale); // Helper to scale the ClipRect field of each ImDrawCmd. Use if your final output buffer is at a different scale than Dear ImGui expects, or if there is a difference between your window resolution and framebuffer resolution. 2226 }; 2227 2228 //----------------------------------------------------------------------------- 2229 // Font API (ImFontConfig, ImFontGlyph, ImFontAtlasFlags, ImFontAtlas, ImFontGlyphRangesBuilder, ImFont) 2230 //----------------------------------------------------------------------------- 1651 2231 1652 2232 struct ImFontConfig 1653 2233 { 1654 void* FontData; // // TTF/OTF data 1655 int FontDataSize; // // TTF/OTF data size 1656 bool FontDataOwnedByAtlas; // true // TTF/OTF data ownership taken by the container ImFontAtlas (will delete memory itself). 1657 int FontNo; // 0 // Index of font within TTF/OTF file 1658 float SizePixels; // // Size in pixels for rasterizer. 1659 int OversampleH; // 3 // Rasterize at higher quality for sub-pixel positioning. We don't use sub-pixel positions on the Y axis. 1660 int OversampleV; // 1 // Rasterize at higher quality for sub-pixel positioning. We don't use sub-pixel positions on the Y axis. 1661 bool PixelSnapH; // false // Align every glyph to pixel boundary. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1. 1662 ImVec2 GlyphExtraSpacing; // 0, 0 // Extra spacing (in pixels) between glyphs. Only X axis is supported for now. 1663 ImVec2 GlyphOffset; // 0, 0 // Offset all glyphs from this font input. 1664 const ImWchar* GlyphRanges; // NULL // Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. 1665 bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights. 1666 unsigned int RasterizerFlags; // 0x00 // Settings for custom font rasterizer (e.g. ImGuiFreeType). Leave as zero if you aren't using one. 1667 float RasterizerMultiply; // 1.0f // Brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable. 1668 1669 // [Internal] 1670 char Name[40]; // Name (strictly to ease debugging) 1671 ImFont* DstFont; 1672 1673 IMGUI_API ImFontConfig(); 1674 }; 1675 2234 void* FontData; // // TTF/OTF data 2235 int FontDataSize; // // TTF/OTF data size 2236 bool FontDataOwnedByAtlas; // true // TTF/OTF data ownership taken by the container ImFontAtlas (will delete memory itself). 2237 int FontNo; // 0 // Index of font within TTF/OTF file 2238 float SizePixels; // // Size in pixels for rasterizer (more or less maps to the resulting font height). 2239 int OversampleH; // 3 // Rasterize at higher quality for sub-pixel positioning. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. 2240 int OversampleV; // 1 // Rasterize at higher quality for sub-pixel positioning. We don't use sub-pixel positions on the Y axis. 2241 bool PixelSnapH; // false // Align every glyph to pixel boundary. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1. 2242 ImVec2 GlyphExtraSpacing; // 0, 0 // Extra spacing (in pixels) between glyphs. Only X axis is supported for now. 2243 ImVec2 GlyphOffset; // 0, 0 // Offset all glyphs from this font input. 2244 const ImWchar* GlyphRanges; // NULL // Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. 2245 float GlyphMinAdvanceX; // 0 // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font 2246 float GlyphMaxAdvanceX; // FLT_MAX // Maximum AdvanceX for glyphs 2247 bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights. 2248 unsigned int RasterizerFlags; // 0x00 // Settings for custom font rasterizer (e.g. ImGuiFreeType). Leave as zero if you aren't using one. 2249 float RasterizerMultiply; // 1.0f // Brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable. 2250 ImWchar EllipsisChar; // -1 // Explicitly specify unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used. 2251 2252 // [Internal] 2253 char Name[40]; // Name (strictly to ease debugging) 2254 ImFont* DstFont; 2255 2256 IMGUI_API ImFontConfig(); 2257 }; 2258 2259 // Hold rendering data for one glyph. 2260 // (Note: some language parsers may fail to convert the 31+1 bitfield members, in this case maybe drop store a single u32 or we can rework this) 1676 2261 struct ImFontGlyph 1677 2262 { 1678 ImWchar Codepoint; // 0x0000..0xFFFF 1679 float AdvanceX; // Distance to next character (= data from font + ImFontConfig::GlyphExtraSpacing.x baked in) 1680 float X0, Y0, X1, Y1; // Glyph corners 1681 float U0, V0, U1, V1; // Texture coordinates 1682 }; 1683 2263 unsigned int Codepoint : 31; // 0x0000..0xFFFF 2264 unsigned int Visible : 1; // Flag to allow early out when rendering 2265 float AdvanceX; // Distance to next character (= data from font + ImFontConfig::GlyphExtraSpacing.x baked in) 2266 float X0, Y0, X1, Y1; // Glyph corners 2267 float U0, V0, U1, V1; // Texture coordinates 2268 }; 2269 2270 // Helper to build glyph ranges from text/string data. Feed your application strings/characters to it then call BuildRanges(). 2271 // This is essentially a tightly packed of vector of 64k booleans = 8KB storage. 2272 struct ImFontGlyphRangesBuilder 2273 { 2274 ImVector<ImU32> UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used) 2275 2276 ImFontGlyphRangesBuilder() { Clear(); } 2277 inline void Clear() { int size_in_bytes = (IM_UNICODE_CODEPOINT_MAX + 1) / 8; UsedChars.resize(size_in_bytes / (int)sizeof(ImU32)); memset(UsedChars.Data, 0, (size_t)size_in_bytes); } 2278 inline bool GetBit(size_t n) const { int off = (int)(n >> 5); ImU32 mask = 1u << (n & 31); return (UsedChars[off] & mask) != 0; } // Get bit n in the array 2279 inline void SetBit(size_t n) { int off = (int)(n >> 5); ImU32 mask = 1u << (n & 31); UsedChars[off] |= mask; } // Set bit n in the array 2280 inline void AddChar(ImWchar c) { SetBit(c); } // Add character 2281 IMGUI_API void AddText(const char* text, const char* text_end = NULL); // Add string (each character of the UTF-8 string are added) 2282 IMGUI_API void AddRanges(const ImWchar* ranges); // Add ranges, e.g. builder.AddRanges(ImFontAtlas::GetGlyphRangesDefault()) to force add all of ASCII/Latin+Ext 2283 IMGUI_API void BuildRanges(ImVector<ImWchar>* out_ranges); // Output new ranges 2284 }; 2285 2286 // See ImFontAtlas::AddCustomRectXXX functions. 2287 struct ImFontAtlasCustomRect 2288 { 2289 unsigned short Width, Height; // Input // Desired rectangle dimension 2290 unsigned short X, Y; // Output // Packed position in Atlas 2291 unsigned int GlyphID; // Input // For custom font glyphs only (ID < 0x110000) 2292 float GlyphAdvanceX; // Input // For custom font glyphs only: glyph xadvance 2293 ImVec2 GlyphOffset; // Input // For custom font glyphs only: glyph display offset 2294 ImFont* Font; // Input // For custom font glyphs only: target font 2295 ImFontAtlasCustomRect() { Width = Height = 0; X = Y = 0xFFFF; GlyphID = 0; GlyphAdvanceX = 0.0f; GlyphOffset = ImVec2(0, 0); Font = NULL; } 2296 bool IsPacked() const { return X != 0xFFFF; } 2297 }; 2298 2299 // Flags for ImFontAtlas build 1684 2300 enum ImFontAtlasFlags_ 1685 2301 { 1686 ImFontAtlasFlags_NoPowerOfTwoHeight = 1 << 0, // Don't round the height to next power of two 1687 ImFontAtlasFlags_NoMouseCursors = 1 << 1 // Don't build software mouse cursors into the atlas 1688 }; 1689 1690 // Load and rasterize multiple TTF/OTF fonts into a same texture. 1691 // Sharing a texture for multiple fonts allows us to reduce the number of draw calls during rendering. 1692 // We also add custom graphic data into the texture that serves for ImGui. 1693 // 1. (Optional) Call AddFont*** functions. If you don't call any, the default font will be loaded for you. 1694 // 2. Call GetTexDataAsAlpha8() or GetTexDataAsRGBA32() to build and retrieve pixels data. 1695 // 3. Upload the pixels data into a texture within your graphics system. 1696 // 4. Call SetTexID(my_tex_id); and pass the pointer/identifier to your texture. This value will be passed back to you during rendering to identify the texture. 1697 // IMPORTANT: If you pass a 'glyph_ranges' array to AddFont*** functions, you need to make sure that your array persist up until the ImFont is build (when calling GetTexData*** or Build()). We only copy the pointer, not the data. 2302 ImFontAtlasFlags_None = 0, 2303 ImFontAtlasFlags_NoPowerOfTwoHeight = 1 << 0, // Don't round the height to next power of two 2304 ImFontAtlasFlags_NoMouseCursors = 1 << 1, // Don't build software mouse cursors into the atlas (save a little texture memory) 2305 ImFontAtlasFlags_NoBakedLines = 1 << 2 // Don't build thick line textures into the atlas (save a little texture memory). The AntiAliasedLinesUseTex features uses them, otherwise they will be rendered using polygons (more expensive for CPU/GPU). 2306 }; 2307 2308 // Load and rasterize multiple TTF/OTF fonts into a same texture. The font atlas will build a single texture holding: 2309 // - One or more fonts. 2310 // - Custom graphics data needed to render the shapes needed by Dear ImGui. 2311 // - Mouse cursor shapes for software cursor rendering (unless setting 'Flags |= ImFontAtlasFlags_NoMouseCursors' in the font atlas). 2312 // It is the user-code responsibility to setup/build the atlas, then upload the pixel data into a texture accessible by your graphics api. 2313 // - Optionally, call any of the AddFont*** functions. If you don't call any, the default font embedded in the code will be loaded for you. 2314 // - Call GetTexDataAsAlpha8() or GetTexDataAsRGBA32() to build and retrieve pixels data. 2315 // - Upload the pixels data into a texture within your graphics system (see imgui_impl_xxxx.cpp examples) 2316 // - Call SetTexID(my_tex_id); and pass the pointer/identifier to your texture in a format natural to your graphics API. 2317 // This value will be passed back to you during rendering to identify the texture. Read FAQ entry about ImTextureID for more details. 2318 // Common pitfalls: 2319 // - If you pass a 'glyph_ranges' array to AddFont*** functions, you need to make sure that your array persist up until the 2320 // atlas is build (when calling GetTexData*** or Build()). We only copy the pointer, not the data. 2321 // - Important: By default, AddFontFromMemoryTTF() takes ownership of the data. Even though we are not writing to it, we will free the pointer on destruction. 2322 // You can set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed, 2323 // - Even though many functions are suffixed with "TTF", OTF data is supported just as well. 2324 // - This is an old API and it is currently awkward for those and and various other reasons! We will address them in the future! 1698 2325 struct ImFontAtlas 1699 2326 { 1700 IMGUI_API ImFontAtlas(); 1701 IMGUI_API ~ImFontAtlas(); 1702 IMGUI_API ImFont* AddFont(const ImFontConfig* font_cfg); 1703 IMGUI_API ImFont* AddFontDefault(const ImFontConfig* font_cfg = NULL); 1704 IMGUI_API ImFont* AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); 1705 IMGUI_API ImFont* AddFontFromMemoryTTF(void* font_data, int font_size, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // Note: Transfer ownership of 'ttf_data' to ImFontAtlas! Will be deleted after Build(). Set font_cfg->FontDataOwnedByAtlas to false to keep ownership. 1706 IMGUI_API ImFont* AddFontFromMemoryCompressedTTF(const void* compressed_font_data, int compressed_font_size, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data' still owned by caller. Compress with binary_to_compressed_c.cpp. 1707 IMGUI_API ImFont* AddFontFromMemoryCompressedBase85TTF(const char* compressed_font_data_base85, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data_base85' still owned by caller. Compress with binary_to_compressed_c.cpp with -base85 parameter. 1708 IMGUI_API void ClearInputData(); // Clear input data (all ImFontConfig structures including sizes, TTF data, glyph ranges, etc.) = all the data used to build the texture and fonts. 1709 IMGUI_API void ClearTexData(); // Clear output texture data (CPU side). Saves RAM once the texture has been copied to graphics memory. 1710 IMGUI_API void ClearFonts(); // Clear output font data (glyphs storage, UV coordinates). 1711 IMGUI_API void Clear(); // Clear all input and output. 1712 1713 // Build atlas, retrieve pixel data. 1714 // User is in charge of copying the pixels into graphics memory (e.g. create a texture with your engine). Then store your texture handle with SetTexID(). 1715 // RGBA32 format is provided for convenience and compatibility, but note that unless you use CustomRect to draw color data, the RGB pixels emitted from Fonts will all be white (~75% of waste). 1716 // Pitch = Width * BytesPerPixels 1717 IMGUI_API bool Build(); // Build pixels data. This is called automatically for you by the GetTexData*** functions. 1718 IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 1 byte per-pixel 1719 IMGUI_API void GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 4 bytes-per-pixel 1720 void SetTexID(ImTextureID id) { TexID = id; } 1721 1722 //------------------------------------------- 1723 // Glyph Ranges 1724 //------------------------------------------- 1725 1726 // Helpers to retrieve list of common Unicode ranges (2 value per range, values are inclusive, zero-terminated list) 1727 // NB: Make sure that your string are UTF-8 and NOT in your local code page. In C++11, you can create UTF-8 string literal using the u8"Hello world" syntax. See FAQ for details. 1728 IMGUI_API const ImWchar* GetGlyphRangesDefault(); // Basic Latin, Extended Latin 1729 IMGUI_API const ImWchar* GetGlyphRangesKorean(); // Default + Korean characters 1730 IMGUI_API const ImWchar* GetGlyphRangesJapanese(); // Default + Hiragana, Katakana, Half-Width, Selection of 1946 Ideographs 1731 IMGUI_API const ImWchar* GetGlyphRangesChinese(); // Default + Japanese + full set of about 21000 CJK Unified Ideographs 1732 IMGUI_API const ImWchar* GetGlyphRangesCyrillic(); // Default + about 400 Cyrillic characters 1733 IMGUI_API const ImWchar* GetGlyphRangesThai(); // Default + Thai characters 1734 1735 // Helpers to build glyph ranges from text data. Feed your application strings/characters to it then call BuildRanges(). 1736 struct GlyphRangesBuilder 1737 { 1738 ImVector<unsigned char> UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used) 1739 GlyphRangesBuilder() { UsedChars.resize(0x10000 / 8); memset(UsedChars.Data, 0, 0x10000 / 8); } 1740 bool GetBit(int n) { return (UsedChars[n >> 3] & (1 << (n & 7))) != 0; } 1741 void SetBit(int n) { UsedChars[n >> 3] |= 1 << (n & 7); } // Set bit 'c' in the array 1742 void AddChar(ImWchar c) { SetBit(c); } // Add character 1743 IMGUI_API void AddText(const char* text, const char* text_end = NULL); // Add string (each character of the UTF-8 string are added) 1744 IMGUI_API void AddRanges(const ImWchar* ranges); // Add ranges, e.g. builder.AddRanges(ImFontAtlas::GetGlyphRangesDefault) to force add all of ASCII/Latin+Ext 1745 IMGUI_API void BuildRanges(ImVector<ImWchar>* out_ranges); // Output new ranges 1746 }; 1747 1748 //------------------------------------------- 1749 // Custom Rectangles/Glyphs API 1750 //------------------------------------------- 1751 1752 // You can request arbitrary rectangles to be packed into the atlas, for your own purposes. After calling Build(), you can query the rectangle position and render your pixels. 1753 // You can also request your rectangles to be mapped as font glyph (given a font + Unicode point), so you can render e.g. custom colorful icons and use them as regular glyphs. 1754 struct CustomRect 1755 { 1756 unsigned int ID; // Input // User ID. Use <0x10000 to map into a font glyph, >=0x10000 for other/internal/custom texture data. 1757 unsigned short Width, Height; // Input // Desired rectangle dimension 1758 unsigned short X, Y; // Output // Packed position in Atlas 1759 float GlyphAdvanceX; // Input // For custom font glyphs only (ID<0x10000): glyph xadvance 1760 ImVec2 GlyphOffset; // Input // For custom font glyphs only (ID<0x10000): glyph display offset 1761 ImFont* Font; // Input // For custom font glyphs only (ID<0x10000): target font 1762 CustomRect() { ID = 0xFFFFFFFF; Width = Height = 0; X = Y = 0xFFFF; GlyphAdvanceX = 0.0f; GlyphOffset = ImVec2(0, 0); Font = NULL; } 1763 bool IsPacked() const { return X != 0xFFFF; } 1764 }; 1765 1766 IMGUI_API int AddCustomRectRegular(unsigned int id, int width, int height); // Id needs to be >= 0x10000. Id >= 0x80000000 are reserved for ImGui and ImDrawList 1767 IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0, 0)); // Id needs to be < 0x10000 to register a rectangle to map into a specific font. 1768 const CustomRect* GetCustomRectByIndex(int index) const { if (index < 0) return NULL; return &CustomRects[index]; } 1769 1770 // [Internal] 1771 IMGUI_API void CalcCustomRectUV(const CustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max); 1772 IMGUI_API bool GetMouseCursorTexData(ImGuiMouseCursor cursor, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]); 1773 1774 //------------------------------------------- 1775 // Members 1776 //------------------------------------------- 1777 1778 ImFontAtlasFlags Flags; // Build flags (see ImFontAtlasFlags_) 1779 ImTextureID TexID; // User data to refer to the texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure. 1780 int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height. 1781 int TexGlyphPadding; // Padding between glyphs within texture in pixels. Defaults to 1. 1782 1783 // [Internal] 1784 // NB: Access texture data via GetTexData*() calls! Which will setup a default font for you. 1785 unsigned char* TexPixelsAlpha8; // 1 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight 1786 unsigned int* TexPixelsRGBA32; // 4 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight * 4 1787 int TexWidth; // Texture width calculated during Build(). 1788 int TexHeight; // Texture height calculated during Build(). 1789 ImVec2 TexUvScale; // = (1.0f/TexWidth, 1.0f/TexHeight) 1790 ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel 1791 ImVector<ImFont*> Fonts; // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font. 1792 ImVector<CustomRect> CustomRects; // Rectangles for packing custom texture data into the atlas. 1793 ImVector<ImFontConfig> ConfigData; // Internal data 1794 int CustomRectIds[1]; // Identifiers of custom texture rectangle used by ImFontAtlas/ImDrawList 2327 IMGUI_API ImFontAtlas(); 2328 IMGUI_API ~ImFontAtlas(); 2329 IMGUI_API ImFont* AddFont(const ImFontConfig* font_cfg); 2330 IMGUI_API ImFont* AddFontDefault(const ImFontConfig* font_cfg = NULL); 2331 IMGUI_API ImFont* AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); 2332 IMGUI_API ImFont* AddFontFromMemoryTTF(void* font_data, int font_size, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // Note: Transfer ownership of 'ttf_data' to ImFontAtlas! Will be deleted after destruction of the atlas. Set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed. 2333 IMGUI_API ImFont* AddFontFromMemoryCompressedTTF(const void* compressed_font_data, int compressed_font_size, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data' still owned by caller. Compress with binary_to_compressed_c.cpp. 2334 IMGUI_API ImFont* AddFontFromMemoryCompressedBase85TTF(const char* compressed_font_data_base85, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data_base85' still owned by caller. Compress with binary_to_compressed_c.cpp with -base85 parameter. 2335 IMGUI_API void ClearInputData(); // Clear input data (all ImFontConfig structures including sizes, TTF data, glyph ranges, etc.) = all the data used to build the texture and fonts. 2336 IMGUI_API void ClearTexData(); // Clear output texture data (CPU side). Saves RAM once the texture has been copied to graphics memory. 2337 IMGUI_API void ClearFonts(); // Clear output font data (glyphs storage, UV coordinates). 2338 IMGUI_API void Clear(); // Clear all input and output. 2339 2340 // Build atlas, retrieve pixel data. 2341 // User is in charge of copying the pixels into graphics memory (e.g. create a texture with your engine). Then store your texture handle with SetTexID(). 2342 // The pitch is always = Width * BytesPerPixels (1 or 4) 2343 // Building in RGBA32 format is provided for convenience and compatibility, but note that unless you manually manipulate or copy color data into 2344 // the texture (e.g. when using the AddCustomRect*** api), then the RGB pixels emitted will always be white (~75% of memory/bandwidth waste. 2345 IMGUI_API bool Build(); // Build pixels data. This is called automatically for you by the GetTexData*** functions. 2346 IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 1 byte per-pixel 2347 IMGUI_API void GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 4 bytes-per-pixel 2348 bool IsBuilt() const { return Fonts.Size > 0 && (TexPixelsAlpha8 != NULL || TexPixelsRGBA32 != NULL); } 2349 void SetTexID(ImTextureID id) { TexID = id; } 2350 2351 //------------------------------------------- 2352 // Glyph Ranges 2353 //------------------------------------------- 2354 2355 // Helpers to retrieve list of common Unicode ranges (2 value per range, values are inclusive, zero-terminated list) 2356 // NB: Make sure that your string are UTF-8 and NOT in your local code page. In C++11, you can create UTF-8 string literal using the u8"Hello world" syntax. See FAQ for details. 2357 // NB: Consider using ImFontGlyphRangesBuilder to build glyph ranges from textual data. 2358 IMGUI_API const ImWchar* GetGlyphRangesDefault(); // Basic Latin, Extended Latin 2359 IMGUI_API const ImWchar* GetGlyphRangesKorean(); // Default + Korean characters 2360 IMGUI_API const ImWchar* GetGlyphRangesJapanese(); // Default + Hiragana, Katakana, Half-Width, Selection of 1946 Ideographs 2361 IMGUI_API const ImWchar* GetGlyphRangesChineseFull(); // Default + Half-Width + Japanese Hiragana/Katakana + full set of about 21000 CJK Unified Ideographs 2362 IMGUI_API const ImWchar* GetGlyphRangesChineseSimplifiedCommon();// Default + Half-Width + Japanese Hiragana/Katakana + set of 2500 CJK Unified Ideographs for common simplified Chinese 2363 IMGUI_API const ImWchar* GetGlyphRangesCyrillic(); // Default + about 400 Cyrillic characters 2364 IMGUI_API const ImWchar* GetGlyphRangesThai(); // Default + Thai characters 2365 IMGUI_API const ImWchar* GetGlyphRangesVietnamese(); // Default + Vietnamese characters 2366 2367 //------------------------------------------- 2368 // [BETA] Custom Rectangles/Glyphs API 2369 //------------------------------------------- 2370 2371 // You can request arbitrary rectangles to be packed into the atlas, for your own purposes. 2372 // After calling Build(), you can query the rectangle position and render your pixels. 2373 // You can also request your rectangles to be mapped as font glyph (given a font + Unicode point), 2374 // so you can render e.g. custom colorful icons and use them as regular glyphs. 2375 // Read docs/FONTS.md for more details about using colorful icons. 2376 // Note: this API may be redesigned later in order to support multi-monitor varying DPI settings. 2377 IMGUI_API int AddCustomRectRegular(int width, int height); 2378 IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0, 0)); 2379 ImFontAtlasCustomRect* GetCustomRectByIndex(int index) { IM_ASSERT(index >= 0); return &CustomRects[index]; } 2380 2381 // [Internal] 2382 IMGUI_API void CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const; 2383 IMGUI_API bool GetMouseCursorTexData(ImGuiMouseCursor cursor, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]); 2384 2385 //------------------------------------------- 2386 // Members 2387 //------------------------------------------- 2388 2389 bool Locked; // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert. 2390 ImFontAtlasFlags Flags; // Build flags (see ImFontAtlasFlags_) 2391 ImTextureID TexID; // User data to refer to the texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure. 2392 int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height. 2393 int TexGlyphPadding; // Padding between glyphs within texture in pixels. Defaults to 1. If your rendering method doesn't rely on bilinear filtering you may set this to 0. 2394 2395 // [Internal] 2396 // NB: Access texture data via GetTexData*() calls! Which will setup a default font for you. 2397 unsigned char* TexPixelsAlpha8; // 1 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight 2398 unsigned int* TexPixelsRGBA32; // 4 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight * 4 2399 int TexWidth; // Texture width calculated during Build(). 2400 int TexHeight; // Texture height calculated during Build(). 2401 ImVec2 TexUvScale; // = (1.0f/TexWidth, 1.0f/TexHeight) 2402 ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel 2403 ImVector<ImFont*> Fonts; // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font. 2404 ImVector<ImFontAtlasCustomRect> CustomRects; // Rectangles for packing custom texture data into the atlas. 2405 ImVector<ImFontConfig> ConfigData; // Configuration data 2406 ImVec4 TexUvLines[IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1]; // UVs for baked anti-aliased lines 2407 2408 // [Internal] Packing data 2409 int PackIdMouseCursors; // Custom texture rectangle ID for white pixel and mouse cursors 2410 int PackIdLines; // Custom texture rectangle ID for baked anti-aliased lines 2411 2412 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS 2413 typedef ImFontAtlasCustomRect CustomRect; // OBSOLETED in 1.72+ 2414 typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+ 2415 #endif 1795 2416 }; 1796 2417 … … 1799 2420 struct ImFont 1800 2421 { 1801 // Members: Hot ~62/78 bytes 1802 float FontSize; // <user set> // Height of characters, set during loading (don't change after loading) 1803 float Scale; // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetFontScale() 1804 ImVec2 DisplayOffset; // = (0.f,0.f) // Offset font rendering by xx pixels 1805 ImVector<ImFontGlyph> Glyphs; // // All glyphs. 1806 ImVector<float> IndexAdvanceX; // // Sparse. Glyphs->AdvanceX in a directly indexable way (more cache-friendly, for CalcTextSize functions which are often bottleneck in large UI). 1807 ImVector<unsigned short> IndexLookup; // // Sparse. Index glyphs by Unicode code-point. 1808 const ImFontGlyph* FallbackGlyph; // == FindGlyph(FontFallbackChar) 1809 float FallbackAdvanceX; // == FallbackGlyph->AdvanceX 1810 ImWchar FallbackChar; // = '?' // Replacement glyph if one isn't found. Only set via SetFallbackChar() 1811 1812 // Members: Cold ~18/26 bytes 1813 short ConfigDataCount; // ~ 1 // Number of ImFontConfig involved in creating this font. Bigger than 1 when merging multiple font sources into one ImFont. 1814 ImFontConfig* ConfigData; // // Pointer within ContainerAtlas->ConfigData 1815 ImFontAtlas* ContainerAtlas; // // What we has been loaded into 1816 float Ascent, Descent; // // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] 1817 bool DirtyLookupTables; 1818 int MetricsTotalSurface;// // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs) 1819 1820 // Methods 1821 IMGUI_API ImFont(); 1822 IMGUI_API ~ImFont(); 1823 IMGUI_API void ClearOutputData(); 1824 IMGUI_API void BuildLookupTable(); 1825 IMGUI_API const ImFontGlyph*FindGlyph(ImWchar c) const; 1826 IMGUI_API const ImFontGlyph*FindGlyphNoFallback(ImWchar c) const; 1827 IMGUI_API void SetFallbackChar(ImWchar c); 1828 float GetCharAdvance(ImWchar c) const { return ((int)c < IndexAdvanceX.Size) ? IndexAdvanceX[(int)c] : FallbackAdvanceX; } 1829 bool IsLoaded() const { return ContainerAtlas != NULL; } 1830 const char* GetDebugName() const { return ConfigData ? ConfigData->Name : "<unknown>"; } 1831 1832 // 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable. 1833 // 'wrap_width' enable automatic word-wrapping across multiple lines to fit into given width. 0.0f to disable. 1834 IMGUI_API ImVec2 CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end = NULL, const char** remaining = NULL) const; // utf8 1835 IMGUI_API const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const; 1836 IMGUI_API void RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, unsigned short c) const; 1837 IMGUI_API void RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, bool cpu_fine_clip = false) const; 1838 1839 // [Internal] 1840 IMGUI_API void GrowIndex(int new_size); 1841 IMGUI_API void AddGlyph(ImWchar c, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x); 1842 IMGUI_API void AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built. 1843 1844 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS 1845 typedef ImFontGlyph Glyph; // OBSOLETE 1.52+ 1846 #endif 2422 // Members: Hot ~20/24 bytes (for CalcTextSize) 2423 ImVector<float> IndexAdvanceX; // 12-16 // out // // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for CalcTextSize functions which only this this info, and are often bottleneck in large UI). 2424 float FallbackAdvanceX; // 4 // out // = FallbackGlyph->AdvanceX 2425 float FontSize; // 4 // in // // Height of characters/line, set during loading (don't change after loading) 2426 2427 // Members: Hot ~28/40 bytes (for CalcTextSize + render loop) 2428 ImVector<ImWchar> IndexLookup; // 12-16 // out // // Sparse. Index glyphs by Unicode code-point. 2429 ImVector<ImFontGlyph> Glyphs; // 12-16 // out // // All glyphs. 2430 const ImFontGlyph* FallbackGlyph; // 4-8 // out // = FindGlyph(FontFallbackChar) 2431 2432 // Members: Cold ~32/40 bytes 2433 ImFontAtlas* ContainerAtlas; // 4-8 // out // // What we has been loaded into 2434 const ImFontConfig* ConfigData; // 4-8 // in // // Pointer within ContainerAtlas->ConfigData 2435 short ConfigDataCount; // 2 // in // ~ 1 // Number of ImFontConfig involved in creating this font. Bigger than 1 when merging multiple font sources into one ImFont. 2436 ImWchar FallbackChar; // 2 // in // = '?' // Replacement character if a glyph isn't found. Only set via SetFallbackChar() 2437 ImWchar EllipsisChar; // 2 // out // = -1 // Character used for ellipsis rendering. 2438 bool DirtyLookupTables; // 1 // out // 2439 float Scale; // 4 // in // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetWindowFontScale() 2440 float Ascent, Descent; // 4+4 // out // // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] 2441 int MetricsTotalSurface;// 4 // out // // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs) 2442 ImU8 Used4kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/4096/8]; // 2 bytes if ImWchar=ImWchar16, 34 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 4K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints. 2443 2444 // Methods 2445 IMGUI_API ImFont(); 2446 IMGUI_API ~ImFont(); 2447 IMGUI_API const ImFontGlyph*FindGlyph(ImWchar c) const; 2448 IMGUI_API const ImFontGlyph*FindGlyphNoFallback(ImWchar c) const; 2449 float GetCharAdvance(ImWchar c) const { return ((int)c < IndexAdvanceX.Size) ? IndexAdvanceX[(int)c] : FallbackAdvanceX; } 2450 bool IsLoaded() const { return ContainerAtlas != NULL; } 2451 const char* GetDebugName() const { return ConfigData ? ConfigData->Name : "<unknown>"; } 2452 2453 // 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable. 2454 // 'wrap_width' enable automatic word-wrapping across multiple lines to fit into given width. 0.0f to disable. 2455 IMGUI_API ImVec2 CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end = NULL, const char** remaining = NULL) const; // utf8 2456 IMGUI_API const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const; 2457 IMGUI_API void RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, ImWchar c) const; 2458 IMGUI_API void RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, bool cpu_fine_clip = false) const; 2459 2460 // [Internal] Don't use! 2461 IMGUI_API void BuildLookupTable(); 2462 IMGUI_API void ClearOutputData(); 2463 IMGUI_API void GrowIndex(int new_size); 2464 IMGUI_API void AddGlyph(const ImFontConfig* src_cfg, ImWchar c, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x); 2465 IMGUI_API void AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built. 2466 IMGUI_API void SetGlyphVisible(ImWchar c, bool visible); 2467 IMGUI_API void SetFallbackChar(ImWchar c); 2468 IMGUI_API bool IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last); 1847 2469 }; 1848 2470 1849 2471 #if defined(__clang__) 1850 2472 #pragma clang diagnostic pop 2473 #elif defined(__GNUC__) 2474 #pragma GCC diagnostic pop 1851 2475 #endif 1852 2476 … … 1855 2479 #include "imgui_user.h" 1856 2480 #endif 2481 2482 #endif // #ifndef IMGUI_DISABLE -
IMGUI/imgui_demo.cpp
r78c3045 re66fd66 1 // dear imgui, v1. 61 WIP1 // dear imgui, v1.79 2 2 // (demo code) 3 3 4 // Message to the person tempted to delete this file when integrating ImGui into their code base: 5 // Don't do it! Do NOT remove this file from your project! It is useful reference code that you and other users will want to refer to. 4 // Help: 5 // - Read FAQ at http://dearimgui.org/faq 6 // - Newcomers, read 'Programmer guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase. 7 // - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that. 8 // Read imgui.cpp for more details, documentation and comments. 9 // Get latest version at https://github.com/ocornut/imgui 10 11 // Message to the person tempted to delete this file when integrating Dear ImGui into their code base: 12 // Do NOT remove this file from your project! Think again! It is the most useful reference code that you and other 13 // coders will want to refer to and call. Have the ImGui::ShowDemoWindow() function wired in an always-available 14 // debug menu of your game/app! Removing this file from your project is hindering access to documentation for everyone 15 // in your team, likely leading you to poorer usage of the library. 6 16 // Everything in this file will be stripped out by the linker if you don't call ImGui::ShowDemoWindow(). 7 // During development, you can call ImGui::ShowDemoWindow() in your code to learn about various features of ImGui. Have it wired in a debug menu! 8 // Removing this file from your project is hindering access to documentation for everyone in your team, likely leading you to poorer usage of the library. 9 // Note that you can #define IMGUI_DISABLE_DEMO_WINDOWS in imconfig.h for the same effect. 10 // If you want to link core ImGui in your final builds but not those demo windows, #define IMGUI_DISABLE_DEMO_WINDOWS in imconfig.h and those functions will be empty. 11 // In other situation, when you have ImGui available you probably want this to be available for reference and execution. 17 // If you want to link core Dear ImGui in your shipped builds but want a thorough guarantee that the demo will not be 18 // linked, you can setup your imconfig.h with #define IMGUI_DISABLE_DEMO_WINDOWS and those functions will be empty. 19 // In other situation, whenever you have Dear ImGui available you probably want this to be available for reference. 12 20 // Thank you, 13 // -Your beloved friend, imgui_demo.cpp (that you won't delete) 14 15 // Message to beginner C/C++ programmers. About the meaning of 'static': in this demo code, we frequently we use 'static' variables inside functions. 16 // We do this as a way to gather code and data in the same place, just to make the demo code faster to read, faster to write, and use less code. 17 // A static variable persist across calls, so it is essentially like a global variable but declared inside the scope of the function. 18 // It also happens to be a convenient way of storing simple UI related information as long as your function doesn't need to be reentrant or used in threads. 19 // This might be a pattern you occasionally want to use in your code, but most of the real data you would be editing is likely to be stored outside your function. 21 // -Your beloved friend, imgui_demo.cpp (which you won't delete) 22 23 // Message to beginner C/C++ programmers about the meaning of the 'static' keyword: 24 // In this demo code, we frequently we use 'static' variables inside functions. A static variable persist across calls, 25 // so it is essentially like a global variable but declared inside the scope of the function. We do this as a way to 26 // gather code and data in the same place, to make the demo source code faster to read, faster to write, and smaller 27 // in size. It also happens to be a convenient way of storing simple UI related information as long as your function 28 // doesn't need to be reentrant or used in multiple threads. This might be a pattern you will want to use in your code, 29 // but most of the real data you would be editing is likely going to be stored outside your functions. 30 31 // The Demo code in this file is designed to be easy to copy-and-paste in into your application! 32 // Because of this: 33 // - We never omit the ImGui:: prefix when calling functions, even though most code here is in the same namespace. 34 // - We try to declare static variables in the local scope, as close as possible to the code using them. 35 // - We never use any of the helpers/facilities used internally by Dear ImGui, unless available in the public API. 36 // - We never use maths operators on ImVec2/ImVec4. For our other sources files we use them, and they are provided 37 // by imgui_internal.h using the IMGUI_DEFINE_MATH_OPERATORS define. For your own sources file they are optional 38 // and require you either enable those, either provide your own via IM_VEC2_CLASS_EXTRA in imconfig.h. 39 // Because we can't assume anything about your support of maths operators, we cannot use them in imgui_demo.cpp. 40 41 /* 42 43 Index of this file: 44 45 // [SECTION] Forward Declarations, Helpers 46 // [SECTION] Demo Window / ShowDemoWindow() 47 // [SECTION] About Window / ShowAboutWindow() 48 // [SECTION] Style Editor / ShowStyleEditor() 49 // [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar() 50 // [SECTION] Example App: Debug Console / ShowExampleAppConsole() 51 // [SECTION] Example App: Debug Log / ShowExampleAppLog() 52 // [SECTION] Example App: Simple Layout / ShowExampleAppLayout() 53 // [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor() 54 // [SECTION] Example App: Long Text / ShowExampleAppLongText() 55 // [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize() 56 // [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize() 57 // [SECTION] Example App: Simple Overlay / ShowExampleAppSimpleOverlay() 58 // [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles() 59 // [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering() 60 // [SECTION] Example App: Documents Handling / ShowExampleAppDocuments() 61 62 */ 20 63 21 64 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) … … 24 67 25 68 #include "imgui.h" 26 #include <ctype.h> // toupper, isprint 69 #ifndef IMGUI_DISABLE 70 71 #include <ctype.h> // toupper 72 #include <limits.h> // INT_MIN, INT_MAX 27 73 #include <math.h> // sqrtf, powf, cosf, sinf, floorf, ceilf 28 74 #include <stdio.h> // vsnprintf, sscanf, printf … … 34 80 #endif 35 81 82 // Visual Studio warnings 36 83 #ifdef _MSC_VER 37 84 #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen 38 #define snprintf _snprintf39 85 #endif 40 #ifdef __clang__ 41 #pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse. 42 #pragma clang diagnostic ignored "-Wdeprecated-declarations" // warning : 'xx' is deprecated: The POSIX name for this item.. // for strdup used in demo code (so user can copy & paste the code) 43 #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int' 44 #pragma clang diagnostic ignored "-Wformat-security" // warning : warning: format string is not a string literal 45 #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. 46 #if __has_warning("-Wreserved-id-macro") 47 #pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier // 86 87 // Clang/GCC warnings with -Weverything 88 #if defined(__clang__) 89 #if __has_warning("-Wunknown-warning-option") 90 #pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great! 48 91 #endif 92 #pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' 93 #pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. 94 #pragma clang diagnostic ignored "-Wdeprecated-declarations" // warning: 'xx' is deprecated: The POSIX name for this.. // for strdup used in demo code (so user can copy & paste the code) 95 #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning: cast to 'void *' from smaller integer type 96 #pragma clang diagnostic ignored "-Wformat-security" // warning: format string is not a string literal 97 #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. 98 #pragma clang diagnostic ignored "-Wunused-macros" // warning: macro is not used // we define snprintf/vsnprintf on Windows so they are available, but not always used. 99 #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0 100 #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. 101 #pragma clang diagnostic ignored "-Wreserved-id-macro" // warning: macro name is a reserved identifier 102 #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision 49 103 #elif defined(__GNUC__) 50 #pragma GCC diagnostic ignored "-W int-to-pointer-cast" // warning: cast to pointer from integer of different size51 #pragma GCC diagnostic ignored "-W format-security" // warning : format string is not a string literal (potentially insecure)52 #pragma GCC diagnostic ignored "-W double-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function53 #pragma GCC diagnostic ignored "-W conversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value54 # if (__GNUC__ >= 6)55 #pragma GCC diagnostic ignored "-Wmisleading-indentation" //warning: this 'if' clause does not guard this statement // GCC 6.0+ only. See #883 on GitHub.104 #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind 105 #pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size 106 #pragma GCC diagnostic ignored "-Wformat-security" // warning: format string is not a string literal (potentially insecure) 107 #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function 108 #pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value 109 #pragma GCC diagnostic ignored "-Wmisleading-indentation" // [__GNUC__ >= 6] warning: this 'if' clause does not guard this statement // GCC 6.0+ only. See #883 on GitHub. 56 110 #endif 111 112 // Play it nice with Windows users (Update: May 2018, Notepad now supports Unix-style carriage returns!) 113 #ifdef _WIN32 114 #define IM_NEWLINE "\r\n" 115 #else 116 #define IM_NEWLINE "\n" 57 117 #endif 58 118 59 // Play it nice with Windows users. Notepad in 2017 still doesn't display text data with Unix-style \n. 60 #ifdef _WIN32 61 #define IM_NEWLINE "\r\n" 62 #else 63 #define IM_NEWLINE "\n" 119 // Helpers 120 #if defined(_MSC_VER) && !defined(snprintf) 121 #define snprintf _snprintf 64 122 #endif 65 66 #define IM_MAX(_A,_B) (((_A) >= (_B)) ? (_A) : (_B)) 123 #if defined(_MSC_VER) && !defined(vsnprintf) 124 #define vsnprintf _vsnprintf 125 #endif 126 127 // Helpers macros 128 // We normally try to not use many helpers in imgui_demo.cpp in order to make code easier to copy and paste, 129 // but making an exception here as those are largely simplifying code... 130 // In other imgui sources we can use nicer internal functions from imgui_internal.h (ImMin/ImMax) but not in the demo. 131 #define IM_MIN(A, B) (((A) < (B)) ? (A) : (B)) 132 #define IM_MAX(A, B) (((A) >= (B)) ? (A) : (B)) 133 #define IM_CLAMP(V, MN, MX) ((V) < (MN) ? (MN) : (V) > (MX) ? (MX) : (V)) 67 134 68 135 //----------------------------------------------------------------------------- 69 // DEMO CODE136 // [SECTION] Forward Declarations, Helpers 70 137 //----------------------------------------------------------------------------- 71 138 72 #if !defined(IMGUI_DISABLE_OBSOLETE_FUNCTIONS) && defined(IMGUI_DISABLE_TEST_WINDOWS) && !defined(IMGUI_DISABLE_DEMO_WINDOWS) // Obsolete name since 1.53, TEST->DEMO73 #define IMGUI_DISABLE_DEMO_WINDOWS74 #endif75 76 139 #if !defined(IMGUI_DISABLE_DEMO_WINDOWS) 77 140 141 // Forward Declarations 142 static void ShowExampleAppDocuments(bool* p_open); 143 static void ShowExampleAppMainMenuBar(); 78 144 static void ShowExampleAppConsole(bool* p_open); 79 145 static void ShowExampleAppLog(bool* p_open); … … 83 149 static void ShowExampleAppAutoResize(bool* p_open); 84 150 static void ShowExampleAppConstrainedResize(bool* p_open); 85 static void ShowExampleApp FixedOverlay(bool* p_open);151 static void ShowExampleAppSimpleOverlay(bool* p_open); 86 152 static void ShowExampleAppWindowTitles(bool* p_open); 87 153 static void ShowExampleAppCustomRendering(bool* p_open); 88 static void ShowExampleAppMainMenuBar();89 154 static void ShowExampleMenuFile(); 90 155 91 static void ShowHelpMarker(const char* desc) 156 // Helper to display a little (?) mark which shows a tooltip when hovered. 157 // In your own code you may want to display an actual icon if you are using a merged icon fonts (see docs/FONTS.md) 158 static void HelpMarker(const char* desc) 92 159 { 93 ImGui::TextDisabled("(?)");94 if (ImGui::IsItemHovered())95 {96 ImGui::BeginTooltip();97 ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);98 ImGui::TextUnformatted(desc);99 ImGui::PopTextWrapPos();100 ImGui::EndTooltip();101 }160 ImGui::TextDisabled("(?)"); 161 if (ImGui::IsItemHovered()) 162 { 163 ImGui::BeginTooltip(); 164 ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); 165 ImGui::TextUnformatted(desc); 166 ImGui::PopTextWrapPos(); 167 ImGui::EndTooltip(); 168 } 102 169 } 103 170 171 // Helper to display basic user controls. 104 172 void ImGui::ShowUserGuide() 105 173 { 106 ImGui::BulletText("Double-click on title bar to collapse window."); 107 ImGui::BulletText("Click and drag on lower right corner to resize window\n(double-click to auto fit window to its contents)."); 108 ImGui::BulletText("Click and drag on any empty space to move window."); 109 ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields."); 110 ImGui::BulletText("CTRL+Click on a slider or drag box to input value as text."); 111 if (ImGui::GetIO().FontAllowUserScaling) 112 ImGui::BulletText("CTRL+Mouse Wheel to zoom window contents."); 113 ImGui::BulletText("Mouse Wheel to scroll."); 114 ImGui::BulletText("While editing text:\n"); 115 ImGui::Indent(); 116 ImGui::BulletText("Hold SHIFT or use mouse to select text."); 117 ImGui::BulletText("CTRL+Left/Right to word jump."); 118 ImGui::BulletText("CTRL+A or double-click to select all."); 119 ImGui::BulletText("CTRL+X,CTRL+C,CTRL+V to use clipboard."); 120 ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo."); 121 ImGui::BulletText("ESCAPE to revert."); 122 ImGui::BulletText("You can apply arithmetic operators +,*,/ on numerical values.\nUse +- to subtract."); 123 ImGui::Unindent(); 174 ImGuiIO& io = ImGui::GetIO(); 175 ImGui::BulletText("Double-click on title bar to collapse window."); 176 ImGui::BulletText( 177 "Click and drag on lower corner to resize window\n" 178 "(double-click to auto fit window to its contents)."); 179 ImGui::BulletText("CTRL+Click on a slider or drag box to input value as text."); 180 ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields."); 181 if (io.FontAllowUserScaling) 182 ImGui::BulletText("CTRL+Mouse Wheel to zoom window contents."); 183 ImGui::BulletText("While inputing text:\n"); 184 ImGui::Indent(); 185 ImGui::BulletText("CTRL+Left/Right to word jump."); 186 ImGui::BulletText("CTRL+A or double-click to select all."); 187 ImGui::BulletText("CTRL+X/C/V to use clipboard cut/copy/paste."); 188 ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo."); 189 ImGui::BulletText("ESCAPE to revert."); 190 ImGui::BulletText("You can apply arithmetic operators +,*,/ on numerical values.\nUse +- to subtract."); 191 ImGui::Unindent(); 192 ImGui::BulletText("With keyboard navigation enabled:"); 193 ImGui::Indent(); 194 ImGui::BulletText("Arrow keys to navigate."); 195 ImGui::BulletText("Space to activate a widget."); 196 ImGui::BulletText("Return to input text into a widget."); 197 ImGui::BulletText("Escape to deactivate a widget, close popup, exit child window."); 198 ImGui::BulletText("Alt to jump to the menu layer of a window."); 199 ImGui::BulletText("CTRL+Tab to select a window."); 200 ImGui::Unindent(); 124 201 } 125 202 126 // Demonstrate most ImGui features (big function!) 203 //----------------------------------------------------------------------------- 204 // [SECTION] Demo Window / ShowDemoWindow() 205 //----------------------------------------------------------------------------- 206 // - ShowDemoWindowWidgets() 207 // - ShowDemoWindowLayout() 208 // - ShowDemoWindowPopups() 209 // - ShowDemoWindowColumns() 210 // - ShowDemoWindowMisc() 211 //----------------------------------------------------------------------------- 212 213 // We split the contents of the big ShowDemoWindow() function into smaller functions 214 // (because the link time of very large functions grow non-linearly) 215 static void ShowDemoWindowWidgets(); 216 static void ShowDemoWindowLayout(); 217 static void ShowDemoWindowPopups(); 218 static void ShowDemoWindowColumns(); 219 static void ShowDemoWindowMisc(); 220 221 // Demonstrate most Dear ImGui features (this is big function!) 222 // You may execute this function to experiment with the UI and understand what it does. 223 // You may then search for keywords in the code when you are interested by a specific feature. 127 224 void ImGui::ShowDemoWindow(bool* p_open) 128 225 { 129 // Examples apps 130 static bool show_app_main_menu_bar = false; 131 static bool show_app_console = false; 132 static bool show_app_log = false; 133 static bool show_app_layout = false; 134 static bool show_app_property_editor = false; 135 static bool show_app_long_text = false; 136 static bool show_app_auto_resize = false; 137 static bool show_app_constrained_resize = false; 138 static bool show_app_fixed_overlay = false; 139 static bool show_app_window_titles = false; 140 static bool show_app_custom_rendering = false; 141 static bool show_app_style_editor = false; 142 143 static bool show_app_metrics = false; 144 static bool show_app_about = false; 145 146 if (show_app_main_menu_bar) ShowExampleAppMainMenuBar(); 147 if (show_app_console) ShowExampleAppConsole(&show_app_console); 148 if (show_app_log) ShowExampleAppLog(&show_app_log); 149 if (show_app_layout) ShowExampleAppLayout(&show_app_layout); 150 if (show_app_property_editor) ShowExampleAppPropertyEditor(&show_app_property_editor); 151 if (show_app_long_text) ShowExampleAppLongText(&show_app_long_text); 152 if (show_app_auto_resize) ShowExampleAppAutoResize(&show_app_auto_resize); 153 if (show_app_constrained_resize) ShowExampleAppConstrainedResize(&show_app_constrained_resize); 154 if (show_app_fixed_overlay) ShowExampleAppFixedOverlay(&show_app_fixed_overlay); 155 if (show_app_window_titles) ShowExampleAppWindowTitles(&show_app_window_titles); 156 if (show_app_custom_rendering) ShowExampleAppCustomRendering(&show_app_custom_rendering); 157 158 if (show_app_metrics) { ImGui::ShowMetricsWindow(&show_app_metrics); } 159 if (show_app_style_editor) { ImGui::Begin("Style Editor", &show_app_style_editor); ImGui::ShowStyleEditor(); ImGui::End(); } 160 if (show_app_about) 161 { 162 ImGui::Begin("About Dear ImGui", &show_app_about, ImGuiWindowFlags_AlwaysAutoResize); 163 ImGui::Text("Dear ImGui, %s", ImGui::GetVersion()); 164 ImGui::Separator(); 165 ImGui::Text("By Omar Cornut and all dear imgui contributors."); 166 ImGui::Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information."); 167 ImGui::End(); 168 } 169 170 static bool no_titlebar = false; 171 static bool no_scrollbar = false; 172 static bool no_menu = false; 173 static bool no_move = false; 174 static bool no_resize = false; 175 static bool no_collapse = false; 176 static bool no_close = false; 177 static bool no_nav = false; 178 179 // Demonstrate the various window flags. Typically you would just use the default. 180 ImGuiWindowFlags window_flags = 0; 181 if (no_titlebar) window_flags |= ImGuiWindowFlags_NoTitleBar; 182 if (no_scrollbar) window_flags |= ImGuiWindowFlags_NoScrollbar; 183 if (!no_menu) window_flags |= ImGuiWindowFlags_MenuBar; 184 if (no_move) window_flags |= ImGuiWindowFlags_NoMove; 185 if (no_resize) window_flags |= ImGuiWindowFlags_NoResize; 186 if (no_collapse) window_flags |= ImGuiWindowFlags_NoCollapse; 187 if (no_nav) window_flags |= ImGuiWindowFlags_NoNav; 188 if (no_close) p_open = NULL; // Don't pass our bool* to Begin 189 190 ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver); 191 if (!ImGui::Begin("ImGui Demo", p_open, window_flags)) 192 { 193 // Early out if the window is collapsed, as an optimization. 194 ImGui::End(); 195 return; 196 } 197 198 //ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.65f); // 2/3 of the space for widget and 1/3 for labels 199 ImGui::PushItemWidth(-140); // Right align, keep 140 pixels for labels 200 201 ImGui::Text("dear imgui says hello. (%s)", IMGUI_VERSION); 202 203 // Menu 204 if (ImGui::BeginMenuBar()) 205 { 206 if (ImGui::BeginMenu("Menu")) 207 { 208 ShowExampleMenuFile(); 209 ImGui::EndMenu(); 210 } 211 if (ImGui::BeginMenu("Examples")) 212 { 213 ImGui::MenuItem("Main menu bar", NULL, &show_app_main_menu_bar); 214 ImGui::MenuItem("Console", NULL, &show_app_console); 215 ImGui::MenuItem("Log", NULL, &show_app_log); 216 ImGui::MenuItem("Simple layout", NULL, &show_app_layout); 217 ImGui::MenuItem("Property editor", NULL, &show_app_property_editor); 218 ImGui::MenuItem("Long text display", NULL, &show_app_long_text); 219 ImGui::MenuItem("Auto-resizing window", NULL, &show_app_auto_resize); 220 ImGui::MenuItem("Constrained-resizing window", NULL, &show_app_constrained_resize); 221 ImGui::MenuItem("Simple overlay", NULL, &show_app_fixed_overlay); 222 ImGui::MenuItem("Manipulating window titles", NULL, &show_app_window_titles); 223 ImGui::MenuItem("Custom rendering", NULL, &show_app_custom_rendering); 224 ImGui::EndMenu(); 225 } 226 if (ImGui::BeginMenu("Help")) 227 { 228 ImGui::MenuItem("Metrics", NULL, &show_app_metrics); 229 ImGui::MenuItem("Style Editor", NULL, &show_app_style_editor); 230 ImGui::MenuItem("About Dear ImGui", NULL, &show_app_about); 231 ImGui::EndMenu(); 232 } 233 ImGui::EndMenuBar(); 234 } 235 236 ImGui::Spacing(); 237 if (ImGui::CollapsingHeader("Help")) 238 { 239 ImGui::TextWrapped("This window is being created by the ShowDemoWindow() function. Please refer to the code in imgui_demo.cpp for reference.\n\n"); 240 ImGui::Text("USER GUIDE:"); 241 ImGui::ShowUserGuide(); 242 } 243 244 if (ImGui::CollapsingHeader("Window options")) 245 { 246 ImGui::Checkbox("No titlebar", &no_titlebar); ImGui::SameLine(150); 247 ImGui::Checkbox("No scrollbar", &no_scrollbar); ImGui::SameLine(300); 248 ImGui::Checkbox("No menu", &no_menu); 249 ImGui::Checkbox("No move", &no_move); ImGui::SameLine(150); 250 ImGui::Checkbox("No resize", &no_resize); ImGui::SameLine(300); 251 ImGui::Checkbox("No collapse", &no_collapse); 252 ImGui::Checkbox("No close", &no_close); ImGui::SameLine(150); 253 ImGui::Checkbox("No nav", &no_nav); 254 255 if (ImGui::TreeNode("Style")) 256 { 257 ImGui::ShowStyleEditor(); 258 ImGui::TreePop(); 259 } 260 261 if (ImGui::TreeNode("Capture/Logging")) 262 { 263 ImGui::TextWrapped("The logging API redirects all text output so you can easily capture the content of a window or a block. Tree nodes can be automatically expanded. You can also call ImGui::LogText() to output directly to the log without a visual output."); 264 ImGui::LogButtons(); 265 ImGui::TreePop(); 266 } 267 } 268 269 if (ImGui::CollapsingHeader("Widgets")) 270 { 271 if (ImGui::TreeNode("Basic")) 272 { 273 static int clicked = 0; 274 if (ImGui::Button("Button")) 226 // Exceptionally add an extra assert here for people confused about initial Dear ImGui setup 227 // Most ImGui functions would normally just crash if the context is missing. 228 IM_ASSERT(ImGui::GetCurrentContext() != NULL && "Missing dear imgui context. Refer to examples app!"); 229 230 // Examples Apps (accessible from the "Examples" menu) 231 static bool show_app_main_menu_bar = false; 232 static bool show_app_documents = false; 233 static bool show_app_console = false; 234 static bool show_app_log = false; 235 static bool show_app_layout = false; 236 static bool show_app_property_editor = false; 237 static bool show_app_long_text = false; 238 static bool show_app_auto_resize = false; 239 static bool show_app_constrained_resize = false; 240 static bool show_app_simple_overlay = false; 241 static bool show_app_window_titles = false; 242 static bool show_app_custom_rendering = false; 243 244 if (show_app_main_menu_bar) ShowExampleAppMainMenuBar(); 245 if (show_app_documents) ShowExampleAppDocuments(&show_app_documents); 246 247 if (show_app_console) ShowExampleAppConsole(&show_app_console); 248 if (show_app_log) ShowExampleAppLog(&show_app_log); 249 if (show_app_layout) ShowExampleAppLayout(&show_app_layout); 250 if (show_app_property_editor) ShowExampleAppPropertyEditor(&show_app_property_editor); 251 if (show_app_long_text) ShowExampleAppLongText(&show_app_long_text); 252 if (show_app_auto_resize) ShowExampleAppAutoResize(&show_app_auto_resize); 253 if (show_app_constrained_resize) ShowExampleAppConstrainedResize(&show_app_constrained_resize); 254 if (show_app_simple_overlay) ShowExampleAppSimpleOverlay(&show_app_simple_overlay); 255 if (show_app_window_titles) ShowExampleAppWindowTitles(&show_app_window_titles); 256 if (show_app_custom_rendering) ShowExampleAppCustomRendering(&show_app_custom_rendering); 257 258 // Dear ImGui Apps (accessible from the "Tools" menu) 259 static bool show_app_metrics = false; 260 static bool show_app_style_editor = false; 261 static bool show_app_about = false; 262 263 if (show_app_metrics) { ImGui::ShowMetricsWindow(&show_app_metrics); } 264 if (show_app_about) { ImGui::ShowAboutWindow(&show_app_about); } 265 if (show_app_style_editor) 266 { 267 ImGui::Begin("Dear ImGui Style Editor", &show_app_style_editor); 268 ImGui::ShowStyleEditor(); 269 ImGui::End(); 270 } 271 272 // Demonstrate the various window flags. Typically you would just use the default! 273 static bool no_titlebar = false; 274 static bool no_scrollbar = false; 275 static bool no_menu = false; 276 static bool no_move = false; 277 static bool no_resize = false; 278 static bool no_collapse = false; 279 static bool no_close = false; 280 static bool no_nav = false; 281 static bool no_background = false; 282 static bool no_bring_to_front = false; 283 284 ImGuiWindowFlags window_flags = 0; 285 if (no_titlebar) window_flags |= ImGuiWindowFlags_NoTitleBar; 286 if (no_scrollbar) window_flags |= ImGuiWindowFlags_NoScrollbar; 287 if (!no_menu) window_flags |= ImGuiWindowFlags_MenuBar; 288 if (no_move) window_flags |= ImGuiWindowFlags_NoMove; 289 if (no_resize) window_flags |= ImGuiWindowFlags_NoResize; 290 if (no_collapse) window_flags |= ImGuiWindowFlags_NoCollapse; 291 if (no_nav) window_flags |= ImGuiWindowFlags_NoNav; 292 if (no_background) window_flags |= ImGuiWindowFlags_NoBackground; 293 if (no_bring_to_front) window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus; 294 if (no_close) p_open = NULL; // Don't pass our bool* to Begin 295 296 // We specify a default position/size in case there's no data in the .ini file. 297 // We only do it to make the demo applications a little more welcoming, but typically this isn't required. 298 ImGui::SetNextWindowPos(ImVec2(650, 20), ImGuiCond_FirstUseEver); 299 ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver); 300 301 // Main body of the Demo window starts here. 302 if (!ImGui::Begin("Dear ImGui Demo", p_open, window_flags)) 303 { 304 // Early out if the window is collapsed, as an optimization. 305 ImGui::End(); 306 return; 307 } 308 309 // Most "big" widgets share a common width settings by default. See 'Demo->Layout->Widgets Width' for details. 310 311 // e.g. Use 2/3 of the space for widgets and 1/3 for labels (default) 312 //ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.65f); 313 314 // e.g. Leave a fixed amount of width for labels (by passing a negative value), the rest goes to widgets. 315 ImGui::PushItemWidth(ImGui::GetFontSize() * -12); 316 317 // Menu Bar 318 if (ImGui::BeginMenuBar()) 319 { 320 if (ImGui::BeginMenu("Menu")) 321 { 322 ShowExampleMenuFile(); 323 ImGui::EndMenu(); 324 } 325 if (ImGui::BeginMenu("Examples")) 326 { 327 ImGui::MenuItem("Main menu bar", NULL, &show_app_main_menu_bar); 328 ImGui::MenuItem("Console", NULL, &show_app_console); 329 ImGui::MenuItem("Log", NULL, &show_app_log); 330 ImGui::MenuItem("Simple layout", NULL, &show_app_layout); 331 ImGui::MenuItem("Property editor", NULL, &show_app_property_editor); 332 ImGui::MenuItem("Long text display", NULL, &show_app_long_text); 333 ImGui::MenuItem("Auto-resizing window", NULL, &show_app_auto_resize); 334 ImGui::MenuItem("Constrained-resizing window", NULL, &show_app_constrained_resize); 335 ImGui::MenuItem("Simple overlay", NULL, &show_app_simple_overlay); 336 ImGui::MenuItem("Manipulating window titles", NULL, &show_app_window_titles); 337 ImGui::MenuItem("Custom rendering", NULL, &show_app_custom_rendering); 338 ImGui::MenuItem("Documents", NULL, &show_app_documents); 339 ImGui::EndMenu(); 340 } 341 if (ImGui::BeginMenu("Tools")) 342 { 343 ImGui::MenuItem("Metrics", NULL, &show_app_metrics); 344 ImGui::MenuItem("Style Editor", NULL, &show_app_style_editor); 345 ImGui::MenuItem("About Dear ImGui", NULL, &show_app_about); 346 ImGui::EndMenu(); 347 } 348 ImGui::EndMenuBar(); 349 } 350 351 ImGui::Text("dear imgui says hello. (%s)", IMGUI_VERSION); 352 ImGui::Spacing(); 353 354 if (ImGui::CollapsingHeader("Help")) 355 { 356 ImGui::Text("ABOUT THIS DEMO:"); 357 ImGui::BulletText("Sections below are demonstrating many aspects of the library."); 358 ImGui::BulletText("The \"Examples\" menu above leads to more demo contents."); 359 ImGui::BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n" 360 "and Metrics (general purpose Dear ImGui debugging tool)."); 361 ImGui::Separator(); 362 363 ImGui::Text("PROGRAMMER GUIDE:"); 364 ImGui::BulletText("See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!"); 365 ImGui::BulletText("See comments in imgui.cpp."); 366 ImGui::BulletText("See example applications in the examples/ folder."); 367 ImGui::BulletText("Read the FAQ at http://www.dearimgui.org/faq/"); 368 ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls."); 369 ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls."); 370 ImGui::Separator(); 371 372 ImGui::Text("USER GUIDE:"); 373 ImGui::ShowUserGuide(); 374 } 375 376 if (ImGui::CollapsingHeader("Configuration")) 377 { 378 ImGuiIO& io = ImGui::GetIO(); 379 380 if (ImGui::TreeNode("Configuration##2")) 381 { 382 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", (unsigned int*)&io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard); 383 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", (unsigned int*)&io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad); 384 ImGui::SameLine(); HelpMarker("Required back-end to feed in gamepad inputs in io.NavInputs[] and set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details."); 385 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableSetMousePos", (unsigned int*)&io.ConfigFlags, ImGuiConfigFlags_NavEnableSetMousePos); 386 ImGui::SameLine(); HelpMarker("Instruct navigation to move the mouse cursor. See comment for ImGuiConfigFlags_NavEnableSetMousePos."); 387 ImGui::CheckboxFlags("io.ConfigFlags: NoMouse", (unsigned int*)&io.ConfigFlags, ImGuiConfigFlags_NoMouse); 388 389 // The "NoMouse" option above can get us stuck with a disable mouse! Provide an alternative way to fix it: 390 if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) 391 { 392 if (fmodf((float)ImGui::GetTime(), 0.40f) < 0.20f) 393 { 394 ImGui::SameLine(); 395 ImGui::Text("<<PRESS SPACE TO DISABLE>>"); 396 } 397 if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Space))) 398 io.ConfigFlags &= ~ImGuiConfigFlags_NoMouse; 399 } 400 ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", (unsigned int*)&io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange); 401 ImGui::SameLine(); HelpMarker("Instruct back-end to not alter mouse cursor shape and visibility."); 402 ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink); 403 ImGui::SameLine(); HelpMarker("Set to false to disable blinking cursor, for users who consider it distracting"); 404 ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges); 405 ImGui::SameLine(); HelpMarker("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback."); 406 ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly); 407 ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor); 408 ImGui::SameLine(); HelpMarker("Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something)."); 409 ImGui::Text("Also see Style->Rendering for rendering options."); 410 ImGui::TreePop(); 411 ImGui::Separator(); 412 } 413 414 if (ImGui::TreeNode("Backend Flags")) 415 { 416 HelpMarker( 417 "Those flags are set by the back-ends (imgui_impl_xxx files) to specify their capabilities.\n" 418 "Here we expose then as read-only fields to avoid breaking interactions with your back-end."); 419 420 // Make a local copy to avoid modifying actual back-end flags. 421 ImGuiBackendFlags backend_flags = io.BackendFlags; 422 ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", (unsigned int*)&backend_flags, ImGuiBackendFlags_HasGamepad); 423 ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", (unsigned int*)&backend_flags, ImGuiBackendFlags_HasMouseCursors); 424 ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos", (unsigned int*)&backend_flags, ImGuiBackendFlags_HasSetMousePos); 425 ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", (unsigned int*)&backend_flags, ImGuiBackendFlags_RendererHasVtxOffset); 426 ImGui::TreePop(); 427 ImGui::Separator(); 428 } 429 430 if (ImGui::TreeNode("Style")) 431 { 432 HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function."); 433 ImGui::ShowStyleEditor(); 434 ImGui::TreePop(); 435 ImGui::Separator(); 436 } 437 438 if (ImGui::TreeNode("Capture/Logging")) 439 { 440 HelpMarker( 441 "The logging API redirects all text output so you can easily capture the content of " 442 "a window or a block. Tree nodes can be automatically expanded.\n" 443 "Try opening any of the contents below in this window and then click one of the \"Log To\" button."); 444 ImGui::LogButtons(); 445 446 HelpMarker("You can also call ImGui::LogText() to output directly to the log without a visual output."); 447 if (ImGui::Button("Copy \"Hello, world!\" to clipboard")) 448 { 449 ImGui::LogToClipboard(); 450 ImGui::LogText("Hello, world!"); 451 ImGui::LogFinish(); 452 } 453 ImGui::TreePop(); 454 } 455 } 456 457 if (ImGui::CollapsingHeader("Window options")) 458 { 459 ImGui::Checkbox("No titlebar", &no_titlebar); ImGui::SameLine(150); 460 ImGui::Checkbox("No scrollbar", &no_scrollbar); ImGui::SameLine(300); 461 ImGui::Checkbox("No menu", &no_menu); 462 ImGui::Checkbox("No move", &no_move); ImGui::SameLine(150); 463 ImGui::Checkbox("No resize", &no_resize); ImGui::SameLine(300); 464 ImGui::Checkbox("No collapse", &no_collapse); 465 ImGui::Checkbox("No close", &no_close); ImGui::SameLine(150); 466 ImGui::Checkbox("No nav", &no_nav); ImGui::SameLine(300); 467 ImGui::Checkbox("No background", &no_background); 468 ImGui::Checkbox("No bring to front", &no_bring_to_front); 469 } 470 471 // All demo contents 472 ShowDemoWindowWidgets(); 473 ShowDemoWindowLayout(); 474 ShowDemoWindowPopups(); 475 ShowDemoWindowColumns(); 476 ShowDemoWindowMisc(); 477 478 // End of ShowDemoWindow() 479 ImGui::End(); 480 } 481 482 static void ShowDemoWindowWidgets() 483 { 484 if (!ImGui::CollapsingHeader("Widgets")) 485 return; 486 487 if (ImGui::TreeNode("Basic")) 488 { 489 static int clicked = 0; 490 if (ImGui::Button("Button")) 275 491 clicked++; 276 277 492 if (clicked & 1) 493 { 278 494 ImGui::SameLine(); 279 495 ImGui::Text("Thanks for clicking me!"); 280 } 281 282 static bool check = true; 283 ImGui::Checkbox("checkbox", &check); 284 285 static int e = 0; 286 ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine(); 287 ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine(); 288 ImGui::RadioButton("radio c", &e, 2); 289 290 // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style. 291 for (int i = 0; i < 7; i++) 292 { 293 if (i > 0) ImGui::SameLine(); 496 } 497 498 static bool check = true; 499 ImGui::Checkbox("checkbox", &check); 500 501 static int e = 0; 502 ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine(); 503 ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine(); 504 ImGui::RadioButton("radio c", &e, 2); 505 506 // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style. 507 for (int i = 0; i < 7; i++) 508 { 509 if (i > 0) 510 ImGui::SameLine(); 294 511 ImGui::PushID(i); 295 512 ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.6f)); … … 299 516 ImGui::PopStyleColor(3); 300 517 ImGui::PopID(); 301 } 302 303 // Arrow buttons 304 float spacing = ImGui::GetStyle().ItemInnerSpacing.x; 305 if (ImGui::ArrowButton("##left", ImGuiDir_Left)) {} 306 ImGui::SameLine(0.0f, spacing); 307 if (ImGui::ArrowButton("##left", ImGuiDir_Right)) {} 308 309 ImGui::Text("Hover over me"); 310 if (ImGui::IsItemHovered()) 518 } 519 520 // Use AlignTextToFramePadding() to align text baseline to the baseline of framed widgets elements 521 // (otherwise a Text+SameLine+Button sequence will have the text a little too high by default!) 522 // See 'Demo->Layout->Text Baseline Alignment' for details. 523 ImGui::AlignTextToFramePadding(); 524 ImGui::Text("Hold to repeat:"); 525 ImGui::SameLine(); 526 527 // Arrow buttons with Repeater 528 static int counter = 0; 529 float spacing = ImGui::GetStyle().ItemInnerSpacing.x; 530 ImGui::PushButtonRepeat(true); 531 if (ImGui::ArrowButton("##left", ImGuiDir_Left)) { counter--; } 532 ImGui::SameLine(0.0f, spacing); 533 if (ImGui::ArrowButton("##right", ImGuiDir_Right)) { counter++; } 534 ImGui::PopButtonRepeat(); 535 ImGui::SameLine(); 536 ImGui::Text("%d", counter); 537 538 ImGui::Text("Hover over me"); 539 if (ImGui::IsItemHovered()) 311 540 ImGui::SetTooltip("I am a tooltip"); 312 541 313 314 315 316 542 ImGui::SameLine(); 543 ImGui::Text("- or me"); 544 if (ImGui::IsItemHovered()) 545 { 317 546 ImGui::BeginTooltip(); 318 547 ImGui::Text("I am a fancy tooltip"); … … 320 549 ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr)); 321 550 ImGui::EndTooltip(); 322 323 324 325 326 327 328 551 } 552 553 ImGui::Separator(); 554 555 ImGui::LabelText("label", "Value"); 556 557 { 329 558 // Using the _simplified_ one-liner Combo() api here 330 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; 559 // See "Combo" section for examples of how to use the more complete BeginCombo()/EndCombo() api. 560 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" }; 331 561 static int item_current = 0; 332 562 ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items)); 333 ImGui::SameLine(); ShowHelpMarker("Refer to the \"Combo\" section below for an explanation of the full BeginCombo/EndCombo API, and demonstration of various flags.\n"); 334 } 335 336 { 563 ImGui::SameLine(); HelpMarker( 564 "Refer to the \"Combo\" section below for an explanation of the full BeginCombo/EndCombo API, " 565 "and demonstration of various flags.\n"); 566 } 567 568 { 569 // To wire InputText() with std::string or any other custom string type, 570 // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file. 337 571 static char str0[128] = "Hello, world!"; 572 ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0)); 573 ImGui::SameLine(); HelpMarker( 574 "USER:\n" 575 "Hold SHIFT or use mouse to select text.\n" 576 "CTRL+Left/Right to word jump.\n" 577 "CTRL+A or double-click to select all.\n" 578 "CTRL+X,CTRL+C,CTRL+V clipboard.\n" 579 "CTRL+Z,CTRL+Y undo/redo.\n" 580 "ESCAPE to revert.\n\n" 581 "PROGRAMMER:\n" 582 "You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() " 583 "to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example (this is not demonstrated " 584 "in imgui_demo.cpp)."); 585 586 static char str1[128] = ""; 587 ImGui::InputTextWithHint("input text (w/ hint)", "enter text here", str1, IM_ARRAYSIZE(str1)); 588 338 589 static int i0 = 123; 339 ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0));340 ImGui::SameLine(); ShowHelpMarker("Hold SHIFT or use mouse to select text.\n" "CTRL+Left/Right to word jump.\n" "CTRL+A or double-click to select all.\n" "CTRL+X,CTRL+C,CTRL+V clipboard.\n" "CTRL+Z,CTRL+Y undo/redo.\n" "ESCAPE to revert.\n");341 342 590 ImGui::InputInt("input int", &i0); 343 ImGui::SameLine(); ShowHelpMarker("You can apply arithmetic operators +,*,/ on numerical values.\n e.g. [ 100 ], input \'*2\', result becomes [ 200 ]\nUse +- to subtract.\n"); 591 ImGui::SameLine(); HelpMarker( 592 "You can apply arithmetic operators +,*,/ on numerical values.\n" 593 " e.g. [ 100 ], input \'*2\', result becomes [ 200 ]\n" 594 "Use +- to subtract."); 344 595 345 596 static float f0 = 0.001f; 346 ImGui::InputFloat("input float", &f0, 0.01f, 1.0f );347 348 static double d0 = 999999.00000 1;349 ImGui::InputDouble("input double", &d0, 0.01f, 1.0f, "%. 6f");597 ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f"); 598 599 static double d0 = 999999.00000001; 600 ImGui::InputDouble("input double", &d0, 0.01f, 1.0f, "%.8f"); 350 601 351 602 static float f1 = 1.e10f; 352 603 ImGui::InputFloat("input scientific", &f1, 0.0f, 0.0f, "%e"); 353 ImGui::SameLine(); ShowHelpMarker("You can input value using the scientific notation,\n e.g. \"1e+8\" becomes \"100000000\".\n"); 604 ImGui::SameLine(); HelpMarker( 605 "You can input value using the scientific notation,\n" 606 " e.g. \"1e+8\" becomes \"100000000\"."); 354 607 355 608 static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; 356 609 ImGui::InputFloat3("input float3", vec4a); 357 358 359 610 } 611 612 { 360 613 static int i1 = 50, i2 = 42; 361 614 ImGui::DragInt("drag int", &i1, 1); 362 ImGui::SameLine(); ShowHelpMarker("Click and drag to edit value.\nHold SHIFT/ALT for faster/slower edit.\nDouble-click or CTRL+click to input value."); 363 364 ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%.0f%%"); 615 ImGui::SameLine(); HelpMarker( 616 "Click and drag to edit value.\n" 617 "Hold SHIFT/ALT for faster/slower edit.\n" 618 "Double-click or CTRL+click to input value."); 619 620 ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp); 365 621 366 622 static float f1 = 1.00f, f2 = 0.0067f; 367 623 ImGui::DragFloat("drag float", &f1, 0.005f); 368 624 ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns"); 369 370 371 625 } 626 627 { 372 628 static int i1 = 0; 373 629 ImGui::SliderInt("slider int", &i1, -1, 3); 374 ImGui::SameLine(); ShowHelpMarker("CTRL+click to input value.");630 ImGui::SameLine(); HelpMarker("CTRL+click to input value."); 375 631 376 632 static float f1 = 0.123f, f2 = 0.0f; 377 633 ImGui::SliderFloat("slider float", &f1, 0.0f, 1.0f, "ratio = %.3f"); 378 ImGui::SliderFloat("slider log float", &f2, -10.0f, 10.0f, "%.4f", 3.0f); 634 ImGui::SliderFloat("slider float (log)", &f2, -10.0f, 10.0f, "%.4f", ImGuiSliderFlags_Logarithmic); 635 379 636 static float angle = 0.0f; 380 637 ImGui::SliderAngle("slider angle", &angle); 381 } 382 383 { 384 static float col1[3] = { 1.0f,0.0f,0.2f }; 385 static float col2[4] = { 0.4f,0.7f,0.0f,0.5f }; 638 639 // Using the format string to display a name instead of an integer. 640 // Here we completely omit '%d' from the format string, so it'll only display a name. 641 // This technique can also be used with DragInt(). 642 enum Element { Element_Fire, Element_Earth, Element_Air, Element_Water, Element_COUNT }; 643 static int elem = Element_Fire; 644 const char* elems_names[Element_COUNT] = { "Fire", "Earth", "Air", "Water" }; 645 const char* elem_name = (elem >= 0 && elem < Element_COUNT) ? elems_names[elem] : "Unknown"; 646 ImGui::SliderInt("slider enum", &elem, 0, Element_COUNT - 1, elem_name); 647 ImGui::SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer."); 648 } 649 650 { 651 static float col1[3] = { 1.0f, 0.0f, 0.2f }; 652 static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f }; 386 653 ImGui::ColorEdit3("color 1", col1); 387 ImGui::SameLine(); ShowHelpMarker("Click on the colored square to open a color picker.\nRight-click on the colored square to show options.\nCTRL+click on individual component to input value.\n"); 654 ImGui::SameLine(); HelpMarker( 655 "Click on the colored square to open a color picker.\n" 656 "Click and hold to use drag and drop.\n" 657 "Right-click on the colored square to show options.\n" 658 "CTRL+click on individual component to input value.\n"); 388 659 389 660 ImGui::ColorEdit4("color 2", col2); 390 391 392 661 } 662 663 { 393 664 // List box 394 const char* listbox_items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" };395 static int listbox_item_current = 1;396 ImGui::ListBox("listbox\n(single select)", & listbox_item_current, listbox_items, IM_ARRAYSIZE(listbox_items), 4);665 const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" }; 666 static int item_current = 1; 667 ImGui::ListBox("listbox\n(single select)", &item_current, items, IM_ARRAYSIZE(items), 4); 397 668 398 669 //static int listbox_item_current2 = 2; 399 //ImGui:: PushItemWidth(-1);670 //ImGui::SetNextItemWidth(-1); 400 671 //ImGui::ListBox("##listbox2", &listbox_item_current2, listbox_items, IM_ARRAYSIZE(listbox_items), 4); 401 //ImGui::PopItemWidth(); 402 } 403 404 ImGui::TreePop(); 405 } 406 407 // Testing ImGuiOnceUponAFrame helper. 408 //static ImGuiOnceUponAFrame once; 409 //for (int i = 0; i < 5; i++) 410 // if (once) 411 // ImGui::Text("This will be displayed only once."); 412 413 if (ImGui::TreeNode("Trees")) 414 { 415 if (ImGui::TreeNode("Basic trees")) 416 { 672 } 673 674 ImGui::TreePop(); 675 } 676 677 // Testing ImGuiOnceUponAFrame helper. 678 //static ImGuiOnceUponAFrame once; 679 //for (int i = 0; i < 5; i++) 680 // if (once) 681 // ImGui::Text("This will be displayed only once."); 682 683 if (ImGui::TreeNode("Trees")) 684 { 685 if (ImGui::TreeNode("Basic trees")) 686 { 417 687 for (int i = 0; i < 5; i++) 418 if (ImGui::TreeNode((void*)(intptr_t)i, "Child %d", i)) 419 { 420 ImGui::Text("blah blah"); 421 ImGui::SameLine(); 422 if (ImGui::SmallButton("button")) {}; 423 ImGui::TreePop(); 424 } 688 { 689 // Use SetNextItemOpen() so set the default state of a node to be open. We could 690 // also use TreeNodeEx() with the ImGuiTreeNodeFlags_DefaultOpen flag to achieve the same thing! 691 if (i == 0) 692 ImGui::SetNextItemOpen(true, ImGuiCond_Once); 693 694 if (ImGui::TreeNode((void*)(intptr_t)i, "Child %d", i)) 695 { 696 ImGui::Text("blah blah"); 697 ImGui::SameLine(); 698 if (ImGui::SmallButton("button")) {} 699 ImGui::TreePop(); 700 } 701 } 425 702 ImGui::TreePop(); 426 } 427 428 if (ImGui::TreeNode("Advanced, with Selectable nodes")) 429 { 430 ShowHelpMarker("This is a more standard looking tree with selectable nodes.\nClick to select, CTRL+Click to toggle, click on arrows or double-click to open."); 703 } 704 705 if (ImGui::TreeNode("Advanced, with Selectable nodes")) 706 { 707 HelpMarker( 708 "This is a more typical looking tree with selectable nodes.\n" 709 "Click to select, CTRL+Click to toggle, click on arrows or double-click to open."); 710 static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth; 431 711 static bool align_label_with_current_x_position = false; 432 ImGui::Checkbox("Align label with current X position)", &align_label_with_current_x_position); 712 static bool test_drag_and_drop = false; 713 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnArrow", (unsigned int*)&base_flags, ImGuiTreeNodeFlags_OpenOnArrow); 714 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", (unsigned int*)&base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick); 715 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAvailWidth", (unsigned int*)&base_flags, ImGuiTreeNodeFlags_SpanAvailWidth); ImGui::SameLine(); HelpMarker("Extend hit area to all available width instead of allowing more items to be laid out after the node."); 716 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", (unsigned int*)&base_flags, ImGuiTreeNodeFlags_SpanFullWidth); 717 ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position); 718 ImGui::Checkbox("Test tree node as drag source", &test_drag_and_drop); 433 719 ImGui::Text("Hello!"); 434 720 if (align_label_with_current_x_position) 435 ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing()); 436 437 static int selection_mask = (1 << 2); // Dumb representation of what may be user-side selection state. You may carry selection state inside or outside your objects in whatever format you see fit. 438 int node_clicked = -1; // Temporary storage of what node we have clicked to process selection at the end of the loop. May be a pointer to your own node type, etc. 439 ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, ImGui::GetFontSize() * 3); // Increase spacing to differentiate leaves from expanded contents. 721 ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing()); 722 723 // 'selection_mask' is dumb representation of what may be user-side selection state. 724 // You may retain selection state inside or outside your objects in whatever format you see fit. 725 // 'node_clicked' is temporary storage of what node we have clicked to process selection at the end 726 /// of the loop. May be a pointer to your own node type, etc. 727 static int selection_mask = (1 << 2); 728 int node_clicked = -1; 440 729 for (int i = 0; i < 6; i++) 441 730 { 442 // Disable the default open on single-click behavior and pass in Selected flag according to our selection state. 443 ImGuiTreeNodeFlags node_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ((selection_mask & (1 << i)) ? ImGuiTreeNodeFlags_Selected : 0); 444 if (i < 3) 445 { 446 // Node 447 bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Node %d", i); 448 if (ImGui::IsItemClicked()) 449 node_clicked = i; 450 if (node_open) 451 { 452 ImGui::Text("Blah blah\nBlah Blah"); 453 ImGui::TreePop(); 454 } 455 } 456 else 457 { 458 // Leaf: The only reason we have a TreeNode at all is to allow selection of the leaf. Otherwise we can use BulletText() or TreeAdvanceToLabelPos()+Text(). 459 node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet 460 ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i); 461 if (ImGui::IsItemClicked()) 462 node_clicked = i; 463 } 731 // Disable the default "open on single-click behavior" + set Selected flag according to our selection. 732 ImGuiTreeNodeFlags node_flags = base_flags; 733 const bool is_selected = (selection_mask & (1 << i)) != 0; 734 if (is_selected) 735 node_flags |= ImGuiTreeNodeFlags_Selected; 736 if (i < 3) 737 { 738 // Items 0..2 are Tree Node 739 bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Node %d", i); 740 if (ImGui::IsItemClicked()) 741 node_clicked = i; 742 if (test_drag_and_drop && ImGui::BeginDragDropSource()) 743 { 744 ImGui::SetDragDropPayload("_TREENODE", NULL, 0); 745 ImGui::Text("This is a drag and drop source"); 746 ImGui::EndDragDropSource(); 747 } 748 if (node_open) 749 { 750 ImGui::BulletText("Blah blah\nBlah Blah"); 751 ImGui::TreePop(); 752 } 753 } 754 else 755 { 756 // Items 3..5 are Tree Leaves 757 // The only reason we use TreeNode at all is to allow selection of the leaf. Otherwise we can 758 // use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text(). 759 node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet 760 ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i); 761 if (ImGui::IsItemClicked()) 762 node_clicked = i; 763 if (test_drag_and_drop && ImGui::BeginDragDropSource()) 764 { 765 ImGui::SetDragDropPayload("_TREENODE", NULL, 0); 766 ImGui::Text("This is a drag and drop source"); 767 ImGui::EndDragDropSource(); 768 } 769 } 464 770 } 465 771 if (node_clicked != -1) 466 772 { 467 // Update selection state. Process outside of tree loop to avoid visual inconsistencies during the clicking-frame.468 if (ImGui::GetIO().KeyCtrl)469 selection_mask ^= (1 << node_clicked); // CTRL+click to toggle470 else //if (!(selection_mask & (1 << node_clicked))) // Depending on selection behavior you want, this commented bit preserve selection when clicking on item that is part of the selection471 selection_mask = (1 << node_clicked); // Click to single-select472 }473 ImGui::PopStyleVar();773 // Update selection state 774 // (process outside of tree loop to avoid visual inconsistencies during the clicking frame) 775 if (ImGui::GetIO().KeyCtrl) 776 selection_mask ^= (1 << node_clicked); // CTRL+click to toggle 777 else //if (!(selection_mask & (1 << node_clicked))) // Depending on selection behavior you want, may want to preserve selection when clicking on item that is part of the selection 778 selection_mask = (1 << node_clicked); // Click to single-select 779 } 474 780 if (align_label_with_current_x_position) 475 ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing());781 ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing()); 476 782 ImGui::TreePop(); 477 478 479 480 481 482 483 484 ImGui::Checkbox("Enable extra group", &closable_group);485 if (ImGui::CollapsingHeader("Header"))486 487 ImGui::Text("IsItemHovered: %d", I sItemHovered());783 } 784 ImGui::TreePop(); 785 } 786 787 if (ImGui::TreeNode("Collapsing Headers")) 788 { 789 static bool closable_group = true; 790 ImGui::Checkbox("Show 2nd header", &closable_group); 791 if (ImGui::CollapsingHeader("Header", ImGuiTreeNodeFlags_None)) 792 { 793 ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered()); 488 794 for (int i = 0; i < 5; i++) 489 ImGui::Text("Some content %d", i);490 491 492 493 ImGui::Text("IsItemHovered: %d", I sItemHovered());795 ImGui::Text("Some content %d", i); 796 } 797 if (ImGui::CollapsingHeader("Header with a close button", &closable_group)) 798 { 799 ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered()); 494 800 for (int i = 0; i < 5; i++) 495 ImGui::Text("More content %d", i); 496 } 497 ImGui::TreePop(); 498 } 499 500 if (ImGui::TreeNode("Bullets")) 501 { 502 ImGui::BulletText("Bullet point 1"); 503 ImGui::BulletText("Bullet point 2\nOn multiple lines"); 504 ImGui::Bullet(); ImGui::Text("Bullet point 3 (two calls)"); 505 ImGui::Bullet(); ImGui::SmallButton("Button"); 506 ImGui::TreePop(); 507 } 508 509 if (ImGui::TreeNode("Text")) 510 { 511 if (ImGui::TreeNode("Colored Text")) 512 { 801 ImGui::Text("More content %d", i); 802 } 803 /* 804 if (ImGui::CollapsingHeader("Header with a bullet", ImGuiTreeNodeFlags_Bullet)) 805 ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered()); 806 */ 807 ImGui::TreePop(); 808 } 809 810 if (ImGui::TreeNode("Bullets")) 811 { 812 ImGui::BulletText("Bullet point 1"); 813 ImGui::BulletText("Bullet point 2\nOn multiple lines"); 814 if (ImGui::TreeNode("Tree node")) 815 { 816 ImGui::BulletText("Another bullet point"); 817 ImGui::TreePop(); 818 } 819 ImGui::Bullet(); ImGui::Text("Bullet point 3 (two calls)"); 820 ImGui::Bullet(); ImGui::SmallButton("Button"); 821 ImGui::TreePop(); 822 } 823 824 if (ImGui::TreeNode("Text")) 825 { 826 if (ImGui::TreeNode("Colored Text")) 827 { 513 828 // Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility. 514 829 ImGui::TextColored(ImVec4(1.0f, 0.0f, 1.0f, 1.0f), "Pink"); 515 830 ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Yellow"); 516 831 ImGui::TextDisabled("Disabled"); 517 ImGui::SameLine(); ShowHelpMarker("The TextDisabled color is stored in ImGuiStyle.");832 ImGui::SameLine(); HelpMarker("The TextDisabled color is stored in ImGuiStyle."); 518 833 ImGui::TreePop(); 519 520 521 522 834 } 835 836 if (ImGui::TreeNode("Word Wrapping")) 837 { 523 838 // Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility. 524 ImGui::TextWrapped("This text should automatically wrap on the edge of the window. The current implementation for text wrapping follows simple rules suitable for English and possibly other languages."); 839 ImGui::TextWrapped( 840 "This text should automatically wrap on the edge of the window. The current implementation " 841 "for text wrapping follows simple rules suitable for English and possibly other languages."); 525 842 ImGui::Spacing(); 526 843 … … 528 845 ImGui::SliderFloat("Wrap width", &wrap_width, -20, 600, "%.0f"); 529 846 530 ImGui::Text("Test paragraph 1:"); 531 ImVec2 pos = ImGui::GetCursorScreenPos(); 532 ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(pos.x + wrap_width, pos.y), ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight()), IM_COL32(255, 0, 255, 255)); 533 ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width); 534 ImGui::Text("The lazy dog is a good dog. This paragraph is made to fit within %.0f pixels. Testing a 1 character word. The quick brown fox jumps over the lazy dog.", wrap_width); 535 ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 255, 0, 255)); 536 ImGui::PopTextWrapPos(); 537 538 ImGui::Text("Test paragraph 2:"); 539 pos = ImGui::GetCursorScreenPos(); 540 ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(pos.x + wrap_width, pos.y), ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight()), IM_COL32(255, 0, 255, 255)); 541 ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width); 542 ImGui::Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh"); 543 ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 255, 0, 255)); 544 ImGui::PopTextWrapPos(); 847 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 848 for (int n = 0; n < 2; n++) 849 { 850 ImGui::Text("Test paragraph %d:", n); 851 ImVec2 pos = ImGui::GetCursorScreenPos(); 852 ImVec2 marker_min = ImVec2(pos.x + wrap_width, pos.y); 853 ImVec2 marker_max = ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight()); 854 ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width); 855 if (n == 0) 856 ImGui::Text("The lazy dog is a good dog. This paragraph should fit within %.0f pixels. Testing a 1 character word. The quick brown fox jumps over the lazy dog.", wrap_width); 857 else 858 ImGui::Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh"); 859 860 // Draw actual text bounding box, following by marker of our expected limit (should not overlap!) 861 draw_list->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 255, 0, 255)); 862 draw_list->AddRectFilled(marker_min, marker_max, IM_COL32(255, 0, 255, 255)); 863 ImGui::PopTextWrapPos(); 864 } 545 865 546 866 ImGui::TreePop(); 547 548 549 550 867 } 868 869 if (ImGui::TreeNode("UTF-8 Text")) 870 { 551 871 // UTF-8 test with Japanese characters 552 // ( needs a suitable font, try Arial Unicode or M+ fonts http://mplus-fonts.sourceforge.jp/mplus-outline-fonts/index-en.html)872 // (Needs a suitable font? Try "Google Noto" or "Arial Unicode". See docs/FONTS.md for details.) 553 873 // - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8 554 // - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. Visual Studio save your file as 'UTF-8 without signature') 555 // - HOWEVER, FOR THIS DEMO FILE, BECAUSE WE WANT TO SUPPORT COMPILER, WE ARE *NOT* INCLUDING RAW UTF-8 CHARACTERS IN THIS SOURCE FILE. 556 // Instead we are encoding a few string with hexadecimal constants. Don't do this in your application! 557 // Note that characters values are preserved even by InputText() if the font cannot be displayed, so you can safely copy & paste garbled characters into another application. 558 ImGui::TextWrapped("CJK text will only appears if the font was loaded with the appropriate CJK character ranges. Call io.Font->LoadFromFileTTF() manually to load extra character ranges."); 559 ImGui::Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)"); 874 // - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. in Visual Studio, you 875 // can save your source files as 'UTF-8 without signature'). 876 // - FOR THIS DEMO FILE ONLY, BECAUSE WE WANT TO SUPPORT OLD COMPILERS, WE ARE *NOT* INCLUDING RAW UTF-8 877 // CHARACTERS IN THIS SOURCE FILE. Instead we are encoding a few strings with hexadecimal constants. 878 // Don't do this in your application! Please use u8"text in any language" in your application! 879 // Note that characters values are preserved even by InputText() if the font cannot be displayed, 880 // so you can safely copy & paste garbled characters into another application. 881 ImGui::TextWrapped( 882 "CJK text will only appears if the font was loaded with the appropriate CJK character ranges. " 883 "Call io.Font->AddFontFromFileTTF() manually to load extra character ranges. " 884 "Read docs/FONTS.md for details."); 885 ImGui::Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)"); // Normally we would use u8"blah blah" with the proper characters directly in the string. 560 886 ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)"); 561 static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"; // "nihongo" 887 static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"; 888 //static char buf[32] = u8"NIHONGO"; // <- this is how you would write it with C++11, using real kanjis 562 889 ImGui::InputText("UTF-8 input", buf, IM_ARRAYSIZE(buf)); 563 890 ImGui::TreePop(); 564 } 565 ImGui::TreePop(); 566 } 567 568 if (ImGui::TreeNode("Images")) 569 { 570 ImGuiIO& io = ImGui::GetIO(); 571 ImGui::TextWrapped("Below we are displaying the font texture (which is the only texture we have access to in this demo). Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. Hover the texture for a zoomed view!"); 572 573 // Here we are grabbing the font texture because that's the only one we have access to inside the demo code. 574 // Remember that ImTextureID is just storage for whatever you want it to be, it is essentially a value that will be passed to the render function inside the ImDrawCmd structure. 575 // If you use one of the default imgui_impl_XXXX.cpp renderer, they all have comments at the top of their file to specify what they expect to be stored in ImTextureID. 576 // (for example, the imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer. The imgui_impl_glfw_gl3.cpp renderer expect a GLuint OpenGL texture identifier etc.) 577 // If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers to ImGui::Image(), and gather width/height through your own functions, etc. 578 // Using ShowMetricsWindow() as a "debugger" to inspect the draw data that are being passed to your render will help you debug issues if you are confused about this. 579 // Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage(). 580 ImTextureID my_tex_id = io.Fonts->TexID; 581 float my_tex_w = (float)io.Fonts->TexWidth; 582 float my_tex_h = (float)io.Fonts->TexHeight; 583 584 ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h); 585 ImVec2 pos = ImGui::GetCursorScreenPos(); 586 ImGui::Image(my_tex_id, ImVec2(my_tex_w, my_tex_h), ImVec2(0, 0), ImVec2(1, 1), ImColor(255, 255, 255, 255), ImColor(255, 255, 255, 128)); 587 if (ImGui::IsItemHovered()) 588 { 589 ImGui::BeginTooltip(); 590 float region_sz = 32.0f; 591 float region_x = io.MousePos.x - pos.x - region_sz * 0.5f; if (region_x < 0.0f) region_x = 0.0f; else if (region_x > my_tex_w - region_sz) region_x = my_tex_w - region_sz; 592 float region_y = io.MousePos.y - pos.y - region_sz * 0.5f; if (region_y < 0.0f) region_y = 0.0f; else if (region_y > my_tex_h - region_sz) region_y = my_tex_h - region_sz; 593 float zoom = 4.0f; 594 ImGui::Text("Min: (%.2f, %.2f)", region_x, region_y); 595 ImGui::Text("Max: (%.2f, %.2f)", region_x + region_sz, region_y + region_sz); 596 ImVec2 uv0 = ImVec2((region_x) / my_tex_w, (region_y) / my_tex_h); 597 ImVec2 uv1 = ImVec2((region_x + region_sz) / my_tex_w, (region_y + region_sz) / my_tex_h); 598 ImGui::Image(my_tex_id, ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, ImColor(255, 255, 255, 255), ImColor(255, 255, 255, 128)); 599 ImGui::EndTooltip(); 600 } 601 ImGui::TextWrapped("And now some textured buttons.."); 602 static int pressed_count = 0; 603 for (int i = 0; i < 8; i++) 604 { 891 } 892 ImGui::TreePop(); 893 } 894 895 if (ImGui::TreeNode("Images")) 896 { 897 ImGuiIO& io = ImGui::GetIO(); 898 ImGui::TextWrapped( 899 "Below we are displaying the font texture (which is the only texture we have access to in this demo). " 900 "Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. " 901 "Hover the texture for a zoomed view!"); 902 903 // Below we are displaying the font texture because it is the only texture we have access to inside the demo! 904 // Remember that ImTextureID is just storage for whatever you want it to be. It is essentially a value that 905 // will be passed to the rendering back-end via the ImDrawCmd structure. 906 // If you use one of the default imgui_impl_XXXX.cpp rendering back-end, they all have comments at the top 907 // of their respective source file to specify what they expect to be stored in ImTextureID, for example: 908 // - The imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer 909 // - The imgui_impl_opengl3.cpp renderer expect a GLuint OpenGL texture identifier, etc. 910 // More: 911 // - If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers 912 // to ImGui::Image(), and gather width/height through your own functions, etc. 913 // - You can use ShowMetricsWindow() to inspect the draw data that are being passed to your renderer, 914 // it will help you debug issues if you are confused about it. 915 // - Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage(). 916 // - Read https://github.com/ocornut/imgui/blob/master/docs/FAQ.md 917 // - Read https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples 918 ImTextureID my_tex_id = io.Fonts->TexID; 919 float my_tex_w = (float)io.Fonts->TexWidth; 920 float my_tex_h = (float)io.Fonts->TexHeight; 921 { 922 ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h); 923 ImVec2 pos = ImGui::GetCursorScreenPos(); 924 ImVec2 uv_min = ImVec2(0.0f, 0.0f); // Top-left 925 ImVec2 uv_max = ImVec2(1.0f, 1.0f); // Lower-right 926 ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint 927 ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f); // 50% opaque white 928 ImGui::Image(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, tint_col, border_col); 929 if (ImGui::IsItemHovered()) 930 { 931 ImGui::BeginTooltip(); 932 float region_sz = 32.0f; 933 float region_x = io.MousePos.x - pos.x - region_sz * 0.5f; 934 float region_y = io.MousePos.y - pos.y - region_sz * 0.5f; 935 float zoom = 4.0f; 936 if (region_x < 0.0f) { region_x = 0.0f; } 937 else if (region_x > my_tex_w - region_sz) { region_x = my_tex_w - region_sz; } 938 if (region_y < 0.0f) { region_y = 0.0f; } 939 else if (region_y > my_tex_h - region_sz) { region_y = my_tex_h - region_sz; } 940 ImGui::Text("Min: (%.2f, %.2f)", region_x, region_y); 941 ImGui::Text("Max: (%.2f, %.2f)", region_x + region_sz, region_y + region_sz); 942 ImVec2 uv0 = ImVec2((region_x) / my_tex_w, (region_y) / my_tex_h); 943 ImVec2 uv1 = ImVec2((region_x + region_sz) / my_tex_w, (region_y + region_sz) / my_tex_h); 944 ImGui::Image(my_tex_id, ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, tint_col, border_col); 945 ImGui::EndTooltip(); 946 } 947 } 948 ImGui::TextWrapped("And now some textured buttons.."); 949 static int pressed_count = 0; 950 for (int i = 0; i < 8; i++) 951 { 605 952 ImGui::PushID(i); 606 int frame_padding = -1 + i; // -1 = uses default padding 607 if (ImGui::ImageButton(my_tex_id, ImVec2(32, 32), ImVec2(0, 0), ImVec2(32.0f / my_tex_w, 32 / my_tex_h), frame_padding, ImColor(0, 0, 0, 255))) 608 pressed_count += 1; 953 int frame_padding = -1 + i; // -1 == uses default padding (style.FramePadding) 954 ImVec2 size = ImVec2(32.0f, 32.0f); // Size of the image we want to make visible 955 ImVec2 uv0 = ImVec2(0.0f, 0.0f); // UV coordinates for lower-left 956 ImVec2 uv1 = ImVec2(32.0f / my_tex_w, 32.0f / my_tex_h);// UV coordinates for (32,32) in our texture 957 ImVec4 bg_col = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); // Black background 958 ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint 959 if (ImGui::ImageButton(my_tex_id, size, uv0, uv1, frame_padding, bg_col, tint_col)) 960 pressed_count += 1; 609 961 ImGui::PopID(); 610 962 ImGui::SameLine(); 611 } 612 ImGui::NewLine(); 613 ImGui::Text("Pressed %d times.", pressed_count); 614 ImGui::TreePop(); 615 } 616 617 if (ImGui::TreeNode("Combo")) 618 { 619 // Expose flags as checkbox for the demo 620 static ImGuiComboFlags flags = 0; 621 ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", (unsigned int*)&flags, ImGuiComboFlags_PopupAlignLeft); 622 if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", (unsigned int*)&flags, ImGuiComboFlags_NoArrowButton)) 963 } 964 ImGui::NewLine(); 965 ImGui::Text("Pressed %d times.", pressed_count); 966 ImGui::TreePop(); 967 } 968 969 if (ImGui::TreeNode("Combo")) 970 { 971 // Expose flags as checkbox for the demo 972 static ImGuiComboFlags flags = 0; 973 ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", (unsigned int*)&flags, ImGuiComboFlags_PopupAlignLeft); 974 ImGui::SameLine(); HelpMarker("Only makes a difference if the popup is larger than the combo"); 975 if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", (unsigned int*)&flags, ImGuiComboFlags_NoArrowButton)) 623 976 flags &= ~ImGuiComboFlags_NoPreview; // Clear the other flag, as we cannot combine both 624 977 if (ImGui::CheckboxFlags("ImGuiComboFlags_NoPreview", (unsigned int*)&flags, ImGuiComboFlags_NoPreview)) 625 978 flags &= ~ImGuiComboFlags_NoArrowButton; // Clear the other flag, as we cannot combine both 626 979 627 // General BeginCombo() API, you have full control over your selection data and display type. 628 // (your selection data could be an index, a pointer to the object, an id for the object, a flag stored in the object itself, etc.) 629 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; 630 static const char* item_current = items[0]; // Here our selection is a single pointer stored outside the object. 631 if (ImGui::BeginCombo("combo 1", item_current, flags)) // The second parameter is the label previewed before opening the combo. 632 { 980 // Using the generic BeginCombo() API, you have full control over how to display the combo contents. 981 // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively 982 // stored in the object itself, etc.) 983 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; 984 static int item_current_idx = 0; // Here our selection data is an index. 985 const char* combo_label = items[item_current_idx]; // Label to preview before opening the combo (technically it could be anything) 986 if (ImGui::BeginCombo("combo 1", combo_label, flags)) 987 { 633 988 for (int n = 0; n < IM_ARRAYSIZE(items); n++) 634 989 { 635 bool is_selected = (item_current == items[n]); 636 if (ImGui::Selectable(items[n], is_selected)) 637 item_current = items[n]; 638 if (is_selected) 639 ImGui::SetItemDefaultFocus(); // Set the initial focus when opening the combo (scrolling + for keyboard navigation support in the upcoming navigation branch) 990 const bool is_selected = (item_current_idx == n); 991 if (ImGui::Selectable(items[n], is_selected)) 992 item_current_idx = n; 993 994 // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) 995 if (is_selected) 996 ImGui::SetItemDefaultFocus(); 640 997 } 641 998 ImGui::EndCombo(); 642 } 643 644 // Simplified one-liner Combo() API, using values packed in a single constant string 645 static int item_current_2 = 0; 646 ImGui::Combo("combo 2 (one-liner)", &item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); 647 648 // Simplified one-liner Combo() using an array of const char* 649 static int item_current_3 = -1; // If the selection isn't within 0..count, Combo won't display a preview 650 ImGui::Combo("combo 3 (array)", &item_current_3, items, IM_ARRAYSIZE(items)); 651 652 // Simplified one-liner Combo() using an accessor function 653 struct FuncHolder { static bool ItemGetter(void* data, int idx, const char** out_str) { *out_str = ((const char**)data)[idx]; return true; } }; 654 static int item_current_4 = 0; 655 ImGui::Combo("combo 4 (function)", &item_current_4, &FuncHolder::ItemGetter, items, IM_ARRAYSIZE(items)); 656 657 ImGui::TreePop(); 658 } 659 660 if (ImGui::TreeNode("Selectables")) 661 { 662 // Selectable() has 2 overloads: 663 // - The one taking "bool selected" as a read-only selection information. When Selectable() has been clicked is returns true and you can alter selection state accordingly. 664 // - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases) 665 // The earlier is more flexible, as in real application your selection may be stored in a different manner (in flags within objects, as an external list, etc). 666 if (ImGui::TreeNode("Basic")) 667 { 999 } 1000 1001 // Simplified one-liner Combo() API, using values packed in a single constant string 1002 static int item_current_2 = 0; 1003 ImGui::Combo("combo 2 (one-liner)", &item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); 1004 1005 // Simplified one-liner Combo() using an array of const char* 1006 static int item_current_3 = -1; // If the selection isn't within 0..count, Combo won't display a preview 1007 ImGui::Combo("combo 3 (array)", &item_current_3, items, IM_ARRAYSIZE(items)); 1008 1009 // Simplified one-liner Combo() using an accessor function 1010 struct Funcs { static bool ItemGetter(void* data, int n, const char** out_str) { *out_str = ((const char**)data)[n]; return true; } }; 1011 static int item_current_4 = 0; 1012 ImGui::Combo("combo 4 (function)", &item_current_4, &Funcs::ItemGetter, items, IM_ARRAYSIZE(items)); 1013 1014 ImGui::TreePop(); 1015 } 1016 1017 if (ImGui::TreeNode("Selectables")) 1018 { 1019 // Selectable() has 2 overloads: 1020 // - The one taking "bool selected" as a read-only selection information. 1021 // When Selectable() has been clicked it returns true and you can alter selection state accordingly. 1022 // - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases) 1023 // The earlier is more flexible, as in real application your selection may be stored in many different ways 1024 // and not necessarily inside a bool value (e.g. in flags within objects, as an external list, etc). 1025 if (ImGui::TreeNode("Basic")) 1026 { 668 1027 static bool selection[5] = { false, true, false, false, false }; 669 1028 ImGui::Selectable("1. I am selectable", &selection[0]); … … 672 1031 ImGui::Selectable("4. I am selectable", &selection[3]); 673 1032 if (ImGui::Selectable("5. I am double clickable", selection[4], ImGuiSelectableFlags_AllowDoubleClick)) 674 if (ImGui::IsMouseDoubleClicked(0))675 selection[4] = !selection[4];1033 if (ImGui::IsMouseDoubleClicked(0)) 1034 selection[4] = !selection[4]; 676 1035 ImGui::TreePop(); 677 678 679 1036 } 1037 if (ImGui::TreeNode("Selection State: Single Selection")) 1038 { 680 1039 static int selected = -1; 681 1040 for (int n = 0; n < 5; n++) 682 1041 { 683 char buf[32];684 sprintf(buf, "Object %d", n);685 if (ImGui::Selectable(buf, selected == n))686 selected = n;1042 char buf[32]; 1043 sprintf(buf, "Object %d", n); 1044 if (ImGui::Selectable(buf, selected == n)) 1045 selected = n; 687 1046 } 688 1047 ImGui::TreePop(); 689 690 691 692 ShowHelpMarker("Hold CTRL and click to select multiple items.");1048 } 1049 if (ImGui::TreeNode("Selection State: Multiple Selection")) 1050 { 1051 HelpMarker("Hold CTRL and click to select multiple items."); 693 1052 static bool selection[5] = { false, false, false, false, false }; 694 1053 for (int n = 0; n < 5; n++) 695 1054 { 696 char buf[32];697 sprintf(buf, "Object %d", n);698 if (ImGui::Selectable(buf, selection[n]))699 {700 if (!ImGui::GetIO().KeyCtrl) // Clear selection when CTRL is not held701 memset(selection, 0, sizeof(selection));702 selection[n] ^= 1;703 }1055 char buf[32]; 1056 sprintf(buf, "Object %d", n); 1057 if (ImGui::Selectable(buf, selection[n])) 1058 { 1059 if (!ImGui::GetIO().KeyCtrl) // Clear selection when CTRL is not held 1060 memset(selection, 0, sizeof(selection)); 1061 selection[n] ^= 1; 1062 } 704 1063 } 705 1064 ImGui::TreePop(); 706 } 707 if (ImGui::TreeNode("Rendering more text into the same line")) 708 { 709 // Using the Selectable() override that takes "bool* p_selected" parameter and toggle your booleans automatically. 1065 } 1066 if (ImGui::TreeNode("Rendering more text into the same line")) 1067 { 1068 // Using the Selectable() override that takes "bool* p_selected" parameter, 1069 // this function toggle your bool value automatically. 710 1070 static bool selected[3] = { false, false, false }; 711 ImGui::Selectable("main.c", &selected[0]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes");1071 ImGui::Selectable("main.c", &selected[0]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes"); 712 1072 ImGui::Selectable("Hello.cpp", &selected[1]); ImGui::SameLine(300); ImGui::Text("12,345 bytes"); 713 ImGui::Selectable("Hello.h", &selected[2]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes");1073 ImGui::Selectable("Hello.h", &selected[2]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes"); 714 1074 ImGui::TreePop(); 715 716 717 1075 } 1076 if (ImGui::TreeNode("In columns")) 1077 { 718 1078 ImGui::Columns(3, NULL, false); 719 static bool selected[16] = { 0};1079 static bool selected[16] = {}; 720 1080 for (int i = 0; i < 16; i++) 721 1081 { 722 char label[32]; sprintf(label, "Item %d", i);723 if (ImGui::Selectable(label, &selected[i])) {}724 ImGui::NextColumn();1082 char label[32]; sprintf(label, "Item %d", i); 1083 if (ImGui::Selectable(label, &selected[i])) {} 1084 ImGui::NextColumn(); 725 1085 } 726 1086 ImGui::Columns(1); 727 1087 ImGui::TreePop(); 728 } 729 if (ImGui::TreeNode("Grid")) 730 { 731 static bool selected[16] = { true, false, false, false, false, true, false, false, false, false, true, false, false, false, false, true }; 732 for (int i = 0; i < 16; i++) 733 { 734 ImGui::PushID(i); 735 if (ImGui::Selectable("Sailor", &selected[i], 0, ImVec2(50, 50))) 736 { 737 int x = i % 4, y = i / 4; 738 if (x > 0) selected[i - 1] ^= 1; 739 if (x < 3) selected[i + 1] ^= 1; 740 if (y > 0) selected[i - 4] ^= 1; 741 if (y < 3) selected[i + 4] ^= 1; 742 } 743 if ((i % 4) < 3) ImGui::SameLine(); 744 ImGui::PopID(); 745 } 1088 } 1089 if (ImGui::TreeNode("Grid")) 1090 { 1091 static char selected[4][4] = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } }; 1092 1093 // Add in a bit of silly fun... 1094 const float time = (float)ImGui::GetTime(); 1095 const bool winning_state = memchr(selected, 0, sizeof(selected)) == NULL; // If all cells are selected... 1096 if (winning_state) 1097 ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f + 0.5f * cosf(time * 2.0f), 0.5f + 0.5f * sinf(time * 3.0f))); 1098 1099 for (int y = 0; y < 4; y++) 1100 for (int x = 0; x < 4; x++) 1101 { 1102 if (x > 0) 1103 ImGui::SameLine(); 1104 ImGui::PushID(y * 4 + x); 1105 if (ImGui::Selectable("Sailor", selected[y][x] != 0, 0, ImVec2(50, 50))) 1106 { 1107 // Toggle clicked cell + toggle neighbors 1108 selected[y][x] ^= 1; 1109 if (x > 0) { selected[y][x - 1] ^= 1; } 1110 if (x < 3) { selected[y][x + 1] ^= 1; } 1111 if (y > 0) { selected[y - 1][x] ^= 1; } 1112 if (y < 3) { selected[y + 1][x] ^= 1; } 1113 } 1114 ImGui::PopID(); 1115 } 1116 1117 if (winning_state) 1118 ImGui::PopStyleVar(); 746 1119 ImGui::TreePop(); 747 } 748 ImGui::TreePop(); 749 } 750 751 if (ImGui::TreeNode("Filtered Text Input")) 752 { 753 static char buf1[64] = ""; ImGui::InputText("default", buf1, 64); 754 static char buf2[64] = ""; ImGui::InputText("decimal", buf2, 64, ImGuiInputTextFlags_CharsDecimal); 755 static char buf3[64] = ""; ImGui::InputText("hexadecimal", buf3, 64, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase); 756 static char buf4[64] = ""; ImGui::InputText("uppercase", buf4, 64, ImGuiInputTextFlags_CharsUppercase); 757 static char buf5[64] = ""; ImGui::InputText("no blank", buf5, 64, ImGuiInputTextFlags_CharsNoBlank); 758 struct TextFilters { static int FilterImGuiLetters(ImGuiTextEditCallbackData* data) { if (data->EventChar < 256 && strchr("imgui", (char)data->EventChar)) return 0; return 1; } }; 759 static char buf6[64] = ""; ImGui::InputText("\"imgui\" letters", buf6, 64, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters); 760 761 ImGui::Text("Password input"); 762 static char bufpass[64] = "password123"; 763 ImGui::InputText("password", bufpass, 64, ImGuiInputTextFlags_Password | ImGuiInputTextFlags_CharsNoBlank); 764 ImGui::SameLine(); ShowHelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n"); 765 ImGui::InputText("password (clear)", bufpass, 64, ImGuiInputTextFlags_CharsNoBlank); 766 767 ImGui::TreePop(); 768 } 769 770 if (ImGui::TreeNode("Multi-line Text Input")) 771 { 772 static bool read_only = false; 773 static char text[1024 * 16] = 774 "/*\n" 775 " The Pentium F00F bug, shorthand for F0 0F C7 C8,\n" 776 " the hexadecimal encoding of one offending instruction,\n" 777 " more formally, the invalid operand with locked CMPXCHG8B\n" 778 " instruction bug, is a design flaw in the majority of\n" 779 " Intel Pentium, Pentium MMX, and Pentium OverDrive\n" 780 " processors (all in the P5 microarchitecture).\n" 781 "*/\n\n" 782 "label:\n" 783 "\tlock cmpxchg8b eax\n"; 784 785 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); 786 ImGui::Checkbox("Read-only", &read_only); 787 ImGui::PopStyleVar(); 788 ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-1.0f, ImGui::GetTextLineHeight() * 16), ImGuiInputTextFlags_AllowTabInput | (read_only ? ImGuiInputTextFlags_ReadOnly : 0)); 789 ImGui::TreePop(); 790 } 791 792 if (ImGui::TreeNode("Plots widgets")) 793 { 794 static bool animate = true; 795 ImGui::Checkbox("Animate", &animate); 796 797 static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; 798 ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr)); 799 800 // Create a dummy array of contiguous float values to plot 801 // Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float and the sizeof() of your structure in the Stride parameter. 802 static float values[90] = { 0 }; 803 static int values_offset = 0; 804 static float refresh_time = 0.0f; 805 if (!animate || refresh_time == 0.0f) 1120 } 1121 if (ImGui::TreeNode("Alignment")) 1122 { 1123 HelpMarker( 1124 "By default, Selectables uses style.SelectableTextAlign but it can be overridden on a per-item " 1125 "basis using PushStyleVar(). You'll probably want to always keep your default situation to " 1126 "left-align otherwise it becomes difficult to layout multiple items on a same line"); 1127 static bool selected[3 * 3] = { true, false, true, false, true, false, true, false, true }; 1128 for (int y = 0; y < 3; y++) 1129 { 1130 for (int x = 0; x < 3; x++) 1131 { 1132 ImVec2 alignment = ImVec2((float)x / 2.0f, (float)y / 2.0f); 1133 char name[32]; 1134 sprintf(name, "(%.1f,%.1f)", alignment.x, alignment.y); 1135 if (x > 0) ImGui::SameLine(); 1136 ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, alignment); 1137 ImGui::Selectable(name, &selected[3 * y + x], ImGuiSelectableFlags_None, ImVec2(80, 80)); 1138 ImGui::PopStyleVar(); 1139 } 1140 } 1141 ImGui::TreePop(); 1142 } 1143 ImGui::TreePop(); 1144 } 1145 1146 // To wire InputText() with std::string or any other custom string type, 1147 // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file. 1148 if (ImGui::TreeNode("Text Input")) 1149 { 1150 if (ImGui::TreeNode("Multi-line Text Input")) 1151 { 1152 // Note: we are using a fixed-sized buffer for simplicity here. See ImGuiInputTextFlags_CallbackResize 1153 // and the code in misc/cpp/imgui_stdlib.h for how to setup InputText() for dynamically resizing strings. 1154 static char text[1024 * 16] = 1155 "/*\n" 1156 " The Pentium F00F bug, shorthand for F0 0F C7 C8,\n" 1157 " the hexadecimal encoding of one offending instruction,\n" 1158 " more formally, the invalid operand with locked CMPXCHG8B\n" 1159 " instruction bug, is a design flaw in the majority of\n" 1160 " Intel Pentium, Pentium MMX, and Pentium OverDrive\n" 1161 " processors (all in the P5 microarchitecture).\n" 1162 "*/\n\n" 1163 "label:\n" 1164 "\tlock cmpxchg8b eax\n"; 1165 1166 static ImGuiInputTextFlags flags = ImGuiInputTextFlags_AllowTabInput; 1167 HelpMarker("You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputTextMultiline() to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example. (This is not demonstrated in imgui_demo.cpp because we don't want to include <string> in here)"); 1168 ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", (unsigned int*)&flags, ImGuiInputTextFlags_ReadOnly); 1169 ImGui::CheckboxFlags("ImGuiInputTextFlags_AllowTabInput", (unsigned int*)&flags, ImGuiInputTextFlags_AllowTabInput); 1170 ImGui::CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", (unsigned int*)&flags, ImGuiInputTextFlags_CtrlEnterForNewLine); 1171 ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16), flags); 1172 ImGui::TreePop(); 1173 } 1174 1175 if (ImGui::TreeNode("Filtered Text Input")) 1176 { 1177 struct TextFilters 1178 { 1179 // Return 0 (pass) if the character is 'i' or 'm' or 'g' or 'u' or 'i' 1180 static int FilterImGuiLetters(ImGuiInputTextCallbackData* data) 1181 { 1182 if (data->EventChar < 256 && strchr("imgui", (char)data->EventChar)) 1183 return 0; 1184 return 1; 1185 } 1186 }; 1187 1188 static char buf1[64] = ""; ImGui::InputText("default", buf1, 64); 1189 static char buf2[64] = ""; ImGui::InputText("decimal", buf2, 64, ImGuiInputTextFlags_CharsDecimal); 1190 static char buf3[64] = ""; ImGui::InputText("hexadecimal", buf3, 64, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase); 1191 static char buf4[64] = ""; ImGui::InputText("uppercase", buf4, 64, ImGuiInputTextFlags_CharsUppercase); 1192 static char buf5[64] = ""; ImGui::InputText("no blank", buf5, 64, ImGuiInputTextFlags_CharsNoBlank); 1193 static char buf6[64] = ""; ImGui::InputText("\"imgui\" letters", buf6, 64, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters); 1194 ImGui::TreePop(); 1195 } 1196 1197 if (ImGui::TreeNode("Password Input")) 1198 { 1199 static char password[64] = "password123"; 1200 ImGui::InputText("password", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password); 1201 ImGui::SameLine(); HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n"); 1202 ImGui::InputTextWithHint("password (w/ hint)", "<password>", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password); 1203 ImGui::InputText("password (clear)", password, IM_ARRAYSIZE(password)); 1204 ImGui::TreePop(); 1205 } 1206 1207 if (ImGui::TreeNode("Completion, History, Edit Callbacks")) 1208 { 1209 struct Funcs 1210 { 1211 static int MyCallback(ImGuiInputTextCallbackData* data) 1212 { 1213 if (data->EventFlag == ImGuiInputTextFlags_CallbackCompletion) 1214 { 1215 data->InsertChars(data->CursorPos, ".."); 1216 } 1217 else if (data->EventFlag == ImGuiInputTextFlags_CallbackHistory) 1218 { 1219 if (data->EventKey == ImGuiKey_UpArrow) 1220 { 1221 data->DeleteChars(0, data->BufTextLen); 1222 data->InsertChars(0, "Pressed Up!"); 1223 data->SelectAll(); 1224 } 1225 else if (data->EventKey == ImGuiKey_DownArrow) 1226 { 1227 data->DeleteChars(0, data->BufTextLen); 1228 data->InsertChars(0, "Pressed Down!"); 1229 data->SelectAll(); 1230 } 1231 } 1232 else if (data->EventFlag == ImGuiInputTextFlags_CallbackEdit) 1233 { 1234 // Toggle casing of first character 1235 char c = data->Buf[0]; 1236 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) data->Buf[0] ^= 32; 1237 data->BufDirty = true; 1238 1239 // Increment a counter 1240 int* p_int = (int*)data->UserData; 1241 *p_int = *p_int + 1; 1242 } 1243 return 0; 1244 } 1245 }; 1246 static char buf1[64]; 1247 ImGui::InputText("Completion", buf1, 64, ImGuiInputTextFlags_CallbackCompletion, Funcs::MyCallback); 1248 ImGui::SameLine(); HelpMarker("Here we append \"..\" each time Tab is pressed. See 'Examples>Console' for a more meaningful demonstration of using this callback."); 1249 1250 static char buf2[64]; 1251 ImGui::InputText("History", buf2, 64, ImGuiInputTextFlags_CallbackHistory, Funcs::MyCallback); 1252 ImGui::SameLine(); HelpMarker("Here we replace and select text each time Up/Down are pressed. See 'Examples>Console' for a more meaningful demonstration of using this callback."); 1253 1254 static char buf3[64]; 1255 static int edit_count = 0; 1256 ImGui::InputText("Edit", buf3, 64, ImGuiInputTextFlags_CallbackEdit, Funcs::MyCallback, (void*)&edit_count); 1257 ImGui::SameLine(); HelpMarker("Here we toggle the casing of the first character on every edits + count edits."); 1258 ImGui::SameLine(); ImGui::Text("(%d)", edit_count); 1259 1260 ImGui::TreePop(); 1261 } 1262 1263 if (ImGui::TreeNode("Resize Callback")) 1264 { 1265 // To wire InputText() with std::string or any other custom string type, 1266 // you can use the ImGuiInputTextFlags_CallbackResize flag + create a custom ImGui::InputText() wrapper 1267 // using your preferred type. See misc/cpp/imgui_stdlib.h for an implementation of this using std::string. 1268 HelpMarker( 1269 "Using ImGuiInputTextFlags_CallbackResize to wire your custom string type to InputText().\n\n" 1270 "See misc/cpp/imgui_stdlib.h for an implementation of this for std::string."); 1271 struct Funcs 1272 { 1273 static int MyResizeCallback(ImGuiInputTextCallbackData* data) 1274 { 1275 if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) 1276 { 1277 ImVector<char>* my_str = (ImVector<char>*)data->UserData; 1278 IM_ASSERT(my_str->begin() == data->Buf); 1279 my_str->resize(data->BufSize); // NB: On resizing calls, generally data->BufSize == data->BufTextLen + 1 1280 data->Buf = my_str->begin(); 1281 } 1282 return 0; 1283 } 1284 1285 // Note: Because ImGui:: is a namespace you would typically add your own function into the namespace. 1286 // For example, you code may declare a function 'ImGui::InputText(const char* label, MyString* my_str)' 1287 static bool MyInputTextMultiline(const char* label, ImVector<char>* my_str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0) 1288 { 1289 IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); 1290 return ImGui::InputTextMultiline(label, my_str->begin(), (size_t)my_str->size(), size, flags | ImGuiInputTextFlags_CallbackResize, Funcs::MyResizeCallback, (void*)my_str); 1291 } 1292 }; 1293 1294 // For this demo we are using ImVector as a string container. 1295 // Note that because we need to store a terminating zero character, our size/capacity are 1 more 1296 // than usually reported by a typical string class. 1297 static ImVector<char> my_str; 1298 if (my_str.empty()) 1299 my_str.push_back(0); 1300 Funcs::MyInputTextMultiline("##MyStr", &my_str, ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16)); 1301 ImGui::Text("Data: %p\nSize: %d\nCapacity: %d", (void*)my_str.begin(), my_str.size(), my_str.capacity()); 1302 ImGui::TreePop(); 1303 } 1304 1305 ImGui::TreePop(); 1306 } 1307 1308 // Plot/Graph widgets are currently fairly limited. 1309 // Consider writing your own plotting widget, or using a third-party one 1310 // (for third-party Plot widgets, see 'Wiki->Useful Widgets' or https://github.com/ocornut/imgui/labels/plot%2Fgraph) 1311 if (ImGui::TreeNode("Plots Widgets")) 1312 { 1313 static bool animate = true; 1314 ImGui::Checkbox("Animate", &animate); 1315 1316 static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; 1317 ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr)); 1318 1319 // Fill an array of contiguous float values to plot 1320 // Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float 1321 // and the sizeof() of your structure in the "stride" parameter. 1322 static float values[90] = {}; 1323 static int values_offset = 0; 1324 static double refresh_time = 0.0; 1325 if (!animate || refresh_time == 0.0) 806 1326 refresh_time = ImGui::GetTime(); 807 while (refresh_time < ImGui::GetTime()) // Create dummy data at fixed 60 hz rate for the demo808 1327 while (refresh_time < ImGui::GetTime()) // Create data at fixed 60 Hz rate for the demo 1328 { 809 1329 static float phase = 0.0f; 810 1330 values[values_offset] = cosf(phase); 811 1331 values_offset = (values_offset + 1) % IM_ARRAYSIZE(values); 812 phase += 0.10f *values_offset;1332 phase += 0.10f * values_offset; 813 1333 refresh_time += 1.0f / 60.0f; 814 } 815 ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, "avg 0.0", -1.0f, 1.0f, ImVec2(0, 80)); 816 ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0, 80)); 817 818 // Use functions to generate output 819 // FIXME: This is rather awkward because current plot API only pass in indices. We probably want an API passing floats and user provide sample rate/count. 820 struct Funcs 821 { 1334 } 1335 1336 // Plots can display overlay texts 1337 // (in this example, we will display an average value) 1338 { 1339 float average = 0.0f; 1340 for (int n = 0; n < IM_ARRAYSIZE(values); n++) 1341 average += values[n]; 1342 average /= (float)IM_ARRAYSIZE(values); 1343 char overlay[32]; 1344 sprintf(overlay, "avg %f", average); 1345 ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, overlay, -1.0f, 1.0f, ImVec2(0, 80.0f)); 1346 } 1347 ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0, 80.0f)); 1348 1349 // Use functions to generate output 1350 // FIXME: This is rather awkward because current plot API only pass in indices. 1351 // We probably want an API passing floats and user provide sample rate/count. 1352 struct Funcs 1353 { 822 1354 static float Sin(void*, int i) { return sinf(i * 0.1f); } 823 1355 static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; } 824 }; 825 static int func_type = 0, display_count = 70; 826 ImGui::Separator(); 827 ImGui::PushItemWidth(100); ImGui::Combo("func", &func_type, "Sin\0Saw\0"); ImGui::PopItemWidth(); 828 ImGui::SameLine(); 829 ImGui::SliderInt("Sample count", &display_count, 1, 400); 830 float(*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw; 831 ImGui::PlotLines("Lines", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); 832 ImGui::PlotHistogram("Histogram", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); 833 ImGui::Separator(); 834 835 // Animate a simple progress bar 836 static float progress = 0.0f, progress_dir = 1.0f; 837 if (animate) 838 { 1356 }; 1357 static int func_type = 0, display_count = 70; 1358 ImGui::Separator(); 1359 ImGui::SetNextItemWidth(100); 1360 ImGui::Combo("func", &func_type, "Sin\0Saw\0"); 1361 ImGui::SameLine(); 1362 ImGui::SliderInt("Sample count", &display_count, 1, 400); 1363 float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw; 1364 ImGui::PlotLines("Lines", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); 1365 ImGui::PlotHistogram("Histogram", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); 1366 ImGui::Separator(); 1367 1368 // Animate a simple progress bar 1369 static float progress = 0.0f, progress_dir = 1.0f; 1370 if (animate) 1371 { 839 1372 progress += progress_dir * 0.4f * ImGui::GetIO().DeltaTime; 840 1373 if (progress >= +1.1f) { progress = +1.1f; progress_dir *= -1.0f; } 841 1374 if (progress <= -0.1f) { progress = -0.1f; progress_dir *= -1.0f; } 842 } 843 844 // Typically we would use ImVec2(-1.0f,0.0f) to use all available width, or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth. 845 ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f)); 846 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); 847 ImGui::Text("Progress Bar"); 848 849 float progress_saturated = (progress < 0.0f) ? 0.0f : (progress > 1.0f) ? 1.0f : progress; 850 char buf[32]; 851 sprintf(buf, "%d/%d", (int)(progress_saturated * 1753), 1753); 852 ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), buf); 853 ImGui::TreePop(); 854 } 855 856 if (ImGui::TreeNode("Color/Picker Widgets")) 857 { 858 static ImVec4 color = ImColor(114, 144, 154, 200); 859 860 static bool alpha_preview = true; 861 static bool alpha_half_preview = false; 862 static bool options_menu = true; 863 static bool hdr = false; 864 ImGui::Checkbox("With Alpha Preview", &alpha_preview); 865 ImGui::Checkbox("With Half Alpha Preview", &alpha_half_preview); 866 ImGui::Checkbox("With Options Menu", &options_menu); ImGui::SameLine(); ShowHelpMarker("Right-click on the individual color widget to show options."); 867 ImGui::Checkbox("With HDR", &hdr); ImGui::SameLine(); ShowHelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets."); 868 int misc_flags = (hdr ? ImGuiColorEditFlags_HDR : 0) | (alpha_half_preview ? ImGuiColorEditFlags_AlphaPreviewHalf : (alpha_preview ? ImGuiColorEditFlags_AlphaPreview : 0)) | (options_menu ? 0 : ImGuiColorEditFlags_NoOptions); 869 870 ImGui::Text("Color widget:"); 871 ImGui::SameLine(); ShowHelpMarker("Click on the colored square to open a color picker.\nCTRL+click on individual component to input value.\n"); 872 ImGui::ColorEdit3("MyColor##1", (float*)&color, misc_flags); 873 874 ImGui::Text("Color widget HSV with Alpha:"); 875 ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_HSV | misc_flags); 876 877 ImGui::Text("Color widget with Float Display:"); 878 ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | misc_flags); 879 880 ImGui::Text("Color button with Picker:"); 881 ImGui::SameLine(); ShowHelpMarker("With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\nWith the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only be used for the tooltip and picker popup."); 882 ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | misc_flags); 883 884 ImGui::Text("Color button with Custom Picker Popup:"); 885 886 // Generate a dummy palette 887 static bool saved_palette_inited = false; 888 static ImVec4 saved_palette[32]; 889 if (!saved_palette_inited) 1375 } 1376 1377 // Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width, 1378 // or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth. 1379 ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f)); 1380 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); 1381 ImGui::Text("Progress Bar"); 1382 1383 float progress_saturated = IM_CLAMP(progress, 0.0f, 1.0f); 1384 char buf[32]; 1385 sprintf(buf, "%d/%d", (int)(progress_saturated * 1753), 1753); 1386 ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), buf); 1387 ImGui::TreePop(); 1388 } 1389 1390 if (ImGui::TreeNode("Color/Picker Widgets")) 1391 { 1392 static ImVec4 color = ImVec4(114.0f / 255.0f, 144.0f / 255.0f, 154.0f / 255.0f, 200.0f / 255.0f); 1393 1394 static bool alpha_preview = true; 1395 static bool alpha_half_preview = false; 1396 static bool drag_and_drop = true; 1397 static bool options_menu = true; 1398 static bool hdr = false; 1399 ImGui::Checkbox("With Alpha Preview", &alpha_preview); 1400 ImGui::Checkbox("With Half Alpha Preview", &alpha_half_preview); 1401 ImGui::Checkbox("With Drag and Drop", &drag_and_drop); 1402 ImGui::Checkbox("With Options Menu", &options_menu); ImGui::SameLine(); HelpMarker("Right-click on the individual color widget to show options."); 1403 ImGui::Checkbox("With HDR", &hdr); ImGui::SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets."); 1404 ImGuiColorEditFlags misc_flags = (hdr ? ImGuiColorEditFlags_HDR : 0) | (drag_and_drop ? 0 : ImGuiColorEditFlags_NoDragDrop) | (alpha_half_preview ? ImGuiColorEditFlags_AlphaPreviewHalf : (alpha_preview ? ImGuiColorEditFlags_AlphaPreview : 0)) | (options_menu ? 0 : ImGuiColorEditFlags_NoOptions); 1405 1406 ImGui::Text("Color widget:"); 1407 ImGui::SameLine(); HelpMarker( 1408 "Click on the colored square to open a color picker.\n" 1409 "CTRL+click on individual component to input value.\n"); 1410 ImGui::ColorEdit3("MyColor##1", (float*)&color, misc_flags); 1411 1412 ImGui::Text("Color widget HSV with Alpha:"); 1413 ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_DisplayHSV | misc_flags); 1414 1415 ImGui::Text("Color widget with Float Display:"); 1416 ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | misc_flags); 1417 1418 ImGui::Text("Color button with Picker:"); 1419 ImGui::SameLine(); HelpMarker( 1420 "With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\n" 1421 "With the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only " 1422 "be used for the tooltip and picker popup."); 1423 ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | misc_flags); 1424 1425 ImGui::Text("Color button with Custom Picker Popup:"); 1426 1427 // Generate a default palette. The palette will persist and can be edited. 1428 static bool saved_palette_init = true; 1429 static ImVec4 saved_palette[32] = {}; 1430 if (saved_palette_init) 1431 { 890 1432 for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++) 891 1433 { 892 ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f, saved_palette[n].x, saved_palette[n].y, saved_palette[n].z); 893 saved_palette[n].w = 1.0f; // Alpha 894 } 895 saved_palette_inited = true; 896 897 static ImVec4 backup_color; 898 bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags); 899 ImGui::SameLine(); 900 open_popup |= ImGui::Button("Palette"); 901 if (open_popup) 902 { 1434 ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f, 1435 saved_palette[n].x, saved_palette[n].y, saved_palette[n].z); 1436 saved_palette[n].w = 1.0f; // Alpha 1437 } 1438 saved_palette_init = false; 1439 } 1440 1441 static ImVec4 backup_color; 1442 bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags); 1443 ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x); 1444 open_popup |= ImGui::Button("Palette"); 1445 if (open_popup) 1446 { 903 1447 ImGui::OpenPopup("mypicker"); 904 1448 backup_color = color; 905 } 906 if (ImGui::BeginPopup("mypicker")) 907 { 908 // FIXME: Adding a drag and drop example here would be perfect! 1449 } 1450 if (ImGui::BeginPopup("mypicker")) 1451 { 909 1452 ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!"); 910 1453 ImGui::Separator(); 911 1454 ImGui::ColorPicker4("##picker", (float*)&color, misc_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview); 912 1455 ImGui::SameLine(); 913 ImGui::BeginGroup(); 1456 1457 ImGui::BeginGroup(); // Lock X position 914 1458 ImGui::Text("Current"); 915 1459 ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40)); 916 1460 ImGui::Text("Previous"); 917 1461 if (ImGui::ColorButton("##previous", backup_color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40))) 918 color = backup_color;1462 color = backup_color; 919 1463 ImGui::Separator(); 920 1464 ImGui::Text("Palette"); 921 1465 for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++) 922 1466 { 923 ImGui::PushID(n); 924 if ((n % 8) != 0) 925 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y); 926 if (ImGui::ColorButton("##palette", saved_palette[n], ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip, ImVec2(20, 20))) 927 color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha! 928 929 if (ImGui::BeginDragDropTarget()) 930 { 931 if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) 932 memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3); 933 if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) 934 memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4); 935 EndDragDropTarget(); 936 } 937 938 ImGui::PopID(); 1467 ImGui::PushID(n); 1468 if ((n % 8) != 0) 1469 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y); 1470 1471 ImGuiColorEditFlags palette_button_flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip; 1472 if (ImGui::ColorButton("##palette", saved_palette[n], palette_button_flags, ImVec2(20, 20))) 1473 color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha! 1474 1475 // Allow user to drop colors into each palette entry. Note that ColorButton() is already a 1476 // drag source by default, unless specifying the ImGuiColorEditFlags_NoDragDrop flag. 1477 if (ImGui::BeginDragDropTarget()) 1478 { 1479 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) 1480 memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3); 1481 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) 1482 memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4); 1483 ImGui::EndDragDropTarget(); 1484 } 1485 1486 ImGui::PopID(); 939 1487 } 940 1488 ImGui::EndGroup(); 941 1489 ImGui::EndPopup(); 942 } 943 944 ImGui::Text("Color button only:"); 945 ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, misc_flags, ImVec2(80, 80)); 946 947 ImGui::Text("Color picker:"); 948 static bool alpha = true; 949 static bool alpha_bar = true; 950 static bool side_preview = true; 951 static bool ref_color = false; 952 static ImVec4 ref_color_v(1.0f, 0.0f, 1.0f, 0.5f); 953 static int inputs_mode = 2; 954 static int picker_mode = 0; 955 ImGui::Checkbox("With Alpha", &alpha); 956 ImGui::Checkbox("With Alpha Bar", &alpha_bar); 957 ImGui::Checkbox("With Side Preview", &side_preview); 958 if (side_preview) 959 { 1490 } 1491 1492 ImGui::Text("Color button only:"); 1493 static bool no_border = false; 1494 ImGui::Checkbox("ImGuiColorEditFlags_NoBorder", &no_border); 1495 ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, misc_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80)); 1496 1497 ImGui::Text("Color picker:"); 1498 static bool alpha = true; 1499 static bool alpha_bar = true; 1500 static bool side_preview = true; 1501 static bool ref_color = false; 1502 static ImVec4 ref_color_v(1.0f, 0.0f, 1.0f, 0.5f); 1503 static int display_mode = 0; 1504 static int picker_mode = 0; 1505 ImGui::Checkbox("With Alpha", &alpha); 1506 ImGui::Checkbox("With Alpha Bar", &alpha_bar); 1507 ImGui::Checkbox("With Side Preview", &side_preview); 1508 if (side_preview) 1509 { 960 1510 ImGui::SameLine(); 961 1511 ImGui::Checkbox("With Ref Color", &ref_color); 962 1512 if (ref_color) 963 1513 { 964 ImGui::SameLine(); 965 ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | misc_flags); 966 } 967 } 968 ImGui::Combo("Inputs Mode", &inputs_mode, "All Inputs\0No Inputs\0RGB Input\0HSV Input\0HEX Input\0"); 969 ImGui::Combo("Picker Mode", &picker_mode, "Auto/Current\0Hue bar + SV rect\0Hue wheel + SV triangle\0"); 970 ImGui::SameLine(); ShowHelpMarker("User can right-click the picker to change mode."); 971 ImGuiColorEditFlags flags = misc_flags; 972 if (!alpha) flags |= ImGuiColorEditFlags_NoAlpha; // This is by default if you call ColorPicker3() instead of ColorPicker4() 973 if (alpha_bar) flags |= ImGuiColorEditFlags_AlphaBar; 974 if (!side_preview) flags |= ImGuiColorEditFlags_NoSidePreview; 975 if (picker_mode == 1) flags |= ImGuiColorEditFlags_PickerHueBar; 976 if (picker_mode == 2) flags |= ImGuiColorEditFlags_PickerHueWheel; 977 if (inputs_mode == 1) flags |= ImGuiColorEditFlags_NoInputs; 978 if (inputs_mode == 2) flags |= ImGuiColorEditFlags_RGB; 979 if (inputs_mode == 3) flags |= ImGuiColorEditFlags_HSV; 980 if (inputs_mode == 4) flags |= ImGuiColorEditFlags_HEX; 981 ImGui::ColorPicker4("MyColor##4", (float*)&color, flags, ref_color ? &ref_color_v.x : NULL); 982 983 ImGui::Text("Programmatically set defaults/options:"); 984 ImGui::SameLine(); ShowHelpMarker("SetColorEditOptions() is designed to allow you to set boot-time default.\nWe don't have Push/Pop functions because you can force options on a per-widget basis if needed, and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid encouraging you to persistently save values that aren't forward-compatible."); 985 if (ImGui::Button("Uint8 + HSV")) 986 ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_HSV); 987 ImGui::SameLine(); 988 if (ImGui::Button("Float + HDR")) 989 ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_RGB); 990 991 ImGui::TreePop(); 992 } 993 994 if (ImGui::TreeNode("Range Widgets")) 995 { 996 static float begin = 10, end = 90; 997 static int begin_i = 100, end_i = 1000; 998 ImGui::DragFloatRange2("range", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%"); 999 ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %.0f units", "Max: %.0f units"); 1000 ImGui::TreePop(); 1001 } 1002 1003 if (ImGui::TreeNode("Multi-component Widgets")) 1004 { 1005 static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; 1006 static int vec4i[4] = { 1, 5, 100, 255 }; 1007 1008 ImGui::InputFloat2("input float2", vec4f); 1009 ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f); 1010 ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f); 1011 ImGui::DragInt2("drag int2", vec4i, 1, 0, 255); 1012 ImGui::InputInt2("input int2", vec4i); 1013 ImGui::SliderInt2("slider int2", vec4i, 0, 255); 1014 ImGui::Spacing(); 1015 1016 ImGui::InputFloat3("input float3", vec4f); 1017 ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f); 1018 ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f); 1019 ImGui::DragInt3("drag int3", vec4i, 1, 0, 255); 1020 ImGui::InputInt3("input int3", vec4i); 1021 ImGui::SliderInt3("slider int3", vec4i, 0, 255); 1022 ImGui::Spacing(); 1023 1024 ImGui::InputFloat4("input float4", vec4f); 1025 ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f); 1026 ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f); 1027 ImGui::InputInt4("input int4", vec4i); 1028 ImGui::DragInt4("drag int4", vec4i, 1, 0, 255); 1029 ImGui::SliderInt4("slider int4", vec4i, 0, 255); 1030 1031 ImGui::TreePop(); 1032 } 1033 1034 if (ImGui::TreeNode("Vertical Sliders")) 1035 { 1036 const float spacing = 4; 1037 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing)); 1038 1039 static int int_value = 0; 1040 ImGui::VSliderInt("##int", ImVec2(18, 160), &int_value, 0, 5); 1041 ImGui::SameLine(); 1042 1043 static float values[7] = { 0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f }; 1044 ImGui::PushID("set1"); 1045 for (int i = 0; i < 7; i++) 1046 { 1514 ImGui::SameLine(); 1515 ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | misc_flags); 1516 } 1517 } 1518 ImGui::Combo("Display Mode", &display_mode, "Auto/Current\0None\0RGB Only\0HSV Only\0Hex Only\0"); 1519 ImGui::SameLine(); HelpMarker( 1520 "ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, " 1521 "but the user can change it with a right-click.\n\nColorPicker defaults to displaying RGB+HSV+Hex " 1522 "if you don't specify a display mode.\n\nYou can change the defaults using SetColorEditOptions()."); 1523 ImGui::Combo("Picker Mode", &picker_mode, "Auto/Current\0Hue bar + SV rect\0Hue wheel + SV triangle\0"); 1524 ImGui::SameLine(); HelpMarker("User can right-click the picker to change mode."); 1525 ImGuiColorEditFlags flags = misc_flags; 1526 if (!alpha) flags |= ImGuiColorEditFlags_NoAlpha; // This is by default if you call ColorPicker3() instead of ColorPicker4() 1527 if (alpha_bar) flags |= ImGuiColorEditFlags_AlphaBar; 1528 if (!side_preview) flags |= ImGuiColorEditFlags_NoSidePreview; 1529 if (picker_mode == 1) flags |= ImGuiColorEditFlags_PickerHueBar; 1530 if (picker_mode == 2) flags |= ImGuiColorEditFlags_PickerHueWheel; 1531 if (display_mode == 1) flags |= ImGuiColorEditFlags_NoInputs; // Disable all RGB/HSV/Hex displays 1532 if (display_mode == 2) flags |= ImGuiColorEditFlags_DisplayRGB; // Override display mode 1533 if (display_mode == 3) flags |= ImGuiColorEditFlags_DisplayHSV; 1534 if (display_mode == 4) flags |= ImGuiColorEditFlags_DisplayHex; 1535 ImGui::ColorPicker4("MyColor##4", (float*)&color, flags, ref_color ? &ref_color_v.x : NULL); 1536 1537 ImGui::Text("Set defaults in code:"); 1538 ImGui::SameLine(); HelpMarker( 1539 "SetColorEditOptions() is designed to allow you to set boot-time default.\n" 1540 "We don't have Push/Pop functions because you can force options on a per-widget basis if needed," 1541 "and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid" 1542 "encouraging you to persistently save values that aren't forward-compatible."); 1543 if (ImGui::Button("Default: Uint8 + HSV + Hue Bar")) 1544 ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_PickerHueBar); 1545 if (ImGui::Button("Default: Float + HDR + Hue Wheel")) 1546 ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel); 1547 1548 // HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0) 1549 static ImVec4 color_hsv(0.23f, 1.0f, 1.0f, 1.0f); // Stored as HSV! 1550 ImGui::Spacing(); 1551 ImGui::Text("HSV encoded colors"); 1552 ImGui::SameLine(); HelpMarker( 1553 "By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV" 1554 "allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV. This comes with the" 1555 "added benefit that you can manipulate hue values with the picker even when saturation or value are zero."); 1556 ImGui::Text("Color widget with InputHSV:"); 1557 ImGui::ColorEdit4("HSV shown as RGB##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float); 1558 ImGui::ColorEdit4("HSV shown as HSV##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float); 1559 ImGui::DragFloat4("Raw HSV values", (float*)&color_hsv, 0.01f, 0.0f, 1.0f); 1560 1561 ImGui::TreePop(); 1562 } 1563 1564 if (ImGui::TreeNode("Drag/Slider Flags")) 1565 { 1566 // Demonstrate using advanced flags for DragXXX and SliderXXX functions. Note that the flags are the same! 1567 static ImGuiSliderFlags flags = ImGuiSliderFlags_None; 1568 ImGui::CheckboxFlags("ImGuiSliderFlags_AlwaysClamp", (unsigned int*)&flags, ImGuiSliderFlags_AlwaysClamp); 1569 ImGui::SameLine(); HelpMarker("Always clamp value to min/max bounds (if any) when input manually with CTRL+Click."); 1570 ImGui::CheckboxFlags("ImGuiSliderFlags_Logarithmic", (unsigned int*)&flags, ImGuiSliderFlags_Logarithmic); 1571 ImGui::SameLine(); HelpMarker("Enable logarithmic editing (more precision for small values)."); 1572 ImGui::CheckboxFlags("ImGuiSliderFlags_NoRoundToFormat", (unsigned int*)&flags, ImGuiSliderFlags_NoRoundToFormat); 1573 ImGui::SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits)."); 1574 ImGui::CheckboxFlags("ImGuiSliderFlags_NoInput", (unsigned int*)&flags, ImGuiSliderFlags_NoInput); 1575 ImGui::SameLine(); HelpMarker("Disable CTRL+Click or Enter key allowing to input text directly into the widget."); 1576 1577 // Drags 1578 static float drag_f = 0.5f; 1579 static int drag_i = 50; 1580 ImGui::Text("Underlying float value: %f", drag_f); 1581 ImGui::DragFloat("DragFloat (0 -> 1)", &drag_f, 0.005f, 0.0f, 1.0f, "%.3f", flags); 1582 ImGui::DragFloat("DragFloat (0 -> +inf)", &drag_f, 0.005f, 0.0f, FLT_MAX, "%.3f", flags); 1583 ImGui::DragFloat("DragFloat (-inf -> 1)", &drag_f, 0.005f, -FLT_MAX, 1.0f, "%.3f", flags); 1584 ImGui::DragFloat("DragFloat (-inf -> +inf)", &drag_f, 0.005f, -FLT_MAX, +FLT_MAX, "%.3f", flags); 1585 ImGui::DragInt("DragInt (0 -> 100)", &drag_i, 0.5f, 0, 100, "%d", flags); 1586 1587 // Sliders 1588 static float slider_f = 0.5f; 1589 static int slider_i = 50; 1590 ImGui::Text("Underlying float value: %f", slider_f); 1591 ImGui::SliderFloat("SliderFloat (0 -> 1)", &slider_f, 0.0f, 1.0f, "%.3f", flags); 1592 ImGui::SliderInt("SliderInt (0 -> 100)", &slider_i, 0, 100, "%d", flags); 1593 1594 ImGui::TreePop(); 1595 } 1596 1597 if (ImGui::TreeNode("Range Widgets")) 1598 { 1599 static float begin = 10, end = 90; 1600 static int begin_i = 100, end_i = 1000; 1601 ImGui::DragFloatRange2("range float", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%", ImGuiSliderFlags_AlwaysClamp); 1602 ImGui::DragIntRange2("range int", &begin_i, &end_i, 5, 0, 1000, "Min: %d units", "Max: %d units"); 1603 ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %d units", "Max: %d units"); 1604 ImGui::TreePop(); 1605 } 1606 1607 if (ImGui::TreeNode("Data Types")) 1608 { 1609 // DragScalar/InputScalar/SliderScalar functions allow various data types 1610 // - signed/unsigned 1611 // - 8/16/32/64-bits 1612 // - integer/float/double 1613 // To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum 1614 // to pass the type, and passing all arguments by pointer. 1615 // This is the reason the test code below creates local variables to hold "zero" "one" etc. for each types. 1616 // In practice, if you frequently use a given type that is not covered by the normal API entry points, 1617 // you can wrap it yourself inside a 1 line function which can take typed argument as value instead of void*, 1618 // and then pass their address to the generic function. For example: 1619 // bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld") 1620 // { 1621 // return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format); 1622 // } 1623 1624 // Setup limits (as helper variables so we can take their address, as explained above) 1625 // Note: SliderScalar() functions have a maximum usable range of half the natural type maximum, hence the /2. 1626 #ifndef LLONG_MIN 1627 ImS64 LLONG_MIN = -9223372036854775807LL - 1; 1628 ImS64 LLONG_MAX = 9223372036854775807LL; 1629 ImU64 ULLONG_MAX = (2ULL * 9223372036854775807LL + 1); 1630 #endif 1631 const char s8_zero = 0, s8_one = 1, s8_fifty = 50, s8_min = -128, s8_max = 127; 1632 const ImU8 u8_zero = 0, u8_one = 1, u8_fifty = 50, u8_min = 0, u8_max = 255; 1633 const short s16_zero = 0, s16_one = 1, s16_fifty = 50, s16_min = -32768, s16_max = 32767; 1634 const ImU16 u16_zero = 0, u16_one = 1, u16_fifty = 50, u16_min = 0, u16_max = 65535; 1635 const ImS32 s32_zero = 0, s32_one = 1, s32_fifty = 50, s32_min = INT_MIN/2, s32_max = INT_MAX/2, s32_hi_a = INT_MAX/2 - 100, s32_hi_b = INT_MAX/2; 1636 const ImU32 u32_zero = 0, u32_one = 1, u32_fifty = 50, u32_min = 0, u32_max = UINT_MAX/2, u32_hi_a = UINT_MAX/2 - 100, u32_hi_b = UINT_MAX/2; 1637 const ImS64 s64_zero = 0, s64_one = 1, s64_fifty = 50, s64_min = LLONG_MIN/2, s64_max = LLONG_MAX/2, s64_hi_a = LLONG_MAX/2 - 100, s64_hi_b = LLONG_MAX/2; 1638 const ImU64 u64_zero = 0, u64_one = 1, u64_fifty = 50, u64_min = 0, u64_max = ULLONG_MAX/2, u64_hi_a = ULLONG_MAX/2 - 100, u64_hi_b = ULLONG_MAX/2; 1639 const float f32_zero = 0.f, f32_one = 1.f, f32_lo_a = -10000000000.0f, f32_hi_a = +10000000000.0f; 1640 const double f64_zero = 0., f64_one = 1., f64_lo_a = -1000000000000000.0, f64_hi_a = +1000000000000000.0; 1641 1642 // State 1643 static char s8_v = 127; 1644 static ImU8 u8_v = 255; 1645 static short s16_v = 32767; 1646 static ImU16 u16_v = 65535; 1647 static ImS32 s32_v = -1; 1648 static ImU32 u32_v = (ImU32)-1; 1649 static ImS64 s64_v = -1; 1650 static ImU64 u64_v = (ImU64)-1; 1651 static float f32_v = 0.123f; 1652 static double f64_v = 90000.01234567890123456789; 1653 1654 const float drag_speed = 0.2f; 1655 static bool drag_clamp = false; 1656 ImGui::Text("Drags:"); 1657 ImGui::Checkbox("Clamp integers to 0..50", &drag_clamp); 1658 ImGui::SameLine(); HelpMarker( 1659 "As with every widgets in dear imgui, we never modify values unless there is a user interaction.\n" 1660 "You can override the clamping limits by using CTRL+Click to input a value."); 1661 ImGui::DragScalar("drag s8", ImGuiDataType_S8, &s8_v, drag_speed, drag_clamp ? &s8_zero : NULL, drag_clamp ? &s8_fifty : NULL); 1662 ImGui::DragScalar("drag u8", ImGuiDataType_U8, &u8_v, drag_speed, drag_clamp ? &u8_zero : NULL, drag_clamp ? &u8_fifty : NULL, "%u ms"); 1663 ImGui::DragScalar("drag s16", ImGuiDataType_S16, &s16_v, drag_speed, drag_clamp ? &s16_zero : NULL, drag_clamp ? &s16_fifty : NULL); 1664 ImGui::DragScalar("drag u16", ImGuiDataType_U16, &u16_v, drag_speed, drag_clamp ? &u16_zero : NULL, drag_clamp ? &u16_fifty : NULL, "%u ms"); 1665 ImGui::DragScalar("drag s32", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL); 1666 ImGui::DragScalar("drag u32", ImGuiDataType_U32, &u32_v, drag_speed, drag_clamp ? &u32_zero : NULL, drag_clamp ? &u32_fifty : NULL, "%u ms"); 1667 ImGui::DragScalar("drag s64", ImGuiDataType_S64, &s64_v, drag_speed, drag_clamp ? &s64_zero : NULL, drag_clamp ? &s64_fifty : NULL); 1668 ImGui::DragScalar("drag u64", ImGuiDataType_U64, &u64_v, drag_speed, drag_clamp ? &u64_zero : NULL, drag_clamp ? &u64_fifty : NULL); 1669 ImGui::DragScalar("drag float", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f"); 1670 ImGui::DragScalar("drag float log", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f", ImGuiSliderFlags_Logarithmic); 1671 ImGui::DragScalar("drag double", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, NULL, "%.10f grams"); 1672 ImGui::DragScalar("drag double log",ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", ImGuiSliderFlags_Logarithmic); 1673 1674 ImGui::Text("Sliders"); 1675 ImGui::SliderScalar("slider s8 full", ImGuiDataType_S8, &s8_v, &s8_min, &s8_max, "%d"); 1676 ImGui::SliderScalar("slider u8 full", ImGuiDataType_U8, &u8_v, &u8_min, &u8_max, "%u"); 1677 ImGui::SliderScalar("slider s16 full", ImGuiDataType_S16, &s16_v, &s16_min, &s16_max, "%d"); 1678 ImGui::SliderScalar("slider u16 full", ImGuiDataType_U16, &u16_v, &u16_min, &u16_max, "%u"); 1679 ImGui::SliderScalar("slider s32 low", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty,"%d"); 1680 ImGui::SliderScalar("slider s32 high", ImGuiDataType_S32, &s32_v, &s32_hi_a, &s32_hi_b, "%d"); 1681 ImGui::SliderScalar("slider s32 full", ImGuiDataType_S32, &s32_v, &s32_min, &s32_max, "%d"); 1682 ImGui::SliderScalar("slider u32 low", ImGuiDataType_U32, &u32_v, &u32_zero, &u32_fifty,"%u"); 1683 ImGui::SliderScalar("slider u32 high", ImGuiDataType_U32, &u32_v, &u32_hi_a, &u32_hi_b, "%u"); 1684 ImGui::SliderScalar("slider u32 full", ImGuiDataType_U32, &u32_v, &u32_min, &u32_max, "%u"); 1685 ImGui::SliderScalar("slider s64 low", ImGuiDataType_S64, &s64_v, &s64_zero, &s64_fifty,"%I64d"); 1686 ImGui::SliderScalar("slider s64 high", ImGuiDataType_S64, &s64_v, &s64_hi_a, &s64_hi_b, "%I64d"); 1687 ImGui::SliderScalar("slider s64 full", ImGuiDataType_S64, &s64_v, &s64_min, &s64_max, "%I64d"); 1688 ImGui::SliderScalar("slider u64 low", ImGuiDataType_U64, &u64_v, &u64_zero, &u64_fifty,"%I64u ms"); 1689 ImGui::SliderScalar("slider u64 high", ImGuiDataType_U64, &u64_v, &u64_hi_a, &u64_hi_b, "%I64u ms"); 1690 ImGui::SliderScalar("slider u64 full", ImGuiDataType_U64, &u64_v, &u64_min, &u64_max, "%I64u ms"); 1691 ImGui::SliderScalar("slider float low", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one); 1692 ImGui::SliderScalar("slider float low log", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one, "%.10f", ImGuiSliderFlags_Logarithmic); 1693 ImGui::SliderScalar("slider float high", ImGuiDataType_Float, &f32_v, &f32_lo_a, &f32_hi_a, "%e"); 1694 ImGui::SliderScalar("slider double low", ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f grams"); 1695 ImGui::SliderScalar("slider double low log",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f", ImGuiSliderFlags_Logarithmic); 1696 ImGui::SliderScalar("slider double high", ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams"); 1697 1698 ImGui::Text("Sliders (reverse)"); 1699 ImGui::SliderScalar("slider s8 reverse", ImGuiDataType_S8, &s8_v, &s8_max, &s8_min, "%d"); 1700 ImGui::SliderScalar("slider u8 reverse", ImGuiDataType_U8, &u8_v, &u8_max, &u8_min, "%u"); 1701 ImGui::SliderScalar("slider s32 reverse", ImGuiDataType_S32, &s32_v, &s32_fifty, &s32_zero, "%d"); 1702 ImGui::SliderScalar("slider u32 reverse", ImGuiDataType_U32, &u32_v, &u32_fifty, &u32_zero, "%u"); 1703 ImGui::SliderScalar("slider s64 reverse", ImGuiDataType_S64, &s64_v, &s64_fifty, &s64_zero, "%I64d"); 1704 ImGui::SliderScalar("slider u64 reverse", ImGuiDataType_U64, &u64_v, &u64_fifty, &u64_zero, "%I64u ms"); 1705 1706 static bool inputs_step = true; 1707 ImGui::Text("Inputs"); 1708 ImGui::Checkbox("Show step buttons", &inputs_step); 1709 ImGui::InputScalar("input s8", ImGuiDataType_S8, &s8_v, inputs_step ? &s8_one : NULL, NULL, "%d"); 1710 ImGui::InputScalar("input u8", ImGuiDataType_U8, &u8_v, inputs_step ? &u8_one : NULL, NULL, "%u"); 1711 ImGui::InputScalar("input s16", ImGuiDataType_S16, &s16_v, inputs_step ? &s16_one : NULL, NULL, "%d"); 1712 ImGui::InputScalar("input u16", ImGuiDataType_U16, &u16_v, inputs_step ? &u16_one : NULL, NULL, "%u"); 1713 ImGui::InputScalar("input s32", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%d"); 1714 ImGui::InputScalar("input s32 hex", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%08X", ImGuiInputTextFlags_CharsHexadecimal); 1715 ImGui::InputScalar("input u32", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%u"); 1716 ImGui::InputScalar("input u32 hex", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%08X", ImGuiInputTextFlags_CharsHexadecimal); 1717 ImGui::InputScalar("input s64", ImGuiDataType_S64, &s64_v, inputs_step ? &s64_one : NULL); 1718 ImGui::InputScalar("input u64", ImGuiDataType_U64, &u64_v, inputs_step ? &u64_one : NULL); 1719 ImGui::InputScalar("input float", ImGuiDataType_Float, &f32_v, inputs_step ? &f32_one : NULL); 1720 ImGui::InputScalar("input double", ImGuiDataType_Double, &f64_v, inputs_step ? &f64_one : NULL); 1721 1722 ImGui::TreePop(); 1723 } 1724 1725 if (ImGui::TreeNode("Multi-component Widgets")) 1726 { 1727 static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; 1728 static int vec4i[4] = { 1, 5, 100, 255 }; 1729 1730 ImGui::InputFloat2("input float2", vec4f); 1731 ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f); 1732 ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f); 1733 ImGui::InputInt2("input int2", vec4i); 1734 ImGui::DragInt2("drag int2", vec4i, 1, 0, 255); 1735 ImGui::SliderInt2("slider int2", vec4i, 0, 255); 1736 ImGui::Spacing(); 1737 1738 ImGui::InputFloat3("input float3", vec4f); 1739 ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f); 1740 ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f); 1741 ImGui::InputInt3("input int3", vec4i); 1742 ImGui::DragInt3("drag int3", vec4i, 1, 0, 255); 1743 ImGui::SliderInt3("slider int3", vec4i, 0, 255); 1744 ImGui::Spacing(); 1745 1746 ImGui::InputFloat4("input float4", vec4f); 1747 ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f); 1748 ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f); 1749 ImGui::InputInt4("input int4", vec4i); 1750 ImGui::DragInt4("drag int4", vec4i, 1, 0, 255); 1751 ImGui::SliderInt4("slider int4", vec4i, 0, 255); 1752 1753 ImGui::TreePop(); 1754 } 1755 1756 if (ImGui::TreeNode("Vertical Sliders")) 1757 { 1758 const float spacing = 4; 1759 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing)); 1760 1761 static int int_value = 0; 1762 ImGui::VSliderInt("##int", ImVec2(18, 160), &int_value, 0, 5); 1763 ImGui::SameLine(); 1764 1765 static float values[7] = { 0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f }; 1766 ImGui::PushID("set1"); 1767 for (int i = 0; i < 7; i++) 1768 { 1047 1769 if (i > 0) ImGui::SameLine(); 1048 1770 ImGui::PushID(i); … … 1053 1775 ImGui::VSliderFloat("##v", ImVec2(18, 160), &values[i], 0.0f, 1.0f, ""); 1054 1776 if (ImGui::IsItemActive() || ImGui::IsItemHovered()) 1055 ImGui::SetTooltip("%.3f", values[i]);1777 ImGui::SetTooltip("%.3f", values[i]); 1056 1778 ImGui::PopStyleColor(4); 1057 1779 ImGui::PopID(); 1058 1059 1060 1061 1062 1063 1064 1065 const ImVec2 small_slider_size(18, (160.0f - (rows - 1)*spacing) / rows);1066 1067 1780 } 1781 ImGui::PopID(); 1782 1783 ImGui::SameLine(); 1784 ImGui::PushID("set2"); 1785 static float values2[4] = { 0.20f, 0.80f, 0.40f, 0.25f }; 1786 const int rows = 3; 1787 const ImVec2 small_slider_size(18, (float)(int)((160.0f - (rows - 1) * spacing) / rows)); 1788 for (int nx = 0; nx < 4; nx++) 1789 { 1068 1790 if (nx > 0) ImGui::SameLine(); 1069 1791 ImGui::BeginGroup(); 1070 1792 for (int ny = 0; ny < rows; ny++) 1071 1793 { 1072 ImGui::PushID(nx*rows + ny);1073 ImGui::VSliderFloat("##v", small_slider_size, &values2[nx], 0.0f, 1.0f, "");1074 if (ImGui::IsItemActive() || ImGui::IsItemHovered())1075 ImGui::SetTooltip("%.3f", values2[nx]);1076 ImGui::PopID();1794 ImGui::PushID(nx * rows + ny); 1795 ImGui::VSliderFloat("##v", small_slider_size, &values2[nx], 0.0f, 1.0f, ""); 1796 if (ImGui::IsItemActive() || ImGui::IsItemHovered()) 1797 ImGui::SetTooltip("%.3f", values2[nx]); 1798 ImGui::PopID(); 1077 1799 } 1078 1800 ImGui::EndGroup(); 1079 1080 1081 1082 1083 1084 1085 1801 } 1802 ImGui::PopID(); 1803 1804 ImGui::SameLine(); 1805 ImGui::PushID("set3"); 1806 for (int i = 0; i < 4; i++) 1807 { 1086 1808 if (i > 0) ImGui::SameLine(); 1087 1809 ImGui::PushID(i); … … 1090 1812 ImGui::PopStyleVar(); 1091 1813 ImGui::PopID(); 1092 } 1093 ImGui::PopID(); 1094 ImGui::PopStyleVar(); 1095 ImGui::TreePop(); 1096 } 1097 } 1098 1099 if (ImGui::CollapsingHeader("Layout")) 1100 { 1101 if (ImGui::TreeNode("Child regions")) 1102 { 1103 static bool disable_mouse_wheel = false; 1104 static bool disable_menu = false; 1105 ImGui::Checkbox("Disable Mouse Wheel", &disable_mouse_wheel); 1106 ImGui::Checkbox("Disable Menu", &disable_menu); 1107 1108 static int line = 50; 1109 bool goto_line = ImGui::Button("Goto"); 1110 ImGui::SameLine(); 1111 ImGui::PushItemWidth(100); 1112 goto_line |= ImGui::InputInt("##Line", &line, 0, 0, ImGuiInputTextFlags_EnterReturnsTrue); 1113 ImGui::PopItemWidth(); 1114 1115 // Child 1: no border, enable horizontal scrollbar 1116 { 1117 ImGui::BeginChild("Child1", ImVec2(ImGui::GetWindowContentRegionWidth() * 0.5f, 300), false, ImGuiWindowFlags_HorizontalScrollbar | (disable_mouse_wheel ? ImGuiWindowFlags_NoScrollWithMouse : 0)); 1814 } 1815 ImGui::PopID(); 1816 ImGui::PopStyleVar(); 1817 ImGui::TreePop(); 1818 } 1819 1820 if (ImGui::TreeNode("Drag and Drop")) 1821 { 1822 if (ImGui::TreeNode("Drag and drop in standard widgets")) 1823 { 1824 // ColorEdit widgets automatically act as drag source and drag target. 1825 // They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F 1826 // to allow your own widgets to use colors in their drag and drop interaction. 1827 // Also see 'Demo->Widgets->Color/Picker Widgets->Palette' demo. 1828 HelpMarker("You can drag from the colored squares."); 1829 static float col1[3] = { 1.0f, 0.0f, 0.2f }; 1830 static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f }; 1831 ImGui::ColorEdit3("color 1", col1); 1832 ImGui::ColorEdit4("color 2", col2); 1833 ImGui::TreePop(); 1834 } 1835 1836 if (ImGui::TreeNode("Drag and drop to copy/swap items")) 1837 { 1838 enum Mode 1839 { 1840 Mode_Copy, 1841 Mode_Move, 1842 Mode_Swap 1843 }; 1844 static int mode = 0; 1845 if (ImGui::RadioButton("Copy", mode == Mode_Copy)) { mode = Mode_Copy; } ImGui::SameLine(); 1846 if (ImGui::RadioButton("Move", mode == Mode_Move)) { mode = Mode_Move; } ImGui::SameLine(); 1847 if (ImGui::RadioButton("Swap", mode == Mode_Swap)) { mode = Mode_Swap; } 1848 static const char* names[9] = 1849 { 1850 "Bobby", "Beatrice", "Betty", 1851 "Brianna", "Barry", "Bernard", 1852 "Bibi", "Blaine", "Bryn" 1853 }; 1854 for (int n = 0; n < IM_ARRAYSIZE(names); n++) 1855 { 1856 ImGui::PushID(n); 1857 if ((n % 3) != 0) 1858 ImGui::SameLine(); 1859 ImGui::Button(names[n], ImVec2(60, 60)); 1860 1861 // Our buttons are both drag sources and drag targets here! 1862 if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) 1863 { 1864 // Set payload to carry the index of our item (could be anything) 1865 ImGui::SetDragDropPayload("DND_DEMO_CELL", &n, sizeof(int)); 1866 1867 // Display preview (could be anything, e.g. when dragging an image we could decide to display 1868 // the filename and a small preview of the image, etc.) 1869 if (mode == Mode_Copy) { ImGui::Text("Copy %s", names[n]); } 1870 if (mode == Mode_Move) { ImGui::Text("Move %s", names[n]); } 1871 if (mode == Mode_Swap) { ImGui::Text("Swap %s", names[n]); } 1872 ImGui::EndDragDropSource(); 1873 } 1874 if (ImGui::BeginDragDropTarget()) 1875 { 1876 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DND_DEMO_CELL")) 1877 { 1878 IM_ASSERT(payload->DataSize == sizeof(int)); 1879 int payload_n = *(const int*)payload->Data; 1880 if (mode == Mode_Copy) 1881 { 1882 names[n] = names[payload_n]; 1883 } 1884 if (mode == Mode_Move) 1885 { 1886 names[n] = names[payload_n]; 1887 names[payload_n] = ""; 1888 } 1889 if (mode == Mode_Swap) 1890 { 1891 const char* tmp = names[n]; 1892 names[n] = names[payload_n]; 1893 names[payload_n] = tmp; 1894 } 1895 } 1896 ImGui::EndDragDropTarget(); 1897 } 1898 ImGui::PopID(); 1899 } 1900 ImGui::TreePop(); 1901 } 1902 1903 if (ImGui::TreeNode("Drag to reorder items (simple)")) 1904 { 1905 // Simple reordering 1906 HelpMarker( 1907 "We don't use the drag and drop api at all here! " 1908 "Instead we query when the item is held but not hovered, and order items accordingly."); 1909 static const char* item_names[] = { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" }; 1910 for (int n = 0; n < IM_ARRAYSIZE(item_names); n++) 1911 { 1912 const char* item = item_names[n]; 1913 ImGui::Selectable(item); 1914 1915 if (ImGui::IsItemActive() && !ImGui::IsItemHovered()) 1916 { 1917 int n_next = n + (ImGui::GetMouseDragDelta(0).y < 0.f ? -1 : 1); 1918 if (n_next >= 0 && n_next < IM_ARRAYSIZE(item_names)) 1919 { 1920 item_names[n] = item_names[n_next]; 1921 item_names[n_next] = item; 1922 ImGui::ResetMouseDragDelta(); 1923 } 1924 } 1925 } 1926 ImGui::TreePop(); 1927 } 1928 1929 ImGui::TreePop(); 1930 } 1931 1932 if (ImGui::TreeNode("Querying Status (Active/Focused/Hovered etc.)")) 1933 { 1934 // Select an item type 1935 const char* item_names[] = 1936 { 1937 "Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputFloat", 1938 "InputFloat3", "ColorEdit4", "MenuItem", "TreeNode", "TreeNode (w/ double-click)", "ListBox" 1939 }; 1940 static int item_type = 1; 1941 ImGui::Combo("Item Type", &item_type, item_names, IM_ARRAYSIZE(item_names), IM_ARRAYSIZE(item_names)); 1942 ImGui::SameLine(); 1943 HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions."); 1944 1945 // Submit selected item item so we can query their status in the code following it. 1946 bool ret = false; 1947 static bool b = false; 1948 static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f }; 1949 static char str[16] = {}; 1950 if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction 1951 if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); } // Testing button 1952 if (item_type == 2) { ImGui::PushButtonRepeat(true); ret = ImGui::Button("ITEM: Button"); ImGui::PopButtonRepeat(); } // Testing button (with repeater) 1953 if (item_type == 3) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); } // Testing checkbox 1954 if (item_type == 4) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item 1955 if (item_type == 5) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which handles tabbing) 1956 if (item_type == 6) { ret = ImGui::InputFloat("ITEM: InputFloat", col4f, 1.0f); } // Testing +/- buttons on scalar input 1957 if (item_type == 7) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) 1958 if (item_type == 8) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) 1959 if (item_type == 9) { ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy) 1960 if (item_type == 10){ ret = ImGui::TreeNode("ITEM: TreeNode"); if (ret) ImGui::TreePop(); } // Testing tree node 1961 if (item_type == 11){ ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy. 1962 if (item_type == 12){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", ¤t, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); } 1963 1964 // Display the values of IsItemHovered() and other common item state functions. 1965 // Note that the ImGuiHoveredFlags_XXX flags can be combined. 1966 // Because BulletText is an item itself and that would affect the output of IsItemXXX functions, 1967 // we query every state in a single call to avoid storing them and to simplify the code. 1968 ImGui::BulletText( 1969 "Return value = %d\n" 1970 "IsItemFocused() = %d\n" 1971 "IsItemHovered() = %d\n" 1972 "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n" 1973 "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n" 1974 "IsItemHovered(_AllowWhenOverlapped) = %d\n" 1975 "IsItemHovered(_RectOnly) = %d\n" 1976 "IsItemActive() = %d\n" 1977 "IsItemEdited() = %d\n" 1978 "IsItemActivated() = %d\n" 1979 "IsItemDeactivated() = %d\n" 1980 "IsItemDeactivatedAfterEdit() = %d\n" 1981 "IsItemVisible() = %d\n" 1982 "IsItemClicked() = %d\n" 1983 "IsItemToggledOpen() = %d\n" 1984 "GetItemRectMin() = (%.1f, %.1f)\n" 1985 "GetItemRectMax() = (%.1f, %.1f)\n" 1986 "GetItemRectSize() = (%.1f, %.1f)", 1987 ret, 1988 ImGui::IsItemFocused(), 1989 ImGui::IsItemHovered(), 1990 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), 1991 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), 1992 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlapped), 1993 ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly), 1994 ImGui::IsItemActive(), 1995 ImGui::IsItemEdited(), 1996 ImGui::IsItemActivated(), 1997 ImGui::IsItemDeactivated(), 1998 ImGui::IsItemDeactivatedAfterEdit(), 1999 ImGui::IsItemVisible(), 2000 ImGui::IsItemClicked(), 2001 ImGui::IsItemToggledOpen(), 2002 ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y, 2003 ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y, 2004 ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y 2005 ); 2006 2007 static bool embed_all_inside_a_child_window = false; 2008 ImGui::Checkbox("Embed everything inside a child window (for additional testing)", &embed_all_inside_a_child_window); 2009 if (embed_all_inside_a_child_window) 2010 ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20.0f), true); 2011 2012 // Testing IsWindowFocused() function with its various flags. 2013 // Note that the ImGuiFocusedFlags_XXX flags can be combined. 2014 ImGui::BulletText( 2015 "IsWindowFocused() = %d\n" 2016 "IsWindowFocused(_ChildWindows) = %d\n" 2017 "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n" 2018 "IsWindowFocused(_RootWindow) = %d\n" 2019 "IsWindowFocused(_AnyWindow) = %d\n", 2020 ImGui::IsWindowFocused(), 2021 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows), 2022 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow), 2023 ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow), 2024 ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow)); 2025 2026 // Testing IsWindowHovered() function with its various flags. 2027 // Note that the ImGuiHoveredFlags_XXX flags can be combined. 2028 ImGui::BulletText( 2029 "IsWindowHovered() = %d\n" 2030 "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n" 2031 "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n" 2032 "IsWindowHovered(_ChildWindows) = %d\n" 2033 "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n" 2034 "IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n" 2035 "IsWindowHovered(_RootWindow) = %d\n" 2036 "IsWindowHovered(_AnyWindow) = %d\n", 2037 ImGui::IsWindowHovered(), 2038 ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), 2039 ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), 2040 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows), 2041 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow), 2042 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup), 2043 ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow), 2044 ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)); 2045 2046 ImGui::BeginChild("child", ImVec2(0, 50), true); 2047 ImGui::Text("This is another child window for testing the _ChildWindows flag."); 2048 ImGui::EndChild(); 2049 if (embed_all_inside_a_child_window) 2050 ImGui::EndChild(); 2051 2052 static char unused_str[] = "This widget is only here to be able to tab-out of the widgets above."; 2053 ImGui::InputText("unused", unused_str, IM_ARRAYSIZE(unused_str), ImGuiInputTextFlags_ReadOnly); 2054 2055 // Calling IsItemHovered() after begin returns the hovered status of the title bar. 2056 // This is useful in particular if you want to create a context menu associated to the title bar of a window. 2057 static bool test_window = false; 2058 ImGui::Checkbox("Hovered/Active tests after Begin() for title bar testing", &test_window); 2059 if (test_window) 2060 { 2061 ImGui::Begin("Title bar Hovered/Active tests", &test_window); 2062 if (ImGui::BeginPopupContextItem()) // <-- This is using IsItemHovered() 2063 { 2064 if (ImGui::MenuItem("Close")) { test_window = false; } 2065 ImGui::EndPopup(); 2066 } 2067 ImGui::Text( 2068 "IsItemHovered() after begin = %d (== is title bar hovered)\n" 2069 "IsItemActive() after begin = %d (== is window being clicked/moved)\n", 2070 ImGui::IsItemHovered(), ImGui::IsItemActive()); 2071 ImGui::End(); 2072 } 2073 2074 ImGui::TreePop(); 2075 } 2076 } 2077 2078 static void ShowDemoWindowLayout() 2079 { 2080 if (!ImGui::CollapsingHeader("Layout & Scrolling")) 2081 return; 2082 2083 if (ImGui::TreeNode("Child windows")) 2084 { 2085 HelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window."); 2086 static bool disable_mouse_wheel = false; 2087 static bool disable_menu = false; 2088 ImGui::Checkbox("Disable Mouse Wheel", &disable_mouse_wheel); 2089 ImGui::Checkbox("Disable Menu", &disable_menu); 2090 2091 // Child 1: no border, enable horizontal scrollbar 2092 { 2093 ImGuiWindowFlags window_flags = ImGuiWindowFlags_HorizontalScrollbar; 2094 if (disable_mouse_wheel) 2095 window_flags |= ImGuiWindowFlags_NoScrollWithMouse; 2096 ImGui::BeginChild("ChildL", ImVec2(ImGui::GetWindowContentRegionWidth() * 0.5f, 260), false, window_flags); 1118 2097 for (int i = 0; i < 100; i++) 1119 { 1120 ImGui::Text("%04d: scrollable region", i); 1121 if (goto_line && line == i) 1122 ImGui::SetScrollHere(); 1123 } 1124 if (goto_line && line >= 100) 1125 ImGui::SetScrollHere(); 2098 ImGui::Text("%04d: scrollable region", i); 1126 2099 ImGui::EndChild(); 1127 } 1128 1129 ImGui::SameLine(); 1130 1131 // Child 2: rounded border 1132 { 2100 } 2101 2102 ImGui::SameLine(); 2103 2104 // Child 2: rounded border 2105 { 2106 ImGuiWindowFlags window_flags = ImGuiWindowFlags_None; 2107 if (disable_mouse_wheel) 2108 window_flags |= ImGuiWindowFlags_NoScrollWithMouse; 2109 if (!disable_menu) 2110 window_flags |= ImGuiWindowFlags_MenuBar; 1133 2111 ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f); 1134 ImGui::BeginChild("Child 2", ImVec2(0, 300), true, (disable_mouse_wheel ? ImGuiWindowFlags_NoScrollWithMouse : 0) | (disable_menu ? 0 : ImGuiWindowFlags_MenuBar));2112 ImGui::BeginChild("ChildR", ImVec2(0, 260), true, window_flags); 1135 2113 if (!disable_menu && ImGui::BeginMenuBar()) 1136 2114 { 1137 if (ImGui::BeginMenu("Menu"))1138 {1139 ShowExampleMenuFile();1140 ImGui::EndMenu();1141 }1142 ImGui::EndMenuBar();2115 if (ImGui::BeginMenu("Menu")) 2116 { 2117 ShowExampleMenuFile(); 2118 ImGui::EndMenu(); 2119 } 2120 ImGui::EndMenuBar(); 1143 2121 } 1144 2122 ImGui::Columns(2); 1145 2123 for (int i = 0; i < 100; i++) 1146 2124 { 1147 if (i == 50) 1148 ImGui::NextColumn(); 1149 char buf[32]; 1150 sprintf(buf, "%08x", i * 5731); 1151 ImGui::Button(buf, ImVec2(-1.0f, 0.0f)); 2125 char buf[32]; 2126 sprintf(buf, "%03d", i); 2127 ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f)); 2128 ImGui::NextColumn(); 1152 2129 } 1153 2130 ImGui::EndChild(); 1154 2131 ImGui::PopStyleVar(); 1155 } 1156 1157 ImGui::TreePop(); 1158 } 1159 1160 if (ImGui::TreeNode("Widgets Width")) 1161 { 1162 static float f = 0.0f; 1163 ImGui::Text("PushItemWidth(100)"); 1164 ImGui::SameLine(); ShowHelpMarker("Fixed width."); 1165 ImGui::PushItemWidth(100); 1166 ImGui::DragFloat("float##1", &f); 1167 ImGui::PopItemWidth(); 1168 1169 ImGui::Text("PushItemWidth(GetWindowWidth() * 0.5f)"); 1170 ImGui::SameLine(); ShowHelpMarker("Half of window width."); 1171 ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.5f); 1172 ImGui::DragFloat("float##2", &f); 1173 ImGui::PopItemWidth(); 1174 1175 ImGui::Text("PushItemWidth(GetContentRegionAvailWidth() * 0.5f)"); 1176 ImGui::SameLine(); ShowHelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)"); 1177 ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth() * 0.5f); 1178 ImGui::DragFloat("float##3", &f); 1179 ImGui::PopItemWidth(); 1180 1181 ImGui::Text("PushItemWidth(-100)"); 1182 ImGui::SameLine(); ShowHelpMarker("Align to right edge minus 100"); 1183 ImGui::PushItemWidth(-100); 1184 ImGui::DragFloat("float##4", &f); 1185 ImGui::PopItemWidth(); 1186 1187 ImGui::Text("PushItemWidth(-1)"); 1188 ImGui::SameLine(); ShowHelpMarker("Align to right edge"); 1189 ImGui::PushItemWidth(-1); 1190 ImGui::DragFloat("float##5", &f); 1191 ImGui::PopItemWidth(); 1192 1193 ImGui::TreePop(); 1194 } 1195 1196 if (ImGui::TreeNode("Basic Horizontal Layout")) 1197 { 1198 ImGui::TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)"); 1199 1200 // Text 1201 ImGui::Text("Two items: Hello"); ImGui::SameLine(); 1202 ImGui::TextColored(ImVec4(1, 1, 0, 1), "Sailor"); 1203 1204 // Adjust spacing 1205 ImGui::Text("More spacing: Hello"); ImGui::SameLine(0, 20); 1206 ImGui::TextColored(ImVec4(1, 1, 0, 1), "Sailor"); 1207 1208 // Button 1209 ImGui::AlignTextToFramePadding(); 1210 ImGui::Text("Normal buttons"); ImGui::SameLine(); 1211 ImGui::Button("Banana"); ImGui::SameLine(); 1212 ImGui::Button("Apple"); ImGui::SameLine(); 1213 ImGui::Button("Corniflower"); 1214 1215 // Button 1216 ImGui::Text("Small buttons"); ImGui::SameLine(); 1217 ImGui::SmallButton("Like this one"); ImGui::SameLine(); 1218 ImGui::Text("can fit within a text block."); 1219 1220 // Aligned to arbitrary position. Easy/cheap column. 1221 ImGui::Text("Aligned"); 1222 ImGui::SameLine(150); ImGui::Text("x=150"); 1223 ImGui::SameLine(300); ImGui::Text("x=300"); 1224 ImGui::Text("Aligned"); 1225 ImGui::SameLine(150); ImGui::SmallButton("x=150"); 1226 ImGui::SameLine(300); ImGui::SmallButton("x=300"); 1227 1228 // Checkbox 1229 static bool c1 = false, c2 = false, c3 = false, c4 = false; 1230 ImGui::Checkbox("My", &c1); ImGui::SameLine(); 1231 ImGui::Checkbox("Tailor", &c2); ImGui::SameLine(); 1232 ImGui::Checkbox("Is", &c3); ImGui::SameLine(); 1233 ImGui::Checkbox("Rich", &c4); 1234 1235 // Various 1236 static float f0 = 1.0f, f1 = 2.0f, f2 = 3.0f; 1237 ImGui::PushItemWidth(80); 1238 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD" }; 1239 static int item = -1; 1240 ImGui::Combo("Combo", &item, items, IM_ARRAYSIZE(items)); ImGui::SameLine(); 1241 ImGui::SliderFloat("X", &f0, 0.0f, 5.0f); ImGui::SameLine(); 1242 ImGui::SliderFloat("Y", &f1, 0.0f, 5.0f); ImGui::SameLine(); 1243 ImGui::SliderFloat("Z", &f2, 0.0f, 5.0f); 1244 ImGui::PopItemWidth(); 1245 1246 ImGui::PushItemWidth(80); 1247 ImGui::Text("Lists:"); 1248 static int selection[4] = { 0, 1, 2, 3 }; 1249 for (int i = 0; i < 4; i++) 1250 { 2132 } 2133 2134 ImGui::Separator(); 2135 2136 // Demonstrate a few extra things 2137 // - Changing ImGuiCol_ChildBg (which is transparent black in default styles) 2138 // - Using SetCursorPos() to position child window (the child window is an item from the POV of parent window) 2139 // You can also call SetNextWindowPos() to position the child window. The parent window will effectively 2140 // layout from this position. 2141 // - Using ImGui::GetItemRectMin/Max() to query the "item" state (because the child window is an item from 2142 // the POV of the parent window). See 'Demo->Querying Status (Active/Focused/Hovered etc.)' for details. 2143 { 2144 static int offset_x = 0; 2145 ImGui::SetNextItemWidth(100); 2146 ImGui::DragInt("Offset X", &offset_x, 1.0f, -1000, 1000); 2147 2148 ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (float)offset_x); 2149 ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(255, 0, 0, 100)); 2150 ImGui::BeginChild("Red", ImVec2(200, 100), true, ImGuiWindowFlags_None); 2151 for (int n = 0; n < 50; n++) 2152 ImGui::Text("Some test %d", n); 2153 ImGui::EndChild(); 2154 bool child_is_hovered = ImGui::IsItemHovered(); 2155 ImVec2 child_rect_min = ImGui::GetItemRectMin(); 2156 ImVec2 child_rect_max = ImGui::GetItemRectMax(); 2157 ImGui::PopStyleColor(); 2158 ImGui::Text("Hovered: %d", child_is_hovered); 2159 ImGui::Text("Rect of child window is: (%.0f,%.0f) (%.0f,%.0f)", child_rect_min.x, child_rect_min.y, child_rect_max.x, child_rect_max.y); 2160 } 2161 2162 ImGui::TreePop(); 2163 } 2164 2165 if (ImGui::TreeNode("Widgets Width")) 2166 { 2167 // Use SetNextItemWidth() to set the width of a single upcoming item. 2168 // Use PushItemWidth()/PopItemWidth() to set the width of a group of items. 2169 // In real code use you'll probably want to choose width values that are proportional to your font size 2170 // e.g. Using '20.0f * GetFontSize()' as width instead of '200.0f', etc. 2171 2172 static float f = 0.0f; 2173 ImGui::Text("SetNextItemWidth/PushItemWidth(100)"); 2174 ImGui::SameLine(); HelpMarker("Fixed width."); 2175 ImGui::SetNextItemWidth(100); 2176 ImGui::DragFloat("float##1", &f); 2177 2178 ImGui::Text("SetNextItemWidth/PushItemWidth(GetWindowWidth() * 0.5f)"); 2179 ImGui::SameLine(); HelpMarker("Half of window width."); 2180 ImGui::SetNextItemWidth(ImGui::GetWindowWidth() * 0.5f); 2181 ImGui::DragFloat("float##2", &f); 2182 2183 ImGui::Text("SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)"); 2184 ImGui::SameLine(); HelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)"); 2185 ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x * 0.5f); 2186 ImGui::DragFloat("float##3", &f); 2187 2188 ImGui::Text("SetNextItemWidth/PushItemWidth(-100)"); 2189 ImGui::SameLine(); HelpMarker("Align to right edge minus 100"); 2190 ImGui::SetNextItemWidth(-100); 2191 ImGui::DragFloat("float##4", &f); 2192 2193 // Demonstrate using PushItemWidth to surround three items. 2194 // Calling SetNextItemWidth() before each of them would have the same effect. 2195 ImGui::Text("SetNextItemWidth/PushItemWidth(-1)"); 2196 ImGui::SameLine(); HelpMarker("Align to right edge"); 2197 ImGui::PushItemWidth(-1); 2198 ImGui::DragFloat("##float5a", &f); 2199 ImGui::DragFloat("##float5b", &f); 2200 ImGui::DragFloat("##float5c", &f); 2201 ImGui::PopItemWidth(); 2202 2203 ImGui::TreePop(); 2204 } 2205 2206 if (ImGui::TreeNode("Basic Horizontal Layout")) 2207 { 2208 ImGui::TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)"); 2209 2210 // Text 2211 ImGui::Text("Two items: Hello"); ImGui::SameLine(); 2212 ImGui::TextColored(ImVec4(1,1,0,1), "Sailor"); 2213 2214 // Adjust spacing 2215 ImGui::Text("More spacing: Hello"); ImGui::SameLine(0, 20); 2216 ImGui::TextColored(ImVec4(1,1,0,1), "Sailor"); 2217 2218 // Button 2219 ImGui::AlignTextToFramePadding(); 2220 ImGui::Text("Normal buttons"); ImGui::SameLine(); 2221 ImGui::Button("Banana"); ImGui::SameLine(); 2222 ImGui::Button("Apple"); ImGui::SameLine(); 2223 ImGui::Button("Corniflower"); 2224 2225 // Button 2226 ImGui::Text("Small buttons"); ImGui::SameLine(); 2227 ImGui::SmallButton("Like this one"); ImGui::SameLine(); 2228 ImGui::Text("can fit within a text block."); 2229 2230 // Aligned to arbitrary position. Easy/cheap column. 2231 ImGui::Text("Aligned"); 2232 ImGui::SameLine(150); ImGui::Text("x=150"); 2233 ImGui::SameLine(300); ImGui::Text("x=300"); 2234 ImGui::Text("Aligned"); 2235 ImGui::SameLine(150); ImGui::SmallButton("x=150"); 2236 ImGui::SameLine(300); ImGui::SmallButton("x=300"); 2237 2238 // Checkbox 2239 static bool c1 = false, c2 = false, c3 = false, c4 = false; 2240 ImGui::Checkbox("My", &c1); ImGui::SameLine(); 2241 ImGui::Checkbox("Tailor", &c2); ImGui::SameLine(); 2242 ImGui::Checkbox("Is", &c3); ImGui::SameLine(); 2243 ImGui::Checkbox("Rich", &c4); 2244 2245 // Various 2246 static float f0 = 1.0f, f1 = 2.0f, f2 = 3.0f; 2247 ImGui::PushItemWidth(80); 2248 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD" }; 2249 static int item = -1; 2250 ImGui::Combo("Combo", &item, items, IM_ARRAYSIZE(items)); ImGui::SameLine(); 2251 ImGui::SliderFloat("X", &f0, 0.0f, 5.0f); ImGui::SameLine(); 2252 ImGui::SliderFloat("Y", &f1, 0.0f, 5.0f); ImGui::SameLine(); 2253 ImGui::SliderFloat("Z", &f2, 0.0f, 5.0f); 2254 ImGui::PopItemWidth(); 2255 2256 ImGui::PushItemWidth(80); 2257 ImGui::Text("Lists:"); 2258 static int selection[4] = { 0, 1, 2, 3 }; 2259 for (int i = 0; i < 4; i++) 2260 { 1251 2261 if (i > 0) ImGui::SameLine(); 1252 2262 ImGui::PushID(i); … … 1254 2264 ImGui::PopID(); 1255 2265 //if (ImGui::IsItemHovered()) ImGui::SetTooltip("ListBox %d hovered", i); 1256 } 1257 ImGui::PopItemWidth(); 1258 1259 // Dummy 1260 ImVec2 sz(30, 30); 1261 ImGui::Button("A", sz); ImGui::SameLine(); 1262 ImGui::Dummy(sz); ImGui::SameLine(); 1263 ImGui::Button("B", sz); 1264 1265 ImGui::TreePop(); 1266 } 1267 1268 if (ImGui::TreeNode("Groups")) 1269 { 1270 ImGui::TextWrapped("(Using ImGui::BeginGroup()/EndGroup() to layout items. BeginGroup() basically locks the horizontal position. EndGroup() bundles the whole group so that you can use functions such as IsItemHovered() on it.)"); 1271 ImGui::BeginGroup(); 1272 { 2266 } 2267 ImGui::PopItemWidth(); 2268 2269 // Dummy 2270 ImVec2 button_sz(40, 40); 2271 ImGui::Button("A", button_sz); ImGui::SameLine(); 2272 ImGui::Dummy(button_sz); ImGui::SameLine(); 2273 ImGui::Button("B", button_sz); 2274 2275 // Manually wrapping 2276 // (we should eventually provide this as an automatic layout feature, but for now you can do it manually) 2277 ImGui::Text("Manually wrapping:"); 2278 ImGuiStyle& style = ImGui::GetStyle(); 2279 int buttons_count = 20; 2280 float window_visible_x2 = ImGui::GetWindowPos().x + ImGui::GetWindowContentRegionMax().x; 2281 for (int n = 0; n < buttons_count; n++) 2282 { 2283 ImGui::PushID(n); 2284 ImGui::Button("Box", button_sz); 2285 float last_button_x2 = ImGui::GetItemRectMax().x; 2286 float next_button_x2 = last_button_x2 + style.ItemSpacing.x + button_sz.x; // Expected position if next button was on same line 2287 if (n + 1 < buttons_count && next_button_x2 < window_visible_x2) 2288 ImGui::SameLine(); 2289 ImGui::PopID(); 2290 } 2291 2292 ImGui::TreePop(); 2293 } 2294 2295 if (ImGui::TreeNode("Tabs")) 2296 { 2297 if (ImGui::TreeNode("Basic")) 2298 { 2299 ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None; 2300 if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) 2301 { 2302 if (ImGui::BeginTabItem("Avocado")) 2303 { 2304 ImGui::Text("This is the Avocado tab!\nblah blah blah blah blah"); 2305 ImGui::EndTabItem(); 2306 } 2307 if (ImGui::BeginTabItem("Broccoli")) 2308 { 2309 ImGui::Text("This is the Broccoli tab!\nblah blah blah blah blah"); 2310 ImGui::EndTabItem(); 2311 } 2312 if (ImGui::BeginTabItem("Cucumber")) 2313 { 2314 ImGui::Text("This is the Cucumber tab!\nblah blah blah blah blah"); 2315 ImGui::EndTabItem(); 2316 } 2317 ImGui::EndTabBar(); 2318 } 2319 ImGui::Separator(); 2320 ImGui::TreePop(); 2321 } 2322 2323 if (ImGui::TreeNode("Advanced & Close Button")) 2324 { 2325 // Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0). 2326 static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable; 2327 ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_Reorderable); 2328 ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs); 2329 ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton); 2330 ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton); 2331 if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0) 2332 tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_; 2333 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown)) 2334 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown); 2335 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll)) 2336 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll); 2337 2338 // Tab Bar 2339 const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" }; 2340 static bool opened[4] = { true, true, true, true }; // Persistent user state 2341 for (int n = 0; n < IM_ARRAYSIZE(opened); n++) 2342 { 2343 if (n > 0) { ImGui::SameLine(); } 2344 ImGui::Checkbox(names[n], &opened[n]); 2345 } 2346 2347 // Passing a bool* to BeginTabItem() is similar to passing one to Begin(): 2348 // the underlying bool will be set to false when the tab is closed. 2349 if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) 2350 { 2351 for (int n = 0; n < IM_ARRAYSIZE(opened); n++) 2352 if (opened[n] && ImGui::BeginTabItem(names[n], &opened[n], ImGuiTabItemFlags_None)) 2353 { 2354 ImGui::Text("This is the %s tab!", names[n]); 2355 if (n & 1) 2356 ImGui::Text("I am an odd tab."); 2357 ImGui::EndTabItem(); 2358 } 2359 ImGui::EndTabBar(); 2360 } 2361 ImGui::Separator(); 2362 ImGui::TreePop(); 2363 } 2364 2365 if (ImGui::TreeNode("TabItemButton & Leading/Trailing flags")) 2366 { 2367 static ImVector<int> active_tabs; 2368 static int next_tab_id = 0; 2369 if (next_tab_id == 0) // Initialize with some default tabs 2370 for (int i = 0; i < 3; i++) 2371 active_tabs.push_back(next_tab_id++); 2372 2373 // TabItemButton() and Leading/Trailing flags are distinct features which we will demo together. 2374 // (It is possible to submit regular tabs with Leading/Trailing flags, or TabItemButton tabs without Leading/Trailing flags... 2375 // but they tend to make more sense together) 2376 static bool show_leading_button = true; 2377 static bool show_trailing_button = true; 2378 ImGui::Checkbox("Show Leading TabItemButton()", &show_leading_button); 2379 ImGui::Checkbox("Show Trailing TabItemButton()", &show_trailing_button); 2380 2381 // Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs 2382 static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_FittingPolicyResizeDown; 2383 ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton); 2384 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown)) 2385 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown); 2386 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll)) 2387 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll); 2388 2389 if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) 2390 { 2391 // Demo a Leading TabItemButton(): click the "?" button to open a menu 2392 if (show_leading_button) 2393 if (ImGui::TabItemButton("?", ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_NoTooltip)) 2394 ImGui::OpenPopup("MyHelpMenu"); 2395 if (ImGui::BeginPopup("MyHelpMenu")) 2396 { 2397 ImGui::Selectable("Hello!"); 2398 ImGui::EndPopup(); 2399 } 2400 2401 // Demo Trailing Tabs: click the "+" button to add a new tab (in your app you may want to use a font icon instead of the "+") 2402 // Note that we submit it before the regular tabs, but because of the ImGuiTabItemFlags_Trailing flag it will always appear at the end. 2403 if (show_trailing_button) 2404 if (ImGui::TabItemButton("+", ImGuiTabItemFlags_Trailing | ImGuiTabItemFlags_NoTooltip)) 2405 active_tabs.push_back(next_tab_id++); // Add new tab 2406 2407 // Submit our regular tabs 2408 for (int n = 0; n < active_tabs.Size; ) 2409 { 2410 bool open = true; 2411 char name[16]; 2412 snprintf(name, IM_ARRAYSIZE(name), "%04d", active_tabs[n]); 2413 if (ImGui::BeginTabItem(name, &open, ImGuiTabItemFlags_None)) 2414 { 2415 ImGui::Text("This is the %s tab!", name); 2416 ImGui::EndTabItem(); 2417 } 2418 2419 if (!open) 2420 active_tabs.erase(active_tabs.Data + n); 2421 else 2422 n++; 2423 } 2424 2425 ImGui::EndTabBar(); 2426 } 2427 ImGui::Separator(); 2428 ImGui::TreePop(); 2429 } 2430 ImGui::TreePop(); 2431 } 2432 2433 if (ImGui::TreeNode("Groups")) 2434 { 2435 HelpMarker( 2436 "BeginGroup() basically locks the horizontal position for new line. " 2437 "EndGroup() bundles the whole group so that you can use \"item\" functions such as " 2438 "IsItemHovered()/IsItemActive() or SameLine() etc. on the whole group."); 2439 ImGui::BeginGroup(); 2440 { 1273 2441 ImGui::BeginGroup(); 1274 2442 ImGui::Button("AAA"); … … 1284 2452 ImGui::EndGroup(); 1285 2453 if (ImGui::IsItemHovered()) 1286 ImGui::SetTooltip("First group hovered");1287 1288 1289 1290 1291 1292 1293 ImGui::Button("ACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x)*0.5f, size.y));1294 1295 ImGui::Button("REACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x)*0.5f, size.y));1296 1297 1298 1299 1300 1301 1302 1303 2454 ImGui::SetTooltip("First group hovered"); 2455 } 2456 // Capture the group size and create widgets using the same size 2457 ImVec2 size = ImGui::GetItemRectSize(); 2458 const float values[5] = { 0.5f, 0.20f, 0.80f, 0.60f, 0.25f }; 2459 ImGui::PlotHistogram("##values", values, IM_ARRAYSIZE(values), 0, NULL, 0.0f, 1.0f, size); 2460 2461 ImGui::Button("ACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y)); 2462 ImGui::SameLine(); 2463 ImGui::Button("REACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y)); 2464 ImGui::EndGroup(); 2465 ImGui::SameLine(); 2466 2467 ImGui::Button("LEVERAGE\nBUZZWORD", size); 2468 ImGui::SameLine(); 2469 2470 if (ImGui::ListBoxHeader("List", size)) 2471 { 1304 2472 ImGui::Selectable("Selected", true); 1305 2473 ImGui::Selectable("Not Selected", false); 1306 2474 ImGui::ListBoxFooter(); 1307 } 1308 1309 ImGui::TreePop(); 1310 } 1311 1312 if (ImGui::TreeNode("Text Baseline Alignment")) 1313 { 1314 ImGui::TextWrapped("(This is testing the vertical alignment that occurs on text to keep it at the same baseline as widgets. Lines only composed of text or \"small\" widgets fit in less vertical spaces than lines with normal widgets)"); 1315 1316 ImGui::Text("One\nTwo\nThree"); ImGui::SameLine(); 1317 ImGui::Text("Hello\nWorld"); ImGui::SameLine(); 1318 ImGui::Text("Banana"); 1319 1320 ImGui::Text("Banana"); ImGui::SameLine(); 1321 ImGui::Text("Hello\nWorld"); ImGui::SameLine(); 1322 ImGui::Text("One\nTwo\nThree"); 1323 1324 ImGui::Button("HOP##1"); ImGui::SameLine(); 1325 ImGui::Text("Banana"); ImGui::SameLine(); 1326 ImGui::Text("Hello\nWorld"); ImGui::SameLine(); 1327 ImGui::Text("Banana"); 1328 1329 ImGui::Button("HOP##2"); ImGui::SameLine(); 1330 ImGui::Text("Hello\nWorld"); ImGui::SameLine(); 1331 ImGui::Text("Banana"); 1332 1333 ImGui::Button("TEST##1"); ImGui::SameLine(); 1334 ImGui::Text("TEST"); ImGui::SameLine(); 1335 ImGui::SmallButton("TEST##2"); 1336 1337 ImGui::AlignTextToFramePadding(); // If your line starts with text, call this to align it to upcoming widgets. 1338 ImGui::Text("Text aligned to Widget"); ImGui::SameLine(); 1339 ImGui::Button("Widget##1"); ImGui::SameLine(); 1340 ImGui::Text("Widget"); ImGui::SameLine(); 1341 ImGui::SmallButton("Widget##2"); ImGui::SameLine(); 1342 ImGui::Button("Widget##3"); 1343 1344 // Tree 1345 const float spacing = ImGui::GetStyle().ItemInnerSpacing.x; 1346 ImGui::Button("Button##1"); 1347 ImGui::SameLine(0.0f, spacing); 1348 if (ImGui::TreeNode("Node##1")) { for (int i = 0; i < 6; i++) ImGui::BulletText("Item %d..", i); ImGui::TreePop(); } // Dummy tree data 1349 1350 ImGui::AlignTextToFramePadding(); // Vertically align text node a bit lower so it'll be vertically centered with upcoming widget. Otherwise you can use SmallButton (smaller fit). 1351 bool node_open = ImGui::TreeNode("Node##2"); // Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add child content. 1352 ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##2"); 1353 if (node_open) { for (int i = 0; i < 6; i++) ImGui::BulletText("Item %d..", i); ImGui::TreePop(); } // Dummy tree data 1354 1355 // Bullet 1356 ImGui::Button("Button##3"); 1357 ImGui::SameLine(0.0f, spacing); 1358 ImGui::BulletText("Bullet text"); 1359 1360 ImGui::AlignTextToFramePadding(); 1361 ImGui::BulletText("Node"); 1362 ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##4"); 1363 1364 ImGui::TreePop(); 1365 } 1366 1367 if (ImGui::TreeNode("Scrolling")) 1368 { 1369 ImGui::TextWrapped("(Use SetScrollHere() or SetScrollFromPosY() to scroll to a given position.)"); 1370 static bool track = true; 1371 static int track_line = 50, scroll_to_px = 200; 1372 ImGui::Checkbox("Track", &track); 1373 ImGui::PushItemWidth(100); 1374 ImGui::SameLine(130); track |= ImGui::DragInt("##line", &track_line, 0.25f, 0, 99, "Line = %.0f"); 1375 bool scroll_to = ImGui::Button("Scroll To Pos"); 1376 ImGui::SameLine(130); scroll_to |= ImGui::DragInt("##pos_y", &scroll_to_px, 1.00f, 0, 9999, "Y = %.0f px"); 1377 ImGui::PopItemWidth(); 1378 if (scroll_to) track = false; 1379 1380 for (int i = 0; i < 5; i++) 1381 { 2475 } 2476 2477 ImGui::TreePop(); 2478 } 2479 2480 if (ImGui::TreeNode("Text Baseline Alignment")) 2481 { 2482 { 2483 ImGui::BulletText("Text baseline:"); 2484 ImGui::SameLine(); HelpMarker( 2485 "This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. " 2486 "Lines only composed of text or \"small\" widgets use less vertical space than lines with framed widgets."); 2487 ImGui::Indent(); 2488 2489 ImGui::Text("KO Blahblah"); ImGui::SameLine(); 2490 ImGui::Button("Some framed item"); ImGui::SameLine(); 2491 HelpMarker("Baseline of button will look misaligned with text.."); 2492 2493 // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets. 2494 // (because we don't know what's coming after the Text() statement, we need to move the text baseline 2495 // down by FramePadding.y ahead of time) 2496 ImGui::AlignTextToFramePadding(); 2497 ImGui::Text("OK Blahblah"); ImGui::SameLine(); 2498 ImGui::Button("Some framed item"); ImGui::SameLine(); 2499 HelpMarker("We call AlignTextToFramePadding() to vertically align the text baseline by +FramePadding.y"); 2500 2501 // SmallButton() uses the same vertical padding as Text 2502 ImGui::Button("TEST##1"); ImGui::SameLine(); 2503 ImGui::Text("TEST"); ImGui::SameLine(); 2504 ImGui::SmallButton("TEST##2"); 2505 2506 // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets. 2507 ImGui::AlignTextToFramePadding(); 2508 ImGui::Text("Text aligned to framed item"); ImGui::SameLine(); 2509 ImGui::Button("Item##1"); ImGui::SameLine(); 2510 ImGui::Text("Item"); ImGui::SameLine(); 2511 ImGui::SmallButton("Item##2"); ImGui::SameLine(); 2512 ImGui::Button("Item##3"); 2513 2514 ImGui::Unindent(); 2515 } 2516 2517 ImGui::Spacing(); 2518 2519 { 2520 ImGui::BulletText("Multi-line text:"); 2521 ImGui::Indent(); 2522 ImGui::Text("One\nTwo\nThree"); ImGui::SameLine(); 2523 ImGui::Text("Hello\nWorld"); ImGui::SameLine(); 2524 ImGui::Text("Banana"); 2525 2526 ImGui::Text("Banana"); ImGui::SameLine(); 2527 ImGui::Text("Hello\nWorld"); ImGui::SameLine(); 2528 ImGui::Text("One\nTwo\nThree"); 2529 2530 ImGui::Button("HOP##1"); ImGui::SameLine(); 2531 ImGui::Text("Banana"); ImGui::SameLine(); 2532 ImGui::Text("Hello\nWorld"); ImGui::SameLine(); 2533 ImGui::Text("Banana"); 2534 2535 ImGui::Button("HOP##2"); ImGui::SameLine(); 2536 ImGui::Text("Hello\nWorld"); ImGui::SameLine(); 2537 ImGui::Text("Banana"); 2538 ImGui::Unindent(); 2539 } 2540 2541 ImGui::Spacing(); 2542 2543 { 2544 ImGui::BulletText("Misc items:"); 2545 ImGui::Indent(); 2546 2547 // SmallButton() sets FramePadding to zero. Text baseline is aligned to match baseline of previous Button. 2548 ImGui::Button("80x80", ImVec2(80, 80)); 2549 ImGui::SameLine(); 2550 ImGui::Button("50x50", ImVec2(50, 50)); 2551 ImGui::SameLine(); 2552 ImGui::Button("Button()"); 2553 ImGui::SameLine(); 2554 ImGui::SmallButton("SmallButton()"); 2555 2556 // Tree 2557 const float spacing = ImGui::GetStyle().ItemInnerSpacing.x; 2558 ImGui::Button("Button##1"); 2559 ImGui::SameLine(0.0f, spacing); 2560 if (ImGui::TreeNode("Node##1")) 2561 { 2562 // Placeholder tree data 2563 for (int i = 0; i < 6; i++) 2564 ImGui::BulletText("Item %d..", i); 2565 ImGui::TreePop(); 2566 } 2567 2568 // Vertically align text node a bit lower so it'll be vertically centered with upcoming widget. 2569 // Otherwise you can use SmallButton() (smaller fit). 2570 ImGui::AlignTextToFramePadding(); 2571 2572 // Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add 2573 // other contents below the node. 2574 bool node_open = ImGui::TreeNode("Node##2"); 2575 ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##2"); 2576 if (node_open) 2577 { 2578 // Placeholder tree data 2579 for (int i = 0; i < 6; i++) 2580 ImGui::BulletText("Item %d..", i); 2581 ImGui::TreePop(); 2582 } 2583 2584 // Bullet 2585 ImGui::Button("Button##3"); 2586 ImGui::SameLine(0.0f, spacing); 2587 ImGui::BulletText("Bullet text"); 2588 2589 ImGui::AlignTextToFramePadding(); 2590 ImGui::BulletText("Node"); 2591 ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##4"); 2592 ImGui::Unindent(); 2593 } 2594 2595 ImGui::TreePop(); 2596 } 2597 2598 if (ImGui::TreeNode("Scrolling")) 2599 { 2600 // Vertical scroll functions 2601 HelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given vertical position."); 2602 2603 static int track_item = 50; 2604 static bool enable_track = true; 2605 static bool enable_extra_decorations = false; 2606 static float scroll_to_off_px = 0.0f; 2607 static float scroll_to_pos_px = 200.0f; 2608 2609 ImGui::Checkbox("Decoration", &enable_extra_decorations); 2610 2611 ImGui::Checkbox("Track", &enable_track); 2612 ImGui::PushItemWidth(100); 2613 ImGui::SameLine(140); enable_track |= ImGui::DragInt("##item", &track_item, 0.25f, 0, 99, "Item = %d"); 2614 2615 bool scroll_to_off = ImGui::Button("Scroll Offset"); 2616 ImGui::SameLine(140); scroll_to_off |= ImGui::DragFloat("##off", &scroll_to_off_px, 1.00f, 0, FLT_MAX, "+%.0f px"); 2617 2618 bool scroll_to_pos = ImGui::Button("Scroll To Pos"); 2619 ImGui::SameLine(140); scroll_to_pos |= ImGui::DragFloat("##pos", &scroll_to_pos_px, 1.00f, -10, FLT_MAX, "X/Y = %.0f px"); 2620 ImGui::PopItemWidth(); 2621 2622 if (scroll_to_off || scroll_to_pos) 2623 enable_track = false; 2624 2625 ImGuiStyle& style = ImGui::GetStyle(); 2626 float child_w = (ImGui::GetContentRegionAvail().x - 4 * style.ItemSpacing.x) / 5; 2627 if (child_w < 1.0f) 2628 child_w = 1.0f; 2629 ImGui::PushID("##VerticalScrolling"); 2630 for (int i = 0; i < 5; i++) 2631 { 1382 2632 if (i > 0) ImGui::SameLine(); 1383 2633 ImGui::BeginGroup(); 1384 ImGui::Text("%s", i == 0 ? "Top" : i == 1 ? "25%" : i == 2 ? "Center" : i == 3 ? "75%" : "Bottom"); 1385 ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(ImGui::GetWindowWidth() * 0.17f, 200.0f), true); 1386 if (scroll_to) 1387 ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_px, i * 0.25f); 1388 for (int line = 0; line < 100; line++) 1389 { 1390 if (track && line == track_line) 1391 { 1392 ImGui::TextColored(ImColor(255, 255, 0), "Line %d", line); 1393 ImGui::SetScrollHere(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom 1394 } 1395 else 1396 { 1397 ImGui::Text("Line %d", line); 1398 } 1399 } 1400 float scroll_y = ImGui::GetScrollY(), scroll_max_y = ImGui::GetScrollMaxY(); 2634 const char* names[] = { "Top", "25%", "Center", "75%", "Bottom" }; 2635 ImGui::TextUnformatted(names[i]); 2636 2637 const ImGuiWindowFlags child_flags = enable_extra_decorations ? ImGuiWindowFlags_MenuBar : 0; 2638 const ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i); 2639 const bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(child_w, 200.0f), true, child_flags); 2640 if (ImGui::BeginMenuBar()) 2641 { 2642 ImGui::TextUnformatted("abc"); 2643 ImGui::EndMenuBar(); 2644 } 2645 if (scroll_to_off) 2646 ImGui::SetScrollY(scroll_to_off_px); 2647 if (scroll_to_pos) 2648 ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_pos_px, i * 0.25f); 2649 if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items 2650 { 2651 for (int item = 0; item < 100; item++) 2652 { 2653 if (enable_track && item == track_item) 2654 { 2655 ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item); 2656 ImGui::SetScrollHereY(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom 2657 } 2658 else 2659 { 2660 ImGui::Text("Item %d", item); 2661 } 2662 } 2663 } 2664 float scroll_y = ImGui::GetScrollY(); 2665 float scroll_max_y = ImGui::GetScrollMaxY(); 1401 2666 ImGui::EndChild(); 1402 ImGui::Text("%.0f/% 0.f", scroll_y, scroll_max_y);2667 ImGui::Text("%.0f/%.0f", scroll_y, scroll_max_y); 1403 2668 ImGui::EndGroup(); 1404 } 1405 ImGui::TreePop(); 1406 } 1407 1408 if (ImGui::TreeNode("Horizontal Scrolling")) 1409 { 1410 ImGui::Bullet(); ImGui::TextWrapped("Horizontal scrolling for a window has to be enabled explicitly via the ImGuiWindowFlags_HorizontalScrollbar flag."); 1411 ImGui::Bullet(); ImGui::TextWrapped("You may want to explicitly specify content width by calling SetNextWindowContentWidth() before Begin()."); 1412 static int lines = 7; 1413 ImGui::SliderInt("Lines", &lines, 1, 15); 1414 ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); 1415 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f)); 1416 ImGui::BeginChild("scrolling", ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30), true, ImGuiWindowFlags_HorizontalScrollbar); 1417 for (int line = 0; line < lines; line++) 1418 { 1419 // Display random stuff (for the sake of this trivial demo we are using basic Button+SameLine. If you want to create your own time line for a real application you may be better off 1420 // manipulating the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets yourself. You may also want to use the lower-level ImDrawList API) 2669 } 2670 ImGui::PopID(); 2671 2672 // Horizontal scroll functions 2673 ImGui::Spacing(); 2674 HelpMarker( 2675 "Use SetScrollHereX() or SetScrollFromPosX() to scroll to a given horizontal position.\n\n" 2676 "Because the clipping rectangle of most window hides half worth of WindowPadding on the " 2677 "left/right, using SetScrollFromPosX(+1) will usually result in clipped text whereas the " 2678 "equivalent SetScrollFromPosY(+1) wouldn't."); 2679 ImGui::PushID("##HorizontalScrolling"); 2680 for (int i = 0; i < 5; i++) 2681 { 2682 float child_height = ImGui::GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0f; 2683 ImGuiWindowFlags child_flags = ImGuiWindowFlags_HorizontalScrollbar | (enable_extra_decorations ? ImGuiWindowFlags_AlwaysVerticalScrollbar : 0); 2684 ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i); 2685 bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(-100, child_height), true, child_flags); 2686 if (scroll_to_off) 2687 ImGui::SetScrollX(scroll_to_off_px); 2688 if (scroll_to_pos) 2689 ImGui::SetScrollFromPosX(ImGui::GetCursorStartPos().x + scroll_to_pos_px, i * 0.25f); 2690 if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items 2691 { 2692 for (int item = 0; item < 100; item++) 2693 { 2694 if (enable_track && item == track_item) 2695 { 2696 ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item); 2697 ImGui::SetScrollHereX(i * 0.25f); // 0.0f:left, 0.5f:center, 1.0f:right 2698 } 2699 else 2700 { 2701 ImGui::Text("Item %d", item); 2702 } 2703 ImGui::SameLine(); 2704 } 2705 } 2706 float scroll_x = ImGui::GetScrollX(); 2707 float scroll_max_x = ImGui::GetScrollMaxX(); 2708 ImGui::EndChild(); 2709 ImGui::SameLine(); 2710 const char* names[] = { "Left", "25%", "Center", "75%", "Right" }; 2711 ImGui::Text("%s\n%.0f/%.0f", names[i], scroll_x, scroll_max_x); 2712 ImGui::Spacing(); 2713 } 2714 ImGui::PopID(); 2715 2716 // Miscellaneous Horizontal Scrolling Demo 2717 HelpMarker( 2718 "Horizontal scrolling for a window is enabled via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\n" 2719 "You may want to also explicitly specify content width by using SetNextWindowContentWidth() before Begin()."); 2720 static int lines = 7; 2721 ImGui::SliderInt("Lines", &lines, 1, 15); 2722 ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); 2723 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f)); 2724 ImVec2 scrolling_child_size = ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30); 2725 ImGui::BeginChild("scrolling", scrolling_child_size, true, ImGuiWindowFlags_HorizontalScrollbar); 2726 for (int line = 0; line < lines; line++) 2727 { 2728 // Display random stuff. For the sake of this trivial demo we are using basic Button() + SameLine() 2729 // If you want to create your own time line for a real application you may be better off manipulating 2730 // the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets 2731 // yourself. You may also want to use the lower-level ImDrawList API. 1421 2732 int num_buttons = 10 + ((line & 1) ? line * 9 : line * 3); 1422 2733 for (int n = 0; n < num_buttons; n++) 1423 2734 { 1424 if (n > 0) ImGui::SameLine(); 1425 ImGui::PushID(n + line * 1000); 1426 char num_buf[16]; 1427 sprintf(num_buf, "%d", n); 1428 const char* label = (!(n % 15)) ? "FizzBuzz" : (!(n % 3)) ? "Fizz" : (!(n % 5)) ? "Buzz" : num_buf; 1429 float hue = n * 0.05f; 1430 ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(hue, 0.6f, 0.6f)); 1431 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(hue, 0.7f, 0.7f)); 1432 ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(hue, 0.8f, 0.8f)); 1433 ImGui::Button(label, ImVec2(40.0f + sinf((float)(line + n)) * 20.0f, 0.0f)); 1434 ImGui::PopStyleColor(3); 1435 ImGui::PopID(); 1436 } 1437 } 1438 float scroll_x = ImGui::GetScrollX(), scroll_max_x = ImGui::GetScrollMaxX(); 1439 ImGui::EndChild(); 1440 ImGui::PopStyleVar(2); 1441 float scroll_x_delta = 0.0f; 1442 ImGui::SmallButton("<<"); if (ImGui::IsItemActive()) scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f; ImGui::SameLine(); 1443 ImGui::Text("Scroll from code"); ImGui::SameLine(); 1444 ImGui::SmallButton(">>"); if (ImGui::IsItemActive()) scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f; ImGui::SameLine(); 1445 ImGui::Text("%.0f/%.0f", scroll_x, scroll_max_x); 1446 if (scroll_x_delta != 0.0f) 1447 { 1448 ImGui::BeginChild("scrolling"); // Demonstrate a trick: you can use Begin to set yourself in the context of another window (here we are already out of your child window) 2735 if (n > 0) ImGui::SameLine(); 2736 ImGui::PushID(n + line * 1000); 2737 char num_buf[16]; 2738 sprintf(num_buf, "%d", n); 2739 const char* label = (!(n % 15)) ? "FizzBuzz" : (!(n % 3)) ? "Fizz" : (!(n % 5)) ? "Buzz" : num_buf; 2740 float hue = n * 0.05f; 2741 ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(hue, 0.6f, 0.6f)); 2742 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(hue, 0.7f, 0.7f)); 2743 ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(hue, 0.8f, 0.8f)); 2744 ImGui::Button(label, ImVec2(40.0f + sinf((float)(line + n)) * 20.0f, 0.0f)); 2745 ImGui::PopStyleColor(3); 2746 ImGui::PopID(); 2747 } 2748 } 2749 float scroll_x = ImGui::GetScrollX(); 2750 float scroll_max_x = ImGui::GetScrollMaxX(); 2751 ImGui::EndChild(); 2752 ImGui::PopStyleVar(2); 2753 float scroll_x_delta = 0.0f; 2754 ImGui::SmallButton("<<"); 2755 if (ImGui::IsItemActive()) 2756 scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f; 2757 ImGui::SameLine(); 2758 ImGui::Text("Scroll from code"); ImGui::SameLine(); 2759 ImGui::SmallButton(">>"); 2760 if (ImGui::IsItemActive()) 2761 scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f; 2762 ImGui::SameLine(); 2763 ImGui::Text("%.0f/%.0f", scroll_x, scroll_max_x); 2764 if (scroll_x_delta != 0.0f) 2765 { 2766 // Demonstrate a trick: you can use Begin to set yourself in the context of another window 2767 // (here we are already out of your child window) 2768 ImGui::BeginChild("scrolling"); 1449 2769 ImGui::SetScrollX(ImGui::GetScrollX() + scroll_x_delta); 2770 ImGui::EndChild(); 2771 } 2772 ImGui::Spacing(); 2773 2774 static bool show_horizontal_contents_size_demo_window = false; 2775 ImGui::Checkbox("Show Horizontal contents size demo window", &show_horizontal_contents_size_demo_window); 2776 2777 if (show_horizontal_contents_size_demo_window) 2778 { 2779 static bool show_h_scrollbar = true; 2780 static bool show_button = true; 2781 static bool show_tree_nodes = true; 2782 static bool show_text_wrapped = false; 2783 static bool show_columns = true; 2784 static bool show_tab_bar = true; 2785 static bool show_child = false; 2786 static bool explicit_content_size = false; 2787 static float contents_size_x = 300.0f; 2788 if (explicit_content_size) 2789 ImGui::SetNextWindowContentSize(ImVec2(contents_size_x, 0.0f)); 2790 ImGui::Begin("Horizontal contents size demo window", &show_horizontal_contents_size_demo_window, show_h_scrollbar ? ImGuiWindowFlags_HorizontalScrollbar : 0); 2791 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 0)); 2792 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 0)); 2793 HelpMarker("Test of different widgets react and impact the work rectangle growing when horizontal scrolling is enabled.\n\nUse 'Metrics->Tools->Show windows rectangles' to visualize rectangles."); 2794 ImGui::Checkbox("H-scrollbar", &show_h_scrollbar); 2795 ImGui::Checkbox("Button", &show_button); // Will grow contents size (unless explicitly overwritten) 2796 ImGui::Checkbox("Tree nodes", &show_tree_nodes); // Will grow contents size and display highlight over full width 2797 ImGui::Checkbox("Text wrapped", &show_text_wrapped);// Will grow and use contents size 2798 ImGui::Checkbox("Columns", &show_columns); // Will use contents size 2799 ImGui::Checkbox("Tab bar", &show_tab_bar); // Will use contents size 2800 ImGui::Checkbox("Child", &show_child); // Will grow and use contents size 2801 ImGui::Checkbox("Explicit content size", &explicit_content_size); 2802 ImGui::Text("Scroll %.1f/%.1f %.1f/%.1f", ImGui::GetScrollX(), ImGui::GetScrollMaxX(), ImGui::GetScrollY(), ImGui::GetScrollMaxY()); 2803 if (explicit_content_size) 2804 { 2805 ImGui::SameLine(); 2806 ImGui::SetNextItemWidth(100); 2807 ImGui::DragFloat("##csx", &contents_size_x); 2808 ImVec2 p = ImGui::GetCursorScreenPos(); 2809 ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + 10, p.y + 10), IM_COL32_WHITE); 2810 ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(p.x + contents_size_x - 10, p.y), ImVec2(p.x + contents_size_x, p.y + 10), IM_COL32_WHITE); 2811 ImGui::Dummy(ImVec2(0, 10)); 2812 } 2813 ImGui::PopStyleVar(2); 2814 ImGui::Separator(); 2815 if (show_button) 2816 { 2817 ImGui::Button("this is a 300-wide button", ImVec2(300, 0)); 2818 } 2819 if (show_tree_nodes) 2820 { 2821 bool open = true; 2822 if (ImGui::TreeNode("this is a tree node")) 2823 { 2824 if (ImGui::TreeNode("another one of those tree node...")) 2825 { 2826 ImGui::Text("Some tree contents"); 2827 ImGui::TreePop(); 2828 } 2829 ImGui::TreePop(); 2830 } 2831 ImGui::CollapsingHeader("CollapsingHeader", &open); 2832 } 2833 if (show_text_wrapped) 2834 { 2835 ImGui::TextWrapped("This text should automatically wrap on the edge of the work rectangle."); 2836 } 2837 if (show_columns) 2838 { 2839 ImGui::Columns(4); 2840 for (int n = 0; n < 4; n++) 2841 { 2842 ImGui::Text("Width %.2f", ImGui::GetColumnWidth()); 2843 ImGui::NextColumn(); 2844 } 2845 ImGui::Columns(1); 2846 } 2847 if (show_tab_bar && ImGui::BeginTabBar("Hello")) 2848 { 2849 if (ImGui::BeginTabItem("OneOneOne")) { ImGui::EndTabItem(); } 2850 if (ImGui::BeginTabItem("TwoTwoTwo")) { ImGui::EndTabItem(); } 2851 if (ImGui::BeginTabItem("ThreeThreeThree")) { ImGui::EndTabItem(); } 2852 if (ImGui::BeginTabItem("FourFourFour")) { ImGui::EndTabItem(); } 2853 ImGui::EndTabBar(); 2854 } 2855 if (show_child) 2856 { 2857 ImGui::BeginChild("child", ImVec2(0, 0), true); 2858 ImGui::EndChild(); 2859 } 1450 2860 ImGui::End(); 1451 } 1452 ImGui::TreePop(); 1453 } 1454 1455 if (ImGui::TreeNode("Clipping")) 1456 { 1457 static ImVec2 size(100, 100), offset(50, 20); 1458 ImGui::TextWrapped("On a per-widget basis we are occasionally clipping text CPU-side if it won't fit in its frame. Otherwise we are doing coarser clipping + passing a scissor rectangle to the renderer. The system is designed to try minimizing both execution and CPU/GPU rendering cost."); 1459 ImGui::DragFloat2("size", (float*)&size, 0.5f, 0.0f, 200.0f, "%.0f"); 1460 ImGui::TextWrapped("(Click and drag)"); 1461 ImVec2 pos = ImGui::GetCursorScreenPos(); 1462 ImVec4 clip_rect(pos.x, pos.y, pos.x + size.x, pos.y + size.y); 1463 ImGui::InvisibleButton("##dummy", size); 1464 if (ImGui::IsItemActive() && ImGui::IsMouseDragging()) { offset.x += ImGui::GetIO().MouseDelta.x; offset.y += ImGui::GetIO().MouseDelta.y; } 1465 ImGui::GetWindowDrawList()->AddRectFilled(pos, ImVec2(pos.x + size.x, pos.y + size.y), IM_COL32(90, 90, 120, 255)); 1466 ImGui::GetWindowDrawList()->AddText(ImGui::GetFont(), ImGui::GetFontSize()*2.0f, ImVec2(pos.x + offset.x, pos.y + offset.y), IM_COL32(255, 255, 255, 255), "Line 1 hello\nLine 2 clip me!", NULL, 0.0f, &clip_rect); 1467 ImGui::TreePop(); 1468 } 1469 } 1470 1471 if (ImGui::CollapsingHeader("Popups & Modal windows")) 1472 { 1473 if (ImGui::TreeNode("Popups")) 1474 { 1475 ImGui::TextWrapped("When a popup is active, it inhibits interacting with windows that are behind the popup. Clicking outside the popup closes it."); 1476 1477 static int selected_fish = -1; 1478 const char* names[] = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" }; 1479 static bool toggles[] = { true, false, false, false, false }; 1480 1481 // Simple selection popup 1482 // (If you want to show the current selection inside the Button itself, you may want to build a string using the "###" operator to preserve a constant ID with a variable label) 1483 if (ImGui::Button("Select..")) 1484 ImGui::OpenPopup("select"); 1485 ImGui::SameLine(); 1486 ImGui::TextUnformatted(selected_fish == -1 ? "<None>" : names[selected_fish]); 1487 if (ImGui::BeginPopup("select")) 1488 { 2861 } 2862 2863 ImGui::TreePop(); 2864 } 2865 2866 if (ImGui::TreeNode("Clipping")) 2867 { 2868 static ImVec2 size(100.0f, 100.0f); 2869 static ImVec2 offset(30.0f, 30.0f); 2870 ImGui::DragFloat2("size", (float*)&size, 0.5f, 1.0f, 200.0f, "%.0f"); 2871 ImGui::TextWrapped("(Click and drag to scroll)"); 2872 2873 for (int n = 0; n < 3; n++) 2874 { 2875 if (n > 0) 2876 ImGui::SameLine(); 2877 ImGui::PushID(n); 2878 ImGui::BeginGroup(); // Lock X position 2879 2880 ImGui::InvisibleButton("##empty", size); 2881 if (ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left)) 2882 { 2883 offset.x += ImGui::GetIO().MouseDelta.x; 2884 offset.y += ImGui::GetIO().MouseDelta.y; 2885 } 2886 const ImVec2 p0 = ImGui::GetItemRectMin(); 2887 const ImVec2 p1 = ImGui::GetItemRectMax(); 2888 const char* text_str = "Line 1 hello\nLine 2 clip me!"; 2889 const ImVec2 text_pos = ImVec2(p0.x + offset.x, p0.y + offset.y); 2890 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 2891 2892 switch (n) 2893 { 2894 case 0: 2895 HelpMarker( 2896 "Using ImGui::PushClipRect():\n" 2897 "Will alter ImGui hit-testing logic + ImDrawList rendering.\n" 2898 "(use this if you want your clipping rectangle to affect interactions)"); 2899 ImGui::PushClipRect(p0, p1, true); 2900 draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)); 2901 draw_list->AddText(text_pos, IM_COL32_WHITE, text_str); 2902 ImGui::PopClipRect(); 2903 break; 2904 case 1: 2905 HelpMarker( 2906 "Using ImDrawList::PushClipRect():\n" 2907 "Will alter ImDrawList rendering only.\n" 2908 "(use this as a shortcut if you are only using ImDrawList calls)"); 2909 draw_list->PushClipRect(p0, p1, true); 2910 draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)); 2911 draw_list->AddText(text_pos, IM_COL32_WHITE, text_str); 2912 draw_list->PopClipRect(); 2913 break; 2914 case 2: 2915 HelpMarker( 2916 "Using ImDrawList::AddText() with a fine ClipRect:\n" 2917 "Will alter only this specific ImDrawList::AddText() rendering.\n" 2918 "(this is often used internally to avoid altering the clipping rectangle and minimize draw calls)"); 2919 ImVec4 clip_rect(p0.x, p0.y, p1.x, p1.y); // AddText() takes a ImVec4* here so let's convert. 2920 draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)); 2921 draw_list->AddText(ImGui::GetFont(), ImGui::GetFontSize(), text_pos, IM_COL32_WHITE, text_str, NULL, 0.0f, &clip_rect); 2922 break; 2923 } 2924 ImGui::EndGroup(); 2925 ImGui::PopID(); 2926 } 2927 2928 ImGui::TreePop(); 2929 } 2930 } 2931 2932 static void ShowDemoWindowPopups() 2933 { 2934 if (!ImGui::CollapsingHeader("Popups & Modal windows")) 2935 return; 2936 2937 // The properties of popups windows are: 2938 // - They block normal mouse hovering detection outside them. (*) 2939 // - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE. 2940 // - Their visibility state (~bool) is held internally by Dear ImGui instead of being held by the programmer as 2941 // we are used to with regular Begin() calls. User can manipulate the visibility state by calling OpenPopup(). 2942 // (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even 2943 // when normally blocked by a popup. 2944 // Those three properties are connected. The library needs to hold their visibility state BECAUSE it can close 2945 // popups at any time. 2946 2947 // Typical use for regular windows: 2948 // bool my_tool_is_active = false; if (ImGui::Button("Open")) my_tool_is_active = true; [...] if (my_tool_is_active) Begin("My Tool", &my_tool_is_active) { [...] } End(); 2949 // Typical use for popups: 2950 // if (ImGui::Button("Open")) ImGui::OpenPopup("MyPopup"); if (ImGui::BeginPopup("MyPopup") { [...] EndPopup(); } 2951 2952 // With popups we have to go through a library call (here OpenPopup) to manipulate the visibility state. 2953 // This may be a bit confusing at first but it should quickly make sense. Follow on the examples below. 2954 2955 if (ImGui::TreeNode("Popups")) 2956 { 2957 ImGui::TextWrapped( 2958 "When a popup is active, it inhibits interacting with windows that are behind the popup. " 2959 "Clicking outside the popup closes it."); 2960 2961 static int selected_fish = -1; 2962 const char* names[] = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" }; 2963 static bool toggles[] = { true, false, false, false, false }; 2964 2965 // Simple selection popup (if you want to show the current selection inside the Button itself, 2966 // you may want to build a string using the "###" operator to preserve a constant ID with a variable label) 2967 if (ImGui::Button("Select..")) 2968 ImGui::OpenPopup("my_select_popup"); 2969 ImGui::SameLine(); 2970 ImGui::TextUnformatted(selected_fish == -1 ? "<None>" : names[selected_fish]); 2971 if (ImGui::BeginPopup("my_select_popup")) 2972 { 1489 2973 ImGui::Text("Aquarium"); 1490 2974 ImGui::Separator(); 1491 2975 for (int i = 0; i < IM_ARRAYSIZE(names); i++) 1492 if (ImGui::Selectable(names[i]))1493 selected_fish = i;2976 if (ImGui::Selectable(names[i])) 2977 selected_fish = i; 1494 2978 ImGui::EndPopup(); 1495 1496 1497 1498 1499 ImGui::OpenPopup(" toggle");1500 if (ImGui::BeginPopup("toggle"))1501 2979 } 2980 2981 // Showing a menu with toggles 2982 if (ImGui::Button("Toggle..")) 2983 ImGui::OpenPopup("my_toggle_popup"); 2984 if (ImGui::BeginPopup("my_toggle_popup")) 2985 { 1502 2986 for (int i = 0; i < IM_ARRAYSIZE(names); i++) 1503 ImGui::MenuItem(names[i], "", &toggles[i]);2987 ImGui::MenuItem(names[i], "", &toggles[i]); 1504 2988 if (ImGui::BeginMenu("Sub-menu")) 1505 2989 { 1506 ImGui::MenuItem("Click me");1507 ImGui::EndMenu();2990 ImGui::MenuItem("Click me"); 2991 ImGui::EndMenu(); 1508 2992 } 1509 2993 … … 1511 2995 ImGui::Text("Tooltip here"); 1512 2996 if (ImGui::IsItemHovered()) 1513 ImGui::SetTooltip("I am a tooltip over a popup");2997 ImGui::SetTooltip("I am a tooltip over a popup"); 1514 2998 1515 2999 if (ImGui::Button("Stacked Popup")) 1516 ImGui::OpenPopup("another popup");3000 ImGui::OpenPopup("another popup"); 1517 3001 if (ImGui::BeginPopup("another popup")) 1518 3002 { 1519 for (int i = 0; i < IM_ARRAYSIZE(names); i++) 1520 ImGui::MenuItem(names[i], "", &toggles[i]); 1521 if (ImGui::BeginMenu("Sub-menu")) 1522 { 1523 ImGui::MenuItem("Click me"); 1524 ImGui::EndMenu(); 1525 } 1526 ImGui::EndPopup(); 3003 for (int i = 0; i < IM_ARRAYSIZE(names); i++) 3004 ImGui::MenuItem(names[i], "", &toggles[i]); 3005 if (ImGui::BeginMenu("Sub-menu")) 3006 { 3007 ImGui::MenuItem("Click me"); 3008 if (ImGui::Button("Stacked Popup")) 3009 ImGui::OpenPopup("another popup"); 3010 if (ImGui::BeginPopup("another popup")) 3011 { 3012 ImGui::Text("I am the last one here."); 3013 ImGui::EndPopup(); 3014 } 3015 ImGui::EndMenu(); 3016 } 3017 ImGui::EndPopup(); 1527 3018 } 1528 3019 ImGui::EndPopup(); 1529 } 1530 1531 if (ImGui::Button("Popup Menu..")) 1532 ImGui::OpenPopup("FilePopup"); 1533 if (ImGui::BeginPopup("FilePopup")) 1534 { 3020 } 3021 3022 // Call the more complete ShowExampleMenuFile which we use in various places of this demo 3023 if (ImGui::Button("File Menu..")) 3024 ImGui::OpenPopup("my_file_popup"); 3025 if (ImGui::BeginPopup("my_file_popup")) 3026 { 1535 3027 ShowExampleMenuFile(); 1536 3028 ImGui::EndPopup(); 1537 } 1538 1539 ImGui::TreePop(); 1540 } 1541 1542 if (ImGui::TreeNode("Context menus")) 1543 { 1544 // BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing: 1545 // if (IsItemHovered() && IsMouseClicked(0)) 1546 // OpenPopup(id); 1547 // return BeginPopup(id); 1548 // For more advanced uses you may want to replicate and cuztomize this code. This the comments inside BeginPopupContextItem() implementation. 1549 static float value = 0.5f; 1550 ImGui::Text("Value = %.3f (<-- right-click here)", value); 1551 if (ImGui::BeginPopupContextItem("item context menu")) 1552 { 3029 } 3030 3031 ImGui::TreePop(); 3032 } 3033 3034 if (ImGui::TreeNode("Context menus")) 3035 { 3036 // BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing: 3037 // if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right)) 3038 // OpenPopup(id); 3039 // return BeginPopup(id); 3040 // For more advanced uses you may want to replicate and customize this code. 3041 // See details in BeginPopupContextItem(). 3042 static float value = 0.5f; 3043 ImGui::Text("Value = %.3f (<-- right-click here)", value); 3044 if (ImGui::BeginPopupContextItem("item context menu")) 3045 { 1553 3046 if (ImGui::Selectable("Set to zero")) value = 0.0f; 1554 3047 if (ImGui::Selectable("Set to PI")) value = 3.1415f; 1555 ImGui:: PushItemWidth(-1);3048 ImGui::SetNextItemWidth(-1); 1556 3049 ImGui::DragFloat("##Value", &value, 0.1f, 0.0f, 0.0f); 1557 ImGui::PopItemWidth();1558 3050 ImGui::EndPopup(); 1559 } 1560 1561 static char name[32] = "Label1"; 1562 char buf[64]; sprintf(buf, "Button: %s###Button", name); // ### operator override ID ignoring the preceding label 1563 ImGui::Button(buf); 1564 if (ImGui::BeginPopupContextItem()) // When used after an item that has an ID (here the Button), we can skip providing an ID to BeginPopupContextItem(). 1565 { 3051 } 3052 3053 // We can also use OpenPopupOnItemClick() which is the same as BeginPopupContextItem() but without the 3054 // Begin() call. So here we will make it that clicking on the text field with the right mouse button (1) 3055 // will toggle the visibility of the popup above. 3056 ImGui::Text("(You can also right-click me to open the same popup as above.)"); 3057 ImGui::OpenPopupOnItemClick("item context menu", 1); 3058 3059 // When used after an item that has an ID (e.g.Button), we can skip providing an ID to BeginPopupContextItem(). 3060 // BeginPopupContextItem() will use the last item ID as the popup ID. 3061 // In addition here, we want to include your editable label inside the button label. 3062 // We use the ### operator to override the ID (read FAQ about ID for details) 3063 static char name[32] = "Label1"; 3064 char buf[64]; 3065 sprintf(buf, "Button: %s###Button", name); // ### operator override ID ignoring the preceding label 3066 ImGui::Button(buf); 3067 if (ImGui::BeginPopupContextItem()) 3068 { 1566 3069 ImGui::Text("Edit name:"); 1567 3070 ImGui::InputText("##edit", name, IM_ARRAYSIZE(name)); 1568 3071 if (ImGui::Button("Close")) 1569 ImGui::CloseCurrentPopup();3072 ImGui::CloseCurrentPopup(); 1570 3073 ImGui::EndPopup(); 1571 1572 1573 1574 1575 1576 1577 1578 1579 ImGui::TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside the window.");1580 1581 3074 } 3075 ImGui::SameLine(); ImGui::Text("(<-- right-click here)"); 3076 3077 ImGui::TreePop(); 3078 } 3079 3080 if (ImGui::TreeNode("Modals")) 3081 { 3082 ImGui::TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside."); 3083 3084 if (ImGui::Button("Delete..")) 1582 3085 ImGui::OpenPopup("Delete?"); 1583 if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize)) 1584 { 3086 3087 // Always center this window when appearing 3088 ImVec2 center(ImGui::GetIO().DisplaySize.x * 0.5f, ImGui::GetIO().DisplaySize.y * 0.5f); 3089 ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); 3090 3091 if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize)) 3092 { 1585 3093 ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!\n\n"); 1586 3094 ImGui::Separator(); 1587 3095 1588 //static int dummy_i = 0;1589 //ImGui::Combo("Combo", & dummy_i, "Delete\0Delete harder\0");3096 //static int unused_i = 0; 3097 //ImGui::Combo("Combo", &unused_i, "Delete\0Delete harder\0"); 1590 3098 1591 3099 static bool dont_ask_me_next_time = false; … … 1599 3107 if (ImGui::Button("Cancel", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); } 1600 3108 ImGui::EndPopup(); 1601 1602 1603 3109 } 3110 3111 if (ImGui::Button("Stacked modals..")) 1604 3112 ImGui::OpenPopup("Stacked 1"); 1605 if (ImGui::BeginPopupModal("Stacked 1")) 1606 { 1607 ImGui::Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDarkening] for darkening."); 3113 if (ImGui::BeginPopupModal("Stacked 1", NULL, ImGuiWindowFlags_MenuBar)) 3114 { 3115 if (ImGui::BeginMenuBar()) 3116 { 3117 if (ImGui::BeginMenu("File")) 3118 { 3119 if (ImGui::MenuItem("Some menu item")) {} 3120 ImGui::EndMenu(); 3121 } 3122 ImGui::EndMenuBar(); 3123 } 3124 ImGui::Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it."); 3125 3126 // Testing behavior of widgets stacking their own regular popups over the modal. 1608 3127 static int item = 1; 3128 static float color[4] = { 0.4f, 0.7f, 0.0f, 0.5f }; 1609 3129 ImGui::Combo("Combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); 1610 static float color[4] = { 0.4f,0.7f,0.0f,0.5f }; 1611 ImGui::ColorEdit4("color", color); // This is to test behavior of stacked regular popups over a modal 3130 ImGui::ColorEdit4("color", color); 1612 3131 1613 3132 if (ImGui::Button("Add another modal..")) 1614 ImGui::OpenPopup("Stacked 2"); 1615 if (ImGui::BeginPopupModal("Stacked 2")) 1616 { 1617 ImGui::Text("Hello from Stacked The Second!"); 1618 if (ImGui::Button("Close")) 1619 ImGui::CloseCurrentPopup(); 1620 ImGui::EndPopup(); 3133 ImGui::OpenPopup("Stacked 2"); 3134 3135 // Also demonstrate passing a bool* to BeginPopupModal(), this will create a regular close button which 3136 // will close the popup. Note that the visibility state of popups is owned by imgui, so the input value 3137 // of the bool actually doesn't matter here. 3138 bool unused_open = true; 3139 if (ImGui::BeginPopupModal("Stacked 2", &unused_open)) 3140 { 3141 ImGui::Text("Hello from Stacked The Second!"); 3142 if (ImGui::Button("Close")) 3143 ImGui::CloseCurrentPopup(); 3144 ImGui::EndPopup(); 1621 3145 } 1622 3146 1623 3147 if (ImGui::Button("Close")) 1624 ImGui::CloseCurrentPopup();3148 ImGui::CloseCurrentPopup(); 1625 3149 ImGui::EndPopup(); 1626 } 1627 1628 ImGui::TreePop(); 1629 } 1630 1631 if (ImGui::TreeNode("Menus inside a regular window")) 1632 { 1633 ImGui::TextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!"); 1634 ImGui::Separator(); 1635 // NB: As a quirk in this very specific example, we want to differentiate the parent of this menu from the parent of the various popup menus above. 1636 // To do so we are encloding the items in a PushID()/PopID() block to make them two different menusets. If we don't, opening any popup above and hovering our menu here 1637 // would open it. This is because once a menu is active, we allow to switch to a sibling menu by just hovering on it, which is the desired behavior for regular menus. 1638 ImGui::PushID("foo"); 1639 ImGui::MenuItem("Menu item", "CTRL+M"); 1640 if (ImGui::BeginMenu("Menu inside a regular window")) 1641 { 3150 } 3151 3152 ImGui::TreePop(); 3153 } 3154 3155 if (ImGui::TreeNode("Menus inside a regular window")) 3156 { 3157 ImGui::TextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!"); 3158 ImGui::Separator(); 3159 3160 // Note: As a quirk in this very specific example, we want to differentiate the parent of this menu from the 3161 // parent of the various popup menus above. To do so we are encloding the items in a PushID()/PopID() block 3162 // to make them two different menusets. If we don't, opening any popup above and hovering our menu here would 3163 // open it. This is because once a menu is active, we allow to switch to a sibling menu by just hovering on it, 3164 // which is the desired behavior for regular menus. 3165 ImGui::PushID("foo"); 3166 ImGui::MenuItem("Menu item", "CTRL+M"); 3167 if (ImGui::BeginMenu("Menu inside a regular window")) 3168 { 1642 3169 ShowExampleMenuFile(); 1643 3170 ImGui::EndMenu(); 1644 } 1645 ImGui::PopID(); 1646 ImGui::Separator(); 1647 ImGui::TreePop(); 1648 } 1649 } 1650 1651 if (ImGui::CollapsingHeader("Columns")) 1652 { 1653 ImGui::PushID("Columns"); 1654 1655 // Basic columns 1656 if (ImGui::TreeNode("Basic")) 1657 { 1658 ImGui::Text("Without border:"); 1659 ImGui::Columns(3, "mycolumns3", false); // 3-ways, no border 1660 ImGui::Separator(); 1661 for (int n = 0; n < 14; n++) 1662 { 3171 } 3172 ImGui::PopID(); 3173 ImGui::Separator(); 3174 ImGui::TreePop(); 3175 } 3176 } 3177 3178 static void ShowDemoWindowColumns() 3179 { 3180 if (!ImGui::CollapsingHeader("Columns")) 3181 return; 3182 3183 ImGui::PushID("Columns"); 3184 3185 static bool disable_indent = false; 3186 ImGui::Checkbox("Disable tree indentation", &disable_indent); 3187 ImGui::SameLine(); 3188 HelpMarker("Disable the indenting of tree nodes so demo columns can use the full window width."); 3189 if (disable_indent) 3190 ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0.0f); 3191 3192 // Basic columns 3193 if (ImGui::TreeNode("Basic")) 3194 { 3195 ImGui::Text("Without border:"); 3196 ImGui::Columns(3, "mycolumns3", false); // 3-ways, no border 3197 ImGui::Separator(); 3198 for (int n = 0; n < 14; n++) 3199 { 1663 3200 char label[32]; 1664 3201 sprintf(label, "Item %d", n); 1665 3202 if (ImGui::Selectable(label)) {} 1666 //if (ImGui::Button(label, ImVec2(- 1,0))) {}3203 //if (ImGui::Button(label, ImVec2(-FLT_MIN,0.0f))) {} 1667 3204 ImGui::NextColumn(); 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 3205 } 3206 ImGui::Columns(1); 3207 ImGui::Separator(); 3208 3209 ImGui::Text("With border:"); 3210 ImGui::Columns(4, "mycolumns"); // 4-ways, with border 3211 ImGui::Separator(); 3212 ImGui::Text("ID"); ImGui::NextColumn(); 3213 ImGui::Text("Name"); ImGui::NextColumn(); 3214 ImGui::Text("Path"); ImGui::NextColumn(); 3215 ImGui::Text("Hovered"); ImGui::NextColumn(); 3216 ImGui::Separator(); 3217 const char* names[3] = { "One", "Two", "Three" }; 3218 const char* paths[3] = { "/path/one", "/path/two", "/path/three" }; 3219 static int selected = -1; 3220 for (int i = 0; i < 3; i++) 3221 { 1685 3222 char label[32]; 1686 3223 sprintf(label, "%04d", i); 1687 3224 if (ImGui::Selectable(label, selected == i, ImGuiSelectableFlags_SpanAllColumns)) 1688 selected = i;3225 selected = i; 1689 3226 bool hovered = ImGui::IsItemHovered(); 1690 3227 ImGui::NextColumn(); … … 1692 3229 ImGui::Text(paths[i]); ImGui::NextColumn(); 1693 3230 ImGui::Text("%d", hovered); ImGui::NextColumn(); 1694 } 1695 ImGui::Columns(1); 1696 ImGui::Separator(); 1697 ImGui::TreePop(); 1698 } 1699 1700 // Create multiple items in a same cell before switching to next column 1701 if (ImGui::TreeNode("Mixed items")) 1702 { 1703 ImGui::Columns(3, "mixed"); 1704 ImGui::Separator(); 1705 1706 ImGui::Text("Hello"); 1707 ImGui::Button("Banana"); 1708 ImGui::NextColumn(); 1709 1710 ImGui::Text("ImGui"); 1711 ImGui::Button("Apple"); 1712 static float foo = 1.0f; 1713 ImGui::InputFloat("red", &foo, 0.05f, 0, "%.3f"); 1714 ImGui::Text("An extra line here."); 1715 ImGui::NextColumn(); 1716 1717 ImGui::Text("Sailor"); 1718 ImGui::Button("Corniflower"); 1719 static float bar = 1.0f; 1720 ImGui::InputFloat("blue", &bar, 0.05f, 0, "%.3f"); 1721 ImGui::NextColumn(); 1722 1723 if (ImGui::CollapsingHeader("Category A")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); 1724 if (ImGui::CollapsingHeader("Category B")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); 1725 if (ImGui::CollapsingHeader("Category C")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); 1726 ImGui::Columns(1); 1727 ImGui::Separator(); 1728 ImGui::TreePop(); 1729 } 1730 1731 // Word wrapping 1732 if (ImGui::TreeNode("Word-wrapping")) 1733 { 1734 ImGui::Columns(2, "word-wrapping"); 1735 ImGui::Separator(); 1736 ImGui::TextWrapped("The quick brown fox jumps over the lazy dog."); 1737 ImGui::TextWrapped("Hello Left"); 1738 ImGui::NextColumn(); 1739 ImGui::TextWrapped("The quick brown fox jumps over the lazy dog."); 1740 ImGui::TextWrapped("Hello Right"); 1741 ImGui::Columns(1); 1742 ImGui::Separator(); 1743 ImGui::TreePop(); 1744 } 1745 1746 if (ImGui::TreeNode("Borders")) 1747 { 1748 // NB: Future columns API should allow automatic horizontal borders. 1749 static bool h_borders = true; 1750 static bool v_borders = true; 1751 ImGui::Checkbox("horizontal", &h_borders); 1752 ImGui::SameLine(); 1753 ImGui::Checkbox("vertical", &v_borders); 1754 ImGui::Columns(4, NULL, v_borders); 1755 for (int i = 0; i < 4 * 3; i++) 1756 { 3231 } 3232 ImGui::Columns(1); 3233 ImGui::Separator(); 3234 ImGui::TreePop(); 3235 } 3236 3237 if (ImGui::TreeNode("Borders")) 3238 { 3239 // NB: Future columns API should allow automatic horizontal borders. 3240 static bool h_borders = true; 3241 static bool v_borders = true; 3242 static int columns_count = 4; 3243 const int lines_count = 3; 3244 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); 3245 ImGui::DragInt("##columns_count", &columns_count, 0.1f, 2, 10, "%d columns"); 3246 if (columns_count < 2) 3247 columns_count = 2; 3248 ImGui::SameLine(); 3249 ImGui::Checkbox("horizontal", &h_borders); 3250 ImGui::SameLine(); 3251 ImGui::Checkbox("vertical", &v_borders); 3252 ImGui::Columns(columns_count, NULL, v_borders); 3253 for (int i = 0; i < columns_count * lines_count; i++) 3254 { 1757 3255 if (h_borders && ImGui::GetColumnIndex() == 0) 1758 ImGui::Separator();3256 ImGui::Separator(); 1759 3257 ImGui::Text("%c%c%c", 'a' + i, 'a' + i, 'a' + i); 1760 ImGui::Text("Width %.2f\nOffset %.2f", ImGui::GetColumnWidth(), ImGui::GetColumnOffset()); 3258 ImGui::Text("Width %.2f", ImGui::GetColumnWidth()); 3259 ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x); 3260 ImGui::Text("Offset %.2f", ImGui::GetColumnOffset()); 3261 ImGui::Text("Long text that is likely to clip"); 3262 ImGui::Button("Button", ImVec2(-FLT_MIN, 0.0f)); 1761 3263 ImGui::NextColumn(); 1762 1763 1764 3264 } 3265 ImGui::Columns(1); 3266 if (h_borders) 1765 3267 ImGui::Separator(); 1766 ImGui::TreePop(); 1767 } 1768 1769 // Scrolling columns 1770 /* 1771 if (ImGui::TreeNode("Vertical Scrolling")) 1772 { 1773 ImGui::BeginChild("##header", ImVec2(0, ImGui::GetTextLineHeightWithSpacing()+ImGui::GetStyle().ItemSpacing.y)); 1774 ImGui::Columns(3); 1775 ImGui::Text("ID"); ImGui::NextColumn(); 1776 ImGui::Text("Name"); ImGui::NextColumn(); 1777 ImGui::Text("Path"); ImGui::NextColumn(); 1778 ImGui::Columns(1); 1779 ImGui::Separator(); 1780 ImGui::EndChild(); 1781 ImGui::BeginChild("##scrollingregion", ImVec2(0, 60)); 1782 ImGui::Columns(3); 1783 for (int i = 0; i < 10; i++) 1784 { 1785 ImGui::Text("%04d", i); ImGui::NextColumn(); 1786 ImGui::Text("Foobar"); ImGui::NextColumn(); 1787 ImGui::Text("/path/foobar/%04d/", i); ImGui::NextColumn(); 1788 } 1789 ImGui::Columns(1); 1790 ImGui::EndChild(); 1791 ImGui::TreePop(); 1792 } 1793 */ 1794 1795 if (ImGui::TreeNode("Horizontal Scrolling")) 1796 { 1797 ImGui::SetNextWindowContentSize(ImVec2(1500.0f, 0.0f)); 1798 ImGui::BeginChild("##ScrollingRegion", ImVec2(0, ImGui::GetFontSize() * 20), false, ImGuiWindowFlags_HorizontalScrollbar); 1799 ImGui::Columns(10); 1800 int ITEMS_COUNT = 2000; 1801 ImGuiListClipper clipper(ITEMS_COUNT); // Also demonstrate using the clipper for large list 1802 while (clipper.Step()) 1803 { 3268 ImGui::TreePop(); 3269 } 3270 3271 // Create multiple items in a same cell before switching to next column 3272 if (ImGui::TreeNode("Mixed items")) 3273 { 3274 ImGui::Columns(3, "mixed"); 3275 ImGui::Separator(); 3276 3277 ImGui::Text("Hello"); 3278 ImGui::Button("Banana"); 3279 ImGui::NextColumn(); 3280 3281 ImGui::Text("ImGui"); 3282 ImGui::Button("Apple"); 3283 static float foo = 1.0f; 3284 ImGui::InputFloat("red", &foo, 0.05f, 0, "%.3f"); 3285 ImGui::Text("An extra line here."); 3286 ImGui::NextColumn(); 3287 3288 ImGui::Text("Sailor"); 3289 ImGui::Button("Corniflower"); 3290 static float bar = 1.0f; 3291 ImGui::InputFloat("blue", &bar, 0.05f, 0, "%.3f"); 3292 ImGui::NextColumn(); 3293 3294 if (ImGui::CollapsingHeader("Category A")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); 3295 if (ImGui::CollapsingHeader("Category B")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); 3296 if (ImGui::CollapsingHeader("Category C")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); 3297 ImGui::Columns(1); 3298 ImGui::Separator(); 3299 ImGui::TreePop(); 3300 } 3301 3302 // Word wrapping 3303 if (ImGui::TreeNode("Word-wrapping")) 3304 { 3305 ImGui::Columns(2, "word-wrapping"); 3306 ImGui::Separator(); 3307 ImGui::TextWrapped("The quick brown fox jumps over the lazy dog."); 3308 ImGui::TextWrapped("Hello Left"); 3309 ImGui::NextColumn(); 3310 ImGui::TextWrapped("The quick brown fox jumps over the lazy dog."); 3311 ImGui::TextWrapped("Hello Right"); 3312 ImGui::Columns(1); 3313 ImGui::Separator(); 3314 ImGui::TreePop(); 3315 } 3316 3317 // Scrolling columns 3318 /* 3319 if (ImGui::TreeNode("Vertical Scrolling")) 3320 { 3321 ImGui::BeginChild("##header", ImVec2(0, ImGui::GetTextLineHeightWithSpacing()+ImGui::GetStyle().ItemSpacing.y)); 3322 ImGui::Columns(3); 3323 ImGui::Text("ID"); ImGui::NextColumn(); 3324 ImGui::Text("Name"); ImGui::NextColumn(); 3325 ImGui::Text("Path"); ImGui::NextColumn(); 3326 ImGui::Columns(1); 3327 ImGui::Separator(); 3328 ImGui::EndChild(); 3329 ImGui::BeginChild("##scrollingregion", ImVec2(0, 60)); 3330 ImGui::Columns(3); 3331 for (int i = 0; i < 10; i++) 3332 { 3333 ImGui::Text("%04d", i); ImGui::NextColumn(); 3334 ImGui::Text("Foobar"); ImGui::NextColumn(); 3335 ImGui::Text("/path/foobar/%04d/", i); ImGui::NextColumn(); 3336 } 3337 ImGui::Columns(1); 3338 ImGui::EndChild(); 3339 ImGui::TreePop(); 3340 } 3341 */ 3342 3343 if (ImGui::TreeNode("Horizontal Scrolling")) 3344 { 3345 ImGui::SetNextWindowContentSize(ImVec2(1500.0f, 0.0f)); 3346 ImVec2 child_size = ImVec2(0, ImGui::GetFontSize() * 20.0f); 3347 ImGui::BeginChild("##ScrollingRegion", child_size, false, ImGuiWindowFlags_HorizontalScrollbar); 3348 ImGui::Columns(10); 3349 int ITEMS_COUNT = 2000; 3350 ImGuiListClipper clipper; // Also demonstrate using the clipper for large list 3351 clipper.Begin(ITEMS_COUNT); 3352 while (clipper.Step()) 3353 { 1804 3354 for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) 1805 for (int j = 0; j < 10; j++) 1806 { 1807 ImGui::Text("Line %d Column %d...", i, j); 1808 ImGui::NextColumn(); 1809 } 1810 } 1811 ImGui::Columns(1); 1812 ImGui::EndChild(); 1813 ImGui::TreePop(); 1814 } 1815 1816 bool node_open = ImGui::TreeNode("Tree within single cell"); 1817 ImGui::SameLine(); ShowHelpMarker("NB: Tree node must be poped before ending the cell. There's no storage of state per-cell."); 1818 if (node_open) 1819 { 1820 ImGui::Columns(2, "tree items"); 1821 ImGui::Separator(); 1822 if (ImGui::TreeNode("Hello")) { ImGui::BulletText("Sailor"); ImGui::TreePop(); } ImGui::NextColumn(); 1823 if (ImGui::TreeNode("Bonjour")) { ImGui::BulletText("Marin"); ImGui::TreePop(); } ImGui::NextColumn(); 1824 ImGui::Columns(1); 1825 ImGui::Separator(); 1826 ImGui::TreePop(); 1827 } 1828 ImGui::PopID(); 1829 } 1830 1831 if (ImGui::CollapsingHeader("Filtering")) 1832 { 1833 static ImGuiTextFilter filter; 1834 ImGui::Text("Filter usage:\n" 1835 " \"\" display all lines\n" 1836 " \"xxx\" display lines containing \"xxx\"\n" 1837 " \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n" 1838 " \"-xxx\" hide lines containing \"xxx\""); 1839 filter.Draw(); 1840 const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" }; 1841 for (int i = 0; i < IM_ARRAYSIZE(lines); i++) 1842 if (filter.PassFilter(lines[i])) 1843 ImGui::BulletText("%s", lines[i]); 1844 } 1845 1846 if (ImGui::CollapsingHeader("Inputs, Navigation & Focus")) 1847 { 1848 ImGuiIO& io = ImGui::GetIO(); 1849 1850 ImGui::Text("WantCaptureMouse: %d", io.WantCaptureMouse); 1851 ImGui::Text("WantCaptureKeyboard: %d", io.WantCaptureKeyboard); 1852 ImGui::Text("WantTextInput: %d", io.WantTextInput); 1853 ImGui::Text("WantSetMousePos: %d", io.WantSetMousePos); 1854 ImGui::Text("NavActive: %d, NavVisible: %d", io.NavActive, io.NavVisible); 1855 1856 ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor); 1857 ImGui::SameLine(); ShowHelpMarker("Instruct ImGui to render a mouse cursor for you in software. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something)."); 1858 1859 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad); 1860 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard); 1861 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableSetMousePos", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NavEnableSetMousePos); 1862 ImGui::SameLine(); ShowHelpMarker("Instruct navigation to move the mouse cursor. See comment for ImGuiConfigFlags_NavEnableSetMousePos."); 1863 ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange); 1864 ImGui::SameLine(); ShowHelpMarker("Instruct back-end to not alter mouse cursor shape and visibility."); 1865 1866 if (ImGui::TreeNode("Keyboard, Mouse & Navigation State")) 1867 { 1868 if (ImGui::IsMousePosValid()) 1869 ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y); 1870 else 1871 ImGui::Text("Mouse pos: <INVALID>"); 1872 ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y); 1873 ImGui::Text("Mouse down:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (io.MouseDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); } 1874 ImGui::Text("Mouse clicked:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } 1875 ImGui::Text("Mouse dbl-clicked:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDoubleClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } 1876 ImGui::Text("Mouse released:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseReleased(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } 1877 ImGui::Text("Mouse wheel: %.1f", io.MouseWheel); 1878 1879 ImGui::Text("Keys down:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (io.KeysDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("%d (%.02f secs)", i, io.KeysDownDuration[i]); } 1880 ImGui::Text("Keys pressed:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyPressed(i)) { ImGui::SameLine(); ImGui::Text("%d", i); } 1881 ImGui::Text("Keys release:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyReleased(i)) { ImGui::SameLine(); ImGui::Text("%d", i); } 1882 ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); 1883 1884 ImGui::Text("NavInputs down:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputs[i] > 0.0f) { ImGui::SameLine(); ImGui::Text("[%d] %.2f", i, io.NavInputs[i]); } 1885 ImGui::Text("NavInputs pressed:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputsDownDuration[i] == 0.0f) { ImGui::SameLine(); ImGui::Text("[%d]", i); } 1886 ImGui::Text("NavInputs duration:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputsDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("[%d] %.2f", i, io.NavInputsDownDuration[i]); } 1887 1888 ImGui::Button("Hovering me sets the\nkeyboard capture flag"); 1889 if (ImGui::IsItemHovered()) 1890 ImGui::CaptureKeyboardFromApp(true); 1891 ImGui::SameLine(); 1892 ImGui::Button("Holding me clears the\nthe keyboard capture flag"); 1893 if (ImGui::IsItemActive()) 1894 ImGui::CaptureKeyboardFromApp(false); 1895 1896 ImGui::TreePop(); 1897 } 1898 1899 if (ImGui::TreeNode("Tabbing")) 1900 { 1901 ImGui::Text("Use TAB/SHIFT+TAB to cycle through keyboard editable fields."); 1902 static char buf[32] = "dummy"; 1903 ImGui::InputText("1", buf, IM_ARRAYSIZE(buf)); 1904 ImGui::InputText("2", buf, IM_ARRAYSIZE(buf)); 1905 ImGui::InputText("3", buf, IM_ARRAYSIZE(buf)); 1906 ImGui::PushAllowKeyboardFocus(false); 1907 ImGui::InputText("4 (tab skip)", buf, IM_ARRAYSIZE(buf)); 1908 //ImGui::SameLine(); ShowHelperMarker("Use ImGui::PushAllowKeyboardFocus(bool)\nto disable tabbing through certain widgets."); 1909 ImGui::PopAllowKeyboardFocus(); 1910 ImGui::InputText("5", buf, IM_ARRAYSIZE(buf)); 1911 ImGui::TreePop(); 1912 } 1913 1914 if (ImGui::TreeNode("Focus from code")) 1915 { 1916 bool focus_1 = ImGui::Button("Focus on 1"); ImGui::SameLine(); 1917 bool focus_2 = ImGui::Button("Focus on 2"); ImGui::SameLine(); 1918 bool focus_3 = ImGui::Button("Focus on 3"); 1919 int has_focus = 0; 1920 static char buf[128] = "click on a button to set focus"; 1921 1922 if (focus_1) ImGui::SetKeyboardFocusHere(); 1923 ImGui::InputText("1", buf, IM_ARRAYSIZE(buf)); 1924 if (ImGui::IsItemActive()) has_focus = 1; 1925 1926 if (focus_2) ImGui::SetKeyboardFocusHere(); 1927 ImGui::InputText("2", buf, IM_ARRAYSIZE(buf)); 1928 if (ImGui::IsItemActive()) has_focus = 2; 1929 1930 ImGui::PushAllowKeyboardFocus(false); 1931 if (focus_3) ImGui::SetKeyboardFocusHere(); 1932 ImGui::InputText("3 (tab skip)", buf, IM_ARRAYSIZE(buf)); 1933 if (ImGui::IsItemActive()) has_focus = 3; 1934 ImGui::PopAllowKeyboardFocus(); 1935 1936 if (has_focus) 1937 ImGui::Text("Item with focus: %d", has_focus); 1938 else 1939 ImGui::Text("Item with focus: <none>"); 1940 1941 // Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item 1942 static float f3[3] = { 0.0f, 0.0f, 0.0f }; 1943 int focus_ahead = -1; 1944 if (ImGui::Button("Focus on X")) focus_ahead = 0; ImGui::SameLine(); 1945 if (ImGui::Button("Focus on Y")) focus_ahead = 1; ImGui::SameLine(); 1946 if (ImGui::Button("Focus on Z")) focus_ahead = 2; 1947 if (focus_ahead != -1) ImGui::SetKeyboardFocusHere(focus_ahead); 1948 ImGui::SliderFloat3("Float3", &f3[0], 0.0f, 1.0f); 1949 1950 ImGui::TextWrapped("NB: Cursor & selection are preserved when refocusing last used item in code."); 1951 ImGui::TreePop(); 1952 } 1953 1954 if (ImGui::TreeNode("Focused & Hovered Test")) 1955 { 1956 static bool embed_all_inside_a_child_window = false; 1957 ImGui::Checkbox("Embed everything inside a child window (for additional testing)", &embed_all_inside_a_child_window); 1958 if (embed_all_inside_a_child_window) 1959 ImGui::BeginChild("embeddingchild", ImVec2(0, ImGui::GetFontSize() * 25), true); 1960 1961 // Testing IsWindowFocused() function with its various flags (note that the flags can be combined) 1962 ImGui::BulletText( 1963 "IsWindowFocused() = %d\n" 1964 "IsWindowFocused(_ChildWindows) = %d\n" 1965 "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n" 1966 "IsWindowFocused(_RootWindow) = %d\n" 1967 "IsWindowFocused(_AnyWindow) = %d\n", 1968 ImGui::IsWindowFocused(), 1969 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows), 1970 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow), 1971 ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow), 1972 ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow)); 1973 1974 // Testing IsWindowHovered() function with its various flags (note that the flags can be combined) 1975 ImGui::BulletText( 1976 "IsWindowHovered() = %d\n" 1977 "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n" 1978 "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n" 1979 "IsWindowHovered(_ChildWindows) = %d\n" 1980 "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n" 1981 "IsWindowHovered(_RootWindow) = %d\n" 1982 "IsWindowHovered(_AnyWindow) = %d\n", 1983 ImGui::IsWindowHovered(), 1984 ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), 1985 ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), 1986 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows), 1987 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow), 1988 ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow), 1989 ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)); 1990 1991 // Testing IsItemHovered() function (because BulletText is an item itself and that would affect the output of IsItemHovered, we pass all lines in a single items to shorten the code) 1992 ImGui::Button("ITEM"); 1993 ImGui::BulletText( 1994 "IsItemHovered() = %d\n" 1995 "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n" 1996 "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n" 1997 "IsItemHovered(_AllowWhenOverlapped) = %d\n" 1998 "IsItemhovered(_RectOnly) = %d\n", 1999 ImGui::IsItemHovered(), 2000 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), 2001 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), 2002 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlapped), 2003 ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly)); 2004 2005 ImGui::BeginChild("child", ImVec2(0, 50), true); 2006 ImGui::Text("This is another child window for testing IsWindowHovered() flags."); 2007 ImGui::EndChild(); 2008 2009 if (embed_all_inside_a_child_window) 2010 EndChild(); 2011 2012 ImGui::TreePop(); 2013 } 2014 2015 if (ImGui::TreeNode("Dragging")) 2016 { 2017 ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget."); 2018 for (int button = 0; button < 3; button++) 2019 ImGui::Text("IsMouseDragging(%d):\n w/ default threshold: %d,\n w/ zero threshold: %d\n w/ large threshold: %d", 2020 button, ImGui::IsMouseDragging(button), ImGui::IsMouseDragging(button, 0.0f), ImGui::IsMouseDragging(button, 20.0f)); 2021 ImGui::Button("Drag Me"); 2022 if (ImGui::IsItemActive()) 2023 { 2024 // Draw a line between the button and the mouse cursor 2025 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 2026 draw_list->PushClipRectFullScreen(); 2027 draw_list->AddLine(io.MouseClickedPos[0], io.MousePos, ImGui::GetColorU32(ImGuiCol_Button), 4.0f); 2028 draw_list->PopClipRect(); 2029 2030 // Drag operations gets "unlocked" when the mouse has moved past a certain threshold (the default threshold is stored in io.MouseDragThreshold) 2031 // You can request a lower or higher threshold using the second parameter of IsMouseDragging() and GetMouseDragDelta() 3355 for (int j = 0; j < 10; j++) 3356 { 3357 ImGui::Text("Line %d Column %d...", i, j); 3358 ImGui::NextColumn(); 3359 } 3360 } 3361 ImGui::Columns(1); 3362 ImGui::EndChild(); 3363 ImGui::TreePop(); 3364 } 3365 3366 if (ImGui::TreeNode("Tree")) 3367 { 3368 ImGui::Columns(2, "tree", true); 3369 for (int x = 0; x < 3; x++) 3370 { 3371 bool open1 = ImGui::TreeNode((void*)(intptr_t)x, "Node%d", x); 3372 ImGui::NextColumn(); 3373 ImGui::Text("Node contents"); 3374 ImGui::NextColumn(); 3375 if (open1) 3376 { 3377 for (int y = 0; y < 3; y++) 3378 { 3379 bool open2 = ImGui::TreeNode((void*)(intptr_t)y, "Node%d.%d", x, y); 3380 ImGui::NextColumn(); 3381 ImGui::Text("Node contents"); 3382 if (open2) 3383 { 3384 ImGui::Text("Even more contents"); 3385 if (ImGui::TreeNode("Tree in column")) 3386 { 3387 ImGui::Text("The quick brown fox jumps over the lazy dog"); 3388 ImGui::TreePop(); 3389 } 3390 } 3391 ImGui::NextColumn(); 3392 if (open2) 3393 ImGui::TreePop(); 3394 } 3395 ImGui::TreePop(); 3396 } 3397 } 3398 ImGui::Columns(1); 3399 ImGui::TreePop(); 3400 } 3401 3402 if (disable_indent) 3403 ImGui::PopStyleVar(); 3404 ImGui::PopID(); 3405 } 3406 3407 static void ShowDemoWindowMisc() 3408 { 3409 if (ImGui::CollapsingHeader("Filtering")) 3410 { 3411 // Helper class to easy setup a text filter. 3412 // You may want to implement a more feature-full filtering scheme in your own application. 3413 static ImGuiTextFilter filter; 3414 ImGui::Text("Filter usage:\n" 3415 " \"\" display all lines\n" 3416 " \"xxx\" display lines containing \"xxx\"\n" 3417 " \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n" 3418 " \"-xxx\" hide lines containing \"xxx\""); 3419 filter.Draw(); 3420 const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" }; 3421 for (int i = 0; i < IM_ARRAYSIZE(lines); i++) 3422 if (filter.PassFilter(lines[i])) 3423 ImGui::BulletText("%s", lines[i]); 3424 } 3425 3426 if (ImGui::CollapsingHeader("Inputs, Navigation & Focus")) 3427 { 3428 ImGuiIO& io = ImGui::GetIO(); 3429 3430 // Display ImGuiIO output flags 3431 ImGui::Text("WantCaptureMouse: %d", io.WantCaptureMouse); 3432 ImGui::Text("WantCaptureKeyboard: %d", io.WantCaptureKeyboard); 3433 ImGui::Text("WantTextInput: %d", io.WantTextInput); 3434 ImGui::Text("WantSetMousePos: %d", io.WantSetMousePos); 3435 ImGui::Text("NavActive: %d, NavVisible: %d", io.NavActive, io.NavVisible); 3436 3437 // Display Keyboard/Mouse state 3438 if (ImGui::TreeNode("Keyboard, Mouse & Navigation State")) 3439 { 3440 if (ImGui::IsMousePosValid()) 3441 ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y); 3442 else 3443 ImGui::Text("Mouse pos: <INVALID>"); 3444 ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y); 3445 ImGui::Text("Mouse down:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (io.MouseDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); } 3446 ImGui::Text("Mouse clicked:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } 3447 ImGui::Text("Mouse dblclick:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDoubleClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } 3448 ImGui::Text("Mouse released:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseReleased(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } 3449 ImGui::Text("Mouse wheel: %.1f", io.MouseWheel); 3450 3451 ImGui::Text("Keys down:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (io.KeysDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("%d (0x%X) (%.02f secs)", i, i, io.KeysDownDuration[i]); } 3452 ImGui::Text("Keys pressed:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyPressed(i)) { ImGui::SameLine(); ImGui::Text("%d (0x%X)", i, i); } 3453 ImGui::Text("Keys release:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyReleased(i)) { ImGui::SameLine(); ImGui::Text("%d (0x%X)", i, i); } 3454 ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); 3455 ImGui::Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; ImGui::SameLine(); ImGui::Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public. 3456 3457 ImGui::Text("NavInputs down:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputs[i] > 0.0f) { ImGui::SameLine(); ImGui::Text("[%d] %.2f", i, io.NavInputs[i]); } 3458 ImGui::Text("NavInputs pressed:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputsDownDuration[i] == 0.0f) { ImGui::SameLine(); ImGui::Text("[%d]", i); } 3459 ImGui::Text("NavInputs duration:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputsDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("[%d] %.2f", i, io.NavInputsDownDuration[i]); } 3460 3461 ImGui::Button("Hovering me sets the\nkeyboard capture flag"); 3462 if (ImGui::IsItemHovered()) 3463 ImGui::CaptureKeyboardFromApp(true); 3464 ImGui::SameLine(); 3465 ImGui::Button("Holding me clears the\nthe keyboard capture flag"); 3466 if (ImGui::IsItemActive()) 3467 ImGui::CaptureKeyboardFromApp(false); 3468 3469 ImGui::TreePop(); 3470 } 3471 3472 if (ImGui::TreeNode("Tabbing")) 3473 { 3474 ImGui::Text("Use TAB/SHIFT+TAB to cycle through keyboard editable fields."); 3475 static char buf[32] = "hello"; 3476 ImGui::InputText("1", buf, IM_ARRAYSIZE(buf)); 3477 ImGui::InputText("2", buf, IM_ARRAYSIZE(buf)); 3478 ImGui::InputText("3", buf, IM_ARRAYSIZE(buf)); 3479 ImGui::PushAllowKeyboardFocus(false); 3480 ImGui::InputText("4 (tab skip)", buf, IM_ARRAYSIZE(buf)); 3481 //ImGui::SameLine(); HelpMarker("Use ImGui::PushAllowKeyboardFocus(bool) to disable tabbing through certain widgets."); 3482 ImGui::PopAllowKeyboardFocus(); 3483 ImGui::InputText("5", buf, IM_ARRAYSIZE(buf)); 3484 ImGui::TreePop(); 3485 } 3486 3487 if (ImGui::TreeNode("Focus from code")) 3488 { 3489 bool focus_1 = ImGui::Button("Focus on 1"); ImGui::SameLine(); 3490 bool focus_2 = ImGui::Button("Focus on 2"); ImGui::SameLine(); 3491 bool focus_3 = ImGui::Button("Focus on 3"); 3492 int has_focus = 0; 3493 static char buf[128] = "click on a button to set focus"; 3494 3495 if (focus_1) ImGui::SetKeyboardFocusHere(); 3496 ImGui::InputText("1", buf, IM_ARRAYSIZE(buf)); 3497 if (ImGui::IsItemActive()) has_focus = 1; 3498 3499 if (focus_2) ImGui::SetKeyboardFocusHere(); 3500 ImGui::InputText("2", buf, IM_ARRAYSIZE(buf)); 3501 if (ImGui::IsItemActive()) has_focus = 2; 3502 3503 ImGui::PushAllowKeyboardFocus(false); 3504 if (focus_3) ImGui::SetKeyboardFocusHere(); 3505 ImGui::InputText("3 (tab skip)", buf, IM_ARRAYSIZE(buf)); 3506 if (ImGui::IsItemActive()) has_focus = 3; 3507 ImGui::PopAllowKeyboardFocus(); 3508 3509 if (has_focus) 3510 ImGui::Text("Item with focus: %d", has_focus); 3511 else 3512 ImGui::Text("Item with focus: <none>"); 3513 3514 // Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item 3515 static float f3[3] = { 0.0f, 0.0f, 0.0f }; 3516 int focus_ahead = -1; 3517 if (ImGui::Button("Focus on X")) { focus_ahead = 0; } ImGui::SameLine(); 3518 if (ImGui::Button("Focus on Y")) { focus_ahead = 1; } ImGui::SameLine(); 3519 if (ImGui::Button("Focus on Z")) { focus_ahead = 2; } 3520 if (focus_ahead != -1) ImGui::SetKeyboardFocusHere(focus_ahead); 3521 ImGui::SliderFloat3("Float3", &f3[0], 0.0f, 1.0f); 3522 3523 ImGui::TextWrapped("NB: Cursor & selection are preserved when refocusing last used item in code."); 3524 ImGui::TreePop(); 3525 } 3526 3527 if (ImGui::TreeNode("Dragging")) 3528 { 3529 ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget."); 3530 for (int button = 0; button < 3; button++) 3531 { 3532 ImGui::Text("IsMouseDragging(%d):", button); 3533 ImGui::Text(" w/ default threshold: %d,", ImGui::IsMouseDragging(button)); 3534 ImGui::Text(" w/ zero threshold: %d,", ImGui::IsMouseDragging(button, 0.0f)); 3535 ImGui::Text(" w/ large threshold: %d,", ImGui::IsMouseDragging(button, 20.0f)); 3536 } 3537 3538 ImGui::Button("Drag Me"); 3539 if (ImGui::IsItemActive()) 3540 ImGui::GetForegroundDrawList()->AddLine(io.MouseClickedPos[0], io.MousePos, ImGui::GetColorU32(ImGuiCol_Button), 4.0f); // Draw a line between the button and the mouse cursor 3541 3542 // Drag operations gets "unlocked" when the mouse has moved past a certain threshold 3543 // (the default threshold is stored in io.MouseDragThreshold). You can request a lower or higher 3544 // threshold using the second parameter of IsMouseDragging() and GetMouseDragDelta(). 2032 3545 ImVec2 value_raw = ImGui::GetMouseDragDelta(0, 0.0f); 2033 3546 ImVec2 value_with_lock_threshold = ImGui::GetMouseDragDelta(0); 2034 3547 ImVec2 mouse_delta = io.MouseDelta; 2035 ImGui::SameLine(); ImGui::Text("Raw (%.1f, %.1f), WithLockThresold (%.1f, %.1f), MouseDelta (%.1f, %.1f)", value_raw.x, value_raw.y, value_with_lock_threshold.x, value_with_lock_threshold.y, mouse_delta.x, mouse_delta.y); 2036 } 2037 ImGui::TreePop(); 2038 } 2039 2040 if (ImGui::TreeNode("Mouse cursors")) 2041 { 2042 const char* mouse_cursors_names[] = { "Arrow", "TextInput", "Move", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE" }; 2043 IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT); 2044 2045 ImGui::Text("Current mouse cursor = %d: %s", ImGui::GetMouseCursor(), mouse_cursors_names[ImGui::GetMouseCursor()]); 2046 ImGui::Text("Hover to see mouse cursors:"); 2047 ImGui::SameLine(); ShowHelpMarker("Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, otherwise your backend needs to handle it."); 2048 for (int i = 0; i < ImGuiMouseCursor_COUNT; i++) 2049 { 2050 char label[32]; 2051 sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]); 2052 ImGui::Bullet(); ImGui::Selectable(label, false); 2053 if (ImGui::IsItemHovered() || ImGui::IsItemFocused()) 2054 ImGui::SetMouseCursor(i); 2055 } 2056 ImGui::TreePop(); 2057 } 2058 } 2059 2060 ImGui::End(); 3548 ImGui::Text("GetMouseDragDelta(0):"); 3549 ImGui::Text(" w/ default threshold: (%.1f, %.1f)", value_with_lock_threshold.x, value_with_lock_threshold.y); 3550 ImGui::Text(" w/ zero threshold: (%.1f, %.1f)", value_raw.x, value_raw.y); 3551 ImGui::Text("io.MouseDelta: (%.1f, %.1f)", mouse_delta.x, mouse_delta.y); 3552 ImGui::TreePop(); 3553 } 3554 3555 if (ImGui::TreeNode("Mouse cursors")) 3556 { 3557 const char* mouse_cursors_names[] = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "NotAllowed" }; 3558 IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT); 3559 3560 ImGuiMouseCursor current = ImGui::GetMouseCursor(); 3561 ImGui::Text("Current mouse cursor = %d: %s", current, mouse_cursors_names[current]); 3562 ImGui::Text("Hover to see mouse cursors:"); 3563 ImGui::SameLine(); HelpMarker( 3564 "Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. " 3565 "If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, " 3566 "otherwise your backend needs to handle it."); 3567 for (int i = 0; i < ImGuiMouseCursor_COUNT; i++) 3568 { 3569 char label[32]; 3570 sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]); 3571 ImGui::Bullet(); ImGui::Selectable(label, false); 3572 if (ImGui::IsItemHovered() || ImGui::IsItemFocused()) 3573 ImGui::SetMouseCursor(i); 3574 } 3575 ImGui::TreePop(); 3576 } 3577 } 2061 3578 } 2062 3579 3580 //----------------------------------------------------------------------------- 3581 // [SECTION] About Window / ShowAboutWindow() 3582 // Access from Dear ImGui Demo -> Tools -> About 3583 //----------------------------------------------------------------------------- 3584 3585 void ImGui::ShowAboutWindow(bool* p_open) 3586 { 3587 if (!ImGui::Begin("About Dear ImGui", p_open, ImGuiWindowFlags_AlwaysAutoResize)) 3588 { 3589 ImGui::End(); 3590 return; 3591 } 3592 ImGui::Text("Dear ImGui %s", ImGui::GetVersion()); 3593 ImGui::Separator(); 3594 ImGui::Text("By Omar Cornut and all Dear ImGui contributors."); 3595 ImGui::Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information."); 3596 3597 static bool show_config_info = false; 3598 ImGui::Checkbox("Config/Build Information", &show_config_info); 3599 if (show_config_info) 3600 { 3601 ImGuiIO& io = ImGui::GetIO(); 3602 ImGuiStyle& style = ImGui::GetStyle(); 3603 3604 bool copy_to_clipboard = ImGui::Button("Copy to clipboard"); 3605 ImVec2 child_size = ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 18); 3606 ImGui::BeginChildFrame(ImGui::GetID("cfg_infos"), child_size, ImGuiWindowFlags_NoMove); 3607 if (copy_to_clipboard) 3608 { 3609 ImGui::LogToClipboard(); 3610 ImGui::LogText("```\n"); // Back quotes will make text appears without formatting when pasting on GitHub 3611 } 3612 3613 ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM); 3614 ImGui::Separator(); 3615 ImGui::Text("sizeof(size_t): %d, sizeof(ImDrawIdx): %d, sizeof(ImDrawVert): %d", (int)sizeof(size_t), (int)sizeof(ImDrawIdx), (int)sizeof(ImDrawVert)); 3616 ImGui::Text("define: __cplusplus=%d", (int)__cplusplus); 3617 #ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS 3618 ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_FUNCTIONS"); 3619 #endif 3620 #ifdef IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS 3621 ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS"); 3622 #endif 3623 #ifdef IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS 3624 ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS"); 3625 #endif 3626 #ifdef IMGUI_DISABLE_WIN32_FUNCTIONS 3627 ImGui::Text("define: IMGUI_DISABLE_WIN32_FUNCTIONS"); 3628 #endif 3629 #ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS 3630 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS"); 3631 #endif 3632 #ifdef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS 3633 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS"); 3634 #endif 3635 #ifdef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS 3636 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS"); 3637 #endif 3638 #ifdef IMGUI_DISABLE_FILE_FUNCTIONS 3639 ImGui::Text("define: IMGUI_DISABLE_FILE_FUNCTIONS"); 3640 #endif 3641 #ifdef IMGUI_DISABLE_DEFAULT_ALLOCATORS 3642 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_ALLOCATORS"); 3643 #endif 3644 #ifdef IMGUI_USE_BGRA_PACKED_COLOR 3645 ImGui::Text("define: IMGUI_USE_BGRA_PACKED_COLOR"); 3646 #endif 3647 #ifdef _WIN32 3648 ImGui::Text("define: _WIN32"); 3649 #endif 3650 #ifdef _WIN64 3651 ImGui::Text("define: _WIN64"); 3652 #endif 3653 #ifdef __linux__ 3654 ImGui::Text("define: __linux__"); 3655 #endif 3656 #ifdef __APPLE__ 3657 ImGui::Text("define: __APPLE__"); 3658 #endif 3659 #ifdef _MSC_VER 3660 ImGui::Text("define: _MSC_VER=%d", _MSC_VER); 3661 #endif 3662 #ifdef __MINGW32__ 3663 ImGui::Text("define: __MINGW32__"); 3664 #endif 3665 #ifdef __MINGW64__ 3666 ImGui::Text("define: __MINGW64__"); 3667 #endif 3668 #ifdef __GNUC__ 3669 ImGui::Text("define: __GNUC__=%d", (int)__GNUC__); 3670 #endif 3671 #ifdef __clang_version__ 3672 ImGui::Text("define: __clang_version__=%s", __clang_version__); 3673 #endif 3674 ImGui::Separator(); 3675 ImGui::Text("io.BackendPlatformName: %s", io.BackendPlatformName ? io.BackendPlatformName : "NULL"); 3676 ImGui::Text("io.BackendRendererName: %s", io.BackendRendererName ? io.BackendRendererName : "NULL"); 3677 ImGui::Text("io.ConfigFlags: 0x%08X", io.ConfigFlags); 3678 if (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) ImGui::Text(" NavEnableKeyboard"); 3679 if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) ImGui::Text(" NavEnableGamepad"); 3680 if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) ImGui::Text(" NavEnableSetMousePos"); 3681 if (io.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard) ImGui::Text(" NavNoCaptureKeyboard"); 3682 if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) ImGui::Text(" NoMouse"); 3683 if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) ImGui::Text(" NoMouseCursorChange"); 3684 if (io.MouseDrawCursor) ImGui::Text("io.MouseDrawCursor"); 3685 if (io.ConfigMacOSXBehaviors) ImGui::Text("io.ConfigMacOSXBehaviors"); 3686 if (io.ConfigInputTextCursorBlink) ImGui::Text("io.ConfigInputTextCursorBlink"); 3687 if (io.ConfigWindowsResizeFromEdges) ImGui::Text("io.ConfigWindowsResizeFromEdges"); 3688 if (io.ConfigWindowsMoveFromTitleBarOnly) ImGui::Text("io.ConfigWindowsMoveFromTitleBarOnly"); 3689 if (io.ConfigWindowsMemoryCompactTimer >= 0.0f) ImGui::Text("io.ConfigWindowsMemoryCompactTimer = %.1ff", io.ConfigWindowsMemoryCompactTimer); 3690 ImGui::Text("io.BackendFlags: 0x%08X", io.BackendFlags); 3691 if (io.BackendFlags & ImGuiBackendFlags_HasGamepad) ImGui::Text(" HasGamepad"); 3692 if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) ImGui::Text(" HasMouseCursors"); 3693 if (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos) ImGui::Text(" HasSetMousePos"); 3694 if (io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) ImGui::Text(" RendererHasVtxOffset"); 3695 ImGui::Separator(); 3696 ImGui::Text("io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", io.Fonts->Fonts.Size, io.Fonts->Flags, io.Fonts->TexWidth, io.Fonts->TexHeight); 3697 ImGui::Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y); 3698 ImGui::Text("io.DisplayFramebufferScale: %.2f,%.2f", io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y); 3699 ImGui::Separator(); 3700 ImGui::Text("style.WindowPadding: %.2f,%.2f", style.WindowPadding.x, style.WindowPadding.y); 3701 ImGui::Text("style.WindowBorderSize: %.2f", style.WindowBorderSize); 3702 ImGui::Text("style.FramePadding: %.2f,%.2f", style.FramePadding.x, style.FramePadding.y); 3703 ImGui::Text("style.FrameRounding: %.2f", style.FrameRounding); 3704 ImGui::Text("style.FrameBorderSize: %.2f", style.FrameBorderSize); 3705 ImGui::Text("style.ItemSpacing: %.2f,%.2f", style.ItemSpacing.x, style.ItemSpacing.y); 3706 ImGui::Text("style.ItemInnerSpacing: %.2f,%.2f", style.ItemInnerSpacing.x, style.ItemInnerSpacing.y); 3707 3708 if (copy_to_clipboard) 3709 { 3710 ImGui::LogText("\n```\n"); 3711 ImGui::LogFinish(); 3712 } 3713 ImGui::EndChildFrame(); 3714 } 3715 ImGui::End(); 3716 } 3717 3718 //----------------------------------------------------------------------------- 3719 // [SECTION] Style Editor / ShowStyleEditor() 3720 //----------------------------------------------------------------------------- 3721 // - ShowStyleSelector() 3722 // - ShowFontSelector() 3723 // - ShowStyleEditor() 3724 //----------------------------------------------------------------------------- 3725 2063 3726 // Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options. 2064 // Here we use the simplified Combo() api that packs items into a single literal string. Useful for quick combo boxes where the choices are known locally. 3727 // Here we use the simplified Combo() api that packs items into a single literal string. 3728 // Useful for quick combo boxes where the choices are known locally. 2065 3729 bool ImGui::ShowStyleSelector(const char* label) 2066 3730 { 2067 static int style_idx = -1;2068 if (ImGui::Combo(label, &style_idx, "Classic\0Dark\0Light\0"))2069 {2070 switch (style_idx)2071 {2072 case 0: ImGui::StyleColorsClassic(); break;2073 case 1: ImGui::StyleColorsDark(); break;2074 case 2: ImGui::StyleColorsLight(); break;2075 }2076 return true;2077 }2078 return false;3731 static int style_idx = -1; 3732 if (ImGui::Combo(label, &style_idx, "Classic\0Dark\0Light\0")) 3733 { 3734 switch (style_idx) 3735 { 3736 case 0: ImGui::StyleColorsClassic(); break; 3737 case 1: ImGui::StyleColorsDark(); break; 3738 case 2: ImGui::StyleColorsLight(); break; 3739 } 3740 return true; 3741 } 3742 return false; 2079 3743 } 2080 3744 … … 2083 3747 void ImGui::ShowFontSelector(const char* label) 2084 3748 { 2085 ImGuiIO& io = ImGui::GetIO(); 2086 ImFont* font_current = ImGui::GetFont(); 2087 if (ImGui::BeginCombo(label, font_current->GetDebugName())) 2088 { 2089 for (int n = 0; n < io.Fonts->Fonts.Size; n++) 2090 if (ImGui::Selectable(io.Fonts->Fonts[n]->GetDebugName(), io.Fonts->Fonts[n] == font_current)) 2091 io.FontDefault = io.Fonts->Fonts[n]; 2092 ImGui::EndCombo(); 2093 } 2094 ImGui::SameLine(); 2095 ShowHelpMarker( 2096 "- Load additional fonts with io.Fonts->AddFontFromFileTTF().\n" 2097 "- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n" 2098 "- Read FAQ and documentation in misc/fonts/ for more details.\n" 2099 "- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame()."); 3749 ImGuiIO& io = ImGui::GetIO(); 3750 ImFont* font_current = ImGui::GetFont(); 3751 if (ImGui::BeginCombo(label, font_current->GetDebugName())) 3752 { 3753 for (int n = 0; n < io.Fonts->Fonts.Size; n++) 3754 { 3755 ImFont* font = io.Fonts->Fonts[n]; 3756 ImGui::PushID((void*)font); 3757 if (ImGui::Selectable(font->GetDebugName(), font == font_current)) 3758 io.FontDefault = font; 3759 ImGui::PopID(); 3760 } 3761 ImGui::EndCombo(); 3762 } 3763 ImGui::SameLine(); 3764 HelpMarker( 3765 "- Load additional fonts with io.Fonts->AddFontFromFileTTF().\n" 3766 "- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n" 3767 "- Read FAQ and docs/FONTS.md for more details.\n" 3768 "- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame()."); 3769 } 3770 3771 // [Internal] Display details for a single font, called by ShowStyleEditor(). 3772 static void NodeFont(ImFont* font) 3773 { 3774 ImGuiIO& io = ImGui::GetIO(); 3775 ImGuiStyle& style = ImGui::GetStyle(); 3776 bool font_details_opened = ImGui::TreeNode(font, "Font: \"%s\"\n%.2f px, %d glyphs, %d file(s)", 3777 font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size, font->ConfigDataCount); 3778 ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) { io.FontDefault = font; } 3779 if (!font_details_opened) 3780 return; 3781 3782 ImGui::PushFont(font); 3783 ImGui::Text("The quick brown fox jumps over the lazy dog"); 3784 ImGui::PopFont(); 3785 ImGui::DragFloat("Font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f"); // Scale only this font 3786 ImGui::SameLine(); HelpMarker( 3787 "Note than the default embedded font is NOT meant to be scaled.\n\n" 3788 "Font are currently rendered into bitmaps at a given size at the time of building the atlas. " 3789 "You may oversample them to get some flexibility with scaling. " 3790 "You can also render at multiple sizes and select which one to use at runtime.\n\n" 3791 "(Glimmer of hope: the atlas system will be rewritten in the future to make scaling more flexible.)"); 3792 ImGui::Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent); 3793 ImGui::Text("Fallback character: '%c' (U+%04X)", font->FallbackChar, font->FallbackChar); 3794 ImGui::Text("Ellipsis character: '%c' (U+%04X)", font->EllipsisChar, font->EllipsisChar); 3795 const int surface_sqrt = (int)sqrtf((float)font->MetricsTotalSurface); 3796 ImGui::Text("Texture Area: about %d px ~%dx%d px", font->MetricsTotalSurface, surface_sqrt, surface_sqrt); 3797 for (int config_i = 0; config_i < font->ConfigDataCount; config_i++) 3798 if (font->ConfigData) 3799 if (const ImFontConfig* cfg = &font->ConfigData[config_i]) 3800 ImGui::BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d, Offset: (%.1f,%.1f)", 3801 config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH, cfg->GlyphOffset.x, cfg->GlyphOffset.y); 3802 if (ImGui::TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size)) 3803 { 3804 // Display all glyphs of the fonts in separate pages of 256 characters 3805 const ImU32 glyph_col = ImGui::GetColorU32(ImGuiCol_Text); 3806 for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256) 3807 { 3808 // Skip ahead if a large bunch of glyphs are not present in the font (test in chunks of 4k) 3809 // This is only a small optimization to reduce the number of iterations when IM_UNICODE_MAX_CODEPOINT 3810 // is large // (if ImWchar==ImWchar32 we will do at least about 272 queries here) 3811 if (!(base & 4095) && font->IsGlyphRangeUnused(base, base + 4095)) 3812 { 3813 base += 4096 - 256; 3814 continue; 3815 } 3816 3817 int count = 0; 3818 for (unsigned int n = 0; n < 256; n++) 3819 if (font->FindGlyphNoFallback((ImWchar)(base + n))) 3820 count++; 3821 if (count <= 0) 3822 continue; 3823 if (!ImGui::TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph")) 3824 continue; 3825 float cell_size = font->FontSize * 1; 3826 float cell_spacing = style.ItemSpacing.y; 3827 ImVec2 base_pos = ImGui::GetCursorScreenPos(); 3828 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 3829 for (unsigned int n = 0; n < 256; n++) 3830 { 3831 // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions 3832 // available here and thus cannot easily generate a zero-terminated UTF-8 encoded string. 3833 ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing)); 3834 ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size); 3835 const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base + n)); 3836 draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50)); 3837 if (glyph) 3838 font->RenderChar(draw_list, cell_size, cell_p1, glyph_col, (ImWchar)(base + n)); 3839 if (glyph && ImGui::IsMouseHoveringRect(cell_p1, cell_p2)) 3840 { 3841 ImGui::BeginTooltip(); 3842 ImGui::Text("Codepoint: U+%04X", base + n); 3843 ImGui::Separator(); 3844 ImGui::Text("Visible: %d", glyph->Visible); 3845 ImGui::Text("AdvanceX: %.1f", glyph->AdvanceX); 3846 ImGui::Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1); 3847 ImGui::Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1); 3848 ImGui::EndTooltip(); 3849 } 3850 } 3851 ImGui::Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16)); 3852 ImGui::TreePop(); 3853 } 3854 ImGui::TreePop(); 3855 } 3856 ImGui::TreePop(); 2100 3857 } 2101 3858 2102 3859 void ImGui::ShowStyleEditor(ImGuiStyle* ref) 2103 3860 { 2104 // You can pass in a reference ImGuiStyle structure to compare to, revert to and save to (else it compares to an internally stored reference) 2105 ImGuiStyle& style = ImGui::GetStyle(); 2106 static ImGuiStyle ref_saved_style; 2107 2108 // Default to using internal storage as reference 2109 static bool init = true; 2110 if (init && ref == NULL) 2111 ref_saved_style = style; 2112 init = false; 2113 if (ref == NULL) 2114 ref = &ref_saved_style; 2115 2116 ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.50f); 2117 2118 if (ImGui::ShowStyleSelector("Colors##Selector")) 2119 ref_saved_style = style; 2120 ImGui::ShowFontSelector("Fonts##Selector"); 2121 2122 // Simplified Settings 2123 if (ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f")) 2124 style.GrabRounding = style.FrameRounding; // Make GrabRounding always the same value as FrameRounding 2125 { bool window_border = (style.WindowBorderSize > 0.0f); if (ImGui::Checkbox("WindowBorder", &window_border)) style.WindowBorderSize = window_border ? 1.0f : 0.0f; } 2126 ImGui::SameLine(); 2127 { bool frame_border = (style.FrameBorderSize > 0.0f); if (ImGui::Checkbox("FrameBorder", &frame_border)) style.FrameBorderSize = frame_border ? 1.0f : 0.0f; } 2128 ImGui::SameLine(); 2129 { bool popup_border = (style.PopupBorderSize > 0.0f); if (ImGui::Checkbox("PopupBorder", &popup_border)) style.PopupBorderSize = popup_border ? 1.0f : 0.0f; } 2130 2131 // Save/Revert button 2132 if (ImGui::Button("Save Ref")) 2133 *ref = ref_saved_style = style; 2134 ImGui::SameLine(); 2135 if (ImGui::Button("Revert Ref")) 2136 style = *ref; 2137 ImGui::SameLine(); 2138 ShowHelpMarker("Save/Revert in local non-persistent storage. Default Colors definition are not affected. Use \"Export Colors\" below to save them somewhere."); 2139 2140 if (ImGui::TreeNode("Rendering")) 2141 { 2142 ImGui::Checkbox("Anti-aliased lines", &style.AntiAliasedLines); ImGui::SameLine(); ShowHelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well."); 2143 ImGui::Checkbox("Anti-aliased fill", &style.AntiAliasedFill); 2144 ImGui::PushItemWidth(100); 2145 ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, FLT_MAX, NULL, 2.0f); 2146 if (style.CurveTessellationTol < 0.0f) style.CurveTessellationTol = 0.10f; 2147 ImGui::DragFloat("Global Alpha", &style.Alpha, 0.005f, 0.20f, 1.0f, "%.2f"); // Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero. 2148 ImGui::PopItemWidth(); 2149 ImGui::TreePop(); 2150 } 2151 2152 if (ImGui::TreeNode("Settings")) 2153 { 2154 ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f"); 2155 ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 16.0f, "%.0f"); 2156 ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f"); 2157 ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f"); 2158 ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f"); 2159 ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f"); 2160 ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f"); 2161 ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f"); 2162 ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f"); 2163 ImGui::Text("BorderSize"); 2164 ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f"); 2165 ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f"); 2166 ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f"); 2167 ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f"); 2168 ImGui::Text("Rounding"); 2169 ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 14.0f, "%.0f"); 2170 ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 16.0f, "%.0f"); 2171 ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"); 2172 ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f"); 2173 ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f"); 2174 ImGui::Text("Alignment"); 2175 ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); 2176 ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); ShowHelpMarker("Alignment applies when a button is larger than its text content."); 2177 ImGui::Text("Safe Area Padding"); ImGui::SameLine(); ShowHelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured)."); 2178 ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); 2179 ImGui::TreePop(); 2180 } 2181 2182 if (ImGui::TreeNode("Colors")) 2183 { 2184 static int output_dest = 0; 2185 static bool output_only_modified = true; 2186 if (ImGui::Button("Export Unsaved")) 2187 { 2188 if (output_dest == 0) 2189 ImGui::LogToClipboard(); 2190 else 2191 ImGui::LogToTTY(); 2192 ImGui::LogText("ImVec4* colors = ImGui::GetStyle().Colors;" IM_NEWLINE); 2193 for (int i = 0; i < ImGuiCol_COUNT; i++) 2194 { 2195 const ImVec4& col = style.Colors[i]; 2196 const char* name = ImGui::GetStyleColorName(i); 2197 if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0) 2198 ImGui::LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE, name, 23 - (int)strlen(name), "", col.x, col.y, col.z, col.w); 2199 } 2200 ImGui::LogFinish(); 2201 } 2202 ImGui::SameLine(); ImGui::PushItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0"); ImGui::PopItemWidth(); 2203 ImGui::SameLine(); ImGui::Checkbox("Only Modified Colors", &output_only_modified); 2204 2205 ImGui::Text("Tip: Left-click on colored square to open color picker,\nRight-click to open edit options menu."); 2206 2207 static ImGuiTextFilter filter; 2208 filter.Draw("Filter colors", 200); 2209 2210 static ImGuiColorEditFlags alpha_flags = 0; 2211 ImGui::RadioButton("Opaque", &alpha_flags, 0); ImGui::SameLine(); 2212 ImGui::RadioButton("Alpha", &alpha_flags, ImGuiColorEditFlags_AlphaPreview); ImGui::SameLine(); 2213 ImGui::RadioButton("Both", &alpha_flags, ImGuiColorEditFlags_AlphaPreviewHalf); 2214 2215 ImGui::BeginChild("#colors", ImVec2(0, 300), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened); 2216 ImGui::PushItemWidth(-160); 2217 for (int i = 0; i < ImGuiCol_COUNT; i++) 2218 { 2219 const char* name = ImGui::GetStyleColorName(i); 2220 if (!filter.PassFilter(name)) 2221 continue; 2222 ImGui::PushID(i); 2223 ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags); 2224 if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0) 2225 { 2226 // Tips: in a real user application, you may want to merge and use an icon font into the main font, so instead of "Save"/"Revert" you'd use icons. 2227 // Read the FAQ and misc/fonts/README.txt about using icon fonts. It's really easy and super convenient! 2228 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) ref->Colors[i] = style.Colors[i]; 2229 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) style.Colors[i] = ref->Colors[i]; 2230 } 2231 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); 2232 ImGui::TextUnformatted(name); 2233 ImGui::PopID(); 2234 } 2235 ImGui::PopItemWidth(); 2236 ImGui::EndChild(); 2237 2238 ImGui::TreePop(); 2239 } 2240 2241 bool fonts_opened = ImGui::TreeNode("Fonts", "Fonts (%d)", ImGui::GetIO().Fonts->Fonts.Size); 2242 if (fonts_opened) 2243 { 2244 ImFontAtlas* atlas = ImGui::GetIO().Fonts; 2245 if (ImGui::TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight)) 2246 { 2247 ImGui::Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0, 0), ImVec2(1, 1), ImColor(255, 255, 255, 255), ImColor(255, 255, 255, 128)); 2248 ImGui::TreePop(); 2249 } 2250 ImGui::PushItemWidth(100); 2251 for (int i = 0; i < atlas->Fonts.Size; i++) 2252 { 2253 ImFont* font = atlas->Fonts[i]; 2254 ImGui::PushID(font); 2255 bool font_details_opened = ImGui::TreeNode(font, "Font %d: \'%s\', %.2f px, %d glyphs", i, font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size); 2256 ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) ImGui::GetIO().FontDefault = font; 2257 if (font_details_opened) 2258 { 2259 ImGui::PushFont(font); 2260 ImGui::Text("The quick brown fox jumps over the lazy dog"); 2261 ImGui::PopFont(); 2262 ImGui::DragFloat("Font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f"); // Scale only this font 2263 ImGui::InputFloat("Font offset", &font->DisplayOffset.y, 1, 1, 0); 2264 ImGui::SameLine(); ShowHelpMarker("Note than the default embedded font is NOT meant to be scaled.\n\nFont are currently rendered into bitmaps at a given size at the time of building the atlas. You may oversample them to get some flexibility with scaling. You can also render at multiple sizes and select which one to use at runtime.\n\n(Glimmer of hope: the atlas system should hopefully be rewritten in the future to make scaling more natural and automatic.)"); 2265 ImGui::Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent); 2266 ImGui::Text("Fallback character: '%c' (%d)", font->FallbackChar, font->FallbackChar); 2267 ImGui::Text("Texture surface: %d pixels (approx) ~ %dx%d", font->MetricsTotalSurface, (int)sqrtf((float)font->MetricsTotalSurface), (int)sqrtf((float)font->MetricsTotalSurface)); 2268 for (int config_i = 0; config_i < font->ConfigDataCount; config_i++) 2269 if (ImFontConfig* cfg = &font->ConfigData[config_i]) 2270 ImGui::BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d", config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH); 2271 if (ImGui::TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size)) 2272 { 2273 // Display all glyphs of the fonts in separate pages of 256 characters 2274 for (int base = 0; base < 0x10000; base += 256) 2275 { 2276 int count = 0; 2277 for (int n = 0; n < 256; n++) 2278 count += font->FindGlyphNoFallback((ImWchar)(base + n)) ? 1 : 0; 2279 if (count > 0 && ImGui::TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph")) 2280 { 2281 float cell_size = font->FontSize * 1; 2282 float cell_spacing = style.ItemSpacing.y; 2283 ImVec2 base_pos = ImGui::GetCursorScreenPos(); 2284 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 2285 for (int n = 0; n < 256; n++) 2286 { 2287 ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing)); 2288 ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size); 2289 const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base + n)); 2290 draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50)); 2291 font->RenderChar(draw_list, cell_size, cell_p1, ImGui::GetColorU32(ImGuiCol_Text), (ImWchar)(base + n)); // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions available to generate a string. 2292 if (glyph && ImGui::IsMouseHoveringRect(cell_p1, cell_p2)) 2293 { 2294 ImGui::BeginTooltip(); 2295 ImGui::Text("Codepoint: U+%04X", base + n); 2296 ImGui::Separator(); 2297 ImGui::Text("AdvanceX: %.1f", glyph->AdvanceX); 2298 ImGui::Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1); 2299 ImGui::Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1); 2300 ImGui::EndTooltip(); 2301 } 2302 } 2303 ImGui::Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16)); 2304 ImGui::TreePop(); 2305 } 2306 } 2307 ImGui::TreePop(); 2308 } 2309 ImGui::TreePop(); 2310 } 2311 ImGui::PopID(); 2312 } 2313 static float window_scale = 1.0f; 2314 ImGui::DragFloat("this window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.1f"); // scale only this window 2315 ImGui::DragFloat("global scale", &ImGui::GetIO().FontGlobalScale, 0.005f, 0.3f, 2.0f, "%.1f"); // scale everything 2316 ImGui::PopItemWidth(); 2317 ImGui::SetWindowFontScale(window_scale); 2318 ImGui::TreePop(); 2319 } 2320 2321 ImGui::PopItemWidth(); 3861 // You can pass in a reference ImGuiStyle structure to compare to, revert to and save to 3862 // (without a reference style pointer, we will use one compared locally as a reference) 3863 ImGuiStyle& style = ImGui::GetStyle(); 3864 static ImGuiStyle ref_saved_style; 3865 3866 // Default to using internal storage as reference 3867 static bool init = true; 3868 if (init && ref == NULL) 3869 ref_saved_style = style; 3870 init = false; 3871 if (ref == NULL) 3872 ref = &ref_saved_style; 3873 3874 ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.50f); 3875 3876 if (ImGui::ShowStyleSelector("Colors##Selector")) 3877 ref_saved_style = style; 3878 ImGui::ShowFontSelector("Fonts##Selector"); 3879 3880 // Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f) 3881 if (ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f")) 3882 style.GrabRounding = style.FrameRounding; // Make GrabRounding always the same value as FrameRounding 3883 { bool border = (style.WindowBorderSize > 0.0f); if (ImGui::Checkbox("WindowBorder", &border)) { style.WindowBorderSize = border ? 1.0f : 0.0f; } } 3884 ImGui::SameLine(); 3885 { bool border = (style.FrameBorderSize > 0.0f); if (ImGui::Checkbox("FrameBorder", &border)) { style.FrameBorderSize = border ? 1.0f : 0.0f; } } 3886 ImGui::SameLine(); 3887 { bool border = (style.PopupBorderSize > 0.0f); if (ImGui::Checkbox("PopupBorder", &border)) { style.PopupBorderSize = border ? 1.0f : 0.0f; } } 3888 3889 // Save/Revert button 3890 if (ImGui::Button("Save Ref")) 3891 *ref = ref_saved_style = style; 3892 ImGui::SameLine(); 3893 if (ImGui::Button("Revert Ref")) 3894 style = *ref; 3895 ImGui::SameLine(); 3896 HelpMarker( 3897 "Save/Revert in local non-persistent storage. Default Colors definition are not affected. " 3898 "Use \"Export\" below to save them somewhere."); 3899 3900 ImGui::Separator(); 3901 3902 if (ImGui::BeginTabBar("##tabs", ImGuiTabBarFlags_None)) 3903 { 3904 if (ImGui::BeginTabItem("Sizes")) 3905 { 3906 ImGui::Text("Main"); 3907 ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f"); 3908 ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f"); 3909 ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f"); 3910 ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f"); 3911 ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f"); 3912 ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f"); 3913 ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f"); 3914 ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f"); 3915 ImGui::Text("Borders"); 3916 ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f"); 3917 ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f"); 3918 ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f"); 3919 ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f"); 3920 ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f"); 3921 ImGui::Text("Rounding"); 3922 ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f"); 3923 ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f"); 3924 ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"); 3925 ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f, "%.0f"); 3926 ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f"); 3927 ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f"); 3928 ImGui::SliderFloat("LogSliderDeadzone", &style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f"); 3929 ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f"); 3930 ImGui::Text("Alignment"); 3931 ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); 3932 int window_menu_button_position = style.WindowMenuButtonPosition + 1; 3933 if (ImGui::Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0")) 3934 style.WindowMenuButtonPosition = window_menu_button_position - 1; 3935 ImGui::Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, "Left\0Right\0"); 3936 ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); 3937 ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content."); 3938 ImGui::SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f"); 3939 ImGui::SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content."); 3940 ImGui::Text("Safe Area Padding"); 3941 ImGui::SameLine(); HelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured)."); 3942 ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); 3943 ImGui::EndTabItem(); 3944 } 3945 3946 if (ImGui::BeginTabItem("Colors")) 3947 { 3948 static int output_dest = 0; 3949 static bool output_only_modified = true; 3950 if (ImGui::Button("Export")) 3951 { 3952 if (output_dest == 0) 3953 ImGui::LogToClipboard(); 3954 else 3955 ImGui::LogToTTY(); 3956 ImGui::LogText("ImVec4* colors = ImGui::GetStyle().Colors;" IM_NEWLINE); 3957 for (int i = 0; i < ImGuiCol_COUNT; i++) 3958 { 3959 const ImVec4& col = style.Colors[i]; 3960 const char* name = ImGui::GetStyleColorName(i); 3961 if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0) 3962 ImGui::LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE, 3963 name, 23 - (int)strlen(name), "", col.x, col.y, col.z, col.w); 3964 } 3965 ImGui::LogFinish(); 3966 } 3967 ImGui::SameLine(); ImGui::SetNextItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0"); 3968 ImGui::SameLine(); ImGui::Checkbox("Only Modified Colors", &output_only_modified); 3969 3970 static ImGuiTextFilter filter; 3971 filter.Draw("Filter colors", ImGui::GetFontSize() * 16); 3972 3973 static ImGuiColorEditFlags alpha_flags = 0; 3974 if (ImGui::RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_None)) { alpha_flags = ImGuiColorEditFlags_None; } ImGui::SameLine(); 3975 if (ImGui::RadioButton("Alpha", alpha_flags == ImGuiColorEditFlags_AlphaPreview)) { alpha_flags = ImGuiColorEditFlags_AlphaPreview; } ImGui::SameLine(); 3976 if (ImGui::RadioButton("Both", alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } ImGui::SameLine(); 3977 HelpMarker( 3978 "In the color list:\n" 3979 "Left-click on colored square to open color picker,\n" 3980 "Right-click to open edit options menu."); 3981 3982 ImGui::BeginChild("##colors", ImVec2(0, 0), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened); 3983 ImGui::PushItemWidth(-160); 3984 for (int i = 0; i < ImGuiCol_COUNT; i++) 3985 { 3986 const char* name = ImGui::GetStyleColorName(i); 3987 if (!filter.PassFilter(name)) 3988 continue; 3989 ImGui::PushID(i); 3990 ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags); 3991 if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0) 3992 { 3993 // Tips: in a real user application, you may want to merge and use an icon font into the main font, 3994 // so instead of "Save"/"Revert" you'd use icons! 3995 // Read the FAQ and docs/FONTS.md about using icon fonts. It's really easy and super convenient! 3996 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) { ref->Colors[i] = style.Colors[i]; } 3997 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) { style.Colors[i] = ref->Colors[i]; } 3998 } 3999 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); 4000 ImGui::TextUnformatted(name); 4001 ImGui::PopID(); 4002 } 4003 ImGui::PopItemWidth(); 4004 ImGui::EndChild(); 4005 4006 ImGui::EndTabItem(); 4007 } 4008 4009 if (ImGui::BeginTabItem("Fonts")) 4010 { 4011 ImGuiIO& io = ImGui::GetIO(); 4012 ImFontAtlas* atlas = io.Fonts; 4013 HelpMarker("Read FAQ and docs/FONTS.md for details on font loading."); 4014 ImGui::PushItemWidth(120); 4015 for (int i = 0; i < atlas->Fonts.Size; i++) 4016 { 4017 ImFont* font = atlas->Fonts[i]; 4018 ImGui::PushID(font); 4019 NodeFont(font); 4020 ImGui::PopID(); 4021 } 4022 if (ImGui::TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight)) 4023 { 4024 ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); 4025 ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f); 4026 ImGui::Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0, 0), ImVec2(1, 1), tint_col, border_col); 4027 ImGui::TreePop(); 4028 } 4029 4030 // Post-baking font scaling. Note that this is NOT the nice way of scaling fonts, read below. 4031 // (we enforce hard clamping manually as by default DragFloat/SliderFloat allows CTRL+Click text to get out of bounds). 4032 const float MIN_SCALE = 0.3f; 4033 const float MAX_SCALE = 2.0f; 4034 HelpMarker( 4035 "Those are old settings provided for convenience.\n" 4036 "However, the _correct_ way of scaling your UI is currently to reload your font at the designed size, " 4037 "rebuild the font atlas, and call style.ScaleAllSizes() on a reference ImGuiStyle structure.\n" 4038 "Using those settings here will give you poor quality results."); 4039 static float window_scale = 1.0f; 4040 if (ImGui::DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp)) // Scale only this window 4041 ImGui::SetWindowFontScale(window_scale); 4042 ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp); // Scale everything 4043 ImGui::PopItemWidth(); 4044 4045 ImGui::EndTabItem(); 4046 } 4047 4048 if (ImGui::BeginTabItem("Rendering")) 4049 { 4050 ImGui::Checkbox("Anti-aliased lines", &style.AntiAliasedLines); 4051 ImGui::SameLine(); 4052 HelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well."); 4053 4054 ImGui::Checkbox("Anti-aliased lines use texture", &style.AntiAliasedLinesUseTex); 4055 ImGui::SameLine(); 4056 HelpMarker("Faster lines using texture data. Require back-end to render with bilinear filtering (not point/nearest filtering)."); 4057 4058 ImGui::Checkbox("Anti-aliased fill", &style.AntiAliasedFill); 4059 ImGui::PushItemWidth(100); 4060 ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, 10.0f, "%.2f"); 4061 if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f; 4062 4063 // When editing the "Circle Segment Max Error" value, draw a preview of its effect on auto-tessellated circles. 4064 ImGui::DragFloat("Circle Segment Max Error", &style.CircleSegmentMaxError, 0.01f, 0.10f, 10.0f, "%.2f"); 4065 if (ImGui::IsItemActive()) 4066 { 4067 ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos()); 4068 ImGui::BeginTooltip(); 4069 ImVec2 p = ImGui::GetCursorScreenPos(); 4070 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 4071 float RAD_MIN = 10.0f, RAD_MAX = 80.0f; 4072 float off_x = 10.0f; 4073 for (int n = 0; n < 7; n++) 4074 { 4075 const float rad = RAD_MIN + (RAD_MAX - RAD_MIN) * (float)n / (7.0f - 1.0f); 4076 draw_list->AddCircle(ImVec2(p.x + off_x + rad, p.y + RAD_MAX), rad, ImGui::GetColorU32(ImGuiCol_Text), 0); 4077 off_x += 10.0f + rad * 2.0f; 4078 } 4079 ImGui::Dummy(ImVec2(off_x, RAD_MAX * 2.0f)); 4080 ImGui::EndTooltip(); 4081 } 4082 ImGui::SameLine(); 4083 HelpMarker("When drawing circle primitives with \"num_segments == 0\" tesselation will be calculated automatically."); 4084 4085 ImGui::DragFloat("Global Alpha", &style.Alpha, 0.005f, 0.20f, 1.0f, "%.2f"); // Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero. 4086 ImGui::PopItemWidth(); 4087 4088 ImGui::EndTabItem(); 4089 } 4090 4091 ImGui::EndTabBar(); 4092 } 4093 4094 ImGui::PopItemWidth(); 2322 4095 } 2323 4096 2324 // Demonstrate creating a fullscreen menu bar and populating it. 4097 //----------------------------------------------------------------------------- 4098 // [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar() 4099 //----------------------------------------------------------------------------- 4100 // - ShowExampleAppMainMenuBar() 4101 // - ShowExampleMenuFile() 4102 //----------------------------------------------------------------------------- 4103 4104 // Demonstrate creating a "main" fullscreen menu bar and populating it. 4105 // Note the difference between BeginMainMenuBar() and BeginMenuBar(): 4106 // - BeginMenuBar() = menu-bar inside current window (which needs the ImGuiWindowFlags_MenuBar flag!) 4107 // - BeginMainMenuBar() = helper to create menu-bar-sized window at the top of the main viewport + call BeginMenuBar() into it. 2325 4108 static void ShowExampleAppMainMenuBar() 2326 4109 { 2327 if (ImGui::BeginMainMenuBar())2328 {2329 if (ImGui::BeginMenu("File"))2330 {2331 ShowExampleMenuFile();2332 ImGui::EndMenu();2333 }2334 if (ImGui::BeginMenu("Edit"))2335 {2336 if (ImGui::MenuItem("Undo", "CTRL+Z")) {}2337 if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) {} // Disabled item2338 ImGui::Separator();2339 if (ImGui::MenuItem("Cut", "CTRL+X")) {}2340 if (ImGui::MenuItem("Copy", "CTRL+C")) {}2341 if (ImGui::MenuItem("Paste", "CTRL+V")) {}2342 ImGui::EndMenu();2343 }2344 ImGui::EndMainMenuBar();2345 }4110 if (ImGui::BeginMainMenuBar()) 4111 { 4112 if (ImGui::BeginMenu("File")) 4113 { 4114 ShowExampleMenuFile(); 4115 ImGui::EndMenu(); 4116 } 4117 if (ImGui::BeginMenu("Edit")) 4118 { 4119 if (ImGui::MenuItem("Undo", "CTRL+Z")) {} 4120 if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) {} // Disabled item 4121 ImGui::Separator(); 4122 if (ImGui::MenuItem("Cut", "CTRL+X")) {} 4123 if (ImGui::MenuItem("Copy", "CTRL+C")) {} 4124 if (ImGui::MenuItem("Paste", "CTRL+V")) {} 4125 ImGui::EndMenu(); 4126 } 4127 ImGui::EndMainMenuBar(); 4128 } 2346 4129 } 2347 4130 4131 // Note that shortcuts are currently provided for display only 4132 // (future version will add explicit flags to BeginMenu() to request processing shortcuts) 2348 4133 static void ShowExampleMenuFile() 2349 4134 { 2350 ImGui::MenuItem("(dummy menu)", NULL, false, false); 2351 if (ImGui::MenuItem("New")) {} 2352 if (ImGui::MenuItem("Open", "Ctrl+O")) {} 2353 if (ImGui::BeginMenu("Open Recent")) 2354 { 2355 ImGui::MenuItem("fish_hat.c"); 2356 ImGui::MenuItem("fish_hat.inl"); 2357 ImGui::MenuItem("fish_hat.h"); 2358 if (ImGui::BeginMenu("More..")) 2359 { 2360 ImGui::MenuItem("Hello"); 2361 ImGui::MenuItem("Sailor"); 2362 if (ImGui::BeginMenu("Recurse..")) 2363 { 2364 ShowExampleMenuFile(); 4135 ImGui::MenuItem("(demo menu)", NULL, false, false); 4136 if (ImGui::MenuItem("New")) {} 4137 if (ImGui::MenuItem("Open", "Ctrl+O")) {} 4138 if (ImGui::BeginMenu("Open Recent")) 4139 { 4140 ImGui::MenuItem("fish_hat.c"); 4141 ImGui::MenuItem("fish_hat.inl"); 4142 ImGui::MenuItem("fish_hat.h"); 4143 if (ImGui::BeginMenu("More..")) 4144 { 4145 ImGui::MenuItem("Hello"); 4146 ImGui::MenuItem("Sailor"); 4147 if (ImGui::BeginMenu("Recurse..")) 4148 { 4149 ShowExampleMenuFile(); 4150 ImGui::EndMenu(); 4151 } 2365 4152 ImGui::EndMenu(); 2366 } 2367 ImGui::EndMenu(); 2368 } 2369 ImGui::EndMenu(); 2370 } 2371 if (ImGui::MenuItem("Save", "Ctrl+S")) {} 2372 if (ImGui::MenuItem("Save As..")) {} 2373 ImGui::Separator(); 2374 if (ImGui::BeginMenu("Options")) 2375 { 2376 static bool enabled = true; 2377 ImGui::MenuItem("Enabled", "", &enabled); 2378 ImGui::BeginChild("child", ImVec2(0, 60), true); 2379 for (int i = 0; i < 10; i++) 2380 ImGui::Text("Scrolling Text %d", i); 2381 ImGui::EndChild(); 2382 static float f = 0.5f; 2383 static int n = 0; 2384 static bool b = true; 2385 ImGui::SliderFloat("Value", &f, 0.0f, 1.0f); 2386 ImGui::InputFloat("Input", &f, 0.1f); 2387 ImGui::Combo("Combo", &n, "Yes\0No\0Maybe\0\0"); 2388 ImGui::Checkbox("Check", &b); 2389 ImGui::EndMenu(); 2390 } 2391 if (ImGui::BeginMenu("Colors")) 2392 { 2393 float sz = ImGui::GetTextLineHeight(); 2394 for (int i = 0; i < ImGuiCol_COUNT; i++) 2395 { 2396 const char* name = ImGui::GetStyleColorName((ImGuiCol)i); 2397 ImVec2 p = ImGui::GetCursorScreenPos(); 2398 ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + sz, p.y + sz), ImGui::GetColorU32((ImGuiCol)i)); 2399 ImGui::Dummy(ImVec2(sz, sz)); 2400 ImGui::SameLine(); 2401 ImGui::MenuItem(name); 2402 } 2403 ImGui::EndMenu(); 2404 } 2405 if (ImGui::BeginMenu("Disabled", false)) // Disabled 2406 { 2407 IM_ASSERT(0); 2408 } 2409 if (ImGui::MenuItem("Checked", NULL, true)) {} 2410 if (ImGui::MenuItem("Quit", "Alt+F4")) {} 4153 } 4154 ImGui::EndMenu(); 4155 } 4156 if (ImGui::MenuItem("Save", "Ctrl+S")) {} 4157 if (ImGui::MenuItem("Save As..")) {} 4158 4159 ImGui::Separator(); 4160 if (ImGui::BeginMenu("Options")) 4161 { 4162 static bool enabled = true; 4163 ImGui::MenuItem("Enabled", "", &enabled); 4164 ImGui::BeginChild("child", ImVec2(0, 60), true); 4165 for (int i = 0; i < 10; i++) 4166 ImGui::Text("Scrolling Text %d", i); 4167 ImGui::EndChild(); 4168 static float f = 0.5f; 4169 static int n = 0; 4170 ImGui::SliderFloat("Value", &f, 0.0f, 1.0f); 4171 ImGui::InputFloat("Input", &f, 0.1f); 4172 ImGui::Combo("Combo", &n, "Yes\0No\0Maybe\0\0"); 4173 ImGui::EndMenu(); 4174 } 4175 4176 if (ImGui::BeginMenu("Colors")) 4177 { 4178 float sz = ImGui::GetTextLineHeight(); 4179 for (int i = 0; i < ImGuiCol_COUNT; i++) 4180 { 4181 const char* name = ImGui::GetStyleColorName((ImGuiCol)i); 4182 ImVec2 p = ImGui::GetCursorScreenPos(); 4183 ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + sz, p.y + sz), ImGui::GetColorU32((ImGuiCol)i)); 4184 ImGui::Dummy(ImVec2(sz, sz)); 4185 ImGui::SameLine(); 4186 ImGui::MenuItem(name); 4187 } 4188 ImGui::EndMenu(); 4189 } 4190 4191 // Here we demonstrate appending again to the "Options" menu (which we already created above) 4192 // Of course in this demo it is a little bit silly that this function calls BeginMenu("Options") twice. 4193 // In a real code-base using it would make senses to use this feature from very different code locations. 4194 if (ImGui::BeginMenu("Options")) // <-- Append! 4195 { 4196 static bool b = true; 4197 ImGui::Checkbox("SomeOption", &b); 4198 ImGui::EndMenu(); 4199 } 4200 4201 if (ImGui::BeginMenu("Disabled", false)) // Disabled 4202 { 4203 IM_ASSERT(0); 4204 } 4205 if (ImGui::MenuItem("Checked", NULL, true)) {} 4206 if (ImGui::MenuItem("Quit", "Alt+F4")) {} 2411 4207 } 2412 4208 2413 // Demonstrate creating a window which gets auto-resized according to its content. 2414 static void ShowExampleAppAutoResize(bool* p_open) 2415 { 2416 if (!ImGui::Begin("Example: Auto-resizing window", p_open, ImGuiWindowFlags_AlwaysAutoResize)) 2417 { 2418 ImGui::End(); 2419 return; 2420 } 2421 2422 static int lines = 10; 2423 ImGui::Text("Window will resize every-frame to the size of its content.\nNote that you probably don't want to query the window size to\noutput your content because that would create a feedback loop."); 2424 ImGui::SliderInt("Number of lines", &lines, 1, 20); 2425 for (int i = 0; i < lines; i++) 2426 ImGui::Text("%*sThis is line %d", i * 4, "", i); // Pad with space to extend size horizontally 2427 ImGui::End(); 2428 } 2429 2430 // Demonstrate creating a window with custom resize constraints. 2431 static void ShowExampleAppConstrainedResize(bool* p_open) 2432 { 2433 struct CustomConstraints // Helper functions to demonstrate programmatic constraints 2434 { 2435 static void Square(ImGuiSizeCallbackData* data) { data->DesiredSize = ImVec2(IM_MAX(data->DesiredSize.x, data->DesiredSize.y), IM_MAX(data->DesiredSize.x, data->DesiredSize.y)); } 2436 static void Step(ImGuiSizeCallbackData* data) { float step = (float)(int)(intptr_t)data->UserData; data->DesiredSize = ImVec2((int)(data->DesiredSize.x / step + 0.5f) * step, (int)(data->DesiredSize.y / step + 0.5f) * step); } 2437 }; 2438 2439 static bool auto_resize = false; 2440 static int type = 0; 2441 static int display_lines = 10; 2442 if (type == 0) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, FLT_MAX)); // Vertical only 2443 if (type == 1) ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(FLT_MAX, -1)); // Horizontal only 2444 if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100 2445 if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)); // Width 400-500 2446 if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, 500)); // Height 400-500 2447 if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square 2448 if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)100);// Fixed Step 2449 2450 ImGuiWindowFlags flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0; 2451 if (ImGui::Begin("Example: Constrained Resize", p_open, flags)) 2452 { 2453 const char* desc[] = 2454 { 2455 "Resize vertical only", 2456 "Resize horizontal only", 2457 "Width > 100, Height > 100", 2458 "Width 400-500", 2459 "Height 400-500", 2460 "Custom: Always Square", 2461 "Custom: Fixed Steps (100)", 2462 }; 2463 if (ImGui::Button("200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine(); 2464 if (ImGui::Button("500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine(); 2465 if (ImGui::Button("800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); } 2466 ImGui::PushItemWidth(200); 2467 ImGui::Combo("Constraint", &type, desc, IM_ARRAYSIZE(desc)); 2468 ImGui::DragInt("Lines", &display_lines, 0.2f, 1, 100); 2469 ImGui::PopItemWidth(); 2470 ImGui::Checkbox("Auto-resize", &auto_resize); 2471 for (int i = 0; i < display_lines; i++) 2472 ImGui::Text("%*sHello, sailor! Making this line long enough for the example.", i * 4, ""); 2473 } 2474 ImGui::End(); 2475 } 2476 2477 // Demonstrate creating a simple static window with no decoration + a context-menu to choose which corner of the screen to use. 2478 static void ShowExampleAppFixedOverlay(bool* p_open) 2479 { 2480 const float DISTANCE = 10.0f; 2481 static int corner = 0; 2482 ImVec2 window_pos = ImVec2((corner & 1) ? ImGui::GetIO().DisplaySize.x - DISTANCE : DISTANCE, (corner & 2) ? ImGui::GetIO().DisplaySize.y - DISTANCE : DISTANCE); 2483 ImVec2 window_pos_pivot = ImVec2((corner & 1) ? 1.0f : 0.0f, (corner & 2) ? 1.0f : 0.0f); 2484 if (corner != -1) 2485 ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot); 2486 ImGui::SetNextWindowBgAlpha(0.3f); // Transparent background 2487 if (ImGui::Begin("Example: Fixed Overlay", p_open, (corner != -1 ? ImGuiWindowFlags_NoMove : 0) | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav)) 2488 { 2489 ImGui::Text("Simple overlay\n" "in the corner of the screen.\n" "(right-click to change position)"); 2490 ImGui::Separator(); 2491 if (ImGui::IsMousePosValid()) 2492 ImGui::Text("Mouse Position: (%.1f,%.1f)", ImGui::GetIO().MousePos.x, ImGui::GetIO().MousePos.y); 2493 else 2494 ImGui::Text("Mouse Position: <invalid>"); 2495 if (ImGui::BeginPopupContextWindow()) 2496 { 2497 if (ImGui::MenuItem("Custom", NULL, corner == -1)) corner = -1; 2498 if (ImGui::MenuItem("Top-left", NULL, corner == 0)) corner = 0; 2499 if (ImGui::MenuItem("Top-right", NULL, corner == 1)) corner = 1; 2500 if (ImGui::MenuItem("Bottom-left", NULL, corner == 2)) corner = 2; 2501 if (ImGui::MenuItem("Bottom-right", NULL, corner == 3)) corner = 3; 2502 if (p_open && ImGui::MenuItem("Close")) *p_open = false; 2503 ImGui::EndPopup(); 2504 } 2505 ImGui::End(); 2506 } 2507 } 2508 2509 // Demonstrate using "##" and "###" in identifiers to manipulate ID generation. 2510 // This apply to regular items as well. Read FAQ section "How can I have multiple widgets with the same label? Can I have widget without a label? (Yes). A primer on the purpose of labels/IDs." for details. 2511 static void ShowExampleAppWindowTitles(bool*) 2512 { 2513 // By default, Windows are uniquely identified by their title. 2514 // You can use the "##" and "###" markers to manipulate the display/ID. 2515 2516 // Using "##" to display same title but have unique identifier. 2517 ImGui::SetNextWindowPos(ImVec2(100, 100), ImGuiCond_FirstUseEver); 2518 ImGui::Begin("Same title as another window##1"); 2519 ImGui::Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique."); 2520 ImGui::End(); 2521 2522 ImGui::SetNextWindowPos(ImVec2(100, 200), ImGuiCond_FirstUseEver); 2523 ImGui::Begin("Same title as another window##2"); 2524 ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique."); 2525 ImGui::End(); 2526 2527 // Using "###" to display a changing title but keep a static identifier "AnimatedTitle" 2528 char buf[128]; 2529 sprintf(buf, "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime() / 0.25f) & 3], ImGui::GetFrameCount()); 2530 ImGui::SetNextWindowPos(ImVec2(100, 300), ImGuiCond_FirstUseEver); 2531 ImGui::Begin(buf); 2532 ImGui::Text("This window has a changing title."); 2533 ImGui::End(); 2534 } 2535 2536 // Demonstrate using the low-level ImDrawList to draw custom shapes. 2537 static void ShowExampleAppCustomRendering(bool* p_open) 2538 { 2539 ImGui::SetNextWindowSize(ImVec2(350, 560), ImGuiCond_FirstUseEver); 2540 if (!ImGui::Begin("Example: Custom rendering", p_open)) 2541 { 2542 ImGui::End(); 2543 return; 2544 } 2545 2546 // Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of overloaded operators, etc. 2547 // Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your types and ImVec2/ImVec4. 2548 // ImGui defines overloaded operators but they are internal to imgui.cpp and not exposed outside (to avoid messing with your types) 2549 // In this example we are not using the maths operators! 2550 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 2551 2552 // Primitives 2553 ImGui::Text("Primitives"); 2554 static float sz = 36.0f; 2555 static ImVec4 col = ImVec4(1.0f, 1.0f, 0.4f, 1.0f); 2556 ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 72.0f, "%.0f"); 2557 ImGui::ColorEdit3("Color", &col.x); 2558 { 2559 const ImVec2 p = ImGui::GetCursorScreenPos(); 2560 const ImU32 col32 = ImColor(col); 2561 float x = p.x + 4.0f, y = p.y + 4.0f, spacing = 8.0f; 2562 for (int n = 0; n < 2; n++) 2563 { 2564 float thickness = (n == 0) ? 1.0f : 4.0f; 2565 draw_list->AddCircle(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz*0.5f, col32, 20, thickness); x += sz + spacing; 2566 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col32, 0.0f, ImDrawCornerFlags_All, thickness); x += sz + spacing; 2567 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col32, 10.0f, ImDrawCornerFlags_All, thickness); x += sz + spacing; 2568 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col32, 10.0f, ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotRight, thickness); x += sz + spacing; 2569 draw_list->AddTriangle(ImVec2(x + sz * 0.5f, y), ImVec2(x + sz, y + sz - 0.5f), ImVec2(x, y + sz - 0.5f), col32, thickness); x += sz + spacing; 2570 draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y), col32, thickness); x += sz + spacing; 2571 draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y + sz), col32, thickness); x += sz + spacing; 2572 draw_list->AddLine(ImVec2(x, y), ImVec2(x, y + sz), col32, thickness); x += spacing; 2573 draw_list->AddBezierCurve(ImVec2(x, y), ImVec2(x + sz * 1.3f, y + sz * 0.3f), ImVec2(x + sz - sz * 1.3f, y + sz - sz * 0.3f), ImVec2(x + sz, y + sz), col32, thickness); 2574 x = p.x + 4; 2575 y += sz + spacing; 2576 } 2577 draw_list->AddCircleFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz*0.5f, col32, 32); x += sz + spacing; 2578 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col32); x += sz + spacing; 2579 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col32, 10.0f); x += sz + spacing; 2580 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col32, 10.0f, ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotRight); x += sz + spacing; 2581 draw_list->AddTriangleFilled(ImVec2(x + sz * 0.5f, y), ImVec2(x + sz, y + sz - 0.5f), ImVec2(x, y + sz - 0.5f), col32); x += sz + spacing; 2582 draw_list->AddRectFilledMultiColor(ImVec2(x, y), ImVec2(x + sz, y + sz), IM_COL32(0, 0, 0, 255), IM_COL32(255, 0, 0, 255), IM_COL32(255, 255, 0, 255), IM_COL32(0, 255, 0, 255)); 2583 ImGui::Dummy(ImVec2((sz + spacing) * 8, (sz + spacing) * 3)); 2584 } 2585 ImGui::Separator(); 2586 { 2587 static ImVector<ImVec2> points; 2588 static bool adding_line = false; 2589 ImGui::Text("Canvas example"); 2590 if (ImGui::Button("Clear")) points.clear(); 2591 if (points.Size >= 2) { ImGui::SameLine(); if (ImGui::Button("Undo")) { points.pop_back(); points.pop_back(); } } 2592 ImGui::Text("Left-click and drag to add lines,\nRight-click to undo"); 2593 2594 // Here we are using InvisibleButton() as a convenience to 1) advance the cursor and 2) allows us to use IsItemHovered() 2595 // However you can draw directly and poll mouse/keyboard by yourself. You can manipulate the cursor using GetCursorPos() and SetCursorPos(). 2596 // If you only use the ImDrawList API, you can notify the owner window of its extends by using SetCursorPos(max). 2597 ImVec2 canvas_pos = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates! 2598 ImVec2 canvas_size = ImGui::GetContentRegionAvail(); // Resize canvas to what's available 2599 if (canvas_size.x < 50.0f) canvas_size.x = 50.0f; 2600 if (canvas_size.y < 50.0f) canvas_size.y = 50.0f; 2601 draw_list->AddRectFilledMultiColor(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), IM_COL32(50, 50, 50, 255), IM_COL32(50, 50, 60, 255), IM_COL32(60, 60, 70, 255), IM_COL32(50, 50, 60, 255)); 2602 draw_list->AddRect(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), IM_COL32(255, 255, 255, 255)); 2603 2604 bool adding_preview = false; 2605 ImGui::InvisibleButton("canvas", canvas_size); 2606 ImVec2 mouse_pos_in_canvas = ImVec2(ImGui::GetIO().MousePos.x - canvas_pos.x, ImGui::GetIO().MousePos.y - canvas_pos.y); 2607 if (adding_line) 2608 { 2609 adding_preview = true; 2610 points.push_back(mouse_pos_in_canvas); 2611 if (!ImGui::IsMouseDown(0)) 2612 adding_line = adding_preview = false; 2613 } 2614 if (ImGui::IsItemHovered()) 2615 { 2616 if (!adding_line && ImGui::IsMouseClicked(0)) 2617 { 2618 points.push_back(mouse_pos_in_canvas); 2619 adding_line = true; 2620 } 2621 if (ImGui::IsMouseClicked(1) && !points.empty()) 2622 { 2623 adding_line = adding_preview = false; 2624 points.pop_back(); 2625 points.pop_back(); 2626 } 2627 } 2628 draw_list->PushClipRect(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), true); // clip lines within the canvas (if we resize it, etc.) 2629 for (int i = 0; i < points.Size - 1; i += 2) 2630 draw_list->AddLine(ImVec2(canvas_pos.x + points[i].x, canvas_pos.y + points[i].y), ImVec2(canvas_pos.x + points[i + 1].x, canvas_pos.y + points[i + 1].y), IM_COL32(255, 255, 0, 255), 2.0f); 2631 draw_list->PopClipRect(); 2632 if (adding_preview) 2633 points.pop_back(); 2634 } 2635 ImGui::End(); 2636 } 2637 2638 // Demonstrating creating a simple console window, with scrolling, filtering, completion and history. 2639 // For the console example, here we are using a more C++ like approach of declaring a class to hold the data and the functions. 4209 //----------------------------------------------------------------------------- 4210 // [SECTION] Example App: Debug Console / ShowExampleAppConsole() 4211 //----------------------------------------------------------------------------- 4212 4213 // Demonstrate creating a simple console window, with scrolling, filtering, completion and history. 4214 // For the console example, we are using a more C++ like approach of declaring a class to hold both data and functions. 2640 4215 struct ExampleAppConsole 2641 4216 { 2642 char InputBuf[256]; 2643 ImVector<char*> Items; 2644 bool ScrollToBottom; 2645 ImVector<char*> History; 2646 int HistoryPos; // -1: new line, 0..History.Size-1 browsing history. 2647 ImVector<const char*> Commands; 2648 2649 ExampleAppConsole() 2650 { 2651 ClearLog(); 2652 memset(InputBuf, 0, sizeof(InputBuf)); 2653 HistoryPos = -1; 2654 Commands.push_back("HELP"); 2655 Commands.push_back("HISTORY"); 2656 Commands.push_back("CLEAR"); 2657 Commands.push_back("CLASSIFY"); // "classify" is here to provide an example of "C"+[tab] completing to "CL" and displaying matches. 2658 AddLog("Welcome to ImGui!"); 2659 } 2660 ~ExampleAppConsole() 2661 { 2662 ClearLog(); 2663 for (int i = 0; i < History.Size; i++) 2664 free(History[i]); 2665 } 2666 2667 // Portable helpers 2668 static int Stricmp(const char* str1, const char* str2) { int d; while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; } return d; } 2669 static int Strnicmp(const char* str1, const char* str2, int n) { int d = 0; while (n > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; n--; } return d; } 2670 static char* Strdup(const char *str) { size_t len = strlen(str) + 1; void* buff = malloc(len); return (char*)memcpy(buff, (const void*)str, len); } 2671 2672 void ClearLog() 2673 { 2674 for (int i = 0; i < Items.Size; i++) 2675 free(Items[i]); 2676 Items.clear(); 2677 ScrollToBottom = true; 2678 } 2679 2680 void AddLog(const char* fmt, ...) IM_FMTARGS(2) 2681 { 2682 // FIXME-OPT 2683 char buf[1024]; 2684 va_list args; 2685 va_start(args, fmt); 2686 vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args); 2687 buf[IM_ARRAYSIZE(buf) - 1] = 0; 2688 va_end(args); 2689 Items.push_back(Strdup(buf)); 2690 ScrollToBottom = true; 2691 } 2692 2693 void Draw(const char* title, bool* p_open) 2694 { 2695 ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); 2696 if (!ImGui::Begin(title, p_open)) 2697 { 2698 ImGui::End(); 2699 return; 2700 } 2701 2702 // As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar. So e.g. IsItemHovered() will return true when hovering the title bar. 2703 // Here we create a context menu only available from the title bar. 2704 if (ImGui::BeginPopupContextItem()) 2705 { 2706 if (ImGui::MenuItem("Close")) 2707 *p_open = false; 2708 ImGui::EndPopup(); 2709 } 2710 2711 ImGui::TextWrapped("This example implements a console with basic coloring, completion and history. A more elaborate implementation may want to store entries along with extra data such as timestamp, emitter, etc."); 2712 ImGui::TextWrapped("Enter 'HELP' for help, press TAB to use text completion."); 2713 2714 // TODO: display items starting from the bottom 2715 2716 if (ImGui::SmallButton("Add Dummy Text")) { AddLog("%d some text", Items.Size); AddLog("some more text"); AddLog("display very important message here!"); } ImGui::SameLine(); 2717 if (ImGui::SmallButton("Add Dummy Error")) { AddLog("[error] something went wrong"); } ImGui::SameLine(); 2718 if (ImGui::SmallButton("Clear")) { ClearLog(); } ImGui::SameLine(); 2719 bool copy_to_clipboard = ImGui::SmallButton("Copy"); ImGui::SameLine(); 2720 if (ImGui::SmallButton("Scroll to bottom")) ScrollToBottom = true; 2721 //static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); } 2722 2723 ImGui::Separator(); 2724 2725 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); 2726 static ImGuiTextFilter filter; 2727 filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180); 2728 ImGui::PopStyleVar(); 2729 ImGui::Separator(); 2730 2731 const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); // 1 separator, 1 input text 2732 ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), false, ImGuiWindowFlags_HorizontalScrollbar); // Leave room for 1 separator + 1 InputText 2733 if (ImGui::BeginPopupContextWindow()) 2734 { 2735 if (ImGui::Selectable("Clear")) ClearLog(); 2736 ImGui::EndPopup(); 2737 } 2738 2739 // Display every line as a separate entry so we can change their color or add custom widgets. If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end()); 2740 // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping to only process visible items. 2741 // You can seek and display only the lines that are visible using the ImGuiListClipper helper, if your elements are evenly spaced and you have cheap random access to the elements. 2742 // To use the clipper we could replace the 'for (int i = 0; i < Items.Size; i++)' loop with: 2743 // ImGuiListClipper clipper(Items.Size); 2744 // while (clipper.Step()) 2745 // for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) 2746 // However take note that you can not use this code as is if a filter is active because it breaks the 'cheap random-access' property. We would need random-access on the post-filtered list. 2747 // A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices that passed the filtering test, recomputing this array when user changes the filter, 2748 // and appending newly elements as they are inserted. This is left as a task to the user until we can manage to improve this example code! 2749 // If your items are of variable size you may want to implement code similar to what ImGuiListClipper does. Or split your data into fixed height items to allow random-seeking into your list. 2750 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing 2751 if (copy_to_clipboard) 2752 ImGui::LogToClipboard(); 2753 ImVec4 col_default_text = ImGui::GetStyleColorVec4(ImGuiCol_Text); 2754 for (int i = 0; i < Items.Size; i++) 2755 { 2756 const char* item = Items[i]; 2757 if (!filter.PassFilter(item)) 2758 continue; 2759 ImVec4 col = col_default_text; 2760 if (strstr(item, "[error]")) col = ImColor(1.0f, 0.4f, 0.4f, 1.0f); 2761 else if (strncmp(item, "# ", 2) == 0) col = ImColor(1.0f, 0.78f, 0.58f, 1.0f); 2762 ImGui::PushStyleColor(ImGuiCol_Text, col); 2763 ImGui::TextUnformatted(item); 2764 ImGui::PopStyleColor(); 2765 } 2766 if (copy_to_clipboard) 2767 ImGui::LogFinish(); 2768 if (ScrollToBottom) 2769 ImGui::SetScrollHere(); 2770 ScrollToBottom = false; 2771 ImGui::PopStyleVar(); 2772 ImGui::EndChild(); 2773 ImGui::Separator(); 2774 2775 // Command-line 2776 bool reclaim_focus = false; 2777 if (ImGui::InputText("Input", InputBuf, IM_ARRAYSIZE(InputBuf), ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory, &TextEditCallbackStub, (void*)this)) 2778 { 2779 char* input_end = InputBuf + strlen(InputBuf); 2780 while (input_end > InputBuf && input_end[-1] == ' ') { input_end--; } *input_end = 0; 2781 if (InputBuf[0]) 2782 ExecCommand(InputBuf); 2783 strcpy(InputBuf, ""); 2784 reclaim_focus = true; 2785 } 2786 2787 // Demonstrate keeping focus on the input box 2788 ImGui::SetItemDefaultFocus(); 2789 if (reclaim_focus) 2790 ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget 2791 2792 ImGui::End(); 2793 } 2794 2795 void ExecCommand(const char* command_line) 2796 { 2797 AddLog("# %s\n", command_line); 2798 2799 // Insert into history. First find match and delete it so it can be pushed to the back. This isn't trying to be smart or optimal. 2800 HistoryPos = -1; 2801 for (int i = History.Size - 1; i >= 0; i--) 2802 if (Stricmp(History[i], command_line) == 0) 2803 { 4217 char InputBuf[256]; 4218 ImVector<char*> Items; 4219 ImVector<const char*> Commands; 4220 ImVector<char*> History; 4221 int HistoryPos; // -1: new line, 0..History.Size-1 browsing history. 4222 ImGuiTextFilter Filter; 4223 bool AutoScroll; 4224 bool ScrollToBottom; 4225 4226 ExampleAppConsole() 4227 { 4228 ClearLog(); 4229 memset(InputBuf, 0, sizeof(InputBuf)); 4230 HistoryPos = -1; 4231 4232 // "CLASSIFY" is here to provide the test case where "C"+[tab] completes to "CL" and display multiple matches. 4233 Commands.push_back("HELP"); 4234 Commands.push_back("HISTORY"); 4235 Commands.push_back("CLEAR"); 4236 Commands.push_back("CLASSIFY"); 4237 AutoScroll = true; 4238 ScrollToBottom = false; 4239 AddLog("Welcome to Dear ImGui!"); 4240 } 4241 ~ExampleAppConsole() 4242 { 4243 ClearLog(); 4244 for (int i = 0; i < History.Size; i++) 2804 4245 free(History[i]); 2805 History.erase(History.begin() + i); 2806 break; 2807 } 2808 History.push_back(Strdup(command_line)); 2809 2810 // Process command 2811 if (Stricmp(command_line, "CLEAR") == 0) 2812 { 2813 ClearLog(); 2814 } 2815 else if (Stricmp(command_line, "HELP") == 0) 2816 { 2817 AddLog("Commands:"); 2818 for (int i = 0; i < Commands.Size; i++) 2819 AddLog("- %s", Commands[i]); 2820 } 2821 else if (Stricmp(command_line, "HISTORY") == 0) 2822 { 2823 int first = History.Size - 10; 2824 for (int i = first > 0 ? first : 0; i < History.Size; i++) 2825 AddLog("%3d: %s\n", i, History[i]); 2826 } 2827 else 2828 { 2829 AddLog("Unknown command: '%s'\n", command_line); 2830 } 2831 } 2832 2833 static int TextEditCallbackStub(ImGuiTextEditCallbackData* data) // In C++11 you are better off using lambdas for this sort of forwarding callbacks 2834 { 2835 ExampleAppConsole* console = (ExampleAppConsole*)data->UserData; 2836 return console->TextEditCallback(data); 2837 } 2838 2839 int TextEditCallback(ImGuiTextEditCallbackData* data) 2840 { 2841 //AddLog("cursor: %d, selection: %d-%d", data->CursorPos, data->SelectionStart, data->SelectionEnd); 2842 switch (data->EventFlag) 2843 { 2844 case ImGuiInputTextFlags_CallbackCompletion: 2845 { 2846 // Example of TEXT COMPLETION 2847 2848 // Locate beginning of current word 2849 const char* word_end = data->Buf + data->CursorPos; 2850 const char* word_start = word_end; 2851 while (word_start > data->Buf) 2852 { 2853 const char c = word_start[-1]; 2854 if (c == ' ' || c == '\t' || c == ',' || c == ';') 2855 break; 2856 word_start--; 2857 } 2858 2859 // Build a list of candidates 2860 ImVector<const char*> candidates; 2861 for (int i = 0; i < Commands.Size; i++) 2862 if (Strnicmp(Commands[i], word_start, (int)(word_end - word_start)) == 0) 2863 candidates.push_back(Commands[i]); 2864 2865 if (candidates.Size == 0) 2866 { 2867 // No match 2868 AddLog("No match for \"%.*s\"!\n", (int)(word_end - word_start), word_start); 2869 } 2870 else if (candidates.Size == 1) 2871 { 2872 // Single match. Delete the beginning of the word and replace it entirely so we've got nice casing 2873 data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start)); 2874 data->InsertChars(data->CursorPos, candidates[0]); 2875 data->InsertChars(data->CursorPos, " "); 2876 } 2877 else 2878 { 2879 // Multiple matches. Complete as much as we can, so inputing "C" will complete to "CL" and display "CLEAR" and "CLASSIFY" 2880 int match_len = (int)(word_end - word_start); 2881 for (;;) 2882 { 2883 int c = 0; 2884 bool all_candidates_matches = true; 2885 for (int i = 0; i < candidates.Size && all_candidates_matches; i++) 2886 if (i == 0) 2887 c = toupper(candidates[i][match_len]); 2888 else if (c == 0 || c != toupper(candidates[i][match_len])) 2889 all_candidates_matches = false; 2890 if (!all_candidates_matches) 2891 break; 2892 match_len++; 2893 } 2894 2895 if (match_len > 0) 2896 { 2897 data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start)); 2898 data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len); 2899 } 2900 2901 // List matches 2902 AddLog("Possible matches:\n"); 2903 for (int i = 0; i < candidates.Size; i++) 2904 AddLog("- %s\n", candidates[i]); 2905 } 2906 2907 break; 2908 } 2909 case ImGuiInputTextFlags_CallbackHistory: 2910 { 2911 // Example of HISTORY 2912 const int prev_history_pos = HistoryPos; 2913 if (data->EventKey == ImGuiKey_UpArrow) 2914 { 2915 if (HistoryPos == -1) 2916 HistoryPos = History.Size - 1; 2917 else if (HistoryPos > 0) 2918 HistoryPos--; 2919 } 2920 else if (data->EventKey == ImGuiKey_DownArrow) 2921 { 2922 if (HistoryPos != -1) 2923 if (++HistoryPos >= History.Size) 2924 HistoryPos = -1; 2925 } 2926 2927 // A better implementation would preserve the data on the current input line along with cursor position. 2928 if (prev_history_pos != HistoryPos) 2929 { 2930 data->CursorPos = data->SelectionStart = data->SelectionEnd = data->BufTextLen = (int)snprintf(data->Buf, (size_t)data->BufSize, "%s", (HistoryPos >= 0) ? History[HistoryPos] : ""); 2931 data->BufDirty = true; 2932 } 2933 } 2934 } 2935 return 0; 2936 } 4246 } 4247 4248 // Portable helpers 4249 static int Stricmp(const char* s1, const char* s2) { int d; while ((d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; } return d; } 4250 static int Strnicmp(const char* s1, const char* s2, int n) { int d = 0; while (n > 0 && (d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; n--; } return d; } 4251 static char* Strdup(const char* s) { size_t len = strlen(s) + 1; void* buf = malloc(len); IM_ASSERT(buf); return (char*)memcpy(buf, (const void*)s, len); } 4252 static void Strtrim(char* s) { char* str_end = s + strlen(s); while (str_end > s && str_end[-1] == ' ') str_end--; *str_end = 0; } 4253 4254 void ClearLog() 4255 { 4256 for (int i = 0; i < Items.Size; i++) 4257 free(Items[i]); 4258 Items.clear(); 4259 } 4260 4261 void AddLog(const char* fmt, ...) IM_FMTARGS(2) 4262 { 4263 // FIXME-OPT 4264 char buf[1024]; 4265 va_list args; 4266 va_start(args, fmt); 4267 vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args); 4268 buf[IM_ARRAYSIZE(buf)-1] = 0; 4269 va_end(args); 4270 Items.push_back(Strdup(buf)); 4271 } 4272 4273 void Draw(const char* title, bool* p_open) 4274 { 4275 ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); 4276 if (!ImGui::Begin(title, p_open)) 4277 { 4278 ImGui::End(); 4279 return; 4280 } 4281 4282 // As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar. 4283 // So e.g. IsItemHovered() will return true when hovering the title bar. 4284 // Here we create a context menu only available from the title bar. 4285 if (ImGui::BeginPopupContextItem()) 4286 { 4287 if (ImGui::MenuItem("Close Console")) 4288 *p_open = false; 4289 ImGui::EndPopup(); 4290 } 4291 4292 ImGui::TextWrapped( 4293 "This example implements a console with basic coloring, completion (TAB key) and history (Up/Down keys). A more elaborate " 4294 "implementation may want to store entries along with extra data such as timestamp, emitter, etc."); 4295 ImGui::TextWrapped("Enter 'HELP' for help."); 4296 4297 // TODO: display items starting from the bottom 4298 4299 if (ImGui::SmallButton("Add Debug Text")) { AddLog("%d some text", Items.Size); AddLog("some more text"); AddLog("display very important message here!"); } 4300 ImGui::SameLine(); 4301 if (ImGui::SmallButton("Add Debug Error")) { AddLog("[error] something went wrong"); } 4302 ImGui::SameLine(); 4303 if (ImGui::SmallButton("Clear")) { ClearLog(); } 4304 ImGui::SameLine(); 4305 bool copy_to_clipboard = ImGui::SmallButton("Copy"); 4306 //static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); } 4307 4308 ImGui::Separator(); 4309 4310 // Options menu 4311 if (ImGui::BeginPopup("Options")) 4312 { 4313 ImGui::Checkbox("Auto-scroll", &AutoScroll); 4314 ImGui::EndPopup(); 4315 } 4316 4317 // Options, Filter 4318 if (ImGui::Button("Options")) 4319 ImGui::OpenPopup("Options"); 4320 ImGui::SameLine(); 4321 Filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180); 4322 ImGui::Separator(); 4323 4324 // Reserve enough left-over height for 1 separator + 1 input text 4325 const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); 4326 ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), false, ImGuiWindowFlags_HorizontalScrollbar); 4327 if (ImGui::BeginPopupContextWindow()) 4328 { 4329 if (ImGui::Selectable("Clear")) ClearLog(); 4330 ImGui::EndPopup(); 4331 } 4332 4333 // Display every line as a separate entry so we can change their color or add custom widgets. 4334 // If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end()); 4335 // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping 4336 // to only process visible items. The clipper will automatically measure the height of your first item and then 4337 // "seek" to display only items in the visible area. 4338 // To use the clipper we can replace your standard loop: 4339 // for (int i = 0; i < Items.Size; i++) 4340 // With: 4341 // ImGuiListClipper clipper; 4342 // clipper.Begin(Items.Size); 4343 // while (clipper.Step()) 4344 // for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) 4345 // - That your items are evenly spaced (same height) 4346 // - That you have cheap random access to your elements (you can access them given their index, 4347 // without processing all the ones before) 4348 // You cannot this code as-is if a filter is active because it breaks the 'cheap random-access' property. 4349 // We would need random-access on the post-filtered list. 4350 // A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices 4351 // or offsets of items that passed the filtering test, recomputing this array when user changes the filter, 4352 // and appending newly elements as they are inserted. This is left as a task to the user until we can manage 4353 // to improve this example code! 4354 // If your items are of variable height: 4355 // - Split them into same height items would be simpler and facilitate random-seeking into your list. 4356 // - Consider using manual call to IsRectVisible() and skipping extraneous decoration from your items. 4357 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing 4358 if (copy_to_clipboard) 4359 ImGui::LogToClipboard(); 4360 for (int i = 0; i < Items.Size; i++) 4361 { 4362 const char* item = Items[i]; 4363 if (!Filter.PassFilter(item)) 4364 continue; 4365 4366 // Normally you would store more information in your item than just a string. 4367 // (e.g. make Items[] an array of structure, store color/type etc.) 4368 ImVec4 color; 4369 bool has_color = false; 4370 if (strstr(item, "[error]")) { color = ImVec4(1.0f, 0.4f, 0.4f, 1.0f); has_color = true; } 4371 else if (strncmp(item, "# ", 2) == 0) { color = ImVec4(1.0f, 0.8f, 0.6f, 1.0f); has_color = true; } 4372 if (has_color) 4373 ImGui::PushStyleColor(ImGuiCol_Text, color); 4374 ImGui::TextUnformatted(item); 4375 if (has_color) 4376 ImGui::PopStyleColor(); 4377 } 4378 if (copy_to_clipboard) 4379 ImGui::LogFinish(); 4380 4381 if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())) 4382 ImGui::SetScrollHereY(1.0f); 4383 ScrollToBottom = false; 4384 4385 ImGui::PopStyleVar(); 4386 ImGui::EndChild(); 4387 ImGui::Separator(); 4388 4389 // Command-line 4390 bool reclaim_focus = false; 4391 ImGuiInputTextFlags input_text_flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory; 4392 if (ImGui::InputText("Input", InputBuf, IM_ARRAYSIZE(InputBuf), input_text_flags, &TextEditCallbackStub, (void*)this)) 4393 { 4394 char* s = InputBuf; 4395 Strtrim(s); 4396 if (s[0]) 4397 ExecCommand(s); 4398 strcpy(s, ""); 4399 reclaim_focus = true; 4400 } 4401 4402 // Auto-focus on window apparition 4403 ImGui::SetItemDefaultFocus(); 4404 if (reclaim_focus) 4405 ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget 4406 4407 ImGui::End(); 4408 } 4409 4410 void ExecCommand(const char* command_line) 4411 { 4412 AddLog("# %s\n", command_line); 4413 4414 // Insert into history. First find match and delete it so it can be pushed to the back. 4415 // This isn't trying to be smart or optimal. 4416 HistoryPos = -1; 4417 for (int i = History.Size - 1; i >= 0; i--) 4418 if (Stricmp(History[i], command_line) == 0) 4419 { 4420 free(History[i]); 4421 History.erase(History.begin() + i); 4422 break; 4423 } 4424 History.push_back(Strdup(command_line)); 4425 4426 // Process command 4427 if (Stricmp(command_line, "CLEAR") == 0) 4428 { 4429 ClearLog(); 4430 } 4431 else if (Stricmp(command_line, "HELP") == 0) 4432 { 4433 AddLog("Commands:"); 4434 for (int i = 0; i < Commands.Size; i++) 4435 AddLog("- %s", Commands[i]); 4436 } 4437 else if (Stricmp(command_line, "HISTORY") == 0) 4438 { 4439 int first = History.Size - 10; 4440 for (int i = first > 0 ? first : 0; i < History.Size; i++) 4441 AddLog("%3d: %s\n", i, History[i]); 4442 } 4443 else 4444 { 4445 AddLog("Unknown command: '%s'\n", command_line); 4446 } 4447 4448 // On command input, we scroll to bottom even if AutoScroll==false 4449 ScrollToBottom = true; 4450 } 4451 4452 // In C++11 you'd be better off using lambdas for this sort of forwarding callbacks 4453 static int TextEditCallbackStub(ImGuiInputTextCallbackData* data) 4454 { 4455 ExampleAppConsole* console = (ExampleAppConsole*)data->UserData; 4456 return console->TextEditCallback(data); 4457 } 4458 4459 int TextEditCallback(ImGuiInputTextCallbackData* data) 4460 { 4461 //AddLog("cursor: %d, selection: %d-%d", data->CursorPos, data->SelectionStart, data->SelectionEnd); 4462 switch (data->EventFlag) 4463 { 4464 case ImGuiInputTextFlags_CallbackCompletion: 4465 { 4466 // Example of TEXT COMPLETION 4467 4468 // Locate beginning of current word 4469 const char* word_end = data->Buf + data->CursorPos; 4470 const char* word_start = word_end; 4471 while (word_start > data->Buf) 4472 { 4473 const char c = word_start[-1]; 4474 if (c == ' ' || c == '\t' || c == ',' || c == ';') 4475 break; 4476 word_start--; 4477 } 4478 4479 // Build a list of candidates 4480 ImVector<const char*> candidates; 4481 for (int i = 0; i < Commands.Size; i++) 4482 if (Strnicmp(Commands[i], word_start, (int)(word_end - word_start)) == 0) 4483 candidates.push_back(Commands[i]); 4484 4485 if (candidates.Size == 0) 4486 { 4487 // No match 4488 AddLog("No match for \"%.*s\"!\n", (int)(word_end - word_start), word_start); 4489 } 4490 else if (candidates.Size == 1) 4491 { 4492 // Single match. Delete the beginning of the word and replace it entirely so we've got nice casing. 4493 data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start)); 4494 data->InsertChars(data->CursorPos, candidates[0]); 4495 data->InsertChars(data->CursorPos, " "); 4496 } 4497 else 4498 { 4499 // Multiple matches. Complete as much as we can.. 4500 // So inputing "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches. 4501 int match_len = (int)(word_end - word_start); 4502 for (;;) 4503 { 4504 int c = 0; 4505 bool all_candidates_matches = true; 4506 for (int i = 0; i < candidates.Size && all_candidates_matches; i++) 4507 if (i == 0) 4508 c = toupper(candidates[i][match_len]); 4509 else if (c == 0 || c != toupper(candidates[i][match_len])) 4510 all_candidates_matches = false; 4511 if (!all_candidates_matches) 4512 break; 4513 match_len++; 4514 } 4515 4516 if (match_len > 0) 4517 { 4518 data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start)); 4519 data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len); 4520 } 4521 4522 // List matches 4523 AddLog("Possible matches:\n"); 4524 for (int i = 0; i < candidates.Size; i++) 4525 AddLog("- %s\n", candidates[i]); 4526 } 4527 4528 break; 4529 } 4530 case ImGuiInputTextFlags_CallbackHistory: 4531 { 4532 // Example of HISTORY 4533 const int prev_history_pos = HistoryPos; 4534 if (data->EventKey == ImGuiKey_UpArrow) 4535 { 4536 if (HistoryPos == -1) 4537 HistoryPos = History.Size - 1; 4538 else if (HistoryPos > 0) 4539 HistoryPos--; 4540 } 4541 else if (data->EventKey == ImGuiKey_DownArrow) 4542 { 4543 if (HistoryPos != -1) 4544 if (++HistoryPos >= History.Size) 4545 HistoryPos = -1; 4546 } 4547 4548 // A better implementation would preserve the data on the current input line along with cursor position. 4549 if (prev_history_pos != HistoryPos) 4550 { 4551 const char* history_str = (HistoryPos >= 0) ? History[HistoryPos] : ""; 4552 data->DeleteChars(0, data->BufTextLen); 4553 data->InsertChars(0, history_str); 4554 } 4555 } 4556 } 4557 return 0; 4558 } 2937 4559 }; 2938 4560 2939 4561 static void ShowExampleAppConsole(bool* p_open) 2940 4562 { 2941 static ExampleAppConsole console;2942 console.Draw("Example: Console", p_open);4563 static ExampleAppConsole console; 4564 console.Draw("Example: Console", p_open); 2943 4565 } 4566 4567 //----------------------------------------------------------------------------- 4568 // [SECTION] Example App: Debug Log / ShowExampleAppLog() 4569 //----------------------------------------------------------------------------- 2944 4570 2945 4571 // Usage: … … 2949 4575 struct ExampleAppLog 2950 4576 { 2951 ImGuiTextBuffer Buf; 2952 ImGuiTextFilter Filter; 2953 ImVector<int> LineOffsets; // Index to lines offset 2954 bool ScrollToBottom; 2955 2956 void Clear() { Buf.clear(); LineOffsets.clear(); } 2957 2958 void AddLog(const char* fmt, ...) IM_FMTARGS(2) 2959 { 2960 int old_size = Buf.size(); 2961 va_list args; 2962 va_start(args, fmt); 2963 Buf.appendfv(fmt, args); 2964 va_end(args); 2965 for (int new_size = Buf.size(); old_size < new_size; old_size++) 2966 if (Buf[old_size] == '\n') 2967 LineOffsets.push_back(old_size); 2968 ScrollToBottom = true; 2969 } 2970 2971 void Draw(const char* title, bool* p_open = NULL) 2972 { 2973 ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver); 2974 ImGui::Begin(title, p_open); 2975 if (ImGui::Button("Clear")) Clear(); 2976 ImGui::SameLine(); 2977 bool copy = ImGui::Button("Copy"); 2978 ImGui::SameLine(); 2979 Filter.Draw("Filter", -100.0f); 2980 ImGui::Separator(); 2981 ImGui::BeginChild("scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar); 2982 if (copy) ImGui::LogToClipboard(); 2983 2984 if (Filter.IsActive()) 2985 { 2986 const char* buf_begin = Buf.begin(); 2987 const char* line = buf_begin; 2988 for (int line_no = 0; line != NULL; line_no++) 2989 { 2990 const char* line_end = (line_no < LineOffsets.Size) ? buf_begin + LineOffsets[line_no] : NULL; 2991 if (Filter.PassFilter(line, line_end)) 2992 ImGui::TextUnformatted(line, line_end); 2993 line = line_end && line_end[1] ? line_end + 1 : NULL; 2994 } 2995 } 2996 else 2997 { 2998 ImGui::TextUnformatted(Buf.begin()); 2999 } 3000 3001 if (ScrollToBottom) 3002 ImGui::SetScrollHere(1.0f); 3003 ScrollToBottom = false; 3004 ImGui::EndChild(); 3005 ImGui::End(); 3006 } 4577 ImGuiTextBuffer Buf; 4578 ImGuiTextFilter Filter; 4579 ImVector<int> LineOffsets; // Index to lines offset. We maintain this with AddLog() calls. 4580 bool AutoScroll; // Keep scrolling if already at the bottom. 4581 4582 ExampleAppLog() 4583 { 4584 AutoScroll = true; 4585 Clear(); 4586 } 4587 4588 void Clear() 4589 { 4590 Buf.clear(); 4591 LineOffsets.clear(); 4592 LineOffsets.push_back(0); 4593 } 4594 4595 void AddLog(const char* fmt, ...) IM_FMTARGS(2) 4596 { 4597 int old_size = Buf.size(); 4598 va_list args; 4599 va_start(args, fmt); 4600 Buf.appendfv(fmt, args); 4601 va_end(args); 4602 for (int new_size = Buf.size(); old_size < new_size; old_size++) 4603 if (Buf[old_size] == '\n') 4604 LineOffsets.push_back(old_size + 1); 4605 } 4606 4607 void Draw(const char* title, bool* p_open = NULL) 4608 { 4609 if (!ImGui::Begin(title, p_open)) 4610 { 4611 ImGui::End(); 4612 return; 4613 } 4614 4615 // Options menu 4616 if (ImGui::BeginPopup("Options")) 4617 { 4618 ImGui::Checkbox("Auto-scroll", &AutoScroll); 4619 ImGui::EndPopup(); 4620 } 4621 4622 // Main window 4623 if (ImGui::Button("Options")) 4624 ImGui::OpenPopup("Options"); 4625 ImGui::SameLine(); 4626 bool clear = ImGui::Button("Clear"); 4627 ImGui::SameLine(); 4628 bool copy = ImGui::Button("Copy"); 4629 ImGui::SameLine(); 4630 Filter.Draw("Filter", -100.0f); 4631 4632 ImGui::Separator(); 4633 ImGui::BeginChild("scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar); 4634 4635 if (clear) 4636 Clear(); 4637 if (copy) 4638 ImGui::LogToClipboard(); 4639 4640 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); 4641 const char* buf = Buf.begin(); 4642 const char* buf_end = Buf.end(); 4643 if (Filter.IsActive()) 4644 { 4645 // In this example we don't use the clipper when Filter is enabled. 4646 // This is because we don't have a random access on the result on our filter. 4647 // A real application processing logs with ten of thousands of entries may want to store the result of 4648 // search/filter.. especially if the filtering function is not trivial (e.g. reg-exp). 4649 for (int line_no = 0; line_no < LineOffsets.Size; line_no++) 4650 { 4651 const char* line_start = buf + LineOffsets[line_no]; 4652 const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; 4653 if (Filter.PassFilter(line_start, line_end)) 4654 ImGui::TextUnformatted(line_start, line_end); 4655 } 4656 } 4657 else 4658 { 4659 // The simplest and easy way to display the entire buffer: 4660 // ImGui::TextUnformatted(buf_begin, buf_end); 4661 // And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward 4662 // to skip non-visible lines. Here we instead demonstrate using the clipper to only process lines that are 4663 // within the visible area. 4664 // If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them 4665 // on your side is recommended. Using ImGuiListClipper requires 4666 // - A) random access into your data 4667 // - B) items all being the same height, 4668 // both of which we can handle since we an array pointing to the beginning of each line of text. 4669 // When using the filter (in the block of code above) we don't have random access into the data to display 4670 // anymore, which is why we don't use the clipper. Storing or skimming through the search result would make 4671 // it possible (and would be recommended if you want to search through tens of thousands of entries). 4672 ImGuiListClipper clipper; 4673 clipper.Begin(LineOffsets.Size); 4674 while (clipper.Step()) 4675 { 4676 for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++) 4677 { 4678 const char* line_start = buf + LineOffsets[line_no]; 4679 const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; 4680 ImGui::TextUnformatted(line_start, line_end); 4681 } 4682 } 4683 clipper.End(); 4684 } 4685 ImGui::PopStyleVar(); 4686 4687 if (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) 4688 ImGui::SetScrollHereY(1.0f); 4689 4690 ImGui::EndChild(); 4691 ImGui::End(); 4692 } 3007 4693 }; 3008 4694 … … 3010 4696 static void ShowExampleAppLog(bool* p_open) 3011 4697 { 3012 static ExampleAppLog log; 3013 3014 // Demo: add random items (unless Ctrl is held) 3015 static float last_time = -1.0f; 3016 float time = ImGui::GetTime(); 3017 if (time - last_time >= 0.20f && !ImGui::GetIO().KeyCtrl) 3018 { 3019 const char* random_words[] = { "system", "info", "warning", "error", "fatal", "notice", "log" }; 3020 log.AddLog("[%s] Hello, time is %.1f, frame count is %d\n", random_words[rand() % IM_ARRAYSIZE(random_words)], time, ImGui::GetFrameCount()); 3021 last_time = time; 3022 } 3023 3024 log.Draw("Example: Log", p_open); 4698 static ExampleAppLog log; 4699 4700 // For the demo: add a debug button _BEFORE_ the normal log window contents 4701 // We take advantage of a rarely used feature: multiple calls to Begin()/End() are appending to the _same_ window. 4702 // Most of the contents of the window will be added by the log.Draw() call. 4703 ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver); 4704 ImGui::Begin("Example: Log", p_open); 4705 if (ImGui::SmallButton("[Debug] Add 5 entries")) 4706 { 4707 static int counter = 0; 4708 const char* categories[3] = { "info", "warn", "error" }; 4709 const char* words[] = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" }; 4710 for (int n = 0; n < 5; n++) 4711 { 4712 const char* category = categories[counter % IM_ARRAYSIZE(categories)]; 4713 const char* word = words[counter % IM_ARRAYSIZE(words)]; 4714 log.AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n", 4715 ImGui::GetFrameCount(), category, ImGui::GetTime(), word); 4716 counter++; 4717 } 4718 } 4719 ImGui::End(); 4720 4721 // Actually call in the regular Log helper (which will Begin() into the same window as we just did) 4722 log.Draw("Example: Log", p_open); 3025 4723 } 4724 4725 //----------------------------------------------------------------------------- 4726 // [SECTION] Example App: Simple Layout / ShowExampleAppLayout() 4727 //----------------------------------------------------------------------------- 3026 4728 3027 4729 // Demonstrate create a window with multiple child windows. 3028 4730 static void ShowExampleAppLayout(bool* p_open) 3029 4731 { 3030 ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiCond_FirstUseEver); 3031 if (ImGui::Begin("Example: Layout", p_open, ImGuiWindowFlags_MenuBar)) 3032 { 3033 if (ImGui::BeginMenuBar()) 3034 { 3035 if (ImGui::BeginMenu("File")) 3036 { 3037 if (ImGui::MenuItem("Close")) *p_open = false; 3038 ImGui::EndMenu(); 3039 } 3040 ImGui::EndMenuBar(); 3041 } 3042 3043 // left 3044 static int selected = 0; 3045 ImGui::BeginChild("left pane", ImVec2(150, 0), true); 3046 for (int i = 0; i < 100; i++) 3047 { 3048 char label[128]; 3049 sprintf(label, "MyObject %d", i); 3050 if (ImGui::Selectable(label, selected == i)) 3051 selected = i; 3052 } 3053 ImGui::EndChild(); 3054 ImGui::SameLine(); 3055 3056 // right 3057 ImGui::BeginGroup(); 3058 ImGui::BeginChild("item view", ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us 3059 ImGui::Text("MyObject: %d", selected); 3060 ImGui::Separator(); 3061 ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "); 3062 ImGui::EndChild(); 3063 if (ImGui::Button("Revert")) {} 3064 ImGui::SameLine(); 3065 if (ImGui::Button("Save")) {} 3066 ImGui::EndGroup(); 3067 } 3068 ImGui::End(); 4732 ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiCond_FirstUseEver); 4733 if (ImGui::Begin("Example: Simple layout", p_open, ImGuiWindowFlags_MenuBar)) 4734 { 4735 if (ImGui::BeginMenuBar()) 4736 { 4737 if (ImGui::BeginMenu("File")) 4738 { 4739 if (ImGui::MenuItem("Close")) *p_open = false; 4740 ImGui::EndMenu(); 4741 } 4742 ImGui::EndMenuBar(); 4743 } 4744 4745 // Left 4746 static int selected = 0; 4747 { 4748 ImGui::BeginChild("left pane", ImVec2(150, 0), true); 4749 for (int i = 0; i < 100; i++) 4750 { 4751 char label[128]; 4752 sprintf(label, "MyObject %d", i); 4753 if (ImGui::Selectable(label, selected == i)) 4754 selected = i; 4755 } 4756 ImGui::EndChild(); 4757 } 4758 ImGui::SameLine(); 4759 4760 // Right 4761 { 4762 ImGui::BeginGroup(); 4763 ImGui::BeginChild("item view", ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us 4764 ImGui::Text("MyObject: %d", selected); 4765 ImGui::Separator(); 4766 if (ImGui::BeginTabBar("##Tabs", ImGuiTabBarFlags_None)) 4767 { 4768 if (ImGui::BeginTabItem("Description")) 4769 { 4770 ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "); 4771 ImGui::EndTabItem(); 4772 } 4773 if (ImGui::BeginTabItem("Details")) 4774 { 4775 ImGui::Text("ID: 0123456789"); 4776 ImGui::EndTabItem(); 4777 } 4778 ImGui::EndTabBar(); 4779 } 4780 ImGui::EndChild(); 4781 if (ImGui::Button("Revert")) {} 4782 ImGui::SameLine(); 4783 if (ImGui::Button("Save")) {} 4784 ImGui::EndGroup(); 4785 } 4786 } 4787 ImGui::End(); 4788 } 4789 4790 //----------------------------------------------------------------------------- 4791 // [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor() 4792 //----------------------------------------------------------------------------- 4793 4794 static void ShowPlaceholderObject(const char* prefix, int uid) 4795 { 4796 // Use object uid as identifier. Most commonly you could also use the object pointer as a base ID. 4797 ImGui::PushID(uid); 4798 4799 // Text and Tree nodes are less high than framed widgets, using AlignTextToFramePadding() we add vertical spacing to make the tree lines equal high. 4800 ImGui::AlignTextToFramePadding(); 4801 bool node_open = ImGui::TreeNode("Object", "%s_%u", prefix, uid); 4802 ImGui::NextColumn(); 4803 ImGui::AlignTextToFramePadding(); 4804 ImGui::Text("my sailor is rich"); 4805 ImGui::NextColumn(); 4806 if (node_open) 4807 { 4808 static float placeholder_members[8] = { 0.0f, 0.0f, 1.0f, 3.1416f, 100.0f, 999.0f }; 4809 for (int i = 0; i < 8; i++) 4810 { 4811 ImGui::PushID(i); // Use field index as identifier. 4812 if (i < 2) 4813 { 4814 ShowPlaceholderObject("Child", 424242); 4815 } 4816 else 4817 { 4818 // Here we use a TreeNode to highlight on hover (we could use e.g. Selectable as well) 4819 ImGui::AlignTextToFramePadding(); 4820 ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_Bullet; 4821 ImGui::TreeNodeEx("Field", flags, "Field_%d", i); 4822 ImGui::NextColumn(); 4823 ImGui::SetNextItemWidth(-1); 4824 if (i >= 5) 4825 ImGui::InputFloat("##value", &placeholder_members[i], 1.0f); 4826 else 4827 ImGui::DragFloat("##value", &placeholder_members[i], 0.01f); 4828 ImGui::NextColumn(); 4829 } 4830 ImGui::PopID(); 4831 } 4832 ImGui::TreePop(); 4833 } 4834 ImGui::PopID(); 3069 4835 } 3070 4836 … … 3072 4838 static void ShowExampleAppPropertyEditor(bool* p_open) 3073 4839 { 3074 ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver); 3075 if (!ImGui::Begin("Example: Property editor", p_open)) 3076 { 3077 ImGui::End(); 3078 return; 3079 } 3080 3081 ShowHelpMarker("This example shows how you may implement a property editor using two columns.\nAll objects/fields data are dummies here.\nRemember that in many simple cases, you can use ImGui::SameLine(xxx) to position\nyour cursor horizontally instead of using the Columns() API."); 3082 3083 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 2)); 3084 ImGui::Columns(2); 3085 ImGui::Separator(); 3086 3087 struct funcs 3088 { 3089 static void ShowDummyObject(const char* prefix, int uid) 3090 { 3091 ImGui::PushID(uid); // Use object uid as identifier. Most commonly you could also use the object pointer as a base ID. 3092 ImGui::AlignTextToFramePadding(); // Text and Tree nodes are less high than regular widgets, here we add vertical spacing to make the tree lines equal high. 3093 bool node_open = ImGui::TreeNode("Object", "%s_%u", prefix, uid); 3094 ImGui::NextColumn(); 3095 ImGui::AlignTextToFramePadding(); 3096 ImGui::Text("my sailor is rich"); 3097 ImGui::NextColumn(); 3098 if (node_open) 3099 { 3100 static float dummy_members[8] = { 0.0f,0.0f,1.0f,3.1416f,100.0f,999.0f }; 3101 for (int i = 0; i < 8; i++) 3102 { 3103 ImGui::PushID(i); // Use field index as identifier. 3104 if (i < 2) 3105 { 3106 ShowDummyObject("Child", 424242); 3107 } 3108 else 3109 { 3110 ImGui::AlignTextToFramePadding(); 3111 // Here we use a Selectable (instead of Text) to highlight on hover 3112 //ImGui::Text("Field_%d", i); 3113 char label[32]; 3114 sprintf(label, "Field_%d", i); 3115 ImGui::Bullet(); 3116 ImGui::Selectable(label); 3117 ImGui::NextColumn(); 3118 ImGui::PushItemWidth(-1); 3119 if (i >= 5) 3120 ImGui::InputFloat("##value", &dummy_members[i], 1.0f); 3121 else 3122 ImGui::DragFloat("##value", &dummy_members[i], 0.01f); 3123 ImGui::PopItemWidth(); 3124 ImGui::NextColumn(); 3125 } 3126 ImGui::PopID(); 3127 } 3128 ImGui::TreePop(); 3129 } 3130 ImGui::PopID(); 3131 } 3132 }; 3133 3134 // Iterate dummy objects with dummy members (all the same data) 3135 for (int obj_i = 0; obj_i < 3; obj_i++) 3136 funcs::ShowDummyObject("Object", obj_i); 3137 3138 ImGui::Columns(1); 3139 ImGui::Separator(); 3140 ImGui::PopStyleVar(); 3141 ImGui::End(); 4840 ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver); 4841 if (!ImGui::Begin("Example: Property editor", p_open)) 4842 { 4843 ImGui::End(); 4844 return; 4845 } 4846 4847 HelpMarker( 4848 "This example shows how you may implement a property editor using two columns.\n" 4849 "All objects/fields data are dummies here.\n" 4850 "Remember that in many simple cases, you can use ImGui::SameLine(xxx) to position\n" 4851 "your cursor horizontally instead of using the Columns() API."); 4852 4853 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 2)); 4854 ImGui::Columns(2); 4855 ImGui::Separator(); 4856 4857 // Iterate placeholder objects (all the same data) 4858 for (int obj_i = 0; obj_i < 3; obj_i++) 4859 ShowPlaceholderObject("Object", obj_i); 4860 4861 ImGui::Columns(1); 4862 ImGui::Separator(); 4863 ImGui::PopStyleVar(); 4864 ImGui::End(); 3142 4865 } 4866 4867 //----------------------------------------------------------------------------- 4868 // [SECTION] Example App: Long Text / ShowExampleAppLongText() 4869 //----------------------------------------------------------------------------- 3143 4870 3144 4871 // Demonstrate/test rendering huge amount of text, and the incidence of clipping. 3145 4872 static void ShowExampleAppLongText(bool* p_open) 3146 4873 { 3147 ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); 3148 if (!ImGui::Begin("Example: Long text display", p_open)) 3149 { 3150 ImGui::End(); 3151 return; 3152 } 3153 3154 static int test_type = 0; 3155 static ImGuiTextBuffer log; 3156 static int lines = 0; 3157 ImGui::Text("Printing unusually long amount of text."); 3158 ImGui::Combo("Test type", &test_type, "Single call to TextUnformatted()\0Multiple calls to Text(), clipped manually\0Multiple calls to Text(), not clipped (slow)\0"); 3159 ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size()); 3160 if (ImGui::Button("Clear")) { log.clear(); lines = 0; } 3161 ImGui::SameLine(); 3162 if (ImGui::Button("Add 1000 lines")) 3163 { 3164 for (int i = 0; i < 1000; i++) 3165 log.appendf("%i The quick brown fox jumps over the lazy dog\n", lines + i); 3166 lines += 1000; 3167 } 3168 ImGui::BeginChild("Log"); 3169 switch (test_type) 3170 { 3171 case 0: 3172 // Single call to TextUnformatted() with a big buffer 3173 ImGui::TextUnformatted(log.begin(), log.end()); 3174 break; 3175 case 1: 3176 { 3177 // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper. 3178 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); 3179 ImGuiListClipper clipper(lines); 3180 while (clipper.Step()) 3181 for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) 4874 ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); 4875 if (!ImGui::Begin("Example: Long text display", p_open)) 4876 { 4877 ImGui::End(); 4878 return; 4879 } 4880 4881 static int test_type = 0; 4882 static ImGuiTextBuffer log; 4883 static int lines = 0; 4884 ImGui::Text("Printing unusually long amount of text."); 4885 ImGui::Combo("Test type", &test_type, 4886 "Single call to TextUnformatted()\0" 4887 "Multiple calls to Text(), clipped\0" 4888 "Multiple calls to Text(), not clipped (slow)\0"); 4889 ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size()); 4890 if (ImGui::Button("Clear")) { log.clear(); lines = 0; } 4891 ImGui::SameLine(); 4892 if (ImGui::Button("Add 1000 lines")) 4893 { 4894 for (int i = 0; i < 1000; i++) 4895 log.appendf("%i The quick brown fox jumps over the lazy dog\n", lines + i); 4896 lines += 1000; 4897 } 4898 ImGui::BeginChild("Log"); 4899 switch (test_type) 4900 { 4901 case 0: 4902 // Single call to TextUnformatted() with a big buffer 4903 ImGui::TextUnformatted(log.begin(), log.end()); 4904 break; 4905 case 1: 4906 { 4907 // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper. 4908 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); 4909 ImGuiListClipper clipper; 4910 clipper.Begin(lines); 4911 while (clipper.Step()) 4912 for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) 4913 ImGui::Text("%i The quick brown fox jumps over the lazy dog", i); 4914 ImGui::PopStyleVar(); 4915 break; 4916 } 4917 case 2: 4918 // Multiple calls to Text(), not clipped (slow) 4919 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); 4920 for (int i = 0; i < lines; i++) 3182 4921 ImGui::Text("%i The quick brown fox jumps over the lazy dog", i); 3183 ImGui::PopStyleVar(); 3184 break; 3185 } 3186 case 2: 3187 // Multiple calls to Text(), not clipped (slow) 3188 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); 3189 for (int i = 0; i < lines; i++) 3190 ImGui::Text("%i The quick brown fox jumps over the lazy dog", i); 3191 ImGui::PopStyleVar(); 3192 break; 3193 } 3194 ImGui::EndChild(); 3195 ImGui::End(); 4922 ImGui::PopStyleVar(); 4923 break; 4924 } 4925 ImGui::EndChild(); 4926 ImGui::End(); 4927 } 4928 4929 //----------------------------------------------------------------------------- 4930 // [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize() 4931 //----------------------------------------------------------------------------- 4932 4933 // Demonstrate creating a window which gets auto-resized according to its content. 4934 static void ShowExampleAppAutoResize(bool* p_open) 4935 { 4936 if (!ImGui::Begin("Example: Auto-resizing window", p_open, ImGuiWindowFlags_AlwaysAutoResize)) 4937 { 4938 ImGui::End(); 4939 return; 4940 } 4941 4942 static int lines = 10; 4943 ImGui::TextUnformatted( 4944 "Window will resize every-frame to the size of its content.\n" 4945 "Note that you probably don't want to query the window size to\n" 4946 "output your content because that would create a feedback loop."); 4947 ImGui::SliderInt("Number of lines", &lines, 1, 20); 4948 for (int i = 0; i < lines; i++) 4949 ImGui::Text("%*sThis is line %d", i * 4, "", i); // Pad with space to extend size horizontally 4950 ImGui::End(); 4951 } 4952 4953 //----------------------------------------------------------------------------- 4954 // [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize() 4955 //----------------------------------------------------------------------------- 4956 4957 // Demonstrate creating a window with custom resize constraints. 4958 static void ShowExampleAppConstrainedResize(bool* p_open) 4959 { 4960 struct CustomConstraints 4961 { 4962 // Helper functions to demonstrate programmatic constraints 4963 static void Square(ImGuiSizeCallbackData* data) { data->DesiredSize.x = data->DesiredSize.y = IM_MAX(data->DesiredSize.x, data->DesiredSize.y); } 4964 static void Step(ImGuiSizeCallbackData* data) { float step = (float)(int)(intptr_t)data->UserData; data->DesiredSize = ImVec2((int)(data->DesiredSize.x / step + 0.5f) * step, (int)(data->DesiredSize.y / step + 0.5f) * step); } 4965 }; 4966 4967 const char* test_desc[] = 4968 { 4969 "Resize vertical only", 4970 "Resize horizontal only", 4971 "Width > 100, Height > 100", 4972 "Width 400-500", 4973 "Height 400-500", 4974 "Custom: Always Square", 4975 "Custom: Fixed Steps (100)", 4976 }; 4977 4978 static bool auto_resize = false; 4979 static int type = 0; 4980 static int display_lines = 10; 4981 if (type == 0) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, FLT_MAX)); // Vertical only 4982 if (type == 1) ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(FLT_MAX, -1)); // Horizontal only 4983 if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100 4984 if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)); // Width 400-500 4985 if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, 500)); // Height 400-500 4986 if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square 4987 if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)(intptr_t)100); // Fixed Step 4988 4989 ImGuiWindowFlags flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0; 4990 if (ImGui::Begin("Example: Constrained Resize", p_open, flags)) 4991 { 4992 if (ImGui::Button("200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine(); 4993 if (ImGui::Button("500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine(); 4994 if (ImGui::Button("800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); } 4995 ImGui::SetNextItemWidth(200); 4996 ImGui::Combo("Constraint", &type, test_desc, IM_ARRAYSIZE(test_desc)); 4997 ImGui::SetNextItemWidth(200); 4998 ImGui::DragInt("Lines", &display_lines, 0.2f, 1, 100); 4999 ImGui::Checkbox("Auto-resize", &auto_resize); 5000 for (int i = 0; i < display_lines; i++) 5001 ImGui::Text("%*sHello, sailor! Making this line long enough for the example.", i * 4, ""); 5002 } 5003 ImGui::End(); 5004 } 5005 5006 //----------------------------------------------------------------------------- 5007 // [SECTION] Example App: Simple Overlay / ShowExampleAppSimpleOverlay() 5008 //----------------------------------------------------------------------------- 5009 5010 // Demonstrate creating a simple static window with no decoration 5011 // + a context-menu to choose which corner of the screen to use. 5012 static void ShowExampleAppSimpleOverlay(bool* p_open) 5013 { 5014 const float DISTANCE = 10.0f; 5015 static int corner = 0; 5016 ImGuiIO& io = ImGui::GetIO(); 5017 ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav; 5018 if (corner != -1) 5019 { 5020 window_flags |= ImGuiWindowFlags_NoMove; 5021 ImVec2 window_pos = ImVec2((corner & 1) ? io.DisplaySize.x - DISTANCE : DISTANCE, (corner & 2) ? io.DisplaySize.y - DISTANCE : DISTANCE); 5022 ImVec2 window_pos_pivot = ImVec2((corner & 1) ? 1.0f : 0.0f, (corner & 2) ? 1.0f : 0.0f); 5023 ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot); 5024 } 5025 ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background 5026 if (ImGui::Begin("Example: Simple overlay", p_open, window_flags)) 5027 { 5028 ImGui::Text("Simple overlay\n" "in the corner of the screen.\n" "(right-click to change position)"); 5029 ImGui::Separator(); 5030 if (ImGui::IsMousePosValid()) 5031 ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y); 5032 else 5033 ImGui::Text("Mouse Position: <invalid>"); 5034 if (ImGui::BeginPopupContextWindow()) 5035 { 5036 if (ImGui::MenuItem("Custom", NULL, corner == -1)) corner = -1; 5037 if (ImGui::MenuItem("Top-left", NULL, corner == 0)) corner = 0; 5038 if (ImGui::MenuItem("Top-right", NULL, corner == 1)) corner = 1; 5039 if (ImGui::MenuItem("Bottom-left", NULL, corner == 2)) corner = 2; 5040 if (ImGui::MenuItem("Bottom-right", NULL, corner == 3)) corner = 3; 5041 if (p_open && ImGui::MenuItem("Close")) *p_open = false; 5042 ImGui::EndPopup(); 5043 } 5044 } 5045 ImGui::End(); 5046 } 5047 5048 //----------------------------------------------------------------------------- 5049 // [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles() 5050 //----------------------------------------------------------------------------- 5051 5052 // Demonstrate using "##" and "###" in identifiers to manipulate ID generation. 5053 // This apply to all regular items as well. 5054 // Read FAQ section "How can I have multiple widgets with the same label?" for details. 5055 static void ShowExampleAppWindowTitles(bool*) 5056 { 5057 // By default, Windows are uniquely identified by their title. 5058 // You can use the "##" and "###" markers to manipulate the display/ID. 5059 5060 // Using "##" to display same title but have unique identifier. 5061 ImGui::SetNextWindowPos(ImVec2(100, 100), ImGuiCond_FirstUseEver); 5062 ImGui::Begin("Same title as another window##1"); 5063 ImGui::Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique."); 5064 ImGui::End(); 5065 5066 ImGui::SetNextWindowPos(ImVec2(100, 200), ImGuiCond_FirstUseEver); 5067 ImGui::Begin("Same title as another window##2"); 5068 ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique."); 5069 ImGui::End(); 5070 5071 // Using "###" to display a changing title but keep a static identifier "AnimatedTitle" 5072 char buf[128]; 5073 sprintf(buf, "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime() / 0.25f) & 3], ImGui::GetFrameCount()); 5074 ImGui::SetNextWindowPos(ImVec2(100, 300), ImGuiCond_FirstUseEver); 5075 ImGui::Begin(buf); 5076 ImGui::Text("This window has a changing title."); 5077 ImGui::End(); 5078 } 5079 5080 //----------------------------------------------------------------------------- 5081 // [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering() 5082 //----------------------------------------------------------------------------- 5083 5084 // Demonstrate using the low-level ImDrawList to draw custom shapes. 5085 static void ShowExampleAppCustomRendering(bool* p_open) 5086 { 5087 if (!ImGui::Begin("Example: Custom rendering", p_open)) 5088 { 5089 ImGui::End(); 5090 return; 5091 } 5092 5093 // Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of 5094 // overloaded operators, etc. Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your 5095 // types and ImVec2/ImVec4. Dear ImGui defines overloaded operators but they are internal to imgui.cpp and not 5096 // exposed outside (to avoid messing with your types) In this example we are not using the maths operators! 5097 5098 if (ImGui::BeginTabBar("##TabBar")) 5099 { 5100 if (ImGui::BeginTabItem("Primitives")) 5101 { 5102 ImGui::PushItemWidth(-ImGui::GetFontSize() * 10); 5103 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 5104 5105 // Draw gradients 5106 // (note that those are currently exacerbating our sRGB/Linear issues) 5107 // Calling ImGui::GetColorU32() multiplies the given colors by the current Style Alpha, but you may pass the IM_COL32() directly as well.. 5108 ImGui::Text("Gradients"); 5109 ImVec2 gradient_size = ImVec2(ImGui::CalcItemWidth(), ImGui::GetFrameHeight()); 5110 { 5111 ImVec2 p0 = ImGui::GetCursorScreenPos(); 5112 ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y); 5113 ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 0, 0, 255)); 5114 ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 255, 255, 255)); 5115 draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a); 5116 ImGui::InvisibleButton("##gradient1", gradient_size); 5117 } 5118 { 5119 ImVec2 p0 = ImGui::GetCursorScreenPos(); 5120 ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y); 5121 ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 255, 0, 255)); 5122 ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 0, 0, 255)); 5123 draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a); 5124 ImGui::InvisibleButton("##gradient2", gradient_size); 5125 } 5126 5127 // Draw a bunch of primitives 5128 ImGui::Text("All primitives"); 5129 static float sz = 36.0f; 5130 static float thickness = 3.0f; 5131 static int ngon_sides = 6; 5132 static bool circle_segments_override = false; 5133 static int circle_segments_override_v = 12; 5134 static ImVec4 colf = ImVec4(1.0f, 1.0f, 0.4f, 1.0f); 5135 ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 72.0f, "%.0f"); 5136 ImGui::DragFloat("Thickness", &thickness, 0.05f, 1.0f, 8.0f, "%.02f"); 5137 ImGui::SliderInt("N-gon sides", &ngon_sides, 3, 12); 5138 ImGui::Checkbox("##circlesegmentoverride", &circle_segments_override); 5139 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); 5140 if (ImGui::SliderInt("Circle segments", &circle_segments_override_v, 3, 40)) 5141 circle_segments_override = true; 5142 ImGui::ColorEdit4("Color", &colf.x); 5143 5144 const ImVec2 p = ImGui::GetCursorScreenPos(); 5145 const ImU32 col = ImColor(colf); 5146 const float spacing = 10.0f; 5147 const ImDrawCornerFlags corners_none = 0; 5148 const ImDrawCornerFlags corners_all = ImDrawCornerFlags_All; 5149 const ImDrawCornerFlags corners_tl_br = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotRight; 5150 const int circle_segments = circle_segments_override ? circle_segments_override_v : 0; 5151 float x = p.x + 4.0f; 5152 float y = p.y + 4.0f; 5153 for (int n = 0; n < 2; n++) 5154 { 5155 // First line uses a thickness of 1.0f, second line uses the configurable thickness 5156 float th = (n == 0) ? 1.0f : thickness; 5157 draw_list->AddNgon(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, ngon_sides, th); x += sz + spacing; // N-gon 5158 draw_list->AddCircle(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments, th); x += sz + spacing; // Circle 5159 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0f, corners_none, th); x += sz + spacing; // Square 5160 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_all, th); x += sz + spacing; // Square with all rounded corners 5161 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_tl_br, th); x += sz + spacing; // Square with two rounded corners 5162 draw_list->AddTriangle(ImVec2(x+sz*0.5f,y), ImVec2(x+sz, y+sz-0.5f), ImVec2(x, y+sz-0.5f), col, th);x += sz + spacing; // Triangle 5163 //draw_list->AddTriangle(ImVec2(x+sz*0.2f,y), ImVec2(x, y+sz-0.5f), ImVec2(x+sz*0.4f, y+sz-0.5f), col, th);x+= sz*0.4f + spacing; // Thin triangle 5164 draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y), col, th); x += sz + spacing; // Horizontal line (note: drawing a filled rectangle will be faster!) 5165 draw_list->AddLine(ImVec2(x, y), ImVec2(x, y + sz), col, th); x += spacing; // Vertical line (note: drawing a filled rectangle will be faster!) 5166 draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y + sz), col, th); x += sz + spacing; // Diagonal line 5167 draw_list->AddBezierCurve(ImVec2(x, y), ImVec2(x + sz*1.3f, y + sz*0.3f), ImVec2(x + sz - sz*1.3f, y + sz - sz*0.3f), ImVec2(x + sz, y + sz), col, th); 5168 x = p.x + 4; 5169 y += sz + spacing; 5170 } 5171 draw_list->AddNgonFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz*0.5f, col, ngon_sides); x += sz + spacing; // N-gon 5172 draw_list->AddCircleFilled(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments); x += sz + spacing; // Circle 5173 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col); x += sz + spacing; // Square 5174 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f); x += sz + spacing; // Square with all rounded corners 5175 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_tl_br); x += sz + spacing; // Square with two rounded corners 5176 draw_list->AddTriangleFilled(ImVec2(x+sz*0.5f,y), ImVec2(x+sz, y+sz-0.5f), ImVec2(x, y+sz-0.5f), col); x += sz + spacing; // Triangle 5177 //draw_list->AddTriangleFilled(ImVec2(x+sz*0.2f,y), ImVec2(x, y+sz-0.5f), ImVec2(x+sz*0.4f, y+sz-0.5f), col); x += sz*0.4f + spacing; // Thin triangle 5178 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + thickness), col); x += sz + spacing; // Horizontal line (faster than AddLine, but only handle integer thickness) 5179 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + thickness, y + sz), col); x += spacing * 2.0f;// Vertical line (faster than AddLine, but only handle integer thickness) 5180 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + 1, y + 1), col); x += sz; // Pixel (faster than AddLine) 5181 draw_list->AddRectFilledMultiColor(ImVec2(x, y), ImVec2(x + sz, y + sz), IM_COL32(0, 0, 0, 255), IM_COL32(255, 0, 0, 255), IM_COL32(255, 255, 0, 255), IM_COL32(0, 255, 0, 255)); 5182 5183 ImGui::Dummy(ImVec2((sz + spacing) * 8.8f, (sz + spacing) * 3.0f)); 5184 ImGui::PopItemWidth(); 5185 ImGui::EndTabItem(); 5186 } 5187 5188 if (ImGui::BeginTabItem("Canvas")) 5189 { 5190 static ImVector<ImVec2> points; 5191 static ImVec2 scrolling(0.0f, 0.0f); 5192 static bool opt_enable_grid = true; 5193 static bool opt_enable_context_menu = true; 5194 static bool adding_line = false; 5195 5196 ImGui::Checkbox("Enable grid", &opt_enable_grid); 5197 ImGui::Checkbox("Enable context menu", &opt_enable_context_menu); 5198 ImGui::Text("Mouse Left: drag to add lines,\nMouse Right: drag to scroll, click for context menu."); 5199 5200 // Typically you would use a BeginChild()/EndChild() pair to benefit from a clipping region + own scrolling. 5201 // Here we demonstrate that this can be replaced by simple offsetting + custom drawing + PushClipRect/PopClipRect() calls. 5202 // To use a child window instead we could use, e.g: 5203 // ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); // Disable padding 5204 // ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(50, 50, 50, 255)); // Set a background color 5205 // ImGui::BeginChild("canvas", ImVec2(0.0f, 0.0f), true, ImGuiWindowFlags_NoMove); 5206 // ImGui::PopStyleColor(); 5207 // ImGui::PopStyleVar(); 5208 // [...] 5209 // ImGui::EndChild(); 5210 5211 // Using InvisibleButton() as a convenience 1) it will advance the layout cursor and 2) allows us to use IsItemHovered()/IsItemActive() 5212 ImVec2 canvas_p0 = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates! 5213 ImVec2 canvas_sz = ImGui::GetContentRegionAvail(); // Resize canvas to what's available 5214 if (canvas_sz.x < 50.0f) canvas_sz.x = 50.0f; 5215 if (canvas_sz.y < 50.0f) canvas_sz.y = 50.0f; 5216 ImVec2 canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y); 5217 5218 // Draw border and background color 5219 ImGuiIO& io = ImGui::GetIO(); 5220 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 5221 draw_list->AddRectFilled(canvas_p0, canvas_p1, IM_COL32(50, 50, 50, 255)); 5222 draw_list->AddRect(canvas_p0, canvas_p1, IM_COL32(255, 255, 255, 255)); 5223 5224 // This will catch our interactions 5225 ImGui::InvisibleButton("canvas", canvas_sz, ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight); 5226 const bool is_hovered = ImGui::IsItemHovered(); // Hovered 5227 const bool is_active = ImGui::IsItemActive(); // Held 5228 const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y); // Lock scrolled origin 5229 const ImVec2 mouse_pos_in_canvas(io.MousePos.x - origin.x, io.MousePos.y - origin.y); 5230 5231 // Add first and second point 5232 if (is_hovered && !adding_line && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) 5233 { 5234 points.push_back(mouse_pos_in_canvas); 5235 points.push_back(mouse_pos_in_canvas); 5236 adding_line = true; 5237 } 5238 if (adding_line) 5239 { 5240 points.back() = mouse_pos_in_canvas; 5241 if (!ImGui::IsMouseDown(ImGuiMouseButton_Left)) 5242 adding_line = false; 5243 } 5244 5245 // Pan (we use a zero mouse threshold when there's no context menu) 5246 // You may decide to make that threshold dynamic based on whether the mouse is hovering something etc. 5247 const float mouse_threshold_for_pan = opt_enable_context_menu ? -1.0f : 0.0f; 5248 if (is_active && ImGui::IsMouseDragging(ImGuiMouseButton_Right, mouse_threshold_for_pan)) 5249 { 5250 scrolling.x += io.MouseDelta.x; 5251 scrolling.y += io.MouseDelta.y; 5252 } 5253 5254 // Context menu (under default mouse threshold) 5255 ImVec2 drag_delta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Right); 5256 if (opt_enable_context_menu && ImGui::IsMouseReleased(ImGuiMouseButton_Right) && drag_delta.x == 0.0f && drag_delta.y == 0.0f) 5257 ImGui::OpenPopupOnItemClick("context"); 5258 if (ImGui::BeginPopup("context")) 5259 { 5260 if (adding_line) 5261 points.resize(points.size() - 2); 5262 adding_line = false; 5263 if (ImGui::MenuItem("Remove one", NULL, false, points.Size > 0)) { points.resize(points.size() - 2); } 5264 if (ImGui::MenuItem("Remove all", NULL, false, points.Size > 0)) { points.clear(); } 5265 ImGui::EndPopup(); 5266 } 5267 5268 // Draw grid + all lines in the canvas 5269 draw_list->PushClipRect(canvas_p0, canvas_p1, true); 5270 if (opt_enable_grid) 5271 { 5272 const float GRID_STEP = 64.0f; 5273 for (float x = fmodf(scrolling.x, GRID_STEP); x < canvas_sz.x; x += GRID_STEP) 5274 draw_list->AddLine(ImVec2(canvas_p0.x + x, canvas_p0.y), ImVec2(canvas_p0.x + x, canvas_p1.y), IM_COL32(200, 200, 200, 40)); 5275 for (float y = fmodf(scrolling.y, GRID_STEP); y < canvas_sz.y; y += GRID_STEP) 5276 draw_list->AddLine(ImVec2(canvas_p0.x, canvas_p0.y + y), ImVec2(canvas_p1.x, canvas_p0.y + y), IM_COL32(200, 200, 200, 40)); 5277 } 5278 for (int n = 0; n < points.Size; n += 2) 5279 draw_list->AddLine(ImVec2(origin.x + points[n].x, origin.y + points[n].y), ImVec2(origin.x + points[n + 1].x, origin.y + points[n + 1].y), IM_COL32(255, 255, 0, 255), 2.0f); 5280 draw_list->PopClipRect(); 5281 5282 ImGui::EndTabItem(); 5283 } 5284 5285 if (ImGui::BeginTabItem("BG/FG draw lists")) 5286 { 5287 static bool draw_bg = true; 5288 static bool draw_fg = true; 5289 ImGui::Checkbox("Draw in Background draw list", &draw_bg); 5290 ImGui::SameLine(); HelpMarker("The Background draw list will be rendered below every Dear ImGui windows."); 5291 ImGui::Checkbox("Draw in Foreground draw list", &draw_fg); 5292 ImGui::SameLine(); HelpMarker("The Foreground draw list will be rendered over every Dear ImGui windows."); 5293 ImVec2 window_pos = ImGui::GetWindowPos(); 5294 ImVec2 window_size = ImGui::GetWindowSize(); 5295 ImVec2 window_center = ImVec2(window_pos.x + window_size.x * 0.5f, window_pos.y + window_size.y * 0.5f); 5296 if (draw_bg) 5297 ImGui::GetBackgroundDrawList()->AddCircle(window_center, window_size.x * 0.6f, IM_COL32(255, 0, 0, 200), 0, 10 + 4); 5298 if (draw_fg) 5299 ImGui::GetForegroundDrawList()->AddCircle(window_center, window_size.y * 0.6f, IM_COL32(0, 255, 0, 200), 0, 10); 5300 ImGui::EndTabItem(); 5301 } 5302 5303 ImGui::EndTabBar(); 5304 } 5305 5306 ImGui::End(); 5307 } 5308 5309 //----------------------------------------------------------------------------- 5310 // [SECTION] Example App: Documents Handling / ShowExampleAppDocuments() 5311 //----------------------------------------------------------------------------- 5312 5313 // Simplified structure to mimic a Document model 5314 struct MyDocument 5315 { 5316 const char* Name; // Document title 5317 bool Open; // Set when open (we keep an array of all available documents to simplify demo code!) 5318 bool OpenPrev; // Copy of Open from last update. 5319 bool Dirty; // Set when the document has been modified 5320 bool WantClose; // Set when the document 5321 ImVec4 Color; // An arbitrary variable associated to the document 5322 5323 MyDocument(const char* name, bool open = true, const ImVec4& color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f)) 5324 { 5325 Name = name; 5326 Open = OpenPrev = open; 5327 Dirty = false; 5328 WantClose = false; 5329 Color = color; 5330 } 5331 void DoOpen() { Open = true; } 5332 void DoQueueClose() { WantClose = true; } 5333 void DoForceClose() { Open = false; Dirty = false; } 5334 void DoSave() { Dirty = false; } 5335 5336 // Display placeholder contents for the Document 5337 static void DisplayContents(MyDocument* doc) 5338 { 5339 ImGui::PushID(doc); 5340 ImGui::Text("Document \"%s\"", doc->Name); 5341 ImGui::PushStyleColor(ImGuiCol_Text, doc->Color); 5342 ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."); 5343 ImGui::PopStyleColor(); 5344 if (ImGui::Button("Modify", ImVec2(100, 0))) 5345 doc->Dirty = true; 5346 ImGui::SameLine(); 5347 if (ImGui::Button("Save", ImVec2(100, 0))) 5348 doc->DoSave(); 5349 ImGui::ColorEdit3("color", &doc->Color.x); // Useful to test drag and drop and hold-dragged-to-open-tab behavior. 5350 ImGui::PopID(); 5351 } 5352 5353 // Display context menu for the Document 5354 static void DisplayContextMenu(MyDocument* doc) 5355 { 5356 if (!ImGui::BeginPopupContextItem()) 5357 return; 5358 5359 char buf[256]; 5360 sprintf(buf, "Save %s", doc->Name); 5361 if (ImGui::MenuItem(buf, "CTRL+S", false, doc->Open)) 5362 doc->DoSave(); 5363 if (ImGui::MenuItem("Close", "CTRL+W", false, doc->Open)) 5364 doc->DoQueueClose(); 5365 ImGui::EndPopup(); 5366 } 5367 }; 5368 5369 struct ExampleAppDocuments 5370 { 5371 ImVector<MyDocument> Documents; 5372 5373 ExampleAppDocuments() 5374 { 5375 Documents.push_back(MyDocument("Lettuce", true, ImVec4(0.4f, 0.8f, 0.4f, 1.0f))); 5376 Documents.push_back(MyDocument("Eggplant", true, ImVec4(0.8f, 0.5f, 1.0f, 1.0f))); 5377 Documents.push_back(MyDocument("Carrot", true, ImVec4(1.0f, 0.8f, 0.5f, 1.0f))); 5378 Documents.push_back(MyDocument("Tomato", false, ImVec4(1.0f, 0.3f, 0.4f, 1.0f))); 5379 Documents.push_back(MyDocument("A Rather Long Title", false)); 5380 Documents.push_back(MyDocument("Some Document", false)); 5381 } 5382 }; 5383 5384 // [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface. 5385 // If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo, 5386 // as opposed to clicking on the regular tab closing button) and stops being submitted, it will take a frame for 5387 // the tab bar to notice its absence. During this frame there will be a gap in the tab bar, and if the tab that has 5388 // disappeared was the selected one, the tab bar will report no selected tab during the frame. This will effectively 5389 // give the impression of a flicker for one frame. 5390 // We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch. 5391 // Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag. 5392 static void NotifyOfDocumentsClosedElsewhere(ExampleAppDocuments& app) 5393 { 5394 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) 5395 { 5396 MyDocument* doc = &app.Documents[doc_n]; 5397 if (!doc->Open && doc->OpenPrev) 5398 ImGui::SetTabItemClosed(doc->Name); 5399 doc->OpenPrev = doc->Open; 5400 } 5401 } 5402 5403 void ShowExampleAppDocuments(bool* p_open) 5404 { 5405 static ExampleAppDocuments app; 5406 5407 // Options 5408 static bool opt_reorderable = true; 5409 static ImGuiTabBarFlags opt_fitting_flags = ImGuiTabBarFlags_FittingPolicyDefault_; 5410 5411 bool window_contents_visible = ImGui::Begin("Example: Documents", p_open, ImGuiWindowFlags_MenuBar); 5412 if (!window_contents_visible) 5413 { 5414 ImGui::End(); 5415 return; 5416 } 5417 5418 // Menu 5419 if (ImGui::BeginMenuBar()) 5420 { 5421 if (ImGui::BeginMenu("File")) 5422 { 5423 int open_count = 0; 5424 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) 5425 open_count += app.Documents[doc_n].Open ? 1 : 0; 5426 5427 if (ImGui::BeginMenu("Open", open_count < app.Documents.Size)) 5428 { 5429 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) 5430 { 5431 MyDocument* doc = &app.Documents[doc_n]; 5432 if (!doc->Open) 5433 if (ImGui::MenuItem(doc->Name)) 5434 doc->DoOpen(); 5435 } 5436 ImGui::EndMenu(); 5437 } 5438 if (ImGui::MenuItem("Close All Documents", NULL, false, open_count > 0)) 5439 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) 5440 app.Documents[doc_n].DoQueueClose(); 5441 if (ImGui::MenuItem("Exit", "Alt+F4")) {} 5442 ImGui::EndMenu(); 5443 } 5444 ImGui::EndMenuBar(); 5445 } 5446 5447 // [Debug] List documents with one checkbox for each 5448 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) 5449 { 5450 MyDocument* doc = &app.Documents[doc_n]; 5451 if (doc_n > 0) 5452 ImGui::SameLine(); 5453 ImGui::PushID(doc); 5454 if (ImGui::Checkbox(doc->Name, &doc->Open)) 5455 if (!doc->Open) 5456 doc->DoForceClose(); 5457 ImGui::PopID(); 5458 } 5459 5460 ImGui::Separator(); 5461 5462 // Submit Tab Bar and Tabs 5463 { 5464 ImGuiTabBarFlags tab_bar_flags = (opt_fitting_flags) | (opt_reorderable ? ImGuiTabBarFlags_Reorderable : 0); 5465 if (ImGui::BeginTabBar("##tabs", tab_bar_flags)) 5466 { 5467 if (opt_reorderable) 5468 NotifyOfDocumentsClosedElsewhere(app); 5469 5470 // [DEBUG] Stress tests 5471 //if ((ImGui::GetFrameCount() % 30) == 0) docs[1].Open ^= 1; // [DEBUG] Automatically show/hide a tab. Test various interactions e.g. dragging with this on. 5472 //if (ImGui::GetIO().KeyCtrl) ImGui::SetTabItemSelected(docs[1].Name); // [DEBUG] Test SetTabItemSelected(), probably not very useful as-is anyway.. 5473 5474 // Submit Tabs 5475 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) 5476 { 5477 MyDocument* doc = &app.Documents[doc_n]; 5478 if (!doc->Open) 5479 continue; 5480 5481 ImGuiTabItemFlags tab_flags = (doc->Dirty ? ImGuiTabItemFlags_UnsavedDocument : 0); 5482 bool visible = ImGui::BeginTabItem(doc->Name, &doc->Open, tab_flags); 5483 5484 // Cancel attempt to close when unsaved add to save queue so we can display a popup. 5485 if (!doc->Open && doc->Dirty) 5486 { 5487 doc->Open = true; 5488 doc->DoQueueClose(); 5489 } 5490 5491 MyDocument::DisplayContextMenu(doc); 5492 if (visible) 5493 { 5494 MyDocument::DisplayContents(doc); 5495 ImGui::EndTabItem(); 5496 } 5497 } 5498 5499 ImGui::EndTabBar(); 5500 } 5501 } 5502 5503 // Update closing queue 5504 static ImVector<MyDocument*> close_queue; 5505 if (close_queue.empty()) 5506 { 5507 // Close queue is locked once we started a popup 5508 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) 5509 { 5510 MyDocument* doc = &app.Documents[doc_n]; 5511 if (doc->WantClose) 5512 { 5513 doc->WantClose = false; 5514 close_queue.push_back(doc); 5515 } 5516 } 5517 } 5518 5519 // Display closing confirmation UI 5520 if (!close_queue.empty()) 5521 { 5522 int close_queue_unsaved_documents = 0; 5523 for (int n = 0; n < close_queue.Size; n++) 5524 if (close_queue[n]->Dirty) 5525 close_queue_unsaved_documents++; 5526 5527 if (close_queue_unsaved_documents == 0) 5528 { 5529 // Close documents when all are unsaved 5530 for (int n = 0; n < close_queue.Size; n++) 5531 close_queue[n]->DoForceClose(); 5532 close_queue.clear(); 5533 } 5534 else 5535 { 5536 if (!ImGui::IsPopupOpen("Save?")) 5537 ImGui::OpenPopup("Save?"); 5538 if (ImGui::BeginPopupModal("Save?")) 5539 { 5540 ImGui::Text("Save change to the following items?"); 5541 ImGui::SetNextItemWidth(-1.0f); 5542 if (ImGui::ListBoxHeader("##", close_queue_unsaved_documents, 6)) 5543 { 5544 for (int n = 0; n < close_queue.Size; n++) 5545 if (close_queue[n]->Dirty) 5546 ImGui::Text("%s", close_queue[n]->Name); 5547 ImGui::ListBoxFooter(); 5548 } 5549 5550 if (ImGui::Button("Yes", ImVec2(80, 0))) 5551 { 5552 for (int n = 0; n < close_queue.Size; n++) 5553 { 5554 if (close_queue[n]->Dirty) 5555 close_queue[n]->DoSave(); 5556 close_queue[n]->DoForceClose(); 5557 } 5558 close_queue.clear(); 5559 ImGui::CloseCurrentPopup(); 5560 } 5561 ImGui::SameLine(); 5562 if (ImGui::Button("No", ImVec2(80, 0))) 5563 { 5564 for (int n = 0; n < close_queue.Size; n++) 5565 close_queue[n]->DoForceClose(); 5566 close_queue.clear(); 5567 ImGui::CloseCurrentPopup(); 5568 } 5569 ImGui::SameLine(); 5570 if (ImGui::Button("Cancel", ImVec2(80, 0))) 5571 { 5572 close_queue.clear(); 5573 ImGui::CloseCurrentPopup(); 5574 } 5575 ImGui::EndPopup(); 5576 } 5577 } 5578 } 5579 5580 ImGui::End(); 3196 5581 } 3197 5582 … … 3199 5584 #else 3200 5585 5586 void ImGui::ShowAboutWindow(bool*) {} 3201 5587 void ImGui::ShowDemoWindow(bool*) {} 3202 5588 void ImGui::ShowUserGuide() {} … … 3204 5590 3205 5591 #endif 5592 5593 #endif // #ifndef IMGUI_DISABLE -
IMGUI/imgui_draw.cpp
r78c3045 re66fd66 1 // dear imgui, v1. 61 WIP1 // dear imgui, v1.79 2 2 // (drawing and font code) 3 3 4 // Contains implementation for 5 // - Default styles 6 // - ImDrawList 7 // - ImDrawData 8 // - ImFontAtlas 9 // - ImFont 10 // - Default font data 4 /* 5 6 Index of this file: 7 8 // [SECTION] STB libraries implementation 9 // [SECTION] Style functions 10 // [SECTION] ImDrawList 11 // [SECTION] ImDrawListSplitter 12 // [SECTION] ImDrawData 13 // [SECTION] Helpers ShadeVertsXXX functions 14 // [SECTION] ImFontConfig 15 // [SECTION] ImFontAtlas 16 // [SECTION] ImFontAtlas glyph ranges helpers 17 // [SECTION] ImFontGlyphRangesBuilder 18 // [SECTION] ImFont 19 // [SECTION] ImGui Internal Render Helpers 20 // [SECTION] Decompression code 21 // [SECTION] Default font data (ProggyClean.ttf) 22 23 */ 11 24 12 25 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) … … 15 28 16 29 #include "imgui.h" 30 #ifndef IMGUI_DISABLE 31 32 #ifndef IMGUI_DEFINE_MATH_OPERATORS 17 33 #define IMGUI_DEFINE_MATH_OPERATORS 34 #endif 18 35 #include "imgui_internal.h" 19 36 20 37 #include <stdio.h> // vsnprintf, sscanf, printf 21 38 #if !defined(alloca) 22 #ifdef _WIN32 39 #if defined(__GLIBC__) || defined(__sun) || defined(__APPLE__) || defined(__NEWLIB__) 40 #include <alloca.h> // alloca (glibc uses <alloca.h>. Note that Cygwin may have _WIN32 defined, so the order matters here) 41 #elif defined(_WIN32) 23 42 #include <malloc.h> // alloca 24 43 #if !defined(alloca) 25 44 #define alloca _alloca // for clang with MS Codegen 26 45 #endif 27 #elif defined(__GLIBC__) || defined(__sun)28 #include <alloca.h> // alloca29 46 #else 30 47 #include <stdlib.h> // alloca … … 32 49 #endif 33 50 51 // Visual Studio warnings 34 52 #ifdef _MSC_VER 53 #pragma warning (disable: 4127) // condition expression is constant 35 54 #pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff) 36 55 #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen 37 56 #endif 38 57 39 #ifdef __clang__ 40 #pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse. 41 #pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants ok. 42 #pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it. 43 #pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness // 44 #if __has_warning("-Wcomma") 45 #pragma clang diagnostic ignored "-Wcomma" // warning : possible misuse of comma operator here // 58 // Clang/GCC warnings with -Weverything 59 #if defined(__clang__) 60 #if __has_warning("-Wunknown-warning-option") 61 #pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great! 46 62 #endif 47 #if __has_warning("-Wreserved-id-macro") 48 #pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier // 49 #endif 50 #if __has_warning("-Wdouble-promotion") 51 #pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function 52 #endif 63 #pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' 64 #pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. 65 #pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants ok. 66 #pragma clang diagnostic ignored "-Wglobal-constructors" // warning: declaration requires a global destructor // similar to above, not sure what the exact difference is. 67 #pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness 68 #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0 69 #pragma clang diagnostic ignored "-Wcomma" // warning: possible misuse of comma operator here 70 #pragma clang diagnostic ignored "-Wreserved-id-macro" // warning: macro name is a reserved identifier 71 #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. 72 #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision 53 73 #elif defined(__GNUC__) 74 #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind 54 75 #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used 55 76 #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function 56 77 #pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value 78 #pragma GCC diagnostic ignored "-Wstack-protector" // warning: stack protector not protecting local variables: variable length buffer 79 #pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead 57 80 #endif 58 81 59 82 //------------------------------------------------------------------------- 60 // STB libraries implementation83 // [SECTION] STB libraries implementation 61 84 //------------------------------------------------------------------------- 62 85 63 86 // Compile time options: 64 //#define IMGUI_STB_NAMESPACE Im GuiStb87 //#define IMGUI_STB_NAMESPACE ImStb 65 88 //#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" 66 89 //#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" … … 78 101 #endif 79 102 80 #if def __clang__103 #if defined(__clang__) 81 104 #pragma clang diagnostic push 82 105 #pragma clang diagnostic ignored "-Wunused-function" 83 106 #pragma clang diagnostic ignored "-Wmissing-prototypes" 84 107 #pragma clang diagnostic ignored "-Wimplicit-fallthrough" 85 #pragma clang diagnostic ignored "-Wcast-qual" // warning : cast from 'const xxxx *' to 'xxx *' drops const qualifier //108 #pragma clang diagnostic ignored "-Wcast-qual" // warning: cast from 'const xxxx *' to 'xxx *' drops const qualifier 86 109 #endif 87 110 88 #if def __GNUC__111 #if defined(__GNUC__) 89 112 #pragma GCC diagnostic push 90 113 #pragma GCC diagnostic ignored "-Wtype-limits" // warning: comparison is always true due to limited range of data type [-Wtype-limits] … … 92 115 #endif 93 116 117 #ifndef STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds) 94 118 #ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION 95 119 #define STBRP_STATIC 96 #define STBRP_ASSERT(x) IM_ASSERT(x) 120 #define STBRP_ASSERT(x) do { IM_ASSERT(x); } while (0) 121 #define STBRP_SORT ImQsort 97 122 #define STB_RECT_PACK_IMPLEMENTATION 98 123 #endif … … 100 125 #include IMGUI_STB_RECT_PACK_FILENAME 101 126 #else 102 #include " stb_rect_pack.h"127 #include "imstb_rectpack.h" 103 128 #endif 104 129 #endif 130 131 #ifndef STB_TRUETYPE_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds) 105 132 #ifndef IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION 106 #define STBTT_malloc(x,u) ((void)(u), ImGui::MemAlloc(x)) 107 #define STBTT_free(x,u) ((void)(u), ImGui::MemFree(x)) 108 #define STBTT_assert(x) IM_ASSERT(x) 133 #define STBTT_malloc(x,u) ((void)(u), IM_ALLOC(x)) 134 #define STBTT_free(x,u) ((void)(u), IM_FREE(x)) 135 #define STBTT_assert(x) do { IM_ASSERT(x); } while(0) 136 #define STBTT_fmod(x,y) ImFmod(x,y) 137 #define STBTT_sqrt(x) ImSqrt(x) 138 #define STBTT_pow(x,y) ImPow(x,y) 139 #define STBTT_fabs(x) ImFabs(x) 140 #define STBTT_ifloor(x) ((int)ImFloorStd(x)) 141 #define STBTT_iceil(x) ((int)ImCeil(x)) 109 142 #define STBTT_STATIC 110 143 #define STB_TRUETYPE_IMPLEMENTATION … … 115 148 #include IMGUI_STB_TRUETYPE_FILENAME 116 149 #else 117 #include " stb_truetype.h"150 #include "imstb_truetype.h" 118 151 #endif 119 120 #ifdef __GNUC__ 152 #endif 153 154 #if defined(__GNUC__) 121 155 #pragma GCC diagnostic pop 122 156 #endif 123 157 124 #if def __clang__158 #if defined(__clang__) 125 159 #pragma clang diagnostic pop 126 160 #endif 127 161 128 #if def _MSC_VER162 #if defined(_MSC_VER) 129 163 #pragma warning (pop) 130 164 #endif 131 165 132 166 #ifdef IMGUI_STB_NAMESPACE 133 } // namespace Im GuiStb167 } // namespace ImStb 134 168 using namespace IMGUI_STB_NAMESPACE; 135 169 #endif 136 170 137 171 //----------------------------------------------------------------------------- 138 // Style functions172 // [SECTION] Style functions 139 173 //----------------------------------------------------------------------------- 140 174 141 175 void ImGui::StyleColorsDark(ImGuiStyle* dst) 142 176 { 143 ImGuiStyle* style = dst ? dst : &ImGui::GetStyle(); 144 ImVec4* colors = style->Colors; 145 146 colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); 147 colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); 148 colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 0.94f); 149 colors[ImGuiCol_ChildBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.00f); 150 colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f); 151 colors[ImGuiCol_Border] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f); 152 colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); 153 colors[ImGuiCol_FrameBg] = ImVec4(0.16f, 0.29f, 0.48f, 0.54f); 154 colors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); 155 colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); 156 colors[ImGuiCol_TitleBg] = ImVec4(0.04f, 0.04f, 0.04f, 1.00f); 157 colors[ImGuiCol_TitleBgActive] = ImVec4(0.16f, 0.29f, 0.48f, 1.00f); 158 colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f); 159 colors[ImGuiCol_MenuBarBg] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f); 160 colors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.53f); 161 colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f); 162 colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f); 163 colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.51f, 0.51f, 0.51f, 1.00f); 164 colors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); 165 colors[ImGuiCol_SliderGrab] = ImVec4(0.24f, 0.52f, 0.88f, 1.00f); 166 colors[ImGuiCol_SliderGrabActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); 167 colors[ImGuiCol_Button] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); 168 colors[ImGuiCol_ButtonHovered] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); 169 colors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f); 170 colors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.31f); 171 colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f); 172 colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); 173 colors[ImGuiCol_Separator] = colors[ImGuiCol_Border]; 174 colors[ImGuiCol_SeparatorHovered] = ImVec4(0.10f, 0.40f, 0.75f, 0.78f); 175 colors[ImGuiCol_SeparatorActive] = ImVec4(0.10f, 0.40f, 0.75f, 1.00f); 176 colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.25f); 177 colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); 178 colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); 179 colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f); 180 colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); 181 colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); 182 colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); 183 colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); 184 colors[ImGuiCol_ModalWindowDarkening] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f); 185 colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); 186 colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); 187 colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); 177 ImGuiStyle* style = dst ? dst : &ImGui::GetStyle(); 178 ImVec4* colors = style->Colors; 179 180 colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); 181 colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); 182 colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 0.94f); 183 colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); 184 colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f); 185 colors[ImGuiCol_Border] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f); 186 colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); 187 colors[ImGuiCol_FrameBg] = ImVec4(0.16f, 0.29f, 0.48f, 0.54f); 188 colors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); 189 colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); 190 colors[ImGuiCol_TitleBg] = ImVec4(0.04f, 0.04f, 0.04f, 1.00f); 191 colors[ImGuiCol_TitleBgActive] = ImVec4(0.16f, 0.29f, 0.48f, 1.00f); 192 colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f); 193 colors[ImGuiCol_MenuBarBg] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f); 194 colors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.53f); 195 colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f); 196 colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f); 197 colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.51f, 0.51f, 0.51f, 1.00f); 198 colors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); 199 colors[ImGuiCol_SliderGrab] = ImVec4(0.24f, 0.52f, 0.88f, 1.00f); 200 colors[ImGuiCol_SliderGrabActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); 201 colors[ImGuiCol_Button] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); 202 colors[ImGuiCol_ButtonHovered] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); 203 colors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f); 204 colors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.31f); 205 colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f); 206 colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); 207 colors[ImGuiCol_Separator] = colors[ImGuiCol_Border]; 208 colors[ImGuiCol_SeparatorHovered] = ImVec4(0.10f, 0.40f, 0.75f, 0.78f); 209 colors[ImGuiCol_SeparatorActive] = ImVec4(0.10f, 0.40f, 0.75f, 1.00f); 210 colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.25f); 211 colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); 212 colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); 213 colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f); 214 colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; 215 colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f); 216 colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); 217 colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f); 218 colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f); 219 colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); 220 colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); 221 colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); 222 colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); 223 colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); 224 colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); 225 colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); 226 colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); 227 colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f); 188 228 } 189 229 190 230 void ImGui::StyleColorsClassic(ImGuiStyle* dst) 191 231 { 192 ImGuiStyle* style = dst ? dst : &ImGui::GetStyle(); 193 ImVec4* colors = style->Colors; 194 195 colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f); 196 colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f); 197 colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.70f); 198 colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); 199 colors[ImGuiCol_PopupBg] = ImVec4(0.11f, 0.11f, 0.14f, 0.92f); 200 colors[ImGuiCol_Border] = ImVec4(0.50f, 0.50f, 0.50f, 0.50f); 201 colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); 202 colors[ImGuiCol_FrameBg] = ImVec4(0.43f, 0.43f, 0.43f, 0.39f); 203 colors[ImGuiCol_FrameBgHovered] = ImVec4(0.47f, 0.47f, 0.69f, 0.40f); 204 colors[ImGuiCol_FrameBgActive] = ImVec4(0.42f, 0.41f, 0.64f, 0.69f); 205 colors[ImGuiCol_TitleBg] = ImVec4(0.27f, 0.27f, 0.54f, 0.83f); 206 colors[ImGuiCol_TitleBgActive] = ImVec4(0.32f, 0.32f, 0.63f, 0.87f); 207 colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.40f, 0.40f, 0.80f, 0.20f); 208 colors[ImGuiCol_MenuBarBg] = ImVec4(0.40f, 0.40f, 0.55f, 0.80f); 209 colors[ImGuiCol_ScrollbarBg] = ImVec4(0.20f, 0.25f, 0.30f, 0.60f); 210 colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.40f, 0.40f, 0.80f, 0.30f); 211 colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.80f, 0.40f); 212 colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.41f, 0.39f, 0.80f, 0.60f); 213 colors[ImGuiCol_CheckMark] = ImVec4(0.90f, 0.90f, 0.90f, 0.50f); 214 colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f); 215 colors[ImGuiCol_SliderGrabActive] = ImVec4(0.41f, 0.39f, 0.80f, 0.60f); 216 colors[ImGuiCol_Button] = ImVec4(0.35f, 0.40f, 0.61f, 0.62f); 217 colors[ImGuiCol_ButtonHovered] = ImVec4(0.40f, 0.48f, 0.71f, 0.79f); 218 colors[ImGuiCol_ButtonActive] = ImVec4(0.46f, 0.54f, 0.80f, 1.00f); 219 colors[ImGuiCol_Header] = ImVec4(0.40f, 0.40f, 0.90f, 0.45f); 220 colors[ImGuiCol_HeaderHovered] = ImVec4(0.45f, 0.45f, 0.90f, 0.80f); 221 colors[ImGuiCol_HeaderActive] = ImVec4(0.53f, 0.53f, 0.87f, 0.80f); 222 colors[ImGuiCol_Separator] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); 223 colors[ImGuiCol_SeparatorHovered] = ImVec4(0.60f, 0.60f, 0.70f, 1.00f); 224 colors[ImGuiCol_SeparatorActive] = ImVec4(0.70f, 0.70f, 0.90f, 1.00f); 225 colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.16f); 226 colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.78f, 0.82f, 1.00f, 0.60f); 227 colors[ImGuiCol_ResizeGripActive] = ImVec4(0.78f, 0.82f, 1.00f, 0.90f); 228 colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); 229 colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); 230 colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); 231 colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); 232 colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f); 233 colors[ImGuiCol_ModalWindowDarkening] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); 234 colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); 235 colors[ImGuiCol_NavHighlight] = colors[ImGuiCol_HeaderHovered]; 236 colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); 232 ImGuiStyle* style = dst ? dst : &ImGui::GetStyle(); 233 ImVec4* colors = style->Colors; 234 235 colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f); 236 colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f); 237 colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.70f); 238 colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); 239 colors[ImGuiCol_PopupBg] = ImVec4(0.11f, 0.11f, 0.14f, 0.92f); 240 colors[ImGuiCol_Border] = ImVec4(0.50f, 0.50f, 0.50f, 0.50f); 241 colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); 242 colors[ImGuiCol_FrameBg] = ImVec4(0.43f, 0.43f, 0.43f, 0.39f); 243 colors[ImGuiCol_FrameBgHovered] = ImVec4(0.47f, 0.47f, 0.69f, 0.40f); 244 colors[ImGuiCol_FrameBgActive] = ImVec4(0.42f, 0.41f, 0.64f, 0.69f); 245 colors[ImGuiCol_TitleBg] = ImVec4(0.27f, 0.27f, 0.54f, 0.83f); 246 colors[ImGuiCol_TitleBgActive] = ImVec4(0.32f, 0.32f, 0.63f, 0.87f); 247 colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.40f, 0.40f, 0.80f, 0.20f); 248 colors[ImGuiCol_MenuBarBg] = ImVec4(0.40f, 0.40f, 0.55f, 0.80f); 249 colors[ImGuiCol_ScrollbarBg] = ImVec4(0.20f, 0.25f, 0.30f, 0.60f); 250 colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.40f, 0.40f, 0.80f, 0.30f); 251 colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.80f, 0.40f); 252 colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.41f, 0.39f, 0.80f, 0.60f); 253 colors[ImGuiCol_CheckMark] = ImVec4(0.90f, 0.90f, 0.90f, 0.50f); 254 colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f); 255 colors[ImGuiCol_SliderGrabActive] = ImVec4(0.41f, 0.39f, 0.80f, 0.60f); 256 colors[ImGuiCol_Button] = ImVec4(0.35f, 0.40f, 0.61f, 0.62f); 257 colors[ImGuiCol_ButtonHovered] = ImVec4(0.40f, 0.48f, 0.71f, 0.79f); 258 colors[ImGuiCol_ButtonActive] = ImVec4(0.46f, 0.54f, 0.80f, 1.00f); 259 colors[ImGuiCol_Header] = ImVec4(0.40f, 0.40f, 0.90f, 0.45f); 260 colors[ImGuiCol_HeaderHovered] = ImVec4(0.45f, 0.45f, 0.90f, 0.80f); 261 colors[ImGuiCol_HeaderActive] = ImVec4(0.53f, 0.53f, 0.87f, 0.80f); 262 colors[ImGuiCol_Separator] = ImVec4(0.50f, 0.50f, 0.50f, 0.60f); 263 colors[ImGuiCol_SeparatorHovered] = ImVec4(0.60f, 0.60f, 0.70f, 1.00f); 264 colors[ImGuiCol_SeparatorActive] = ImVec4(0.70f, 0.70f, 0.90f, 1.00f); 265 colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.16f); 266 colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.78f, 0.82f, 1.00f, 0.60f); 267 colors[ImGuiCol_ResizeGripActive] = ImVec4(0.78f, 0.82f, 1.00f, 0.90f); 268 colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f); 269 colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; 270 colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f); 271 colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); 272 colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f); 273 colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); 274 colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); 275 colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); 276 colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); 277 colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f); 278 colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); 279 colors[ImGuiCol_NavHighlight] = colors[ImGuiCol_HeaderHovered]; 280 colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); 281 colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); 282 colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); 237 283 } 238 284 … … 240 286 void ImGui::StyleColorsLight(ImGuiStyle* dst) 241 287 { 242 ImGuiStyle* style = dst ? dst : &ImGui::GetStyle(); 243 ImVec4* colors = style->Colors; 244 245 colors[ImGuiCol_Text] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); 246 colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f); 247 colors[ImGuiCol_WindowBg] = ImVec4(0.94f, 0.94f, 0.94f, 1.00f); 248 colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); 249 colors[ImGuiCol_PopupBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.98f); 250 colors[ImGuiCol_Border] = ImVec4(0.00f, 0.00f, 0.00f, 0.30f); 251 colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); 252 colors[ImGuiCol_FrameBg] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); 253 colors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); 254 colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); 255 colors[ImGuiCol_TitleBg] = ImVec4(0.96f, 0.96f, 0.96f, 1.00f); 256 colors[ImGuiCol_TitleBgActive] = ImVec4(0.82f, 0.82f, 0.82f, 1.00f); 257 colors[ImGuiCol_TitleBgCollapsed] = ImVec4(1.00f, 1.00f, 1.00f, 0.51f); 258 colors[ImGuiCol_MenuBarBg] = ImVec4(0.86f, 0.86f, 0.86f, 1.00f); 259 colors[ImGuiCol_ScrollbarBg] = ImVec4(0.98f, 0.98f, 0.98f, 0.53f); 260 colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.69f, 0.69f, 0.69f, 0.80f); 261 colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.49f, 0.49f, 0.49f, 0.80f); 262 colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.49f, 0.49f, 0.49f, 1.00f); 263 colors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); 264 colors[ImGuiCol_SliderGrab] = ImVec4(0.26f, 0.59f, 0.98f, 0.78f); 265 colors[ImGuiCol_SliderGrabActive] = ImVec4(0.46f, 0.54f, 0.80f, 0.60f); 266 colors[ImGuiCol_Button] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); 267 colors[ImGuiCol_ButtonHovered] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); 268 colors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f); 269 colors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.31f); 270 colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f); 271 colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); 272 colors[ImGuiCol_Separator] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f); 273 colors[ImGuiCol_SeparatorHovered] = ImVec4(0.14f, 0.44f, 0.80f, 0.78f); 274 colors[ImGuiCol_SeparatorActive] = ImVec4(0.14f, 0.44f, 0.80f, 1.00f); 275 colors[ImGuiCol_ResizeGrip] = ImVec4(0.80f, 0.80f, 0.80f, 0.56f); 276 colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); 277 colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); 278 colors[ImGuiCol_PlotLines] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f); 279 colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); 280 colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); 281 colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.45f, 0.00f, 1.00f); 282 colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); 283 colors[ImGuiCol_ModalWindowDarkening] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); 284 colors[ImGuiCol_DragDropTarget] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); 285 colors[ImGuiCol_NavHighlight] = colors[ImGuiCol_HeaderHovered]; 286 colors[ImGuiCol_NavWindowingHighlight] = ImVec4(0.70f, 0.70f, 0.70f, 0.70f); 288 ImGuiStyle* style = dst ? dst : &ImGui::GetStyle(); 289 ImVec4* colors = style->Colors; 290 291 colors[ImGuiCol_Text] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); 292 colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f); 293 colors[ImGuiCol_WindowBg] = ImVec4(0.94f, 0.94f, 0.94f, 1.00f); 294 colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); 295 colors[ImGuiCol_PopupBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.98f); 296 colors[ImGuiCol_Border] = ImVec4(0.00f, 0.00f, 0.00f, 0.30f); 297 colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); 298 colors[ImGuiCol_FrameBg] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); 299 colors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); 300 colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); 301 colors[ImGuiCol_TitleBg] = ImVec4(0.96f, 0.96f, 0.96f, 1.00f); 302 colors[ImGuiCol_TitleBgActive] = ImVec4(0.82f, 0.82f, 0.82f, 1.00f); 303 colors[ImGuiCol_TitleBgCollapsed] = ImVec4(1.00f, 1.00f, 1.00f, 0.51f); 304 colors[ImGuiCol_MenuBarBg] = ImVec4(0.86f, 0.86f, 0.86f, 1.00f); 305 colors[ImGuiCol_ScrollbarBg] = ImVec4(0.98f, 0.98f, 0.98f, 0.53f); 306 colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.69f, 0.69f, 0.69f, 0.80f); 307 colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.49f, 0.49f, 0.49f, 0.80f); 308 colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.49f, 0.49f, 0.49f, 1.00f); 309 colors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); 310 colors[ImGuiCol_SliderGrab] = ImVec4(0.26f, 0.59f, 0.98f, 0.78f); 311 colors[ImGuiCol_SliderGrabActive] = ImVec4(0.46f, 0.54f, 0.80f, 0.60f); 312 colors[ImGuiCol_Button] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); 313 colors[ImGuiCol_ButtonHovered] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); 314 colors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f); 315 colors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.31f); 316 colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f); 317 colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); 318 colors[ImGuiCol_Separator] = ImVec4(0.39f, 0.39f, 0.39f, 0.62f); 319 colors[ImGuiCol_SeparatorHovered] = ImVec4(0.14f, 0.44f, 0.80f, 0.78f); 320 colors[ImGuiCol_SeparatorActive] = ImVec4(0.14f, 0.44f, 0.80f, 1.00f); 321 colors[ImGuiCol_ResizeGrip] = ImVec4(0.80f, 0.80f, 0.80f, 0.56f); 322 colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); 323 colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); 324 colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.90f); 325 colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; 326 colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f); 327 colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); 328 colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f); 329 colors[ImGuiCol_PlotLines] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f); 330 colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); 331 colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); 332 colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.45f, 0.00f, 1.00f); 333 colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); 334 colors[ImGuiCol_DragDropTarget] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); 335 colors[ImGuiCol_NavHighlight] = colors[ImGuiCol_HeaderHovered]; 336 colors[ImGuiCol_NavWindowingHighlight] = ImVec4(0.70f, 0.70f, 0.70f, 0.70f); 337 colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.20f); 338 colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); 287 339 } 288 340 289 341 //----------------------------------------------------------------------------- 290 // ImDrawListData342 // [SECTION] ImDrawList 291 343 //----------------------------------------------------------------------------- 292 344 293 345 ImDrawListSharedData::ImDrawListSharedData() 294 346 { 295 Font = NULL; 296 FontSize = 0.0f; 297 CurveTessellationTol = 0.0f; 298 ClipRectFullscreen = ImVec4(-8192.0f, -8192.0f, +8192.0f, +8192.0f); 299 300 // Const data 301 for (int i = 0; i < IM_ARRAYSIZE(CircleVtx12); i++) 302 { 303 const float a = ((float)i * 2 * IM_PI) / (float)IM_ARRAYSIZE(CircleVtx12); 304 CircleVtx12[i] = ImVec2(cosf(a), sinf(a)); 305 } 306 } 307 308 //----------------------------------------------------------------------------- 309 // ImDrawList 310 //----------------------------------------------------------------------------- 311 312 void ImDrawList::Clear() 313 { 314 CmdBuffer.resize(0); 315 IdxBuffer.resize(0); 316 VtxBuffer.resize(0); 317 Flags = ImDrawListFlags_AntiAliasedLines | ImDrawListFlags_AntiAliasedFill; 318 _VtxCurrentIdx = 0; 319 _VtxWritePtr = NULL; 320 _IdxWritePtr = NULL; 321 _ClipRectStack.resize(0); 322 _TextureIdStack.resize(0); 323 _Path.resize(0); 324 _ChannelsCurrent = 0; 325 _ChannelsCount = 1; 326 // NB: Do not clear channels so our allocations are re-used after the first frame. 327 } 328 329 void ImDrawList::ClearFreeMemory() 330 { 331 CmdBuffer.clear(); 332 IdxBuffer.clear(); 333 VtxBuffer.clear(); 334 _VtxCurrentIdx = 0; 335 _VtxWritePtr = NULL; 336 _IdxWritePtr = NULL; 337 _ClipRectStack.clear(); 338 _TextureIdStack.clear(); 339 _Path.clear(); 340 _ChannelsCurrent = 0; 341 _ChannelsCount = 1; 342 for (int i = 0; i < _Channels.Size; i++) 343 { 344 if (i == 0) memset(&_Channels[0], 0, sizeof(_Channels[0])); // channel 0 is a copy of CmdBuffer/IdxBuffer, don't destruct again 345 _Channels[i].CmdBuffer.clear(); 346 _Channels[i].IdxBuffer.clear(); 347 } 348 _Channels.clear(); 347 Font = NULL; 348 FontSize = 0.0f; 349 CurveTessellationTol = 0.0f; 350 CircleSegmentMaxError = 0.0f; 351 ClipRectFullscreen = ImVec4(-8192.0f, -8192.0f, +8192.0f, +8192.0f); 352 InitialFlags = ImDrawListFlags_None; 353 354 // Lookup tables 355 for (int i = 0; i < IM_ARRAYSIZE(ArcFastVtx); i++) 356 { 357 const float a = ((float)i * 2 * IM_PI) / (float)IM_ARRAYSIZE(ArcFastVtx); 358 ArcFastVtx[i] = ImVec2(ImCos(a), ImSin(a)); 359 } 360 memset(CircleSegmentCounts, 0, sizeof(CircleSegmentCounts)); // This will be set by SetCircleSegmentMaxError() 361 TexUvLines = NULL; 362 } 363 364 void ImDrawListSharedData::SetCircleSegmentMaxError(float max_error) 365 { 366 if (CircleSegmentMaxError == max_error) 367 return; 368 CircleSegmentMaxError = max_error; 369 for (int i = 0; i < IM_ARRAYSIZE(CircleSegmentCounts); i++) 370 { 371 const float radius = i + 1.0f; 372 const int segment_count = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, CircleSegmentMaxError); 373 CircleSegmentCounts[i] = (ImU8)ImMin(segment_count, 255); 374 } 375 } 376 377 // Initialize before use in a new frame. We always have a command ready in the buffer. 378 void ImDrawList::_ResetForNewFrame() 379 { 380 // Verify that the ImDrawCmd fields we want to memcmp() are contiguous in memory. 381 // (those should be IM_STATIC_ASSERT() in theory but with our pre C++11 setup the whole check doesn't compile with GCC) 382 IM_ASSERT(IM_OFFSETOF(ImDrawCmd, ClipRect) == 0); 383 IM_ASSERT(IM_OFFSETOF(ImDrawCmd, TextureId) == sizeof(ImVec4)); 384 IM_ASSERT(IM_OFFSETOF(ImDrawCmd, VtxOffset) == sizeof(ImVec4) + sizeof(ImTextureID)); 385 386 CmdBuffer.resize(0); 387 IdxBuffer.resize(0); 388 VtxBuffer.resize(0); 389 Flags = _Data->InitialFlags; 390 memset(&_CmdHeader, 0, sizeof(_CmdHeader)); 391 _VtxCurrentIdx = 0; 392 _VtxWritePtr = NULL; 393 _IdxWritePtr = NULL; 394 _ClipRectStack.resize(0); 395 _TextureIdStack.resize(0); 396 _Path.resize(0); 397 _Splitter.Clear(); 398 CmdBuffer.push_back(ImDrawCmd()); 399 } 400 401 void ImDrawList::_ClearFreeMemory() 402 { 403 CmdBuffer.clear(); 404 IdxBuffer.clear(); 405 VtxBuffer.clear(); 406 Flags = ImDrawListFlags_None; 407 _VtxCurrentIdx = 0; 408 _VtxWritePtr = NULL; 409 _IdxWritePtr = NULL; 410 _ClipRectStack.clear(); 411 _TextureIdStack.clear(); 412 _Path.clear(); 413 _Splitter.ClearFreeMemory(); 349 414 } 350 415 351 416 ImDrawList* ImDrawList::CloneOutput() const 352 417 { 353 ImDrawList* dst = IM_NEW(ImDrawList(NULL)); 354 dst->CmdBuffer = CmdBuffer; 355 dst->IdxBuffer = IdxBuffer; 356 dst->VtxBuffer = VtxBuffer; 357 dst->Flags = Flags; 358 return dst; 359 } 360 361 // Using macros because C++ is a terrible language, we want guaranteed inline, no code in header, and no overhead in Debug builds 362 #define GetCurrentClipRect() (_ClipRectStack.Size ? _ClipRectStack.Data[_ClipRectStack.Size-1] : _Data->ClipRectFullscreen) 363 #define GetCurrentTextureId() (_TextureIdStack.Size ? _TextureIdStack.Data[_TextureIdStack.Size-1] : NULL) 418 ImDrawList* dst = IM_NEW(ImDrawList(_Data)); 419 dst->CmdBuffer = CmdBuffer; 420 dst->IdxBuffer = IdxBuffer; 421 dst->VtxBuffer = VtxBuffer; 422 dst->Flags = Flags; 423 return dst; 424 } 364 425 365 426 void ImDrawList::AddDrawCmd() 366 427 { 367 ImDrawCmd draw_cmd; 368 draw_cmd.ClipRect = GetCurrentClipRect(); 369 draw_cmd.TextureId = GetCurrentTextureId(); 370 371 IM_ASSERT(draw_cmd.ClipRect.x <= draw_cmd.ClipRect.z && draw_cmd.ClipRect.y <= draw_cmd.ClipRect.w); 372 CmdBuffer.push_back(draw_cmd); 428 ImDrawCmd draw_cmd; 429 draw_cmd.ClipRect = _CmdHeader.ClipRect; // Same as calling ImDrawCmd_HeaderCopy() 430 draw_cmd.TextureId = _CmdHeader.TextureId; 431 draw_cmd.VtxOffset = _CmdHeader.VtxOffset; 432 draw_cmd.IdxOffset = IdxBuffer.Size; 433 434 IM_ASSERT(draw_cmd.ClipRect.x <= draw_cmd.ClipRect.z && draw_cmd.ClipRect.y <= draw_cmd.ClipRect.w); 435 CmdBuffer.push_back(draw_cmd); 436 } 437 438 // Pop trailing draw command (used before merging or presenting to user) 439 // Note that this leaves the ImDrawList in a state unfit for further commands, as most code assume that CmdBuffer.Size > 0 && CmdBuffer.back().UserCallback == NULL 440 void ImDrawList::_PopUnusedDrawCmd() 441 { 442 if (CmdBuffer.Size == 0) 443 return; 444 ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; 445 if (curr_cmd->ElemCount == 0 && curr_cmd->UserCallback == NULL) 446 CmdBuffer.pop_back(); 373 447 } 374 448 375 449 void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data) 376 450 { 377 ImDrawCmd* current_cmd = CmdBuffer.Size ? &CmdBuffer.back() : NULL; 378 if (!current_cmd || current_cmd->ElemCount != 0 || current_cmd->UserCallback != NULL) 379 { 380 AddDrawCmd(); 381 current_cmd = &CmdBuffer.back(); 382 } 383 current_cmd->UserCallback = callback; 384 current_cmd->UserCallbackData = callback_data; 385 386 AddDrawCmd(); // Force a new command after us (see comment below) 387 } 451 ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; 452 IM_ASSERT(curr_cmd->UserCallback == NULL); 453 if (curr_cmd->ElemCount != 0) 454 { 455 AddDrawCmd(); 456 curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; 457 } 458 curr_cmd->UserCallback = callback; 459 curr_cmd->UserCallbackData = callback_data; 460 461 AddDrawCmd(); // Force a new command after us (see comment below) 462 } 463 464 // Compare ClipRect, TextureId and VtxOffset with a single memcmp() 465 #define ImDrawCmd_HeaderSize (IM_OFFSETOF(ImDrawCmd, VtxOffset) + sizeof(unsigned int)) 466 #define ImDrawCmd_HeaderCompare(CMD_LHS, CMD_RHS) (memcmp(CMD_LHS, CMD_RHS, ImDrawCmd_HeaderSize)) // Compare ClipRect, TextureId, VtxOffset 467 #define ImDrawCmd_HeaderCopy(CMD_DST, CMD_SRC) (memcpy(CMD_DST, CMD_SRC, ImDrawCmd_HeaderSize)) // Copy ClipRect, TextureId, VtxOffset 388 468 389 469 // Our scheme may appears a bit unusual, basically we want the most-common calls AddLine AddRect etc. to not have to perform any check so we always have a command ready in the stack. 390 470 // The cost of figuring out if a new command has to be added or if we can merge is paid in those Update** functions only. 391 void ImDrawList::UpdateClipRect() 392 { 393 // If current command is used with different settings we need to add a new command 394 const ImVec4 curr_clip_rect = GetCurrentClipRect(); 395 ImDrawCmd* curr_cmd = CmdBuffer.Size > 0 ? &CmdBuffer.Data[CmdBuffer.Size - 1] : NULL; 396 if (!curr_cmd || (curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &curr_clip_rect, sizeof(ImVec4)) != 0) || curr_cmd->UserCallback != NULL) 397 { 398 AddDrawCmd(); 399 return; 400 } 401 402 // Try to merge with previous command if it matches, else use current command 403 ImDrawCmd* prev_cmd = CmdBuffer.Size > 1 ? curr_cmd - 1 : NULL; 404 if (curr_cmd->ElemCount == 0 && prev_cmd && memcmp(&prev_cmd->ClipRect, &curr_clip_rect, sizeof(ImVec4)) == 0 && prev_cmd->TextureId == GetCurrentTextureId() && prev_cmd->UserCallback == NULL) 405 CmdBuffer.pop_back(); 406 else 407 curr_cmd->ClipRect = curr_clip_rect; 408 } 409 410 void ImDrawList::UpdateTextureID() 411 { 412 // If current command is used with different settings we need to add a new command 413 const ImTextureID curr_texture_id = GetCurrentTextureId(); 414 ImDrawCmd* curr_cmd = CmdBuffer.Size ? &CmdBuffer.back() : NULL; 415 if (!curr_cmd || (curr_cmd->ElemCount != 0 && curr_cmd->TextureId != curr_texture_id) || curr_cmd->UserCallback != NULL) 416 { 417 AddDrawCmd(); 418 return; 419 } 420 421 // Try to merge with previous command if it matches, else use current command 422 ImDrawCmd* prev_cmd = CmdBuffer.Size > 1 ? curr_cmd - 1 : NULL; 423 if (curr_cmd->ElemCount == 0 && prev_cmd && prev_cmd->TextureId == curr_texture_id && memcmp(&prev_cmd->ClipRect, &GetCurrentClipRect(), sizeof(ImVec4)) == 0 && prev_cmd->UserCallback == NULL) 424 CmdBuffer.pop_back(); 425 else 426 curr_cmd->TextureId = curr_texture_id; 427 } 428 429 #undef GetCurrentClipRect 430 #undef GetCurrentTextureId 471 void ImDrawList::_OnChangedClipRect() 472 { 473 // If current command is used with different settings we need to add a new command 474 ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; 475 if (curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &_CmdHeader.ClipRect, sizeof(ImVec4)) != 0) 476 { 477 AddDrawCmd(); 478 return; 479 } 480 IM_ASSERT(curr_cmd->UserCallback == NULL); 481 482 // Try to merge with previous command if it matches, else use current command 483 ImDrawCmd* prev_cmd = curr_cmd - 1; 484 if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && prev_cmd->UserCallback == NULL) 485 { 486 CmdBuffer.pop_back(); 487 return; 488 } 489 490 curr_cmd->ClipRect = _CmdHeader.ClipRect; 491 } 492 493 void ImDrawList::_OnChangedTextureID() 494 { 495 // If current command is used with different settings we need to add a new command 496 ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; 497 if (curr_cmd->ElemCount != 0 && curr_cmd->TextureId != _CmdHeader.TextureId) 498 { 499 AddDrawCmd(); 500 return; 501 } 502 IM_ASSERT(curr_cmd->UserCallback == NULL); 503 504 // Try to merge with previous command if it matches, else use current command 505 ImDrawCmd* prev_cmd = curr_cmd - 1; 506 if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && prev_cmd->UserCallback == NULL) 507 { 508 CmdBuffer.pop_back(); 509 return; 510 } 511 512 curr_cmd->TextureId = _CmdHeader.TextureId; 513 } 514 515 void ImDrawList::_OnChangedVtxOffset() 516 { 517 // We don't need to compare curr_cmd->VtxOffset != _CmdHeader.VtxOffset because we know it'll be different at the time we call this. 518 _VtxCurrentIdx = 0; 519 ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; 520 //IM_ASSERT(curr_cmd->VtxOffset != _CmdHeader.VtxOffset); // See #3349 521 if (curr_cmd->ElemCount != 0) 522 { 523 AddDrawCmd(); 524 return; 525 } 526 IM_ASSERT(curr_cmd->UserCallback == NULL); 527 curr_cmd->VtxOffset = _CmdHeader.VtxOffset; 528 } 431 529 432 530 // Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling) 433 531 void ImDrawList::PushClipRect(ImVec2 cr_min, ImVec2 cr_max, bool intersect_with_current_clip_rect) 434 532 { 435 ImVec4 cr(cr_min.x, cr_min.y, cr_max.x, cr_max.y); 436 if (intersect_with_current_clip_rect && _ClipRectStack.Size) 437 { 438 ImVec4 current = _ClipRectStack.Data[_ClipRectStack.Size - 1]; 439 if (cr.x < current.x) cr.x = current.x; 440 if (cr.y < current.y) cr.y = current.y; 441 if (cr.z > current.z) cr.z = current.z; 442 if (cr.w > current.w) cr.w = current.w; 443 } 444 cr.z = ImMax(cr.x, cr.z); 445 cr.w = ImMax(cr.y, cr.w); 446 447 _ClipRectStack.push_back(cr); 448 UpdateClipRect(); 533 ImVec4 cr(cr_min.x, cr_min.y, cr_max.x, cr_max.y); 534 if (intersect_with_current_clip_rect) 535 { 536 ImVec4 current = _CmdHeader.ClipRect; 537 if (cr.x < current.x) cr.x = current.x; 538 if (cr.y < current.y) cr.y = current.y; 539 if (cr.z > current.z) cr.z = current.z; 540 if (cr.w > current.w) cr.w = current.w; 541 } 542 cr.z = ImMax(cr.x, cr.z); 543 cr.w = ImMax(cr.y, cr.w); 544 545 _ClipRectStack.push_back(cr); 546 _CmdHeader.ClipRect = cr; 547 _OnChangedClipRect(); 449 548 } 450 549 451 550 void ImDrawList::PushClipRectFullScreen() 452 551 { 453 PushClipRect(ImVec2(_Data->ClipRectFullscreen.x, _Data->ClipRectFullscreen.y), ImVec2(_Data->ClipRectFullscreen.z, _Data->ClipRectFullscreen.w));552 PushClipRect(ImVec2(_Data->ClipRectFullscreen.x, _Data->ClipRectFullscreen.y), ImVec2(_Data->ClipRectFullscreen.z, _Data->ClipRectFullscreen.w)); 454 553 } 455 554 456 555 void ImDrawList::PopClipRect() 457 556 { 458 IM_ASSERT(_ClipRectStack.Size > 0);459 _ClipRectStack.pop_back();460 UpdateClipRect();557 _ClipRectStack.pop_back(); 558 _CmdHeader.ClipRect = (_ClipRectStack.Size == 0) ? _Data->ClipRectFullscreen : _ClipRectStack.Data[_ClipRectStack.Size - 1]; 559 _OnChangedClipRect(); 461 560 } 462 561 463 562 void ImDrawList::PushTextureID(ImTextureID texture_id) 464 563 { 465 _TextureIdStack.push_back(texture_id); 466 UpdateTextureID(); 564 _TextureIdStack.push_back(texture_id); 565 _CmdHeader.TextureId = texture_id; 566 _OnChangedTextureID(); 467 567 } 468 568 469 569 void ImDrawList::PopTextureID() 470 570 { 471 IM_ASSERT(_TextureIdStack.Size > 0); 472 _TextureIdStack.pop_back(); 473 UpdateTextureID(); 474 } 475 476 void ImDrawList::ChannelsSplit(int channels_count) 477 { 478 IM_ASSERT(_ChannelsCurrent == 0 && _ChannelsCount == 1); 479 int old_channels_count = _Channels.Size; 480 if (old_channels_count < channels_count) 481 _Channels.resize(channels_count); 482 _ChannelsCount = channels_count; 483 484 // _Channels[] (24/32 bytes each) hold storage that we'll swap with this->_CmdBuffer/_IdxBuffer 485 // The content of _Channels[0] at this point doesn't matter. We clear it to make state tidy in a debugger but we don't strictly need to. 486 // When we switch to the next channel, we'll copy _CmdBuffer/_IdxBuffer into _Channels[0] and then _Channels[1] into _CmdBuffer/_IdxBuffer 487 memset(&_Channels[0], 0, sizeof(ImDrawChannel)); 488 for (int i = 1; i < channels_count; i++) 489 { 490 if (i >= old_channels_count) 491 { 492 IM_PLACEMENT_NEW(&_Channels[i]) ImDrawChannel(); 493 } 494 else 495 { 496 _Channels[i].CmdBuffer.resize(0); 497 _Channels[i].IdxBuffer.resize(0); 498 } 499 if (_Channels[i].CmdBuffer.Size == 0) 500 { 501 ImDrawCmd draw_cmd; 502 draw_cmd.ClipRect = _ClipRectStack.back(); 503 draw_cmd.TextureId = _TextureIdStack.back(); 504 _Channels[i].CmdBuffer.push_back(draw_cmd); 505 } 506 } 507 } 508 509 void ImDrawList::ChannelsMerge() 510 { 511 // Note that we never use or rely on channels.Size because it is merely a buffer that we never shrink back to 0 to keep all sub-buffers ready for use. 512 if (_ChannelsCount <= 1) 513 return; 514 515 ChannelsSetCurrent(0); 516 if (CmdBuffer.Size && CmdBuffer.back().ElemCount == 0) 517 CmdBuffer.pop_back(); 518 519 int new_cmd_buffer_count = 0, new_idx_buffer_count = 0; 520 for (int i = 1; i < _ChannelsCount; i++) 521 { 522 ImDrawChannel& ch = _Channels[i]; 523 if (ch.CmdBuffer.Size && ch.CmdBuffer.back().ElemCount == 0) 524 ch.CmdBuffer.pop_back(); 525 new_cmd_buffer_count += ch.CmdBuffer.Size; 526 new_idx_buffer_count += ch.IdxBuffer.Size; 527 } 528 CmdBuffer.resize(CmdBuffer.Size + new_cmd_buffer_count); 529 IdxBuffer.resize(IdxBuffer.Size + new_idx_buffer_count); 530 531 ImDrawCmd* cmd_write = CmdBuffer.Data + CmdBuffer.Size - new_cmd_buffer_count; 532 _IdxWritePtr = IdxBuffer.Data + IdxBuffer.Size - new_idx_buffer_count; 533 for (int i = 1; i < _ChannelsCount; i++) 534 { 535 ImDrawChannel& ch = _Channels[i]; 536 if (int sz = ch.CmdBuffer.Size) { memcpy(cmd_write, ch.CmdBuffer.Data, sz * sizeof(ImDrawCmd)); cmd_write += sz; } 537 if (int sz = ch.IdxBuffer.Size) { memcpy(_IdxWritePtr, ch.IdxBuffer.Data, sz * sizeof(ImDrawIdx)); _IdxWritePtr += sz; } 538 } 539 UpdateClipRect(); // We call this instead of AddDrawCmd(), so that empty channels won't produce an extra draw call. 540 _ChannelsCount = 1; 541 } 542 543 void ImDrawList::ChannelsSetCurrent(int idx) 544 { 545 IM_ASSERT(idx < _ChannelsCount); 546 if (_ChannelsCurrent == idx) return; 547 memcpy(&_Channels.Data[_ChannelsCurrent].CmdBuffer, &CmdBuffer, sizeof(CmdBuffer)); // copy 12 bytes, four times 548 memcpy(&_Channels.Data[_ChannelsCurrent].IdxBuffer, &IdxBuffer, sizeof(IdxBuffer)); 549 _ChannelsCurrent = idx; 550 memcpy(&CmdBuffer, &_Channels.Data[_ChannelsCurrent].CmdBuffer, sizeof(CmdBuffer)); 551 memcpy(&IdxBuffer, &_Channels.Data[_ChannelsCurrent].IdxBuffer, sizeof(IdxBuffer)); 552 _IdxWritePtr = IdxBuffer.Data + IdxBuffer.Size; 553 } 554 555 // NB: this can be called with negative count for removing primitives (as long as the result does not underflow) 571 _TextureIdStack.pop_back(); 572 _CmdHeader.TextureId = (_TextureIdStack.Size == 0) ? (ImTextureID)NULL : _TextureIdStack.Data[_TextureIdStack.Size - 1]; 573 _OnChangedTextureID(); 574 } 575 576 // Reserve space for a number of vertices and indices. 577 // You must finish filling your reserved data before calling PrimReserve() again, as it may reallocate or 578 // submit the intermediate results. PrimUnreserve() can be used to release unused allocations. 556 579 void ImDrawList::PrimReserve(int idx_count, int vtx_count) 557 580 { 558 ImDrawCmd& draw_cmd = CmdBuffer.Data[CmdBuffer.Size - 1]; 559 draw_cmd.ElemCount += idx_count; 560 561 int vtx_buffer_old_size = VtxBuffer.Size; 562 VtxBuffer.resize(vtx_buffer_old_size + vtx_count); 563 _VtxWritePtr = VtxBuffer.Data + vtx_buffer_old_size; 564 565 int idx_buffer_old_size = IdxBuffer.Size; 566 IdxBuffer.resize(idx_buffer_old_size + idx_count); 567 _IdxWritePtr = IdxBuffer.Data + idx_buffer_old_size; 581 // Large mesh support (when enabled) 582 IM_ASSERT_PARANOID(idx_count >= 0 && vtx_count >= 0); 583 if (sizeof(ImDrawIdx) == 2 && (_VtxCurrentIdx + vtx_count >= (1 << 16)) && (Flags & ImDrawListFlags_AllowVtxOffset)) 584 { 585 // FIXME: In theory we should be testing that vtx_count <64k here. 586 // In practice, RenderText() relies on reserving ahead for a worst case scenario so it is currently useful for us 587 // to not make that check until we rework the text functions to handle clipping and large horizontal lines better. 588 _CmdHeader.VtxOffset = VtxBuffer.Size; 589 _OnChangedVtxOffset(); 590 } 591 592 ImDrawCmd* draw_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; 593 draw_cmd->ElemCount += idx_count; 594 595 int vtx_buffer_old_size = VtxBuffer.Size; 596 VtxBuffer.resize(vtx_buffer_old_size + vtx_count); 597 _VtxWritePtr = VtxBuffer.Data + vtx_buffer_old_size; 598 599 int idx_buffer_old_size = IdxBuffer.Size; 600 IdxBuffer.resize(idx_buffer_old_size + idx_count); 601 _IdxWritePtr = IdxBuffer.Data + idx_buffer_old_size; 602 } 603 604 // Release the a number of reserved vertices/indices from the end of the last reservation made with PrimReserve(). 605 void ImDrawList::PrimUnreserve(int idx_count, int vtx_count) 606 { 607 IM_ASSERT_PARANOID(idx_count >= 0 && vtx_count >= 0); 608 609 ImDrawCmd* draw_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; 610 draw_cmd->ElemCount -= idx_count; 611 VtxBuffer.shrink(VtxBuffer.Size - vtx_count); 612 IdxBuffer.shrink(IdxBuffer.Size - idx_count); 568 613 } 569 614 … … 571 616 void ImDrawList::PrimRect(const ImVec2& a, const ImVec2& c, ImU32 col) 572 617 { 573 ImVec2 b(c.x, a.y), d(a.x, c.y), uv(_Data->TexUvWhitePixel);574 ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;575 _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx + 1); _IdxWritePtr[2] = (ImDrawIdx)(idx +2);576 _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx +3);577 _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;578 _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col;579 _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col;580 _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col;581 _VtxWritePtr += 4;582 _VtxCurrentIdx += 4;583 _IdxWritePtr += 6;618 ImVec2 b(c.x, a.y), d(a.x, c.y), uv(_Data->TexUvWhitePixel); 619 ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx; 620 _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2); 621 _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3); 622 _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; 623 _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col; 624 _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col; 625 _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col; 626 _VtxWritePtr += 4; 627 _VtxCurrentIdx += 4; 628 _IdxWritePtr += 6; 584 629 } 585 630 586 631 void ImDrawList::PrimRectUV(const ImVec2& a, const ImVec2& c, const ImVec2& uv_a, const ImVec2& uv_c, ImU32 col) 587 632 { 588 ImVec2 b(c.x, a.y), d(a.x, c.y), uv_b(uv_c.x, uv_a.y), uv_d(uv_a.x, uv_c.y);589 ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;590 _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx + 1); _IdxWritePtr[2] = (ImDrawIdx)(idx +2);591 _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx +3);592 _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col;593 _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col;594 _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col;595 _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col;596 _VtxWritePtr += 4;597 _VtxCurrentIdx += 4;598 _IdxWritePtr += 6;633 ImVec2 b(c.x, a.y), d(a.x, c.y), uv_b(uv_c.x, uv_a.y), uv_d(uv_a.x, uv_c.y); 634 ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx; 635 _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2); 636 _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3); 637 _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col; 638 _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col; 639 _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col; 640 _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col; 641 _VtxWritePtr += 4; 642 _VtxCurrentIdx += 4; 643 _IdxWritePtr += 6; 599 644 } 600 645 601 646 void ImDrawList::PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a, const ImVec2& uv_b, const ImVec2& uv_c, const ImVec2& uv_d, ImU32 col) 602 647 { 603 ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx; 604 _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx + 1); _IdxWritePtr[2] = (ImDrawIdx)(idx + 2); 605 _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx + 3); 606 _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col; 607 _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col; 608 _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col; 609 _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col; 610 _VtxWritePtr += 4; 611 _VtxCurrentIdx += 4; 612 _IdxWritePtr += 6; 613 } 648 ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx; 649 _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2); 650 _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3); 651 _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col; 652 _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col; 653 _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col; 654 _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col; 655 _VtxWritePtr += 4; 656 _VtxCurrentIdx += 4; 657 _IdxWritePtr += 6; 658 } 659 660 // On AddPolyline() and AddConvexPolyFilled() we intentionally avoid using ImVec2 and superfluous function calls to optimize debug/non-inlined builds. 661 // Those macros expects l-values. 662 #define IM_NORMALIZE2F_OVER_ZERO(VX,VY) do { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = 1.0f / ImSqrt(d2); VX *= inv_len; VY *= inv_len; } } while (0) 663 #define IM_FIXNORMAL2F(VX,VY) do { float d2 = VX*VX + VY*VY; if (d2 < 0.5f) d2 = 0.5f; float inv_lensq = 1.0f / d2; VX *= inv_lensq; VY *= inv_lensq; } while (0) 614 664 615 665 // TODO: Thickness anti-aliased lines cap are missing their AA fringe. 666 // We avoid using the ImVec2 math operators here to reduce cost to a minimum for debug/non-inlined builds. 616 667 void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, bool closed, float thickness) 617 668 { 618 if (points_count < 2) 619 return; 620 621 const ImVec2 uv = _Data->TexUvWhitePixel; 622 623 int count = points_count; 624 if (!closed) 625 count = points_count - 1; 626 627 const bool thick_line = thickness > 1.0f; 628 if (Flags & ImDrawListFlags_AntiAliasedLines) 629 { 630 // Anti-aliased stroke 631 const float AA_SIZE = 1.0f; 632 const ImU32 col_trans = col & ~IM_COL32_A_MASK; 633 634 const int idx_count = thick_line ? count * 18 : count * 12; 635 const int vtx_count = thick_line ? points_count * 4 : points_count * 3; 636 PrimReserve(idx_count, vtx_count); 637 638 // Temporary buffer 639 ImVec2* temp_normals = (ImVec2*)alloca(points_count * (thick_line ? 5 : 3) * sizeof(ImVec2)); 640 ImVec2* temp_points = temp_normals + points_count; 641 642 for (int i1 = 0; i1 < count; i1++) 643 { 644 const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1; 645 ImVec2 diff = points[i2] - points[i1]; 646 diff *= ImInvLength(diff, 1.0f); 647 temp_normals[i1].x = diff.y; 648 temp_normals[i1].y = -diff.x; 649 } 650 if (!closed) 651 temp_normals[points_count - 1] = temp_normals[points_count - 2]; 652 653 if (!thick_line) 654 { 655 if (!closed) 656 { 657 temp_points[0] = points[0] + temp_normals[0] * AA_SIZE; 658 temp_points[1] = points[0] - temp_normals[0] * AA_SIZE; 659 temp_points[(points_count - 1) * 2 + 0] = points[points_count - 1] + temp_normals[points_count - 1] * AA_SIZE; 660 temp_points[(points_count - 1) * 2 + 1] = points[points_count - 1] - temp_normals[points_count - 1] * AA_SIZE; 661 } 662 663 // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer. 664 unsigned int idx1 = _VtxCurrentIdx; 665 for (int i1 = 0; i1 < count; i1++) 666 { 669 if (points_count < 2) 670 return; 671 672 const ImVec2 opaque_uv = _Data->TexUvWhitePixel; 673 const int count = closed ? points_count : points_count - 1; // The number of line segments we need to draw 674 const bool thick_line = (thickness > 1.0f); 675 676 if (Flags & ImDrawListFlags_AntiAliasedLines) 677 { 678 // Anti-aliased stroke 679 const float AA_SIZE = 1.0f; 680 const ImU32 col_trans = col & ~IM_COL32_A_MASK; 681 682 // Thicknesses <1.0 should behave like thickness 1.0 683 thickness = ImMax(thickness, 1.0f); 684 const int integer_thickness = (int)thickness; 685 const float fractional_thickness = thickness - integer_thickness; 686 687 // Do we want to draw this line using a texture? 688 // - For now, only draw integer-width lines using textures to avoid issues with the way scaling occurs, could be improved. 689 // - If AA_SIZE is not 1.0f we cannot use the texture path. 690 const bool use_texture = (Flags & ImDrawListFlags_AntiAliasedLinesUseTex) && (integer_thickness < IM_DRAWLIST_TEX_LINES_WIDTH_MAX) && (fractional_thickness <= 0.00001f); 691 692 // We should never hit this, because NewFrame() doesn't set ImDrawListFlags_AntiAliasedLinesUseTex unless ImFontAtlasFlags_NoBakedLines is off 693 IM_ASSERT_PARANOID(!use_texture || !(_Data->Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoBakedLines)); 694 695 const int idx_count = use_texture ? (count * 6) : (thick_line ? count * 18 : count * 12); 696 const int vtx_count = use_texture ? (points_count * 2) : (thick_line ? points_count * 4 : points_count * 3); 697 PrimReserve(idx_count, vtx_count); 698 699 // Temporary buffer 700 // The first <points_count> items are normals at each line point, then after that there are either 2 or 4 temp points for each line point 701 ImVec2* temp_normals = (ImVec2*)alloca(points_count * ((use_texture || !thick_line) ? 3 : 5) * sizeof(ImVec2)); //-V630 702 ImVec2* temp_points = temp_normals + points_count; 703 704 // Calculate normals (tangents) for each line segment 705 for (int i1 = 0; i1 < count; i1++) 706 { 667 707 const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1; 668 unsigned int idx2 = (i1 + 1) == points_count ? _VtxCurrentIdx : idx1 + 3; 669 708 float dx = points[i2].x - points[i1].x; 709 float dy = points[i2].y - points[i1].y; 710 IM_NORMALIZE2F_OVER_ZERO(dx, dy); 711 temp_normals[i1].x = dy; 712 temp_normals[i1].y = -dx; 713 } 714 if (!closed) 715 temp_normals[points_count - 1] = temp_normals[points_count - 2]; 716 717 // If we are drawing a one-pixel-wide line without a texture, or a textured line of any width, we only need 2 or 3 vertices per point 718 if (use_texture || !thick_line) 719 { 720 // [PATH 1] Texture-based lines (thick or non-thick) 721 // [PATH 2] Non texture-based lines (non-thick) 722 723 // The width of the geometry we need to draw - this is essentially <thickness> pixels for the line itself, plus "one pixel" for AA. 724 // - In the texture-based path, we don't use AA_SIZE here because the +1 is tied to the generated texture 725 // (see ImFontAtlasBuildRenderLinesTexData() function), and so alternate values won't work without changes to that code. 726 // - In the non texture-based paths, we would allow AA_SIZE to potentially be != 1.0f with a patch (e.g. fringe_scale patch to 727 // allow scaling geometry while preserving one-screen-pixel AA fringe). 728 const float half_draw_size = use_texture ? ((thickness * 0.5f) + 1) : AA_SIZE; 729 730 // If line is not closed, the first and last points need to be generated differently as there are no normals to blend 731 if (!closed) 732 { 733 temp_points[0] = points[0] + temp_normals[0] * half_draw_size; 734 temp_points[1] = points[0] - temp_normals[0] * half_draw_size; 735 temp_points[(points_count-1)*2+0] = points[points_count-1] + temp_normals[points_count-1] * half_draw_size; 736 temp_points[(points_count-1)*2+1] = points[points_count-1] - temp_normals[points_count-1] * half_draw_size; 737 } 738 739 // Generate the indices to form a number of triangles for each line segment, and the vertices for the line edges 740 // This takes points n and n+1 and writes into n+1, with the first point in a closed line being generated from the final one (as n+1 wraps) 741 // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer. 742 unsigned int idx1 = _VtxCurrentIdx; // Vertex index for start of line segment 743 for (int i1 = 0; i1 < count; i1++) // i1 is the first point of the line segment 744 { 745 const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1; // i2 is the second point of the line segment 746 const unsigned int idx2 = ((i1 + 1) == points_count) ? _VtxCurrentIdx : (idx1 + (use_texture ? 2 : 3)); // Vertex index for end of segment 747 748 // Average normals 749 float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f; 750 float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f; 751 IM_FIXNORMAL2F(dm_x, dm_y); 752 dm_x *= half_draw_size; // dm_x, dm_y are offset to the outer edge of the AA area 753 dm_y *= half_draw_size; 754 755 // Add temporary vertexes for the outer edges 756 ImVec2* out_vtx = &temp_points[i2 * 2]; 757 out_vtx[0].x = points[i2].x + dm_x; 758 out_vtx[0].y = points[i2].y + dm_y; 759 out_vtx[1].x = points[i2].x - dm_x; 760 out_vtx[1].y = points[i2].y - dm_y; 761 762 if (use_texture) 763 { 764 // Add indices for two triangles 765 _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 1); // Right tri 766 _IdxWritePtr[3] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[4] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0); // Left tri 767 _IdxWritePtr += 6; 768 } 769 else 770 { 771 // Add indexes for four triangles 772 _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 2); // Right tri 1 773 _IdxWritePtr[3] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[4] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0); // Right tri 2 774 _IdxWritePtr[6] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[7] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[8] = (ImDrawIdx)(idx1 + 0); // Left tri 1 775 _IdxWritePtr[9] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1); // Left tri 2 776 _IdxWritePtr += 12; 777 } 778 779 idx1 = idx2; 780 } 781 782 // Add vertexes for each point on the line 783 if (use_texture) 784 { 785 // If we're using textures we only need to emit the left/right edge vertices 786 ImVec4 tex_uvs = _Data->TexUvLines[integer_thickness]; 787 if (fractional_thickness != 0.0f) 788 { 789 const ImVec4 tex_uvs_1 = _Data->TexUvLines[integer_thickness + 1]; 790 tex_uvs.x = tex_uvs.x + (tex_uvs_1.x - tex_uvs.x) * fractional_thickness; // inlined ImLerp() 791 tex_uvs.y = tex_uvs.y + (tex_uvs_1.y - tex_uvs.y) * fractional_thickness; 792 tex_uvs.z = tex_uvs.z + (tex_uvs_1.z - tex_uvs.z) * fractional_thickness; 793 tex_uvs.w = tex_uvs.w + (tex_uvs_1.w - tex_uvs.w) * fractional_thickness; 794 } 795 ImVec2 tex_uv0(tex_uvs.x, tex_uvs.y); 796 ImVec2 tex_uv1(tex_uvs.z, tex_uvs.w); 797 for (int i = 0; i < points_count; i++) 798 { 799 _VtxWritePtr[0].pos = temp_points[i * 2 + 0]; _VtxWritePtr[0].uv = tex_uv0; _VtxWritePtr[0].col = col; // Left-side outer edge 800 _VtxWritePtr[1].pos = temp_points[i * 2 + 1]; _VtxWritePtr[1].uv = tex_uv1; _VtxWritePtr[1].col = col; // Right-side outer edge 801 _VtxWritePtr += 2; 802 } 803 } 804 else 805 { 806 // If we're not using a texture, we need the center vertex as well 807 for (int i = 0; i < points_count; i++) 808 { 809 _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col; // Center of line 810 _VtxWritePtr[1].pos = temp_points[i * 2 + 0]; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col_trans; // Left-side outer edge 811 _VtxWritePtr[2].pos = temp_points[i * 2 + 1]; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col_trans; // Right-side outer edge 812 _VtxWritePtr += 3; 813 } 814 } 815 } 816 else 817 { 818 // [PATH 2] Non texture-based lines (thick): we need to draw the solid line core and thus require four vertices per point 819 const float half_inner_thickness = (thickness - AA_SIZE) * 0.5f; 820 821 // If line is not closed, the first and last points need to be generated differently as there are no normals to blend 822 if (!closed) 823 { 824 const int points_last = points_count - 1; 825 temp_points[0] = points[0] + temp_normals[0] * (half_inner_thickness + AA_SIZE); 826 temp_points[1] = points[0] + temp_normals[0] * (half_inner_thickness); 827 temp_points[2] = points[0] - temp_normals[0] * (half_inner_thickness); 828 temp_points[3] = points[0] - temp_normals[0] * (half_inner_thickness + AA_SIZE); 829 temp_points[points_last * 4 + 0] = points[points_last] + temp_normals[points_last] * (half_inner_thickness + AA_SIZE); 830 temp_points[points_last * 4 + 1] = points[points_last] + temp_normals[points_last] * (half_inner_thickness); 831 temp_points[points_last * 4 + 2] = points[points_last] - temp_normals[points_last] * (half_inner_thickness); 832 temp_points[points_last * 4 + 3] = points[points_last] - temp_normals[points_last] * (half_inner_thickness + AA_SIZE); 833 } 834 835 // Generate the indices to form a number of triangles for each line segment, and the vertices for the line edges 836 // This takes points n and n+1 and writes into n+1, with the first point in a closed line being generated from the final one (as n+1 wraps) 837 // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer. 838 unsigned int idx1 = _VtxCurrentIdx; // Vertex index for start of line segment 839 for (int i1 = 0; i1 < count; i1++) // i1 is the first point of the line segment 840 { 841 const int i2 = (i1 + 1) == points_count ? 0 : (i1 + 1); // i2 is the second point of the line segment 842 const unsigned int idx2 = (i1 + 1) == points_count ? _VtxCurrentIdx : (idx1 + 4); // Vertex index for end of segment 843 844 // Average normals 845 float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f; 846 float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f; 847 IM_FIXNORMAL2F(dm_x, dm_y); 848 float dm_out_x = dm_x * (half_inner_thickness + AA_SIZE); 849 float dm_out_y = dm_y * (half_inner_thickness + AA_SIZE); 850 float dm_in_x = dm_x * half_inner_thickness; 851 float dm_in_y = dm_y * half_inner_thickness; 852 853 // Add temporary vertices 854 ImVec2* out_vtx = &temp_points[i2 * 4]; 855 out_vtx[0].x = points[i2].x + dm_out_x; 856 out_vtx[0].y = points[i2].y + dm_out_y; 857 out_vtx[1].x = points[i2].x + dm_in_x; 858 out_vtx[1].y = points[i2].y + dm_in_y; 859 out_vtx[2].x = points[i2].x - dm_in_x; 860 out_vtx[2].y = points[i2].y - dm_in_y; 861 out_vtx[3].x = points[i2].x - dm_out_x; 862 out_vtx[3].y = points[i2].y - dm_out_y; 863 864 // Add indexes 865 _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 2); 866 _IdxWritePtr[3] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[4] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 1); 867 _IdxWritePtr[6] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[7] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[8] = (ImDrawIdx)(idx1 + 0); 868 _IdxWritePtr[9] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1); 869 _IdxWritePtr[12] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[13] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[14] = (ImDrawIdx)(idx1 + 3); 870 _IdxWritePtr[15] = (ImDrawIdx)(idx1 + 3); _IdxWritePtr[16] = (ImDrawIdx)(idx2 + 3); _IdxWritePtr[17] = (ImDrawIdx)(idx2 + 2); 871 _IdxWritePtr += 18; 872 873 idx1 = idx2; 874 } 875 876 // Add vertices 877 for (int i = 0; i < points_count; i++) 878 { 879 _VtxWritePtr[0].pos = temp_points[i * 4 + 0]; _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col_trans; 880 _VtxWritePtr[1].pos = temp_points[i * 4 + 1]; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col; 881 _VtxWritePtr[2].pos = temp_points[i * 4 + 2]; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col; 882 _VtxWritePtr[3].pos = temp_points[i * 4 + 3]; _VtxWritePtr[3].uv = opaque_uv; _VtxWritePtr[3].col = col_trans; 883 _VtxWritePtr += 4; 884 } 885 } 886 _VtxCurrentIdx += (ImDrawIdx)vtx_count; 887 } 888 else 889 { 890 // [PATH 4] Non texture-based, Non anti-aliased lines 891 const int idx_count = count * 6; 892 const int vtx_count = count * 4; // FIXME-OPT: Not sharing edges 893 PrimReserve(idx_count, vtx_count); 894 895 for (int i1 = 0; i1 < count; i1++) 896 { 897 const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1; 898 const ImVec2& p1 = points[i1]; 899 const ImVec2& p2 = points[i2]; 900 901 float dx = p2.x - p1.x; 902 float dy = p2.y - p1.y; 903 IM_NORMALIZE2F_OVER_ZERO(dx, dy); 904 dx *= (thickness * 0.5f); 905 dy *= (thickness * 0.5f); 906 907 _VtxWritePtr[0].pos.x = p1.x + dy; _VtxWritePtr[0].pos.y = p1.y - dx; _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col; 908 _VtxWritePtr[1].pos.x = p2.x + dy; _VtxWritePtr[1].pos.y = p2.y - dx; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col; 909 _VtxWritePtr[2].pos.x = p2.x - dy; _VtxWritePtr[2].pos.y = p2.y + dx; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col; 910 _VtxWritePtr[3].pos.x = p1.x - dy; _VtxWritePtr[3].pos.y = p1.y + dx; _VtxWritePtr[3].uv = opaque_uv; _VtxWritePtr[3].col = col; 911 _VtxWritePtr += 4; 912 913 _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + 1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + 2); 914 _IdxWritePtr[3] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[4] = (ImDrawIdx)(_VtxCurrentIdx + 2); _IdxWritePtr[5] = (ImDrawIdx)(_VtxCurrentIdx + 3); 915 _IdxWritePtr += 6; 916 _VtxCurrentIdx += 4; 917 } 918 } 919 } 920 921 // We intentionally avoid using ImVec2 and its math operators here to reduce cost to a minimum for debug/non-inlined builds. 922 void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col) 923 { 924 if (points_count < 3) 925 return; 926 927 const ImVec2 uv = _Data->TexUvWhitePixel; 928 929 if (Flags & ImDrawListFlags_AntiAliasedFill) 930 { 931 // Anti-aliased Fill 932 const float AA_SIZE = 1.0f; 933 const ImU32 col_trans = col & ~IM_COL32_A_MASK; 934 const int idx_count = (points_count - 2)*3 + points_count * 6; 935 const int vtx_count = (points_count * 2); 936 PrimReserve(idx_count, vtx_count); 937 938 // Add indexes for fill 939 unsigned int vtx_inner_idx = _VtxCurrentIdx; 940 unsigned int vtx_outer_idx = _VtxCurrentIdx + 1; 941 for (int i = 2; i < points_count; i++) 942 { 943 _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + ((i - 1) << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_inner_idx + (i << 1)); 944 _IdxWritePtr += 3; 945 } 946 947 // Compute normals 948 ImVec2* temp_normals = (ImVec2*)alloca(points_count * sizeof(ImVec2)); //-V630 949 for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++) 950 { 951 const ImVec2& p0 = points[i0]; 952 const ImVec2& p1 = points[i1]; 953 float dx = p1.x - p0.x; 954 float dy = p1.y - p0.y; 955 IM_NORMALIZE2F_OVER_ZERO(dx, dy); 956 temp_normals[i0].x = dy; 957 temp_normals[i0].y = -dx; 958 } 959 960 for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++) 961 { 670 962 // Average normals 671 ImVec2 dm = (temp_normals[i1] + temp_normals[i2]) * 0.5f; 672 float dmr2 = dm.x*dm.x + dm.y*dm.y; 673 if (dmr2 > 0.000001f) 963 const ImVec2& n0 = temp_normals[i0]; 964 const ImVec2& n1 = temp_normals[i1]; 965 float dm_x = (n0.x + n1.x) * 0.5f; 966 float dm_y = (n0.y + n1.y) * 0.5f; 967 IM_FIXNORMAL2F(dm_x, dm_y); 968 dm_x *= AA_SIZE * 0.5f; 969 dm_y *= AA_SIZE * 0.5f; 970 971 // Add vertices 972 _VtxWritePtr[0].pos.x = (points[i1].x - dm_x); _VtxWritePtr[0].pos.y = (points[i1].y - dm_y); _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; // Inner 973 _VtxWritePtr[1].pos.x = (points[i1].x + dm_x); _VtxWritePtr[1].pos.y = (points[i1].y + dm_y); _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans; // Outer 974 _VtxWritePtr += 2; 975 976 // Add indexes for fringes 977 _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1)); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + (i0 << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1)); 978 _IdxWritePtr[3] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1)); _IdxWritePtr[4] = (ImDrawIdx)(vtx_outer_idx + (i1 << 1)); _IdxWritePtr[5] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1)); 979 _IdxWritePtr += 6; 980 } 981 _VtxCurrentIdx += (ImDrawIdx)vtx_count; 982 } 983 else 984 { 985 // Non Anti-aliased Fill 986 const int idx_count = (points_count - 2)*3; 987 const int vtx_count = points_count; 988 PrimReserve(idx_count, vtx_count); 989 for (int i = 0; i < vtx_count; i++) 990 { 991 _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; 992 _VtxWritePtr++; 993 } 994 for (int i = 2; i < points_count; i++) 995 { 996 _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + i - 1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + i); 997 _IdxWritePtr += 3; 998 } 999 _VtxCurrentIdx += (ImDrawIdx)vtx_count; 1000 } 1001 } 1002 1003 void ImDrawList::PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12) 1004 { 1005 if (radius == 0.0f || a_min_of_12 > a_max_of_12) 1006 { 1007 _Path.push_back(center); 1008 return; 1009 } 1010 1011 // For legacy reason the PathArcToFast() always takes angles where 2*PI is represented by 12, 1012 // but it is possible to set IM_DRAWLIST_ARCFAST_TESSELATION_MULTIPLIER to a higher value. This should compile to a no-op otherwise. 1013 #if IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER != 1 1014 a_min_of_12 *= IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER; 1015 a_max_of_12 *= IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER; 1016 #endif 1017 1018 _Path.reserve(_Path.Size + (a_max_of_12 - a_min_of_12 + 1)); 1019 for (int a = a_min_of_12; a <= a_max_of_12; a++) 1020 { 1021 const ImVec2& c = _Data->ArcFastVtx[a % IM_ARRAYSIZE(_Data->ArcFastVtx)]; 1022 _Path.push_back(ImVec2(center.x + c.x * radius, center.y + c.y * radius)); 1023 } 1024 } 1025 1026 void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments) 1027 { 1028 if (radius == 0.0f) 1029 { 1030 _Path.push_back(center); 1031 return; 1032 } 1033 1034 // Note that we are adding a point at both a_min and a_max. 1035 // If you are trying to draw a full closed circle you don't want the overlapping points! 1036 _Path.reserve(_Path.Size + (num_segments + 1)); 1037 for (int i = 0; i <= num_segments; i++) 1038 { 1039 const float a = a_min + ((float)i / (float)num_segments) * (a_max - a_min); 1040 _Path.push_back(ImVec2(center.x + ImCos(a) * radius, center.y + ImSin(a) * radius)); 1041 } 1042 } 1043 1044 ImVec2 ImBezierCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, float t) 1045 { 1046 float u = 1.0f - t; 1047 float w1 = u*u*u; 1048 float w2 = 3*u*u*t; 1049 float w3 = 3*u*t*t; 1050 float w4 = t*t*t; 1051 return ImVec2(w1*p1.x + w2*p2.x + w3*p3.x + w4*p4.x, w1*p1.y + w2*p2.y + w3*p3.y + w4*p4.y); 1052 } 1053 1054 // Closely mimics BezierClosestPointCasteljauStep() in imgui.cpp 1055 static void PathBezierToCasteljau(ImVector<ImVec2>* path, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level) 1056 { 1057 float dx = x4 - x1; 1058 float dy = y4 - y1; 1059 float d2 = ((x2 - x4) * dy - (y2 - y4) * dx); 1060 float d3 = ((x3 - x4) * dy - (y3 - y4) * dx); 1061 d2 = (d2 >= 0) ? d2 : -d2; 1062 d3 = (d3 >= 0) ? d3 : -d3; 1063 if ((d2 + d3) * (d2 + d3) < tess_tol * (dx * dx + dy * dy)) 1064 { 1065 path->push_back(ImVec2(x4, y4)); 1066 } 1067 else if (level < 10) 1068 { 1069 float x12 = (x1 + x2)*0.5f, y12 = (y1 + y2)*0.5f; 1070 float x23 = (x2 + x3)*0.5f, y23 = (y2 + y3)*0.5f; 1071 float x34 = (x3 + x4)*0.5f, y34 = (y3 + y4)*0.5f; 1072 float x123 = (x12 + x23)*0.5f, y123 = (y12 + y23)*0.5f; 1073 float x234 = (x23 + x34)*0.5f, y234 = (y23 + y34)*0.5f; 1074 float x1234 = (x123 + x234)*0.5f, y1234 = (y123 + y234)*0.5f; 1075 PathBezierToCasteljau(path, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1); 1076 PathBezierToCasteljau(path, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1); 1077 } 1078 } 1079 1080 void ImDrawList::PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments) 1081 { 1082 ImVec2 p1 = _Path.back(); 1083 if (num_segments == 0) 1084 { 1085 PathBezierToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, _Data->CurveTessellationTol, 0); // Auto-tessellated 1086 } 1087 else 1088 { 1089 float t_step = 1.0f / (float)num_segments; 1090 for (int i_step = 1; i_step <= num_segments; i_step++) 1091 _Path.push_back(ImBezierCalc(p1, p2, p3, p4, t_step * i_step)); 1092 } 1093 } 1094 1095 void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, ImDrawCornerFlags rounding_corners) 1096 { 1097 rounding = ImMin(rounding, ImFabs(b.x - a.x) * ( ((rounding_corners & ImDrawCornerFlags_Top) == ImDrawCornerFlags_Top) || ((rounding_corners & ImDrawCornerFlags_Bot) == ImDrawCornerFlags_Bot) ? 0.5f : 1.0f ) - 1.0f); 1098 rounding = ImMin(rounding, ImFabs(b.y - a.y) * ( ((rounding_corners & ImDrawCornerFlags_Left) == ImDrawCornerFlags_Left) || ((rounding_corners & ImDrawCornerFlags_Right) == ImDrawCornerFlags_Right) ? 0.5f : 1.0f ) - 1.0f); 1099 1100 if (rounding <= 0.0f || rounding_corners == 0) 1101 { 1102 PathLineTo(a); 1103 PathLineTo(ImVec2(b.x, a.y)); 1104 PathLineTo(b); 1105 PathLineTo(ImVec2(a.x, b.y)); 1106 } 1107 else 1108 { 1109 const float rounding_tl = (rounding_corners & ImDrawCornerFlags_TopLeft) ? rounding : 0.0f; 1110 const float rounding_tr = (rounding_corners & ImDrawCornerFlags_TopRight) ? rounding : 0.0f; 1111 const float rounding_br = (rounding_corners & ImDrawCornerFlags_BotRight) ? rounding : 0.0f; 1112 const float rounding_bl = (rounding_corners & ImDrawCornerFlags_BotLeft) ? rounding : 0.0f; 1113 PathArcToFast(ImVec2(a.x + rounding_tl, a.y + rounding_tl), rounding_tl, 6, 9); 1114 PathArcToFast(ImVec2(b.x - rounding_tr, a.y + rounding_tr), rounding_tr, 9, 12); 1115 PathArcToFast(ImVec2(b.x - rounding_br, b.y - rounding_br), rounding_br, 0, 3); 1116 PathArcToFast(ImVec2(a.x + rounding_bl, b.y - rounding_bl), rounding_bl, 3, 6); 1117 } 1118 } 1119 1120 void ImDrawList::AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float thickness) 1121 { 1122 if ((col & IM_COL32_A_MASK) == 0) 1123 return; 1124 PathLineTo(p1 + ImVec2(0.5f, 0.5f)); 1125 PathLineTo(p2 + ImVec2(0.5f, 0.5f)); 1126 PathStroke(col, false, thickness); 1127 } 1128 1129 // p_min = upper-left, p_max = lower-right 1130 // Note we don't render 1 pixels sized rectangles properly. 1131 void ImDrawList::AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawCornerFlags rounding_corners, float thickness) 1132 { 1133 if ((col & IM_COL32_A_MASK) == 0) 1134 return; 1135 if (Flags & ImDrawListFlags_AntiAliasedLines) 1136 PathRect(p_min + ImVec2(0.50f, 0.50f), p_max - ImVec2(0.50f, 0.50f), rounding, rounding_corners); 1137 else 1138 PathRect(p_min + ImVec2(0.50f, 0.50f), p_max - ImVec2(0.49f, 0.49f), rounding, rounding_corners); // Better looking lower-right corner and rounded non-AA shapes. 1139 PathStroke(col, true, thickness); 1140 } 1141 1142 void ImDrawList::AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawCornerFlags rounding_corners) 1143 { 1144 if ((col & IM_COL32_A_MASK) == 0) 1145 return; 1146 if (rounding > 0.0f) 1147 { 1148 PathRect(p_min, p_max, rounding, rounding_corners); 1149 PathFillConvex(col); 1150 } 1151 else 1152 { 1153 PrimReserve(6, 4); 1154 PrimRect(p_min, p_max, col); 1155 } 1156 } 1157 1158 // p_min = upper-left, p_max = lower-right 1159 void ImDrawList::AddRectFilledMultiColor(const ImVec2& p_min, const ImVec2& p_max, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left) 1160 { 1161 if (((col_upr_left | col_upr_right | col_bot_right | col_bot_left) & IM_COL32_A_MASK) == 0) 1162 return; 1163 1164 const ImVec2 uv = _Data->TexUvWhitePixel; 1165 PrimReserve(6, 4); 1166 PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 1)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 2)); 1167 PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 2)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 3)); 1168 PrimWriteVtx(p_min, uv, col_upr_left); 1169 PrimWriteVtx(ImVec2(p_max.x, p_min.y), uv, col_upr_right); 1170 PrimWriteVtx(p_max, uv, col_bot_right); 1171 PrimWriteVtx(ImVec2(p_min.x, p_max.y), uv, col_bot_left); 1172 } 1173 1174 void ImDrawList::AddQuad(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness) 1175 { 1176 if ((col & IM_COL32_A_MASK) == 0) 1177 return; 1178 1179 PathLineTo(p1); 1180 PathLineTo(p2); 1181 PathLineTo(p3); 1182 PathLineTo(p4); 1183 PathStroke(col, true, thickness); 1184 } 1185 1186 void ImDrawList::AddQuadFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col) 1187 { 1188 if ((col & IM_COL32_A_MASK) == 0) 1189 return; 1190 1191 PathLineTo(p1); 1192 PathLineTo(p2); 1193 PathLineTo(p3); 1194 PathLineTo(p4); 1195 PathFillConvex(col); 1196 } 1197 1198 void ImDrawList::AddTriangle(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness) 1199 { 1200 if ((col & IM_COL32_A_MASK) == 0) 1201 return; 1202 1203 PathLineTo(p1); 1204 PathLineTo(p2); 1205 PathLineTo(p3); 1206 PathStroke(col, true, thickness); 1207 } 1208 1209 void ImDrawList::AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col) 1210 { 1211 if ((col & IM_COL32_A_MASK) == 0) 1212 return; 1213 1214 PathLineTo(p1); 1215 PathLineTo(p2); 1216 PathLineTo(p3); 1217 PathFillConvex(col); 1218 } 1219 1220 void ImDrawList::AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness) 1221 { 1222 if ((col & IM_COL32_A_MASK) == 0 || radius <= 0.0f) 1223 return; 1224 1225 // Obtain segment count 1226 if (num_segments <= 0) 1227 { 1228 // Automatic segment count 1229 const int radius_idx = (int)radius - 1; 1230 if (radius_idx < IM_ARRAYSIZE(_Data->CircleSegmentCounts)) 1231 num_segments = _Data->CircleSegmentCounts[radius_idx]; // Use cached value 1232 else 1233 num_segments = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, _Data->CircleSegmentMaxError); 1234 } 1235 else 1236 { 1237 // Explicit segment count (still clamp to avoid drawing insanely tessellated shapes) 1238 num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX); 1239 } 1240 1241 // Because we are filling a closed shape we remove 1 from the count of segments/points 1242 const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments; 1243 if (num_segments == 12) 1244 PathArcToFast(center, radius - 0.5f, 0, 12 - 1); 1245 else 1246 PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1); 1247 PathStroke(col, true, thickness); 1248 } 1249 1250 void ImDrawList::AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments) 1251 { 1252 if ((col & IM_COL32_A_MASK) == 0 || radius <= 0.0f) 1253 return; 1254 1255 // Obtain segment count 1256 if (num_segments <= 0) 1257 { 1258 // Automatic segment count 1259 const int radius_idx = (int)radius - 1; 1260 if (radius_idx < IM_ARRAYSIZE(_Data->CircleSegmentCounts)) 1261 num_segments = _Data->CircleSegmentCounts[radius_idx]; // Use cached value 1262 else 1263 num_segments = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, _Data->CircleSegmentMaxError); 1264 } 1265 else 1266 { 1267 // Explicit segment count (still clamp to avoid drawing insanely tessellated shapes) 1268 num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX); 1269 } 1270 1271 // Because we are filling a closed shape we remove 1 from the count of segments/points 1272 const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments; 1273 if (num_segments == 12) 1274 PathArcToFast(center, radius, 0, 12 - 1); 1275 else 1276 PathArcTo(center, radius, 0.0f, a_max, num_segments - 1); 1277 PathFillConvex(col); 1278 } 1279 1280 // Guaranteed to honor 'num_segments' 1281 void ImDrawList::AddNgon(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness) 1282 { 1283 if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2) 1284 return; 1285 1286 // Because we are filling a closed shape we remove 1 from the count of segments/points 1287 const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments; 1288 PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1); 1289 PathStroke(col, true, thickness); 1290 } 1291 1292 // Guaranteed to honor 'num_segments' 1293 void ImDrawList::AddNgonFilled(const ImVec2& center, float radius, ImU32 col, int num_segments) 1294 { 1295 if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2) 1296 return; 1297 1298 // Because we are filling a closed shape we remove 1 from the count of segments/points 1299 const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments; 1300 PathArcTo(center, radius, 0.0f, a_max, num_segments - 1); 1301 PathFillConvex(col); 1302 } 1303 1304 // Cubic Bezier takes 4 controls points 1305 void ImDrawList::AddBezierCurve(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments) 1306 { 1307 if ((col & IM_COL32_A_MASK) == 0) 1308 return; 1309 1310 PathLineTo(p1); 1311 PathBezierCurveTo(p2, p3, p4, num_segments); 1312 PathStroke(col, false, thickness); 1313 } 1314 1315 void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end, float wrap_width, const ImVec4* cpu_fine_clip_rect) 1316 { 1317 if ((col & IM_COL32_A_MASK) == 0) 1318 return; 1319 1320 if (text_end == NULL) 1321 text_end = text_begin + strlen(text_begin); 1322 if (text_begin == text_end) 1323 return; 1324 1325 // Pull default font/size from the shared ImDrawListSharedData instance 1326 if (font == NULL) 1327 font = _Data->Font; 1328 if (font_size == 0.0f) 1329 font_size = _Data->FontSize; 1330 1331 IM_ASSERT(font->ContainerAtlas->TexID == _CmdHeader.TextureId); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font. 1332 1333 ImVec4 clip_rect = _CmdHeader.ClipRect; 1334 if (cpu_fine_clip_rect) 1335 { 1336 clip_rect.x = ImMax(clip_rect.x, cpu_fine_clip_rect->x); 1337 clip_rect.y = ImMax(clip_rect.y, cpu_fine_clip_rect->y); 1338 clip_rect.z = ImMin(clip_rect.z, cpu_fine_clip_rect->z); 1339 clip_rect.w = ImMin(clip_rect.w, cpu_fine_clip_rect->w); 1340 } 1341 font->RenderText(this, font_size, pos, col, clip_rect, text_begin, text_end, wrap_width, cpu_fine_clip_rect != NULL); 1342 } 1343 1344 void ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end) 1345 { 1346 AddText(NULL, 0.0f, pos, col, text_begin, text_end); 1347 } 1348 1349 void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col) 1350 { 1351 if ((col & IM_COL32_A_MASK) == 0) 1352 return; 1353 1354 const bool push_texture_id = user_texture_id != _CmdHeader.TextureId; 1355 if (push_texture_id) 1356 PushTextureID(user_texture_id); 1357 1358 PrimReserve(6, 4); 1359 PrimRectUV(p_min, p_max, uv_min, uv_max, col); 1360 1361 if (push_texture_id) 1362 PopTextureID(); 1363 } 1364 1365 void ImDrawList::AddImageQuad(ImTextureID user_texture_id, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& uv1, const ImVec2& uv2, const ImVec2& uv3, const ImVec2& uv4, ImU32 col) 1366 { 1367 if ((col & IM_COL32_A_MASK) == 0) 1368 return; 1369 1370 const bool push_texture_id = user_texture_id != _CmdHeader.TextureId; 1371 if (push_texture_id) 1372 PushTextureID(user_texture_id); 1373 1374 PrimReserve(6, 4); 1375 PrimQuadUV(p1, p2, p3, p4, uv1, uv2, uv3, uv4, col); 1376 1377 if (push_texture_id) 1378 PopTextureID(); 1379 } 1380 1381 void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawCornerFlags rounding_corners) 1382 { 1383 if ((col & IM_COL32_A_MASK) == 0) 1384 return; 1385 1386 if (rounding <= 0.0f || (rounding_corners & ImDrawCornerFlags_All) == 0) 1387 { 1388 AddImage(user_texture_id, p_min, p_max, uv_min, uv_max, col); 1389 return; 1390 } 1391 1392 const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back(); 1393 if (push_texture_id) 1394 PushTextureID(user_texture_id); 1395 1396 int vert_start_idx = VtxBuffer.Size; 1397 PathRect(p_min, p_max, rounding, rounding_corners); 1398 PathFillConvex(col); 1399 int vert_end_idx = VtxBuffer.Size; 1400 ImGui::ShadeVertsLinearUV(this, vert_start_idx, vert_end_idx, p_min, p_max, uv_min, uv_max, true); 1401 1402 if (push_texture_id) 1403 PopTextureID(); 1404 } 1405 1406 1407 //----------------------------------------------------------------------------- 1408 // [SECTION] ImDrawListSplitter 1409 //----------------------------------------------------------------------------- 1410 // FIXME: This may be a little confusing, trying to be a little too low-level/optimal instead of just doing vector swap.. 1411 //----------------------------------------------------------------------------- 1412 1413 void ImDrawListSplitter::ClearFreeMemory() 1414 { 1415 for (int i = 0; i < _Channels.Size; i++) 1416 { 1417 if (i == _Current) 1418 memset(&_Channels[i], 0, sizeof(_Channels[i])); // Current channel is a copy of CmdBuffer/IdxBuffer, don't destruct again 1419 _Channels[i]._CmdBuffer.clear(); 1420 _Channels[i]._IdxBuffer.clear(); 1421 } 1422 _Current = 0; 1423 _Count = 1; 1424 _Channels.clear(); 1425 } 1426 1427 void ImDrawListSplitter::Split(ImDrawList* draw_list, int channels_count) 1428 { 1429 IM_ASSERT(_Current == 0 && _Count <= 1 && "Nested channel splitting is not supported. Please use separate instances of ImDrawListSplitter."); 1430 int old_channels_count = _Channels.Size; 1431 if (old_channels_count < channels_count) 1432 _Channels.resize(channels_count); 1433 _Count = channels_count; 1434 1435 // Channels[] (24/32 bytes each) hold storage that we'll swap with draw_list->_CmdBuffer/_IdxBuffer 1436 // The content of Channels[0] at this point doesn't matter. We clear it to make state tidy in a debugger but we don't strictly need to. 1437 // When we switch to the next channel, we'll copy draw_list->_CmdBuffer/_IdxBuffer into Channels[0] and then Channels[1] into draw_list->CmdBuffer/_IdxBuffer 1438 memset(&_Channels[0], 0, sizeof(ImDrawChannel)); 1439 for (int i = 1; i < channels_count; i++) 1440 { 1441 if (i >= old_channels_count) 1442 { 1443 IM_PLACEMENT_NEW(&_Channels[i]) ImDrawChannel(); 1444 } 1445 else 1446 { 1447 _Channels[i]._CmdBuffer.resize(0); 1448 _Channels[i]._IdxBuffer.resize(0); 1449 } 1450 if (_Channels[i]._CmdBuffer.Size == 0) 1451 { 1452 ImDrawCmd draw_cmd; 1453 ImDrawCmd_HeaderCopy(&draw_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TextureId, VtxOffset 1454 _Channels[i]._CmdBuffer.push_back(draw_cmd); 1455 } 1456 } 1457 } 1458 1459 void ImDrawListSplitter::Merge(ImDrawList* draw_list) 1460 { 1461 // Note that we never use or rely on _Channels.Size because it is merely a buffer that we never shrink back to 0 to keep all sub-buffers ready for use. 1462 if (_Count <= 1) 1463 return; 1464 1465 SetCurrentChannel(draw_list, 0); 1466 draw_list->_PopUnusedDrawCmd(); 1467 1468 // Calculate our final buffer sizes. Also fix the incorrect IdxOffset values in each command. 1469 int new_cmd_buffer_count = 0; 1470 int new_idx_buffer_count = 0; 1471 ImDrawCmd* last_cmd = (_Count > 0 && draw_list->CmdBuffer.Size > 0) ? &draw_list->CmdBuffer.back() : NULL; 1472 int idx_offset = last_cmd ? last_cmd->IdxOffset + last_cmd->ElemCount : 0; 1473 for (int i = 1; i < _Count; i++) 1474 { 1475 ImDrawChannel& ch = _Channels[i]; 1476 1477 // Equivalent of PopUnusedDrawCmd() for this channel's cmdbuffer and except we don't need to test for UserCallback. 1478 if (ch._CmdBuffer.Size > 0 && ch._CmdBuffer.back().ElemCount == 0) 1479 ch._CmdBuffer.pop_back(); 1480 1481 if (ch._CmdBuffer.Size > 0 && last_cmd != NULL) 1482 { 1483 ImDrawCmd* next_cmd = &ch._CmdBuffer[0]; 1484 if (ImDrawCmd_HeaderCompare(last_cmd, next_cmd) == 0 && last_cmd->UserCallback == NULL && next_cmd->UserCallback == NULL) 674 1485 { 675 float scale = 1.0f / dmr2; 676 if (scale > 100.0f) scale = 100.0f; 677 dm *= scale; 1486 // Merge previous channel last draw command with current channel first draw command if matching. 1487 last_cmd->ElemCount += next_cmd->ElemCount; 1488 idx_offset += next_cmd->ElemCount; 1489 ch._CmdBuffer.erase(ch._CmdBuffer.Data); // FIXME-OPT: Improve for multiple merges. 678 1490 } 679 dm *= AA_SIZE; 680 temp_points[i2 * 2 + 0] = points[i2] + dm; 681 temp_points[i2 * 2 + 1] = points[i2] - dm; 682 683 // Add indexes 684 _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 2); 685 _IdxWritePtr[3] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[4] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0); 686 _IdxWritePtr[6] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[7] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[8] = (ImDrawIdx)(idx1 + 0); 687 _IdxWritePtr[9] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1); 688 _IdxWritePtr += 12; 689 690 idx1 = idx2; 691 } 692 693 // Add vertexes 694 for (int i = 0; i < points_count; i++) 695 { 696 _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; 697 _VtxWritePtr[1].pos = temp_points[i * 2 + 0]; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans; 698 _VtxWritePtr[2].pos = temp_points[i * 2 + 1]; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col_trans; 699 _VtxWritePtr += 3; 700 } 701 } 702 else 703 { 704 const float half_inner_thickness = (thickness - AA_SIZE) * 0.5f; 705 if (!closed) 706 { 707 temp_points[0] = points[0] + temp_normals[0] * (half_inner_thickness + AA_SIZE); 708 temp_points[1] = points[0] + temp_normals[0] * (half_inner_thickness); 709 temp_points[2] = points[0] - temp_normals[0] * (half_inner_thickness); 710 temp_points[3] = points[0] - temp_normals[0] * (half_inner_thickness + AA_SIZE); 711 temp_points[(points_count - 1) * 4 + 0] = points[points_count - 1] + temp_normals[points_count - 1] * (half_inner_thickness + AA_SIZE); 712 temp_points[(points_count - 1) * 4 + 1] = points[points_count - 1] + temp_normals[points_count - 1] * (half_inner_thickness); 713 temp_points[(points_count - 1) * 4 + 2] = points[points_count - 1] - temp_normals[points_count - 1] * (half_inner_thickness); 714 temp_points[(points_count - 1) * 4 + 3] = points[points_count - 1] - temp_normals[points_count - 1] * (half_inner_thickness + AA_SIZE); 715 } 716 717 // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer. 718 unsigned int idx1 = _VtxCurrentIdx; 719 for (int i1 = 0; i1 < count; i1++) 720 { 721 const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1; 722 unsigned int idx2 = (i1 + 1) == points_count ? _VtxCurrentIdx : idx1 + 4; 723 724 // Average normals 725 ImVec2 dm = (temp_normals[i1] + temp_normals[i2]) * 0.5f; 726 float dmr2 = dm.x*dm.x + dm.y*dm.y; 727 if (dmr2 > 0.000001f) 728 { 729 float scale = 1.0f / dmr2; 730 if (scale > 100.0f) scale = 100.0f; 731 dm *= scale; 732 } 733 ImVec2 dm_out = dm * (half_inner_thickness + AA_SIZE); 734 ImVec2 dm_in = dm * half_inner_thickness; 735 temp_points[i2 * 4 + 0] = points[i2] + dm_out; 736 temp_points[i2 * 4 + 1] = points[i2] + dm_in; 737 temp_points[i2 * 4 + 2] = points[i2] - dm_in; 738 temp_points[i2 * 4 + 3] = points[i2] - dm_out; 739 740 // Add indexes 741 _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 2); 742 _IdxWritePtr[3] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[4] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 1); 743 _IdxWritePtr[6] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[7] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[8] = (ImDrawIdx)(idx1 + 0); 744 _IdxWritePtr[9] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1); 745 _IdxWritePtr[12] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[13] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[14] = (ImDrawIdx)(idx1 + 3); 746 _IdxWritePtr[15] = (ImDrawIdx)(idx1 + 3); _IdxWritePtr[16] = (ImDrawIdx)(idx2 + 3); _IdxWritePtr[17] = (ImDrawIdx)(idx2 + 2); 747 _IdxWritePtr += 18; 748 749 idx1 = idx2; 750 } 751 752 // Add vertexes 753 for (int i = 0; i < points_count; i++) 754 { 755 _VtxWritePtr[0].pos = temp_points[i * 4 + 0]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col_trans; 756 _VtxWritePtr[1].pos = temp_points[i * 4 + 1]; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col; 757 _VtxWritePtr[2].pos = temp_points[i * 4 + 2]; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col; 758 _VtxWritePtr[3].pos = temp_points[i * 4 + 3]; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col_trans; 759 _VtxWritePtr += 4; 760 } 761 } 762 _VtxCurrentIdx += (ImDrawIdx)vtx_count; 763 } 764 else 765 { 766 // Non Anti-aliased Stroke 767 const int idx_count = count * 6; 768 const int vtx_count = count * 4; // FIXME-OPT: Not sharing edges 769 PrimReserve(idx_count, vtx_count); 770 771 for (int i1 = 0; i1 < count; i1++) 772 { 773 const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1; 774 const ImVec2& p1 = points[i1]; 775 const ImVec2& p2 = points[i2]; 776 ImVec2 diff = p2 - p1; 777 diff *= ImInvLength(diff, 1.0f); 778 779 const float dx = diff.x * (thickness * 0.5f); 780 const float dy = diff.y * (thickness * 0.5f); 781 _VtxWritePtr[0].pos.x = p1.x + dy; _VtxWritePtr[0].pos.y = p1.y - dx; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; 782 _VtxWritePtr[1].pos.x = p2.x + dy; _VtxWritePtr[1].pos.y = p2.y - dx; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col; 783 _VtxWritePtr[2].pos.x = p2.x - dy; _VtxWritePtr[2].pos.y = p2.y + dx; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col; 784 _VtxWritePtr[3].pos.x = p1.x - dy; _VtxWritePtr[3].pos.y = p1.y + dx; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col; 785 _VtxWritePtr += 4; 786 787 _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + 1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + 2); 788 _IdxWritePtr[3] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[4] = (ImDrawIdx)(_VtxCurrentIdx + 2); _IdxWritePtr[5] = (ImDrawIdx)(_VtxCurrentIdx + 3); 789 _IdxWritePtr += 6; 790 _VtxCurrentIdx += 4; 791 } 792 } 793 } 794 795 void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col) 796 { 797 const ImVec2 uv = _Data->TexUvWhitePixel; 798 799 if (Flags & ImDrawListFlags_AntiAliasedFill) 800 { 801 // Anti-aliased Fill 802 const float AA_SIZE = 1.0f; 803 const ImU32 col_trans = col & ~IM_COL32_A_MASK; 804 const int idx_count = (points_count - 2) * 3 + points_count * 6; 805 const int vtx_count = (points_count * 2); 806 PrimReserve(idx_count, vtx_count); 807 808 // Add indexes for fill 809 unsigned int vtx_inner_idx = _VtxCurrentIdx; 810 unsigned int vtx_outer_idx = _VtxCurrentIdx + 1; 811 for (int i = 2; i < points_count; i++) 812 { 813 _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + ((i - 1) << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_inner_idx + (i << 1)); 814 _IdxWritePtr += 3; 815 } 816 817 // Compute normals 818 ImVec2* temp_normals = (ImVec2*)alloca(points_count * sizeof(ImVec2)); 819 for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++) 820 { 821 const ImVec2& p0 = points[i0]; 822 const ImVec2& p1 = points[i1]; 823 ImVec2 diff = p1 - p0; 824 diff *= ImInvLength(diff, 1.0f); 825 temp_normals[i0].x = diff.y; 826 temp_normals[i0].y = -diff.x; 827 } 828 829 for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++) 830 { 831 // Average normals 832 const ImVec2& n0 = temp_normals[i0]; 833 const ImVec2& n1 = temp_normals[i1]; 834 ImVec2 dm = (n0 + n1) * 0.5f; 835 float dmr2 = dm.x*dm.x + dm.y*dm.y; 836 if (dmr2 > 0.000001f) 837 { 838 float scale = 1.0f / dmr2; 839 if (scale > 100.0f) scale = 100.0f; 840 dm *= scale; 841 } 842 dm *= AA_SIZE * 0.5f; 843 844 // Add vertices 845 _VtxWritePtr[0].pos = (points[i1] - dm); _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; // Inner 846 _VtxWritePtr[1].pos = (points[i1] + dm); _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans; // Outer 847 _VtxWritePtr += 2; 848 849 // Add indexes for fringes 850 _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1)); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + (i0 << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1)); 851 _IdxWritePtr[3] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1)); _IdxWritePtr[4] = (ImDrawIdx)(vtx_outer_idx + (i1 << 1)); _IdxWritePtr[5] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1)); 852 _IdxWritePtr += 6; 853 } 854 _VtxCurrentIdx += (ImDrawIdx)vtx_count; 855 } 856 else 857 { 858 // Non Anti-aliased Fill 859 const int idx_count = (points_count - 2) * 3; 860 const int vtx_count = points_count; 861 PrimReserve(idx_count, vtx_count); 862 for (int i = 0; i < vtx_count; i++) 863 { 864 _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; 865 _VtxWritePtr++; 866 } 867 for (int i = 2; i < points_count; i++) 868 { 869 _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + i - 1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + i); 870 _IdxWritePtr += 3; 871 } 872 _VtxCurrentIdx += (ImDrawIdx)vtx_count; 873 } 874 } 875 876 void ImDrawList::PathArcToFast(const ImVec2& centre, float radius, int a_min_of_12, int a_max_of_12) 877 { 878 if (radius == 0.0f || a_min_of_12 > a_max_of_12) 879 { 880 _Path.push_back(centre); 881 return; 882 } 883 _Path.reserve(_Path.Size + (a_max_of_12 - a_min_of_12 + 1)); 884 for (int a = a_min_of_12; a <= a_max_of_12; a++) 885 { 886 const ImVec2& c = _Data->CircleVtx12[a % IM_ARRAYSIZE(_Data->CircleVtx12)]; 887 _Path.push_back(ImVec2(centre.x + c.x * radius, centre.y + c.y * radius)); 888 } 889 } 890 891 void ImDrawList::PathArcTo(const ImVec2& centre, float radius, float a_min, float a_max, int num_segments) 892 { 893 if (radius == 0.0f) 894 { 895 _Path.push_back(centre); 896 return; 897 } 898 _Path.reserve(_Path.Size + (num_segments + 1)); 899 for (int i = 0; i <= num_segments; i++) 900 { 901 const float a = a_min + ((float)i / (float)num_segments) * (a_max - a_min); 902 _Path.push_back(ImVec2(centre.x + cosf(a) * radius, centre.y + sinf(a) * radius)); 903 } 904 } 905 906 static void PathBezierToCasteljau(ImVector<ImVec2>* path, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level) 907 { 908 float dx = x4 - x1; 909 float dy = y4 - y1; 910 float d2 = ((x2 - x4) * dy - (y2 - y4) * dx); 911 float d3 = ((x3 - x4) * dy - (y3 - y4) * dx); 912 d2 = (d2 >= 0) ? d2 : -d2; 913 d3 = (d3 >= 0) ? d3 : -d3; 914 if ((d2 + d3) * (d2 + d3) < tess_tol * (dx*dx + dy * dy)) 915 { 916 path->push_back(ImVec2(x4, y4)); 917 } 918 else if (level < 10) 919 { 920 float x12 = (x1 + x2)*0.5f, y12 = (y1 + y2)*0.5f; 921 float x23 = (x2 + x3)*0.5f, y23 = (y2 + y3)*0.5f; 922 float x34 = (x3 + x4)*0.5f, y34 = (y3 + y4)*0.5f; 923 float x123 = (x12 + x23)*0.5f, y123 = (y12 + y23)*0.5f; 924 float x234 = (x23 + x34)*0.5f, y234 = (y23 + y34)*0.5f; 925 float x1234 = (x123 + x234)*0.5f, y1234 = (y123 + y234)*0.5f; 926 927 PathBezierToCasteljau(path, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1); 928 PathBezierToCasteljau(path, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1); 929 } 930 } 931 932 void ImDrawList::PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments) 933 { 934 ImVec2 p1 = _Path.back(); 935 if (num_segments == 0) 936 { 937 // Auto-tessellated 938 PathBezierToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, _Data->CurveTessellationTol, 0); 939 } 940 else 941 { 942 float t_step = 1.0f / (float)num_segments; 943 for (int i_step = 1; i_step <= num_segments; i_step++) 944 { 945 float t = t_step * i_step; 946 float u = 1.0f - t; 947 float w1 = u * u*u; 948 float w2 = 3 * u*u*t; 949 float w3 = 3 * u*t*t; 950 float w4 = t * t*t; 951 _Path.push_back(ImVec2(w1*p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x, w1*p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y)); 952 } 953 } 954 } 955 956 void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, int rounding_corners) 957 { 958 rounding = ImMin(rounding, fabsf(b.x - a.x) * (((rounding_corners & ImDrawCornerFlags_Top) == ImDrawCornerFlags_Top) || ((rounding_corners & ImDrawCornerFlags_Bot) == ImDrawCornerFlags_Bot) ? 0.5f : 1.0f) - 1.0f); 959 rounding = ImMin(rounding, fabsf(b.y - a.y) * (((rounding_corners & ImDrawCornerFlags_Left) == ImDrawCornerFlags_Left) || ((rounding_corners & ImDrawCornerFlags_Right) == ImDrawCornerFlags_Right) ? 0.5f : 1.0f) - 1.0f); 960 961 if (rounding <= 0.0f || rounding_corners == 0) 962 { 963 PathLineTo(a); 964 PathLineTo(ImVec2(b.x, a.y)); 965 PathLineTo(b); 966 PathLineTo(ImVec2(a.x, b.y)); 967 } 968 else 969 { 970 const float rounding_tl = (rounding_corners & ImDrawCornerFlags_TopLeft) ? rounding : 0.0f; 971 const float rounding_tr = (rounding_corners & ImDrawCornerFlags_TopRight) ? rounding : 0.0f; 972 const float rounding_br = (rounding_corners & ImDrawCornerFlags_BotRight) ? rounding : 0.0f; 973 const float rounding_bl = (rounding_corners & ImDrawCornerFlags_BotLeft) ? rounding : 0.0f; 974 PathArcToFast(ImVec2(a.x + rounding_tl, a.y + rounding_tl), rounding_tl, 6, 9); 975 PathArcToFast(ImVec2(b.x - rounding_tr, a.y + rounding_tr), rounding_tr, 9, 12); 976 PathArcToFast(ImVec2(b.x - rounding_br, b.y - rounding_br), rounding_br, 0, 3); 977 PathArcToFast(ImVec2(a.x + rounding_bl, b.y - rounding_bl), rounding_bl, 3, 6); 978 } 979 } 980 981 void ImDrawList::AddLine(const ImVec2& a, const ImVec2& b, ImU32 col, float thickness) 982 { 983 if ((col & IM_COL32_A_MASK) == 0) 984 return; 985 PathLineTo(a + ImVec2(0.5f, 0.5f)); 986 PathLineTo(b + ImVec2(0.5f, 0.5f)); 987 PathStroke(col, false, thickness); 988 } 989 990 // a: upper-left, b: lower-right. we don't render 1 px sized rectangles properly. 991 void ImDrawList::AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, int rounding_corners_flags, float thickness) 992 { 993 if ((col & IM_COL32_A_MASK) == 0) 994 return; 995 if (Flags & ImDrawListFlags_AntiAliasedLines) 996 PathRect(a + ImVec2(0.5f, 0.5f), b - ImVec2(0.50f, 0.50f), rounding, rounding_corners_flags); 997 else 998 PathRect(a + ImVec2(0.5f, 0.5f), b - ImVec2(0.49f, 0.49f), rounding, rounding_corners_flags); // Better looking lower-right corner and rounded non-AA shapes. 999 PathStroke(col, true, thickness); 1000 } 1001 1002 void ImDrawList::AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, int rounding_corners_flags) 1003 { 1004 if ((col & IM_COL32_A_MASK) == 0) 1005 return; 1006 if (rounding > 0.0f) 1007 { 1008 PathRect(a, b, rounding, rounding_corners_flags); 1009 PathFillConvex(col); 1010 } 1011 else 1012 { 1013 PrimReserve(6, 4); 1014 PrimRect(a, b, col); 1015 } 1016 } 1017 1018 void ImDrawList::AddRectFilledMultiColor(const ImVec2& a, const ImVec2& c, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left) 1019 { 1020 if (((col_upr_left | col_upr_right | col_bot_right | col_bot_left) & IM_COL32_A_MASK) == 0) 1021 return; 1022 1023 const ImVec2 uv = _Data->TexUvWhitePixel; 1024 PrimReserve(6, 4); 1025 PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 1)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 2)); 1026 PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 2)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 3)); 1027 PrimWriteVtx(a, uv, col_upr_left); 1028 PrimWriteVtx(ImVec2(c.x, a.y), uv, col_upr_right); 1029 PrimWriteVtx(c, uv, col_bot_right); 1030 PrimWriteVtx(ImVec2(a.x, c.y), uv, col_bot_left); 1031 } 1032 1033 void ImDrawList::AddQuad(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col, float thickness) 1034 { 1035 if ((col & IM_COL32_A_MASK) == 0) 1036 return; 1037 1038 PathLineTo(a); 1039 PathLineTo(b); 1040 PathLineTo(c); 1041 PathLineTo(d); 1042 PathStroke(col, true, thickness); 1043 } 1044 1045 void ImDrawList::AddQuadFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col) 1046 { 1047 if ((col & IM_COL32_A_MASK) == 0) 1048 return; 1049 1050 PathLineTo(a); 1051 PathLineTo(b); 1052 PathLineTo(c); 1053 PathLineTo(d); 1054 PathFillConvex(col); 1055 } 1056 1057 void ImDrawList::AddTriangle(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col, float thickness) 1058 { 1059 if ((col & IM_COL32_A_MASK) == 0) 1060 return; 1061 1062 PathLineTo(a); 1063 PathLineTo(b); 1064 PathLineTo(c); 1065 PathStroke(col, true, thickness); 1066 } 1067 1068 void ImDrawList::AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col) 1069 { 1070 if ((col & IM_COL32_A_MASK) == 0) 1071 return; 1072 1073 PathLineTo(a); 1074 PathLineTo(b); 1075 PathLineTo(c); 1076 PathFillConvex(col); 1077 } 1078 1079 void ImDrawList::AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments, float thickness) 1080 { 1081 if ((col & IM_COL32_A_MASK) == 0) 1082 return; 1083 1084 const float a_max = IM_PI * 2.0f * ((float)num_segments - 1.0f) / (float)num_segments; 1085 PathArcTo(centre, radius - 0.5f, 0.0f, a_max, num_segments); 1086 PathStroke(col, true, thickness); 1087 } 1088 1089 void ImDrawList::AddCircleFilled(const ImVec2& centre, float radius, ImU32 col, int num_segments) 1090 { 1091 if ((col & IM_COL32_A_MASK) == 0) 1092 return; 1093 1094 const float a_max = IM_PI * 2.0f * ((float)num_segments - 1.0f) / (float)num_segments; 1095 PathArcTo(centre, radius, 0.0f, a_max, num_segments); 1096 PathFillConvex(col); 1097 } 1098 1099 void ImDrawList::AddBezierCurve(const ImVec2& pos0, const ImVec2& cp0, const ImVec2& cp1, const ImVec2& pos1, ImU32 col, float thickness, int num_segments) 1100 { 1101 if ((col & IM_COL32_A_MASK) == 0) 1102 return; 1103 1104 PathLineTo(pos0); 1105 PathBezierCurveTo(cp0, cp1, pos1, num_segments); 1106 PathStroke(col, false, thickness); 1107 } 1108 1109 void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end, float wrap_width, const ImVec4* cpu_fine_clip_rect) 1110 { 1111 if ((col & IM_COL32_A_MASK) == 0) 1112 return; 1113 1114 if (text_end == NULL) 1115 text_end = text_begin + strlen(text_begin); 1116 if (text_begin == text_end) 1117 return; 1118 1119 // Pull default font/size from the shared ImDrawListSharedData instance 1120 if (font == NULL) 1121 font = _Data->Font; 1122 if (font_size == 0.0f) 1123 font_size = _Data->FontSize; 1124 1125 IM_ASSERT(font->ContainerAtlas->TexID == _TextureIdStack.back()); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font. 1126 1127 ImVec4 clip_rect = _ClipRectStack.back(); 1128 if (cpu_fine_clip_rect) 1129 { 1130 clip_rect.x = ImMax(clip_rect.x, cpu_fine_clip_rect->x); 1131 clip_rect.y = ImMax(clip_rect.y, cpu_fine_clip_rect->y); 1132 clip_rect.z = ImMin(clip_rect.z, cpu_fine_clip_rect->z); 1133 clip_rect.w = ImMin(clip_rect.w, cpu_fine_clip_rect->w); 1134 } 1135 font->RenderText(this, font_size, pos, col, clip_rect, text_begin, text_end, wrap_width, cpu_fine_clip_rect != NULL); 1136 } 1137 1138 void ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end) 1139 { 1140 AddText(NULL, 0.0f, pos, col, text_begin, text_end); 1141 } 1142 1143 void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col) 1144 { 1145 if ((col & IM_COL32_A_MASK) == 0) 1146 return; 1147 1148 const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back(); 1149 if (push_texture_id) 1150 PushTextureID(user_texture_id); 1151 1152 PrimReserve(6, 4); 1153 PrimRectUV(a, b, uv_a, uv_b, col); 1154 1155 if (push_texture_id) 1156 PopTextureID(); 1157 } 1158 1159 void ImDrawList::AddImageQuad(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a, const ImVec2& uv_b, const ImVec2& uv_c, const ImVec2& uv_d, ImU32 col) 1160 { 1161 if ((col & IM_COL32_A_MASK) == 0) 1162 return; 1163 1164 const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back(); 1165 if (push_texture_id) 1166 PushTextureID(user_texture_id); 1167 1168 PrimReserve(6, 4); 1169 PrimQuadUV(a, b, c, d, uv_a, uv_b, uv_c, uv_d, col); 1170 1171 if (push_texture_id) 1172 PopTextureID(); 1173 } 1174 1175 void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col, float rounding, int rounding_corners) 1176 { 1177 if ((col & IM_COL32_A_MASK) == 0) 1178 return; 1179 1180 if (rounding <= 0.0f || (rounding_corners & ImDrawCornerFlags_All) == 0) 1181 { 1182 AddImage(user_texture_id, a, b, uv_a, uv_b, col); 1183 return; 1184 } 1185 1186 const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back(); 1187 if (push_texture_id) 1188 PushTextureID(user_texture_id); 1189 1190 int vert_start_idx = VtxBuffer.Size; 1191 PathRect(a, b, rounding, rounding_corners); 1192 PathFillConvex(col); 1193 int vert_end_idx = VtxBuffer.Size; 1194 ImGui::ShadeVertsLinearUV(VtxBuffer.Data + vert_start_idx, VtxBuffer.Data + vert_end_idx, a, b, uv_a, uv_b, true); 1195 1196 if (push_texture_id) 1197 PopTextureID(); 1491 } 1492 if (ch._CmdBuffer.Size > 0) 1493 last_cmd = &ch._CmdBuffer.back(); 1494 new_cmd_buffer_count += ch._CmdBuffer.Size; 1495 new_idx_buffer_count += ch._IdxBuffer.Size; 1496 for (int cmd_n = 0; cmd_n < ch._CmdBuffer.Size; cmd_n++) 1497 { 1498 ch._CmdBuffer.Data[cmd_n].IdxOffset = idx_offset; 1499 idx_offset += ch._CmdBuffer.Data[cmd_n].ElemCount; 1500 } 1501 } 1502 draw_list->CmdBuffer.resize(draw_list->CmdBuffer.Size + new_cmd_buffer_count); 1503 draw_list->IdxBuffer.resize(draw_list->IdxBuffer.Size + new_idx_buffer_count); 1504 1505 // Write commands and indices in order (they are fairly small structures, we don't copy vertices only indices) 1506 ImDrawCmd* cmd_write = draw_list->CmdBuffer.Data + draw_list->CmdBuffer.Size - new_cmd_buffer_count; 1507 ImDrawIdx* idx_write = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size - new_idx_buffer_count; 1508 for (int i = 1; i < _Count; i++) 1509 { 1510 ImDrawChannel& ch = _Channels[i]; 1511 if (int sz = ch._CmdBuffer.Size) { memcpy(cmd_write, ch._CmdBuffer.Data, sz * sizeof(ImDrawCmd)); cmd_write += sz; } 1512 if (int sz = ch._IdxBuffer.Size) { memcpy(idx_write, ch._IdxBuffer.Data, sz * sizeof(ImDrawIdx)); idx_write += sz; } 1513 } 1514 draw_list->_IdxWritePtr = idx_write; 1515 1516 // Ensure there's always a non-callback draw command trailing the command-buffer 1517 if (draw_list->CmdBuffer.Size == 0 || draw_list->CmdBuffer.back().UserCallback != NULL) 1518 draw_list->AddDrawCmd(); 1519 1520 // If current command is used with different settings we need to add a new command 1521 ImDrawCmd* curr_cmd = &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1]; 1522 if (curr_cmd->ElemCount == 0) 1523 ImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TextureId, VtxOffset 1524 else if (ImDrawCmd_HeaderCompare(curr_cmd, &draw_list->_CmdHeader) != 0) 1525 draw_list->AddDrawCmd(); 1526 1527 _Count = 1; 1528 } 1529 1530 void ImDrawListSplitter::SetCurrentChannel(ImDrawList* draw_list, int idx) 1531 { 1532 IM_ASSERT(idx >= 0 && idx < _Count); 1533 if (_Current == idx) 1534 return; 1535 1536 // Overwrite ImVector (12/16 bytes), four times. This is merely a silly optimization instead of doing .swap() 1537 memcpy(&_Channels.Data[_Current]._CmdBuffer, &draw_list->CmdBuffer, sizeof(draw_list->CmdBuffer)); 1538 memcpy(&_Channels.Data[_Current]._IdxBuffer, &draw_list->IdxBuffer, sizeof(draw_list->IdxBuffer)); 1539 _Current = idx; 1540 memcpy(&draw_list->CmdBuffer, &_Channels.Data[idx]._CmdBuffer, sizeof(draw_list->CmdBuffer)); 1541 memcpy(&draw_list->IdxBuffer, &_Channels.Data[idx]._IdxBuffer, sizeof(draw_list->IdxBuffer)); 1542 draw_list->_IdxWritePtr = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size; 1543 1544 // If current command is used with different settings we need to add a new command 1545 ImDrawCmd* curr_cmd = &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1]; 1546 if (curr_cmd->ElemCount == 0) 1547 ImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TextureId, VtxOffset 1548 else if (ImDrawCmd_HeaderCompare(curr_cmd, &draw_list->_CmdHeader) != 0) 1549 draw_list->AddDrawCmd(); 1198 1550 } 1199 1551 1200 1552 //----------------------------------------------------------------------------- 1201 // ImDrawData1553 // [SECTION] ImDrawData 1202 1554 //----------------------------------------------------------------------------- 1203 1555 … … 1205 1557 void ImDrawData::DeIndexAllBuffers() 1206 1558 { 1207 ImVector<ImDrawVert> new_vtx_buffer; 1208 TotalVtxCount = TotalIdxCount = 0; 1209 for (int i = 0; i < CmdListsCount; i++) 1210 { 1211 ImDrawList* cmd_list = CmdLists[i]; 1212 if (cmd_list->IdxBuffer.empty()) 1213 continue; 1214 new_vtx_buffer.resize(cmd_list->IdxBuffer.Size); 1215 for (int j = 0; j < cmd_list->IdxBuffer.Size; j++) 1216 new_vtx_buffer[j] = cmd_list->VtxBuffer[cmd_list->IdxBuffer[j]]; 1217 cmd_list->VtxBuffer.swap(new_vtx_buffer); 1218 cmd_list->IdxBuffer.resize(0); 1219 TotalVtxCount += cmd_list->VtxBuffer.Size; 1220 } 1221 } 1222 1223 // Helper to scale the ClipRect field of each ImDrawCmd. Use if your final output buffer is at a different scale than ImGui expects, or if there is a difference between your window resolution and framebuffer resolution. 1224 void ImDrawData::ScaleClipRects(const ImVec2& scale) 1225 { 1226 for (int i = 0; i < CmdListsCount; i++) 1227 { 1228 ImDrawList* cmd_list = CmdLists[i]; 1229 for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) 1230 { 1231 ImDrawCmd* cmd = &cmd_list->CmdBuffer[cmd_i]; 1232 cmd->ClipRect = ImVec4(cmd->ClipRect.x * scale.x, cmd->ClipRect.y * scale.y, cmd->ClipRect.z * scale.x, cmd->ClipRect.w * scale.y); 1233 } 1234 } 1559 ImVector<ImDrawVert> new_vtx_buffer; 1560 TotalVtxCount = TotalIdxCount = 0; 1561 for (int i = 0; i < CmdListsCount; i++) 1562 { 1563 ImDrawList* cmd_list = CmdLists[i]; 1564 if (cmd_list->IdxBuffer.empty()) 1565 continue; 1566 new_vtx_buffer.resize(cmd_list->IdxBuffer.Size); 1567 for (int j = 0; j < cmd_list->IdxBuffer.Size; j++) 1568 new_vtx_buffer[j] = cmd_list->VtxBuffer[cmd_list->IdxBuffer[j]]; 1569 cmd_list->VtxBuffer.swap(new_vtx_buffer); 1570 cmd_list->IdxBuffer.resize(0); 1571 TotalVtxCount += cmd_list->VtxBuffer.Size; 1572 } 1573 } 1574 1575 // Helper to scale the ClipRect field of each ImDrawCmd. 1576 // Use if your final output buffer is at a different scale than draw_data->DisplaySize, 1577 // or if there is a difference between your window resolution and framebuffer resolution. 1578 void ImDrawData::ScaleClipRects(const ImVec2& fb_scale) 1579 { 1580 for (int i = 0; i < CmdListsCount; i++) 1581 { 1582 ImDrawList* cmd_list = CmdLists[i]; 1583 for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) 1584 { 1585 ImDrawCmd* cmd = &cmd_list->CmdBuffer[cmd_i]; 1586 cmd->ClipRect = ImVec4(cmd->ClipRect.x * fb_scale.x, cmd->ClipRect.y * fb_scale.y, cmd->ClipRect.z * fb_scale.x, cmd->ClipRect.w * fb_scale.y); 1587 } 1588 } 1235 1589 } 1236 1590 1237 1591 //----------------------------------------------------------------------------- 1238 // Shadefunctions1592 // [SECTION] Helpers ShadeVertsXXX functions 1239 1593 //----------------------------------------------------------------------------- 1240 1594 1241 1595 // Generic linear color gradient, write to RGB fields, leave A untouched. 1242 void ImGui::ShadeVertsLinearColorGradientKeepAlpha(ImDrawVert* vert_start, ImDrawVert* vert_end, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1) 1243 { 1244 ImVec2 gradient_extent = gradient_p1 - gradient_p0; 1245 float gradient_inv_length2 = 1.0f / ImLengthSqr(gradient_extent); 1246 for (ImDrawVert* vert = vert_start; vert < vert_end; vert++) 1247 { 1248 float d = ImDot(vert->pos - gradient_p0, gradient_extent); 1249 float t = ImClamp(d * gradient_inv_length2, 0.0f, 1.0f); 1250 int r = ImLerp((int)(col0 >> IM_COL32_R_SHIFT) & 0xFF, (int)(col1 >> IM_COL32_R_SHIFT) & 0xFF, t); 1251 int g = ImLerp((int)(col0 >> IM_COL32_G_SHIFT) & 0xFF, (int)(col1 >> IM_COL32_G_SHIFT) & 0xFF, t); 1252 int b = ImLerp((int)(col0 >> IM_COL32_B_SHIFT) & 0xFF, (int)(col1 >> IM_COL32_B_SHIFT) & 0xFF, t); 1253 vert->col = (r << IM_COL32_R_SHIFT) | (g << IM_COL32_G_SHIFT) | (b << IM_COL32_B_SHIFT) | (vert->col & IM_COL32_A_MASK); 1254 } 1255 } 1256 1257 // Scan and shade backward from the end of given vertices. Assume vertices are text only (= vert_start..vert_end going left to right) so we can break as soon as we are out the gradient bounds. 1258 void ImGui::ShadeVertsLinearAlphaGradientForLeftToRightText(ImDrawVert* vert_start, ImDrawVert* vert_end, float gradient_p0_x, float gradient_p1_x) 1259 { 1260 float gradient_extent_x = gradient_p1_x - gradient_p0_x; 1261 float gradient_inv_length2 = 1.0f / (gradient_extent_x * gradient_extent_x); 1262 int full_alpha_count = 0; 1263 for (ImDrawVert* vert = vert_end - 1; vert >= vert_start; vert--) 1264 { 1265 float d = (vert->pos.x - gradient_p0_x) * (gradient_extent_x); 1266 float alpha_mul = 1.0f - ImClamp(d * gradient_inv_length2, 0.0f, 1.0f); 1267 if (alpha_mul >= 1.0f && ++full_alpha_count > 2) 1268 return; // Early out 1269 int a = (int)(((vert->col >> IM_COL32_A_SHIFT) & 0xFF) * alpha_mul); 1270 vert->col = (vert->col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT); 1271 } 1596 void ImGui::ShadeVertsLinearColorGradientKeepAlpha(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1) 1597 { 1598 ImVec2 gradient_extent = gradient_p1 - gradient_p0; 1599 float gradient_inv_length2 = 1.0f / ImLengthSqr(gradient_extent); 1600 ImDrawVert* vert_start = draw_list->VtxBuffer.Data + vert_start_idx; 1601 ImDrawVert* vert_end = draw_list->VtxBuffer.Data + vert_end_idx; 1602 const int col0_r = (int)(col0 >> IM_COL32_R_SHIFT) & 0xFF; 1603 const int col0_g = (int)(col0 >> IM_COL32_G_SHIFT) & 0xFF; 1604 const int col0_b = (int)(col0 >> IM_COL32_B_SHIFT) & 0xFF; 1605 const int col_delta_r = ((int)(col1 >> IM_COL32_R_SHIFT) & 0xFF) - col0_r; 1606 const int col_delta_g = ((int)(col1 >> IM_COL32_G_SHIFT) & 0xFF) - col0_g; 1607 const int col_delta_b = ((int)(col1 >> IM_COL32_B_SHIFT) & 0xFF) - col0_b; 1608 for (ImDrawVert* vert = vert_start; vert < vert_end; vert++) 1609 { 1610 float d = ImDot(vert->pos - gradient_p0, gradient_extent); 1611 float t = ImClamp(d * gradient_inv_length2, 0.0f, 1.0f); 1612 int r = (int)(col0_r + col_delta_r * t); 1613 int g = (int)(col0_g + col_delta_g * t); 1614 int b = (int)(col0_b + col_delta_b * t); 1615 vert->col = (r << IM_COL32_R_SHIFT) | (g << IM_COL32_G_SHIFT) | (b << IM_COL32_B_SHIFT) | (vert->col & IM_COL32_A_MASK); 1616 } 1272 1617 } 1273 1618 1274 1619 // Distribute UV over (a, b) rectangle 1275 void ImGui::ShadeVertsLinearUV(ImDrawVert* vert_start, ImDrawVert* vert_end, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp) 1276 { 1277 const ImVec2 size = b - a; 1278 const ImVec2 uv_size = uv_b - uv_a; 1279 const ImVec2 scale = ImVec2( 1280 size.x != 0.0f ? (uv_size.x / size.x) : 0.0f, 1281 size.y != 0.0f ? (uv_size.y / size.y) : 0.0f); 1282 1283 if (clamp) 1284 { 1285 const ImVec2 min = ImMin(uv_a, uv_b); 1286 const ImVec2 max = ImMax(uv_a, uv_b); 1287 1288 for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex) 1289 vertex->uv = ImClamp(uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale), min, max); 1290 } 1291 else 1292 { 1293 for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex) 1294 vertex->uv = uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale); 1295 } 1620 void ImGui::ShadeVertsLinearUV(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp) 1621 { 1622 const ImVec2 size = b - a; 1623 const ImVec2 uv_size = uv_b - uv_a; 1624 const ImVec2 scale = ImVec2( 1625 size.x != 0.0f ? (uv_size.x / size.x) : 0.0f, 1626 size.y != 0.0f ? (uv_size.y / size.y) : 0.0f); 1627 1628 ImDrawVert* vert_start = draw_list->VtxBuffer.Data + vert_start_idx; 1629 ImDrawVert* vert_end = draw_list->VtxBuffer.Data + vert_end_idx; 1630 if (clamp) 1631 { 1632 const ImVec2 min = ImMin(uv_a, uv_b); 1633 const ImVec2 max = ImMax(uv_a, uv_b); 1634 for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex) 1635 vertex->uv = ImClamp(uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale), min, max); 1636 } 1637 else 1638 { 1639 for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex) 1640 vertex->uv = uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale); 1641 } 1296 1642 } 1297 1643 1298 1644 //----------------------------------------------------------------------------- 1299 // ImFontConfig1645 // [SECTION] ImFontConfig 1300 1646 //----------------------------------------------------------------------------- 1301 1647 1302 1648 ImFontConfig::ImFontConfig() 1303 1649 { 1304 FontData = NULL; 1305 FontDataSize = 0; 1306 FontDataOwnedByAtlas = true; 1307 FontNo = 0; 1308 SizePixels = 0.0f; 1309 OversampleH = 3; 1310 OversampleV = 1; 1311 PixelSnapH = false; 1312 GlyphExtraSpacing = ImVec2(0.0f, 0.0f); 1313 GlyphOffset = ImVec2(0.0f, 0.0f); 1314 GlyphRanges = NULL; 1315 MergeMode = false; 1316 RasterizerFlags = 0x00; 1317 RasterizerMultiply = 1.0f; 1318 memset(Name, 0, sizeof(Name)); 1319 DstFont = NULL; 1650 FontData = NULL; 1651 FontDataSize = 0; 1652 FontDataOwnedByAtlas = true; 1653 FontNo = 0; 1654 SizePixels = 0.0f; 1655 OversampleH = 3; // FIXME: 2 may be a better default? 1656 OversampleV = 1; 1657 PixelSnapH = false; 1658 GlyphExtraSpacing = ImVec2(0.0f, 0.0f); 1659 GlyphOffset = ImVec2(0.0f, 0.0f); 1660 GlyphRanges = NULL; 1661 GlyphMinAdvanceX = 0.0f; 1662 GlyphMaxAdvanceX = FLT_MAX; 1663 MergeMode = false; 1664 RasterizerFlags = 0x00; 1665 RasterizerMultiply = 1.0f; 1666 EllipsisChar = (ImWchar)-1; 1667 memset(Name, 0, sizeof(Name)); 1668 DstFont = NULL; 1320 1669 } 1321 1670 1322 1671 //----------------------------------------------------------------------------- 1323 // ImFontAtlas1672 // [SECTION] ImFontAtlas 1324 1673 //----------------------------------------------------------------------------- 1325 1674 1326 1675 // A work of art lies ahead! (. = white layer, X = black layer, others are blank) 1327 // The white texels on the top left are the ones we'll use everywhere inImGui to render filled shapes.1328 const int FONT_ATLAS_DEFAULT_TEX_DATA_W _HALF = 90;1676 // The 2x2 white texels on the top left are the ones we'll use everywhere in Dear ImGui to render filled shapes. 1677 const int FONT_ATLAS_DEFAULT_TEX_DATA_W = 108; // Actual texture will be 2 times that + 1 spacing. 1329 1678 const int FONT_ATLAS_DEFAULT_TEX_DATA_H = 27; 1330 const unsigned int FONT_ATLAS_DEFAULT_TEX_DATA_ID = 0x80000000; 1331 static const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF * FONT_ATLAS_DEFAULT_TEX_DATA_H + 1] = 1332 { 1333 "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX" 1334 "..- -X.....X- X.X - X.X -X.....X - X.....X" 1335 "--- -XXX.XXX- X...X - X...X -X....X - X....X" 1336 "X - X.X - X.....X - X.....X -X...X - X...X" 1337 "XX - X.X -X.......X- X.......X -X..X.X - X.X..X" 1338 "X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X" 1339 "X..X - X.X - X.X - X.X -XX X.X - X.X XX" 1340 "X...X - X.X - X.X - XX X.X XX - X.X - X.X " 1341 "X....X - X.X - X.X - X.X X.X X.X - X.X - X.X " 1342 "X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X " 1343 "X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X " 1344 "X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X " 1345 "X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X " 1346 "X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X " 1347 "X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X " 1348 "X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X " 1349 "X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX " 1350 "X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------" 1351 "X.X X..X - -X.......X- X.......X - XX XX - " 1352 "XX X..X - - X.....X - X.....X - X.X X.X - " 1353 " X..X - X...X - X...X - X..X X..X - " 1354 " XX - X.X - X.X - X...XXXXXXXXXXXXX...X - " 1355 "------------ - X - X -X.....................X- " 1356 " ----------------------------------- X...XXXXXXXXXXXXX...X - " 1357 " - X..X X..X - " 1358 " - X.X X.X - " 1359 " - XX XX - " 1679 static const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W * FONT_ATLAS_DEFAULT_TEX_DATA_H + 1] = 1680 { 1681 "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX- XX " 1682 "..- -X.....X- X.X - X.X -X.....X - X.....X- X..X " 1683 "--- -XXX.XXX- X...X - X...X -X....X - X....X- X..X " 1684 "X - X.X - X.....X - X.....X -X...X - X...X- X..X " 1685 "XX - X.X -X.......X- X.......X -X..X.X - X.X..X- X..X " 1686 "X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X- X..XXX " 1687 "X..X - X.X - X.X - X.X -XX X.X - X.X XX- X..X..XXX " 1688 "X...X - X.X - X.X - XX X.X XX - X.X - X.X - X..X..X..XX " 1689 "X....X - X.X - X.X - X.X X.X X.X - X.X - X.X - X..X..X..X.X " 1690 "X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X -XXX X..X..X..X..X" 1691 "X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X -X..XX........X..X" 1692 "X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X -X...X...........X" 1693 "X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X - X..............X" 1694 "X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X - X.............X" 1695 "X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X - X.............X" 1696 "X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X - X............X" 1697 "X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX - X...........X " 1698 "X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------- X..........X " 1699 "X.X X..X - -X.......X- X.......X - XX XX - - X..........X " 1700 "XX X..X - - X.....X - X.....X - X.X X.X - - X........X " 1701 " X..X - X...X - X...X - X..X X..X - - X........X " 1702 " XX - X.X - X.X - X...XXXXXXXXXXXXX...X - - XXXXXXXXXX " 1703 "------------ - X - X -X.....................X- ------------------" 1704 " ----------------------------------- X...XXXXXXXXXXXXX...X - " 1705 " - X..X X..X - " 1706 " - X.X X.X - " 1707 " - XX XX - " 1360 1708 }; 1361 1709 1362 1710 static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3] = 1363 1711 { 1364 // Pos ........ Size ......... Offset ...... 1365 { ImVec2(0,3), ImVec2(12,19), ImVec2(0, 0) }, // ImGuiMouseCursor_Arrow 1366 { ImVec2(13,0), ImVec2(7,16), ImVec2(4, 8) }, // ImGuiMouseCursor_TextInput 1367 { ImVec2(31,0), ImVec2(23,23), ImVec2(11,11) }, // ImGuiMouseCursor_ResizeAll 1368 { ImVec2(21,0), ImVec2(9,23), ImVec2(5,11) }, // ImGuiMouseCursor_ResizeNS 1369 { ImVec2(55,18),ImVec2(23, 9), ImVec2(11, 5) }, // ImGuiMouseCursor_ResizeEW 1370 { ImVec2(73,0), ImVec2(17,17), ImVec2(9, 9) }, // ImGuiMouseCursor_ResizeNESW 1371 { ImVec2(55,0), ImVec2(17,17), ImVec2(9, 9) }, // ImGuiMouseCursor_ResizeNWSE 1712 // Pos ........ Size ......... Offset ...... 1713 { ImVec2( 0,3), ImVec2(12,19), ImVec2( 0, 0) }, // ImGuiMouseCursor_Arrow 1714 { ImVec2(13,0), ImVec2( 7,16), ImVec2( 1, 8) }, // ImGuiMouseCursor_TextInput 1715 { ImVec2(31,0), ImVec2(23,23), ImVec2(11,11) }, // ImGuiMouseCursor_ResizeAll 1716 { ImVec2(21,0), ImVec2( 9,23), ImVec2( 4,11) }, // ImGuiMouseCursor_ResizeNS 1717 { ImVec2(55,18),ImVec2(23, 9), ImVec2(11, 4) }, // ImGuiMouseCursor_ResizeEW 1718 { ImVec2(73,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNESW 1719 { ImVec2(55,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNWSE 1720 { ImVec2(91,0), ImVec2(17,22), ImVec2( 5, 0) }, // ImGuiMouseCursor_Hand 1372 1721 }; 1373 1722 1374 1723 ImFontAtlas::ImFontAtlas() 1375 1724 { 1376 Flags = 0x00;1377 TexID = NULL;1378 TexDesiredWidth = 0;1379 TexGlyphPadding = 1;1380 1381 TexPixelsAlpha8 = NULL; 1382 TexPixelsRGBA32= NULL;1383 TexWidth = TexHeight = 0;1384 TexUvScale = ImVec2(0.0f, 0.0f);1385 TexUvWhitePixel= ImVec2(0.0f, 0.0f);1386 for (int n = 0; n < IM_ARRAYSIZE(CustomRectIds); n++)1387 CustomRectIds[n]= -1;1725 Locked = false; 1726 Flags = ImFontAtlasFlags_None; 1727 TexID = (ImTextureID)NULL; 1728 TexDesiredWidth = 0; 1729 TexGlyphPadding = 1; 1730 1731 TexPixelsAlpha8 = NULL; 1732 TexPixelsRGBA32 = NULL; 1733 TexWidth = TexHeight = 0; 1734 TexUvScale = ImVec2(0.0f, 0.0f); 1735 TexUvWhitePixel = ImVec2(0.0f, 0.0f); 1736 PackIdMouseCursors = PackIdLines = -1; 1388 1737 } 1389 1738 1390 1739 ImFontAtlas::~ImFontAtlas() 1391 1740 { 1392 Clear(); 1741 IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); 1742 Clear(); 1393 1743 } 1394 1744 1395 1745 void ImFontAtlas::ClearInputData() 1396 1746 { 1397 for (int i = 0; i < ConfigData.Size; i++)1398 if (ConfigData[i].FontData && ConfigData[i].FontDataOwnedByAtlas)1399 {1400 ImGui::MemFree(ConfigData[i].FontData);1401 ConfigData[i].FontData = NULL;1402 }1403 1404 // When clearing this we lose access to the font name and other information used to build the font. 1405 for (int i = 0; i < Fonts.Size; i++)1406 if (Fonts[i]->ConfigData >= ConfigData.Data && Fonts[i]->ConfigData < ConfigData.Data + ConfigData.Size)1407 {1408 Fonts[i]->ConfigData = NULL;1409 Fonts[i]->ConfigDataCount = 0;1410 }1411 ConfigData.clear();1412 CustomRects.clear();1413 for (int n = 0; n < IM_ARRAYSIZE(CustomRectIds); n++)1414 CustomRectIds[n]= -1;1747 IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); 1748 for (int i = 0; i < ConfigData.Size; i++) 1749 if (ConfigData[i].FontData && ConfigData[i].FontDataOwnedByAtlas) 1750 { 1751 IM_FREE(ConfigData[i].FontData); 1752 ConfigData[i].FontData = NULL; 1753 } 1754 1755 // When clearing this we lose access to the font name and other information used to build the font. 1756 for (int i = 0; i < Fonts.Size; i++) 1757 if (Fonts[i]->ConfigData >= ConfigData.Data && Fonts[i]->ConfigData < ConfigData.Data + ConfigData.Size) 1758 { 1759 Fonts[i]->ConfigData = NULL; 1760 Fonts[i]->ConfigDataCount = 0; 1761 } 1762 ConfigData.clear(); 1763 CustomRects.clear(); 1764 PackIdMouseCursors = PackIdLines = -1; 1415 1765 } 1416 1766 1417 1767 void ImFontAtlas::ClearTexData() 1418 1768 { 1419 if (TexPixelsAlpha8) 1420 ImGui::MemFree(TexPixelsAlpha8); 1421 if (TexPixelsRGBA32) 1422 ImGui::MemFree(TexPixelsRGBA32); 1423 TexPixelsAlpha8 = NULL; 1424 TexPixelsRGBA32 = NULL; 1769 IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); 1770 if (TexPixelsAlpha8) 1771 IM_FREE(TexPixelsAlpha8); 1772 if (TexPixelsRGBA32) 1773 IM_FREE(TexPixelsRGBA32); 1774 TexPixelsAlpha8 = NULL; 1775 TexPixelsRGBA32 = NULL; 1425 1776 } 1426 1777 1427 1778 void ImFontAtlas::ClearFonts() 1428 1779 { 1429 for (int i = 0; i < Fonts.Size; i++) 1430 IM_DELETE(Fonts[i]); 1431 Fonts.clear(); 1780 IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); 1781 for (int i = 0; i < Fonts.Size; i++) 1782 IM_DELETE(Fonts[i]); 1783 Fonts.clear(); 1432 1784 } 1433 1785 1434 1786 void ImFontAtlas::Clear() 1435 1787 { 1436 ClearInputData();1437 ClearTexData();1438 ClearFonts();1788 ClearInputData(); 1789 ClearTexData(); 1790 ClearFonts(); 1439 1791 } 1440 1792 1441 1793 void ImFontAtlas::GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel) 1442 1794 { 1443 // Build atlas on demand1444 if (TexPixelsAlpha8 == NULL)1445 {1446 if (ConfigData.empty())1447 AddFontDefault();1448 Build();1449 }1450 1451 *out_pixels = TexPixelsAlpha8;1452 if (out_width) *out_width = TexWidth;1453 if (out_height) *out_height = TexHeight;1454 if (out_bytes_per_pixel) *out_bytes_per_pixel = 1;1795 // Build atlas on demand 1796 if (TexPixelsAlpha8 == NULL) 1797 { 1798 if (ConfigData.empty()) 1799 AddFontDefault(); 1800 Build(); 1801 } 1802 1803 *out_pixels = TexPixelsAlpha8; 1804 if (out_width) *out_width = TexWidth; 1805 if (out_height) *out_height = TexHeight; 1806 if (out_bytes_per_pixel) *out_bytes_per_pixel = 1; 1455 1807 } 1456 1808 1457 1809 void ImFontAtlas::GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel) 1458 1810 { 1459 // Convert to RGBA32 format on demand1460 // Although it is likely to be the most commonly used format, our font rendering is 1 channel / 8 bpp1461 if (!TexPixelsRGBA32)1462 {1463 unsigned char* pixels = NULL;1464 GetTexDataAsAlpha8(&pixels, NULL, NULL);1465 if (pixels)1466 {1467 TexPixelsRGBA32 = (unsigned int*)ImGui::MemAlloc((size_t)(TexWidth * TexHeight * 4));1468 const unsigned char* src = pixels;1469 unsigned int* dst = TexPixelsRGBA32;1470 for (int n = TexWidth * TexHeight; n > 0; n--)1471 *dst++ = IM_COL32(255, 255, 255, (unsigned int)(*src++));1472 }1473 }1474 1475 *out_pixels = (unsigned char*)TexPixelsRGBA32;1476 if (out_width) *out_width = TexWidth;1477 if (out_height) *out_height = TexHeight;1478 if (out_bytes_per_pixel) *out_bytes_per_pixel = 4;1811 // Convert to RGBA32 format on demand 1812 // Although it is likely to be the most commonly used format, our font rendering is 1 channel / 8 bpp 1813 if (!TexPixelsRGBA32) 1814 { 1815 unsigned char* pixels = NULL; 1816 GetTexDataAsAlpha8(&pixels, NULL, NULL); 1817 if (pixels) 1818 { 1819 TexPixelsRGBA32 = (unsigned int*)IM_ALLOC((size_t)TexWidth * (size_t)TexHeight * 4); 1820 const unsigned char* src = pixels; 1821 unsigned int* dst = TexPixelsRGBA32; 1822 for (int n = TexWidth * TexHeight; n > 0; n--) 1823 *dst++ = IM_COL32(255, 255, 255, (unsigned int)(*src++)); 1824 } 1825 } 1826 1827 *out_pixels = (unsigned char*)TexPixelsRGBA32; 1828 if (out_width) *out_width = TexWidth; 1829 if (out_height) *out_height = TexHeight; 1830 if (out_bytes_per_pixel) *out_bytes_per_pixel = 4; 1479 1831 } 1480 1832 1481 1833 ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) 1482 1834 { 1483 IM_ASSERT(font_cfg->FontData != NULL && font_cfg->FontDataSize > 0); 1484 IM_ASSERT(font_cfg->SizePixels > 0.0f); 1485 1486 // Create new font 1487 if (!font_cfg->MergeMode) 1488 Fonts.push_back(IM_NEW(ImFont)); 1489 else 1490 IM_ASSERT(!Fonts.empty()); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font. 1491 1492 ConfigData.push_back(*font_cfg); 1493 ImFontConfig& new_font_cfg = ConfigData.back(); 1494 if (!new_font_cfg.DstFont) 1495 new_font_cfg.DstFont = Fonts.back(); 1496 if (!new_font_cfg.FontDataOwnedByAtlas) 1497 { 1498 new_font_cfg.FontData = ImGui::MemAlloc(new_font_cfg.FontDataSize); 1499 new_font_cfg.FontDataOwnedByAtlas = true; 1500 memcpy(new_font_cfg.FontData, font_cfg->FontData, (size_t)new_font_cfg.FontDataSize); 1501 } 1502 1503 // Invalidate texture 1504 ClearTexData(); 1505 return new_font_cfg.DstFont; 1835 IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); 1836 IM_ASSERT(font_cfg->FontData != NULL && font_cfg->FontDataSize > 0); 1837 IM_ASSERT(font_cfg->SizePixels > 0.0f); 1838 1839 // Create new font 1840 if (!font_cfg->MergeMode) 1841 Fonts.push_back(IM_NEW(ImFont)); 1842 else 1843 IM_ASSERT(!Fonts.empty() && "Cannot use MergeMode for the first font"); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font. 1844 1845 ConfigData.push_back(*font_cfg); 1846 ImFontConfig& new_font_cfg = ConfigData.back(); 1847 if (new_font_cfg.DstFont == NULL) 1848 new_font_cfg.DstFont = Fonts.back(); 1849 if (!new_font_cfg.FontDataOwnedByAtlas) 1850 { 1851 new_font_cfg.FontData = IM_ALLOC(new_font_cfg.FontDataSize); 1852 new_font_cfg.FontDataOwnedByAtlas = true; 1853 memcpy(new_font_cfg.FontData, font_cfg->FontData, (size_t)new_font_cfg.FontDataSize); 1854 } 1855 1856 if (new_font_cfg.DstFont->EllipsisChar == (ImWchar)-1) 1857 new_font_cfg.DstFont->EllipsisChar = font_cfg->EllipsisChar; 1858 1859 // Invalidate texture 1860 ClearTexData(); 1861 return new_font_cfg.DstFont; 1506 1862 } 1507 1863 1508 1864 // Default font TTF is compressed with stb_compress then base85 encoded (see misc/fonts/binary_to_compressed_c.cpp for encoder) 1509 static unsigned int stb_decompress_length(const unsigned char *input);1510 static unsigned int stb_decompress(unsigned char *output, const unsigned char *input, unsigned int length);1865 static unsigned int stb_decompress_length(const unsigned char* input); 1866 static unsigned int stb_decompress(unsigned char* output, const unsigned char* input, unsigned int length); 1511 1867 static const char* GetDefaultCompressedFontDataTTFBase85(); 1512 static unsigned int Decode85Byte(char c) { return c >= '\\' ? c - 36 : c -35; }1868 static unsigned int Decode85Byte(char c) { return c >= '\\' ? c-36 : c-35; } 1513 1869 static void Decode85(const unsigned char* src, unsigned char* dst) 1514 1870 { 1515 while (*src)1516 {1517 unsigned int tmp = Decode85Byte(src[0]) + 85 * (Decode85Byte(src[1]) + 85 * (Decode85Byte(src[2]) + 85 * (Decode85Byte(src[3]) + 85 * Decode85Byte(src[4]))));1518 dst[0] = ((tmp >> 0) & 0xFF); dst[1] = ((tmp >> 8) & 0xFF); dst[2] = ((tmp >> 16) & 0xFF); dst[3] = ((tmp >> 24) & 0xFF); // We can't assume little-endianness.1519 src += 5;1520 dst += 4;1521 }1871 while (*src) 1872 { 1873 unsigned int tmp = Decode85Byte(src[0]) + 85 * (Decode85Byte(src[1]) + 85 * (Decode85Byte(src[2]) + 85 * (Decode85Byte(src[3]) + 85 * Decode85Byte(src[4])))); 1874 dst[0] = ((tmp >> 0) & 0xFF); dst[1] = ((tmp >> 8) & 0xFF); dst[2] = ((tmp >> 16) & 0xFF); dst[3] = ((tmp >> 24) & 0xFF); // We can't assume little-endianness. 1875 src += 5; 1876 dst += 4; 1877 } 1522 1878 } 1523 1879 … … 1525 1881 ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template) 1526 1882 { 1527 ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); 1528 if (!font_cfg_template) 1529 { 1530 font_cfg.OversampleH = font_cfg.OversampleV = 1; 1531 font_cfg.PixelSnapH = true; 1532 } 1533 if (font_cfg.Name[0] == '\0') strcpy(font_cfg.Name, "ProggyClean.ttf, 13px"); 1534 if (font_cfg.SizePixels <= 0.0f) font_cfg.SizePixels = 13.0f; 1535 1536 const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85(); 1537 ImFont* font = AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_cfg.SizePixels, &font_cfg, GetGlyphRangesDefault()); 1538 font->DisplayOffset.y = 1.0f; 1539 return font; 1883 ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); 1884 if (!font_cfg_template) 1885 { 1886 font_cfg.OversampleH = font_cfg.OversampleV = 1; 1887 font_cfg.PixelSnapH = true; 1888 } 1889 if (font_cfg.SizePixels <= 0.0f) 1890 font_cfg.SizePixels = 13.0f * 1.0f; 1891 if (font_cfg.Name[0] == '\0') 1892 ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "ProggyClean.ttf, %dpx", (int)font_cfg.SizePixels); 1893 font_cfg.EllipsisChar = (ImWchar)0x0085; 1894 font_cfg.GlyphOffset.y = 1.0f * IM_FLOOR(font_cfg.SizePixels / 13.0f); // Add +1 offset per 13 units 1895 1896 const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85(); 1897 const ImWchar* glyph_ranges = font_cfg.GlyphRanges != NULL ? font_cfg.GlyphRanges : GetGlyphRangesDefault(); 1898 ImFont* font = AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_cfg.SizePixels, &font_cfg, glyph_ranges); 1899 return font; 1540 1900 } 1541 1901 1542 1902 ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges) 1543 1903 { 1544 int data_size = 0; 1545 void* data = ImFileLoadToMemory(filename, "rb", &data_size, 0); 1546 if (!data) 1547 { 1548 IM_ASSERT(0); // Could not load file. 1549 return NULL; 1550 } 1551 ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); 1552 if (font_cfg.Name[0] == '\0') 1553 { 1554 // Store a short copy of filename into into the font name for convenience 1555 const char* p; 1556 for (p = filename + strlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) {} 1557 ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "%s, %.0fpx", p, size_pixels); 1558 } 1559 return AddFontFromMemoryTTF(data, data_size, size_pixels, &font_cfg, glyph_ranges); 1904 IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); 1905 size_t data_size = 0; 1906 void* data = ImFileLoadToMemory(filename, "rb", &data_size, 0); 1907 if (!data) 1908 { 1909 IM_ASSERT_USER_ERROR(0, "Could not load font file!"); 1910 return NULL; 1911 } 1912 ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); 1913 if (font_cfg.Name[0] == '\0') 1914 { 1915 // Store a short copy of filename into into the font name for convenience 1916 const char* p; 1917 for (p = filename + strlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) {} 1918 ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "%s, %.0fpx", p, size_pixels); 1919 } 1920 return AddFontFromMemoryTTF(data, (int)data_size, size_pixels, &font_cfg, glyph_ranges); 1560 1921 } 1561 1922 … … 1563 1924 ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* ttf_data, int ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges) 1564 1925 { 1565 ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); 1566 IM_ASSERT(font_cfg.FontData == NULL); 1567 font_cfg.FontData = ttf_data; 1568 font_cfg.FontDataSize = ttf_size; 1569 font_cfg.SizePixels = size_pixels; 1570 if (glyph_ranges) 1571 font_cfg.GlyphRanges = glyph_ranges; 1572 return AddFont(&font_cfg); 1926 IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); 1927 ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); 1928 IM_ASSERT(font_cfg.FontData == NULL); 1929 font_cfg.FontData = ttf_data; 1930 font_cfg.FontDataSize = ttf_size; 1931 font_cfg.SizePixels = size_pixels; 1932 if (glyph_ranges) 1933 font_cfg.GlyphRanges = glyph_ranges; 1934 return AddFont(&font_cfg); 1573 1935 } 1574 1936 1575 1937 ImFont* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* compressed_ttf_data, int compressed_ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges) 1576 1938 { 1577 const unsigned int buf_decompressed_size = stb_decompress_length((const unsigned char*)compressed_ttf_data);1578 unsigned char* buf_decompressed_data = (unsigned char *)ImGui::MemAlloc(buf_decompressed_size);1579 stb_decompress(buf_decompressed_data, (const unsigned char*)compressed_ttf_data, (unsigned int)compressed_ttf_size);1580 1581 ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();1582 IM_ASSERT(font_cfg.FontData == NULL);1583 font_cfg.FontDataOwnedByAtlas = true;1584 return AddFontFromMemoryTTF(buf_decompressed_data, (int)buf_decompressed_size, size_pixels, &font_cfg, glyph_ranges);1939 const unsigned int buf_decompressed_size = stb_decompress_length((const unsigned char*)compressed_ttf_data); 1940 unsigned char* buf_decompressed_data = (unsigned char*)IM_ALLOC(buf_decompressed_size); 1941 stb_decompress(buf_decompressed_data, (const unsigned char*)compressed_ttf_data, (unsigned int)compressed_ttf_size); 1942 1943 ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); 1944 IM_ASSERT(font_cfg.FontData == NULL); 1945 font_cfg.FontDataOwnedByAtlas = true; 1946 return AddFontFromMemoryTTF(buf_decompressed_data, (int)buf_decompressed_size, size_pixels, &font_cfg, glyph_ranges); 1585 1947 } 1586 1948 1587 1949 ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed_ttf_data_base85, float size_pixels, const ImFontConfig* font_cfg, const ImWchar* glyph_ranges) 1588 1950 { 1589 int compressed_ttf_size = (((int)strlen(compressed_ttf_data_base85) + 4) / 5) * 4; 1590 void* compressed_ttf = ImGui::MemAlloc((size_t)compressed_ttf_size); 1591 Decode85((const unsigned char*)compressed_ttf_data_base85, (unsigned char*)compressed_ttf); 1592 ImFont* font = AddFontFromMemoryCompressedTTF(compressed_ttf, compressed_ttf_size, size_pixels, font_cfg, glyph_ranges); 1593 ImGui::MemFree(compressed_ttf); 1594 return font; 1595 } 1596 1597 int ImFontAtlas::AddCustomRectRegular(unsigned int id, int width, int height) 1598 { 1599 IM_ASSERT(id >= 0x10000); 1600 IM_ASSERT(width > 0 && width <= 0xFFFF); 1601 IM_ASSERT(height > 0 && height <= 0xFFFF); 1602 CustomRect r; 1603 r.ID = id; 1604 r.Width = (unsigned short)width; 1605 r.Height = (unsigned short)height; 1606 CustomRects.push_back(r); 1607 return CustomRects.Size - 1; // Return index 1951 int compressed_ttf_size = (((int)strlen(compressed_ttf_data_base85) + 4) / 5) * 4; 1952 void* compressed_ttf = IM_ALLOC((size_t)compressed_ttf_size); 1953 Decode85((const unsigned char*)compressed_ttf_data_base85, (unsigned char*)compressed_ttf); 1954 ImFont* font = AddFontFromMemoryCompressedTTF(compressed_ttf, compressed_ttf_size, size_pixels, font_cfg, glyph_ranges); 1955 IM_FREE(compressed_ttf); 1956 return font; 1957 } 1958 1959 int ImFontAtlas::AddCustomRectRegular(int width, int height) 1960 { 1961 IM_ASSERT(width > 0 && width <= 0xFFFF); 1962 IM_ASSERT(height > 0 && height <= 0xFFFF); 1963 ImFontAtlasCustomRect r; 1964 r.Width = (unsigned short)width; 1965 r.Height = (unsigned short)height; 1966 CustomRects.push_back(r); 1967 return CustomRects.Size - 1; // Return index 1608 1968 } 1609 1969 1610 1970 int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset) 1611 1971 { 1612 IM_ASSERT(font != NULL); 1613 IM_ASSERT(width > 0 && width <= 0xFFFF); 1614 IM_ASSERT(height > 0 && height <= 0xFFFF); 1615 CustomRect r; 1616 r.ID = id; 1617 r.Width = (unsigned short)width; 1618 r.Height = (unsigned short)height; 1619 r.GlyphAdvanceX = advance_x; 1620 r.GlyphOffset = offset; 1621 r.Font = font; 1622 CustomRects.push_back(r); 1623 return CustomRects.Size - 1; // Return index 1624 } 1625 1626 void ImFontAtlas::CalcCustomRectUV(const CustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) 1627 { 1628 IM_ASSERT(TexWidth > 0 && TexHeight > 0); // Font atlas needs to be built before we can calculate UV coordinates 1629 IM_ASSERT(rect->IsPacked()); // Make sure the rectangle has been packed 1630 *out_uv_min = ImVec2((float)rect->X * TexUvScale.x, (float)rect->Y * TexUvScale.y); 1631 *out_uv_max = ImVec2((float)(rect->X + rect->Width) * TexUvScale.x, (float)(rect->Y + rect->Height) * TexUvScale.y); 1972 #ifdef IMGUI_USE_WCHAR32 1973 IM_ASSERT(id <= IM_UNICODE_CODEPOINT_MAX); 1974 #endif 1975 IM_ASSERT(font != NULL); 1976 IM_ASSERT(width > 0 && width <= 0xFFFF); 1977 IM_ASSERT(height > 0 && height <= 0xFFFF); 1978 ImFontAtlasCustomRect r; 1979 r.Width = (unsigned short)width; 1980 r.Height = (unsigned short)height; 1981 r.GlyphID = id; 1982 r.GlyphAdvanceX = advance_x; 1983 r.GlyphOffset = offset; 1984 r.Font = font; 1985 CustomRects.push_back(r); 1986 return CustomRects.Size - 1; // Return index 1987 } 1988 1989 void ImFontAtlas::CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const 1990 { 1991 IM_ASSERT(TexWidth > 0 && TexHeight > 0); // Font atlas needs to be built before we can calculate UV coordinates 1992 IM_ASSERT(rect->IsPacked()); // Make sure the rectangle has been packed 1993 *out_uv_min = ImVec2((float)rect->X * TexUvScale.x, (float)rect->Y * TexUvScale.y); 1994 *out_uv_max = ImVec2((float)(rect->X + rect->Width) * TexUvScale.x, (float)(rect->Y + rect->Height) * TexUvScale.y); 1632 1995 } 1633 1996 1634 1997 bool ImFontAtlas::GetMouseCursorTexData(ImGuiMouseCursor cursor_type, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]) 1635 1998 { 1636 if (cursor_type <= ImGuiMouseCursor_None || cursor_type >= ImGuiMouseCursor_COUNT) 1637 return false; 1638 if (Flags & ImFontAtlasFlags_NoMouseCursors) 1639 return false; 1640 1641 IM_ASSERT(CustomRectIds[0] != -1); 1642 ImFontAtlas::CustomRect& r = CustomRects[CustomRectIds[0]]; 1643 IM_ASSERT(r.ID == FONT_ATLAS_DEFAULT_TEX_DATA_ID); 1644 ImVec2 pos = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][0] + ImVec2((float)r.X, (float)r.Y); 1645 ImVec2 size = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][1]; 1646 *out_size = size; 1647 *out_offset = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][2]; 1648 out_uv_border[0] = (pos)* TexUvScale; 1649 out_uv_border[1] = (pos + size) * TexUvScale; 1650 pos.x += FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF + 1; 1651 out_uv_fill[0] = (pos)* TexUvScale; 1652 out_uv_fill[1] = (pos + size) * TexUvScale; 1653 return true; 1999 if (cursor_type <= ImGuiMouseCursor_None || cursor_type >= ImGuiMouseCursor_COUNT) 2000 return false; 2001 if (Flags & ImFontAtlasFlags_NoMouseCursors) 2002 return false; 2003 2004 IM_ASSERT(PackIdMouseCursors != -1); 2005 ImFontAtlasCustomRect* r = GetCustomRectByIndex(PackIdMouseCursors); 2006 ImVec2 pos = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][0] + ImVec2((float)r->X, (float)r->Y); 2007 ImVec2 size = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][1]; 2008 *out_size = size; 2009 *out_offset = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][2]; 2010 out_uv_border[0] = (pos) * TexUvScale; 2011 out_uv_border[1] = (pos + size) * TexUvScale; 2012 pos.x += FONT_ATLAS_DEFAULT_TEX_DATA_W + 1; 2013 out_uv_fill[0] = (pos) * TexUvScale; 2014 out_uv_fill[1] = (pos + size) * TexUvScale; 2015 return true; 1654 2016 } 1655 2017 1656 2018 bool ImFontAtlas::Build() 1657 2019 { 1658 return ImFontAtlasBuildWithStbTruetype(this); 2020 IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); 2021 return ImFontAtlasBuildWithStbTruetype(this); 1659 2022 } 1660 2023 1661 2024 void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_brighten_factor) 1662 2025 { 1663 for (unsigned int i = 0; i < 256; i++)1664 {1665 unsigned int value = (unsigned int)(i * in_brighten_factor);1666 out_table[i] = value > 255 ? 255 : (value & 0xFF);1667 }2026 for (unsigned int i = 0; i < 256; i++) 2027 { 2028 unsigned int value = (unsigned int)(i * in_brighten_factor); 2029 out_table[i] = value > 255 ? 255 : (value & 0xFF); 2030 } 1668 2031 } 1669 2032 1670 2033 void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride) 1671 2034 { 1672 unsigned char* data = pixels + x + y * stride; 1673 for (int j = h; j > 0; j--, data += stride) 1674 for (int i = 0; i < w; i++) 1675 data[i] = table[data[i]]; 2035 unsigned char* data = pixels + x + y * stride; 2036 for (int j = h; j > 0; j--, data += stride) 2037 for (int i = 0; i < w; i++) 2038 data[i] = table[data[i]]; 2039 } 2040 2041 // Temporary data for one source font (multiple source fonts can be merged into one destination ImFont) 2042 // (C++03 doesn't allow instancing ImVector<> with function-local types so we declare the type here.) 2043 struct ImFontBuildSrcData 2044 { 2045 stbtt_fontinfo FontInfo; 2046 stbtt_pack_range PackRange; // Hold the list of codepoints to pack (essentially points to Codepoints.Data) 2047 stbrp_rect* Rects; // Rectangle to pack. We first fill in their size and the packer will give us their position. 2048 stbtt_packedchar* PackedChars; // Output glyphs 2049 const ImWchar* SrcRanges; // Ranges as requested by user (user is allowed to request too much, e.g. 0x0020..0xFFFF) 2050 int DstIndex; // Index into atlas->Fonts[] and dst_tmp_array[] 2051 int GlyphsHighest; // Highest requested codepoint 2052 int GlyphsCount; // Glyph count (excluding missing glyphs and glyphs already set by an earlier source font) 2053 ImBitVector GlyphsSet; // Glyph bit map (random access, 1-bit per codepoint. This will be a maximum of 8KB) 2054 ImVector<int> GlyphsList; // Glyph codepoints list (flattened version of GlyphsMap) 2055 }; 2056 2057 // Temporary data for one destination ImFont* (multiple source fonts can be merged into one destination ImFont) 2058 struct ImFontBuildDstData 2059 { 2060 int SrcCount; // Number of source fonts targeting this destination font. 2061 int GlyphsHighest; 2062 int GlyphsCount; 2063 ImBitVector GlyphsSet; // This is used to resolve collision when multiple sources are merged into a same destination font. 2064 }; 2065 2066 static void UnpackBitVectorToFlatIndexList(const ImBitVector* in, ImVector<int>* out) 2067 { 2068 IM_ASSERT(sizeof(in->Storage.Data[0]) == sizeof(int)); 2069 const ImU32* it_begin = in->Storage.begin(); 2070 const ImU32* it_end = in->Storage.end(); 2071 for (const ImU32* it = it_begin; it < it_end; it++) 2072 if (ImU32 entries_32 = *it) 2073 for (ImU32 bit_n = 0; bit_n < 32; bit_n++) 2074 if (entries_32 & ((ImU32)1 << bit_n)) 2075 out->push_back((int)(((it - it_begin) << 5) + bit_n)); 1676 2076 } 1677 2077 1678 2078 bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) 1679 2079 { 1680 IM_ASSERT(atlas->ConfigData.Size > 0); 1681 1682 ImFontAtlasBuildRegisterDefaultCustomRects(atlas); 1683 1684 atlas->TexID = NULL; 1685 atlas->TexWidth = atlas->TexHeight = 0; 1686 atlas->TexUvScale = ImVec2(0.0f, 0.0f); 1687 atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f); 1688 atlas->ClearTexData(); 1689 1690 // Count glyphs/ranges 1691 int total_glyphs_count = 0; 1692 int total_ranges_count = 0; 1693 for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++) 1694 { 1695 ImFontConfig& cfg = atlas->ConfigData[input_i]; 1696 if (!cfg.GlyphRanges) 1697 cfg.GlyphRanges = atlas->GetGlyphRangesDefault(); 1698 for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2, total_ranges_count++) 1699 total_glyphs_count += (in_range[1] - in_range[0]) + 1; 1700 } 1701 1702 // We need a width for the skyline algorithm. Using a dumb heuristic here to decide of width. User can override TexDesiredWidth and TexGlyphPadding if they wish. 1703 // Width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height. 1704 atlas->TexWidth = (atlas->TexDesiredWidth > 0) ? atlas->TexDesiredWidth : (total_glyphs_count > 4000) ? 4096 : (total_glyphs_count > 2000) ? 2048 : (total_glyphs_count > 1000) ? 1024 : 512; 1705 atlas->TexHeight = 0; 1706 1707 // Start packing 1708 const int max_tex_height = 1024 * 32; 1709 stbtt_pack_context spc = {}; 1710 if (!stbtt_PackBegin(&spc, NULL, atlas->TexWidth, max_tex_height, 0, atlas->TexGlyphPadding, NULL)) 1711 return false; 1712 stbtt_PackSetOversampling(&spc, 1, 1); 1713 1714 // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values). 1715 ImFontAtlasBuildPackCustomRects(atlas, spc.pack_info); 1716 1717 // Initialize font information (so we can error without any cleanup) 1718 struct ImFontTempBuildData 1719 { 1720 stbtt_fontinfo FontInfo; 1721 stbrp_rect* Rects; 1722 int RectsCount; 1723 stbtt_pack_range* Ranges; 1724 int RangesCount; 1725 }; 1726 ImFontTempBuildData* tmp_array = (ImFontTempBuildData*)ImGui::MemAlloc((size_t)atlas->ConfigData.Size * sizeof(ImFontTempBuildData)); 1727 for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++) 1728 { 1729 ImFontConfig& cfg = atlas->ConfigData[input_i]; 1730 ImFontTempBuildData& tmp = tmp_array[input_i]; 1731 IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas)); 1732 1733 const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)cfg.FontData, cfg.FontNo); 1734 IM_ASSERT(font_offset >= 0 && "FontData is incorrect, or FontNo cannot be found."); 1735 if (!stbtt_InitFont(&tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset)) 1736 { 1737 atlas->TexWidth = atlas->TexHeight = 0; // Reset output on failure 1738 ImGui::MemFree(tmp_array); 1739 return false; 1740 } 1741 } 1742 1743 // Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0) 1744 int buf_packedchars_n = 0, buf_rects_n = 0, buf_ranges_n = 0; 1745 stbtt_packedchar* buf_packedchars = (stbtt_packedchar*)ImGui::MemAlloc(total_glyphs_count * sizeof(stbtt_packedchar)); 1746 stbrp_rect* buf_rects = (stbrp_rect*)ImGui::MemAlloc(total_glyphs_count * sizeof(stbrp_rect)); 1747 stbtt_pack_range* buf_ranges = (stbtt_pack_range*)ImGui::MemAlloc(total_ranges_count * sizeof(stbtt_pack_range)); 1748 memset(buf_packedchars, 0, total_glyphs_count * sizeof(stbtt_packedchar)); 1749 memset(buf_rects, 0, total_glyphs_count * sizeof(stbrp_rect)); // Unnecessary but let's clear this for the sake of sanity. 1750 memset(buf_ranges, 0, total_ranges_count * sizeof(stbtt_pack_range)); 1751 1752 // First font pass: pack all glyphs (no rendering at this point, we are working with rectangles in an infinitely tall texture at this point) 1753 for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++) 1754 { 1755 ImFontConfig& cfg = atlas->ConfigData[input_i]; 1756 ImFontTempBuildData& tmp = tmp_array[input_i]; 1757 1758 // Setup ranges 1759 int font_glyphs_count = 0; 1760 int font_ranges_count = 0; 1761 for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2, font_ranges_count++) 1762 font_glyphs_count += (in_range[1] - in_range[0]) + 1; 1763 tmp.Ranges = buf_ranges + buf_ranges_n; 1764 tmp.RangesCount = font_ranges_count; 1765 buf_ranges_n += font_ranges_count; 1766 for (int i = 0; i < font_ranges_count; i++) 1767 { 1768 const ImWchar* in_range = &cfg.GlyphRanges[i * 2]; 1769 stbtt_pack_range& range = tmp.Ranges[i]; 1770 range.font_size = cfg.SizePixels; 1771 range.first_unicode_codepoint_in_range = in_range[0]; 1772 range.num_chars = (in_range[1] - in_range[0]) + 1; 1773 range.chardata_for_range = buf_packedchars + buf_packedchars_n; 1774 buf_packedchars_n += range.num_chars; 1775 } 1776 1777 // Pack 1778 tmp.Rects = buf_rects + buf_rects_n; 1779 tmp.RectsCount = font_glyphs_count; 1780 buf_rects_n += font_glyphs_count; 1781 stbtt_PackSetOversampling(&spc, cfg.OversampleH, cfg.OversampleV); 1782 int n = stbtt_PackFontRangesGatherRects(&spc, &tmp.FontInfo, tmp.Ranges, tmp.RangesCount, tmp.Rects); 1783 IM_ASSERT(n == font_glyphs_count); 1784 stbrp_pack_rects((stbrp_context*)spc.pack_info, tmp.Rects, n); 1785 1786 // Extend texture height 1787 for (int i = 0; i < n; i++) 1788 if (tmp.Rects[i].was_packed) 1789 atlas->TexHeight = ImMax(atlas->TexHeight, tmp.Rects[i].y + tmp.Rects[i].h); 1790 } 1791 IM_ASSERT(buf_rects_n == total_glyphs_count); 1792 IM_ASSERT(buf_packedchars_n == total_glyphs_count); 1793 IM_ASSERT(buf_ranges_n == total_ranges_count); 1794 1795 // Create texture 1796 atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight); 1797 atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight); 1798 atlas->TexPixelsAlpha8 = (unsigned char*)ImGui::MemAlloc(atlas->TexWidth * atlas->TexHeight); 1799 memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight); 1800 spc.pixels = atlas->TexPixelsAlpha8; 1801 spc.height = atlas->TexHeight; 1802 1803 // Second pass: render font characters 1804 for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++) 1805 { 1806 ImFontConfig& cfg = atlas->ConfigData[input_i]; 1807 ImFontTempBuildData& tmp = tmp_array[input_i]; 1808 stbtt_PackSetOversampling(&spc, cfg.OversampleH, cfg.OversampleV); 1809 stbtt_PackFontRangesRenderIntoRects(&spc, &tmp.FontInfo, tmp.Ranges, tmp.RangesCount, tmp.Rects); 1810 if (cfg.RasterizerMultiply != 1.0f) 1811 { 1812 unsigned char multiply_table[256]; 1813 ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply); 1814 for (const stbrp_rect* r = tmp.Rects; r != tmp.Rects + tmp.RectsCount; r++) 1815 if (r->was_packed) 1816 ImFontAtlasBuildMultiplyRectAlpha8(multiply_table, spc.pixels, r->x, r->y, r->w, r->h, spc.stride_in_bytes); 1817 } 1818 tmp.Rects = NULL; 1819 } 1820 1821 // End packing 1822 stbtt_PackEnd(&spc); 1823 ImGui::MemFree(buf_rects); 1824 buf_rects = NULL; 1825 1826 // Third pass: setup ImFont and glyphs for runtime 1827 for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++) 1828 { 1829 ImFontConfig& cfg = atlas->ConfigData[input_i]; 1830 ImFontTempBuildData& tmp = tmp_array[input_i]; 1831 ImFont* dst_font = cfg.DstFont; // We can have multiple input fonts writing into a same destination font (when using MergeMode=true) 1832 if (cfg.MergeMode) 1833 dst_font->BuildLookupTable(); 1834 1835 const float font_scale = stbtt_ScaleForPixelHeight(&tmp.FontInfo, cfg.SizePixels); 1836 int unscaled_ascent, unscaled_descent, unscaled_line_gap; 1837 stbtt_GetFontVMetrics(&tmp.FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap); 1838 1839 const float ascent = ImFloor(unscaled_ascent * font_scale + ((unscaled_ascent > 0.0f) ? +1 : -1)); 1840 const float descent = ImFloor(unscaled_descent * font_scale + ((unscaled_descent > 0.0f) ? +1 : -1)); 1841 ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent); 1842 const float off_x = cfg.GlyphOffset.x; 1843 const float off_y = cfg.GlyphOffset.y + (float)(int)(dst_font->Ascent + 0.5f); 1844 1845 for (int i = 0; i < tmp.RangesCount; i++) 1846 { 1847 stbtt_pack_range& range = tmp.Ranges[i]; 1848 for (int char_idx = 0; char_idx < range.num_chars; char_idx += 1) 1849 { 1850 const stbtt_packedchar& pc = range.chardata_for_range[char_idx]; 1851 if (!pc.x0 && !pc.x1 && !pc.y0 && !pc.y1) 1852 continue; 1853 1854 const int codepoint = range.first_unicode_codepoint_in_range + char_idx; 1855 if (cfg.MergeMode && dst_font->FindGlyphNoFallback((unsigned short)codepoint)) 1856 continue; 1857 2080 IM_ASSERT(atlas->ConfigData.Size > 0); 2081 2082 ImFontAtlasBuildInit(atlas); 2083 2084 // Clear atlas 2085 atlas->TexID = (ImTextureID)NULL; 2086 atlas->TexWidth = atlas->TexHeight = 0; 2087 atlas->TexUvScale = ImVec2(0.0f, 0.0f); 2088 atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f); 2089 atlas->ClearTexData(); 2090 2091 // Temporary storage for building 2092 ImVector<ImFontBuildSrcData> src_tmp_array; 2093 ImVector<ImFontBuildDstData> dst_tmp_array; 2094 src_tmp_array.resize(atlas->ConfigData.Size); 2095 dst_tmp_array.resize(atlas->Fonts.Size); 2096 memset(src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes()); 2097 memset(dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes()); 2098 2099 // 1. Initialize font loading structure, check font data validity 2100 for (int src_i = 0; src_i < atlas->ConfigData.Size; src_i++) 2101 { 2102 ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; 2103 ImFontConfig& cfg = atlas->ConfigData[src_i]; 2104 IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas)); 2105 2106 // Find index from cfg.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices) 2107 src_tmp.DstIndex = -1; 2108 for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++) 2109 if (cfg.DstFont == atlas->Fonts[output_i]) 2110 src_tmp.DstIndex = output_i; 2111 IM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array? 2112 if (src_tmp.DstIndex == -1) 2113 return false; 2114 2115 // Initialize helper structure for font loading and verify that the TTF/OTF data is correct 2116 const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)cfg.FontData, cfg.FontNo); 2117 IM_ASSERT(font_offset >= 0 && "FontData is incorrect, or FontNo cannot be found."); 2118 if (!stbtt_InitFont(&src_tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset)) 2119 return false; 2120 2121 // Measure highest codepoints 2122 ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; 2123 src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault(); 2124 for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) 2125 src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]); 2126 dst_tmp.SrcCount++; 2127 dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest); 2128 } 2129 2130 // 2. For every requested codepoint, check for their presence in the font data, and handle redundancy or overlaps between source fonts to avoid unused glyphs. 2131 int total_glyphs_count = 0; 2132 for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) 2133 { 2134 ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; 2135 ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; 2136 src_tmp.GlyphsSet.Create(src_tmp.GlyphsHighest + 1); 2137 if (dst_tmp.GlyphsSet.Storage.empty()) 2138 dst_tmp.GlyphsSet.Create(dst_tmp.GlyphsHighest + 1); 2139 2140 for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) 2141 for (unsigned int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++) 2142 { 2143 if (dst_tmp.GlyphsSet.TestBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option for MergeMode (e.g. MergeOverwrite==true) 2144 continue; 2145 if (!stbtt_FindGlyphIndex(&src_tmp.FontInfo, codepoint)) // It is actually in the font? 2146 continue; 2147 2148 // Add to avail set/counters 2149 src_tmp.GlyphsCount++; 2150 dst_tmp.GlyphsCount++; 2151 src_tmp.GlyphsSet.SetBit(codepoint); 2152 dst_tmp.GlyphsSet.SetBit(codepoint); 2153 total_glyphs_count++; 2154 } 2155 } 2156 2157 // 3. Unpack our bit map into a flat list (we now have all the Unicode points that we know are requested _and_ available _and_ not overlapping another) 2158 for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) 2159 { 2160 ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; 2161 src_tmp.GlyphsList.reserve(src_tmp.GlyphsCount); 2162 UnpackBitVectorToFlatIndexList(&src_tmp.GlyphsSet, &src_tmp.GlyphsList); 2163 src_tmp.GlyphsSet.Clear(); 2164 IM_ASSERT(src_tmp.GlyphsList.Size == src_tmp.GlyphsCount); 2165 } 2166 for (int dst_i = 0; dst_i < dst_tmp_array.Size; dst_i++) 2167 dst_tmp_array[dst_i].GlyphsSet.Clear(); 2168 dst_tmp_array.clear(); 2169 2170 // Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0) 2171 // (We technically don't need to zero-clear buf_rects, but let's do it for the sake of sanity) 2172 ImVector<stbrp_rect> buf_rects; 2173 ImVector<stbtt_packedchar> buf_packedchars; 2174 buf_rects.resize(total_glyphs_count); 2175 buf_packedchars.resize(total_glyphs_count); 2176 memset(buf_rects.Data, 0, (size_t)buf_rects.size_in_bytes()); 2177 memset(buf_packedchars.Data, 0, (size_t)buf_packedchars.size_in_bytes()); 2178 2179 // 4. Gather glyphs sizes so we can pack them in our virtual canvas. 2180 int total_surface = 0; 2181 int buf_rects_out_n = 0; 2182 int buf_packedchars_out_n = 0; 2183 for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) 2184 { 2185 ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; 2186 if (src_tmp.GlyphsCount == 0) 2187 continue; 2188 2189 src_tmp.Rects = &buf_rects[buf_rects_out_n]; 2190 src_tmp.PackedChars = &buf_packedchars[buf_packedchars_out_n]; 2191 buf_rects_out_n += src_tmp.GlyphsCount; 2192 buf_packedchars_out_n += src_tmp.GlyphsCount; 2193 2194 // Convert our ranges in the format stb_truetype wants 2195 ImFontConfig& cfg = atlas->ConfigData[src_i]; 2196 src_tmp.PackRange.font_size = cfg.SizePixels; 2197 src_tmp.PackRange.first_unicode_codepoint_in_range = 0; 2198 src_tmp.PackRange.array_of_unicode_codepoints = src_tmp.GlyphsList.Data; 2199 src_tmp.PackRange.num_chars = src_tmp.GlyphsList.Size; 2200 src_tmp.PackRange.chardata_for_range = src_tmp.PackedChars; 2201 src_tmp.PackRange.h_oversample = (unsigned char)cfg.OversampleH; 2202 src_tmp.PackRange.v_oversample = (unsigned char)cfg.OversampleV; 2203 2204 // Gather the sizes of all rectangles we will need to pack (this loop is based on stbtt_PackFontRangesGatherRects) 2205 const float scale = (cfg.SizePixels > 0) ? stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels) : stbtt_ScaleForMappingEmToPixels(&src_tmp.FontInfo, -cfg.SizePixels); 2206 const int padding = atlas->TexGlyphPadding; 2207 for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++) 2208 { 2209 int x0, y0, x1, y1; 2210 const int glyph_index_in_font = stbtt_FindGlyphIndex(&src_tmp.FontInfo, src_tmp.GlyphsList[glyph_i]); 2211 IM_ASSERT(glyph_index_in_font != 0); 2212 stbtt_GetGlyphBitmapBoxSubpixel(&src_tmp.FontInfo, glyph_index_in_font, scale * cfg.OversampleH, scale * cfg.OversampleV, 0, 0, &x0, &y0, &x1, &y1); 2213 src_tmp.Rects[glyph_i].w = (stbrp_coord)(x1 - x0 + padding + cfg.OversampleH - 1); 2214 src_tmp.Rects[glyph_i].h = (stbrp_coord)(y1 - y0 + padding + cfg.OversampleV - 1); 2215 total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h; 2216 } 2217 } 2218 2219 // We need a width for the skyline algorithm, any width! 2220 // The exact width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height. 2221 // User can override TexDesiredWidth and TexGlyphPadding if they wish, otherwise we use a simple heuristic to select the width based on expected surface. 2222 const int surface_sqrt = (int)ImSqrt((float)total_surface) + 1; 2223 atlas->TexHeight = 0; 2224 if (atlas->TexDesiredWidth > 0) 2225 atlas->TexWidth = atlas->TexDesiredWidth; 2226 else 2227 atlas->TexWidth = (surface_sqrt >= 4096 * 0.7f) ? 4096 : (surface_sqrt >= 2048 * 0.7f) ? 2048 : (surface_sqrt >= 1024 * 0.7f) ? 1024 : 512; 2228 2229 // 5. Start packing 2230 // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values). 2231 const int TEX_HEIGHT_MAX = 1024 * 32; 2232 stbtt_pack_context spc = {}; 2233 stbtt_PackBegin(&spc, NULL, atlas->TexWidth, TEX_HEIGHT_MAX, 0, atlas->TexGlyphPadding, NULL); 2234 ImFontAtlasBuildPackCustomRects(atlas, spc.pack_info); 2235 2236 // 6. Pack each source font. No rendering yet, we are working with rectangles in an infinitely tall texture at this point. 2237 for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) 2238 { 2239 ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; 2240 if (src_tmp.GlyphsCount == 0) 2241 continue; 2242 2243 stbrp_pack_rects((stbrp_context*)spc.pack_info, src_tmp.Rects, src_tmp.GlyphsCount); 2244 2245 // Extend texture height and mark missing glyphs as non-packed so we won't render them. 2246 // FIXME: We are not handling packing failure here (would happen if we got off TEX_HEIGHT_MAX or if a single if larger than TexWidth?) 2247 for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++) 2248 if (src_tmp.Rects[glyph_i].was_packed) 2249 atlas->TexHeight = ImMax(atlas->TexHeight, src_tmp.Rects[glyph_i].y + src_tmp.Rects[glyph_i].h); 2250 } 2251 2252 // 7. Allocate texture 2253 atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight); 2254 atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight); 2255 atlas->TexPixelsAlpha8 = (unsigned char*)IM_ALLOC(atlas->TexWidth * atlas->TexHeight); 2256 memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight); 2257 spc.pixels = atlas->TexPixelsAlpha8; 2258 spc.height = atlas->TexHeight; 2259 2260 // 8. Render/rasterize font characters into the texture 2261 for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) 2262 { 2263 ImFontConfig& cfg = atlas->ConfigData[src_i]; 2264 ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; 2265 if (src_tmp.GlyphsCount == 0) 2266 continue; 2267 2268 stbtt_PackFontRangesRenderIntoRects(&spc, &src_tmp.FontInfo, &src_tmp.PackRange, 1, src_tmp.Rects); 2269 2270 // Apply multiply operator 2271 if (cfg.RasterizerMultiply != 1.0f) 2272 { 2273 unsigned char multiply_table[256]; 2274 ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply); 2275 stbrp_rect* r = &src_tmp.Rects[0]; 2276 for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++, r++) 2277 if (r->was_packed) 2278 ImFontAtlasBuildMultiplyRectAlpha8(multiply_table, atlas->TexPixelsAlpha8, r->x, r->y, r->w, r->h, atlas->TexWidth * 1); 2279 } 2280 src_tmp.Rects = NULL; 2281 } 2282 2283 // End packing 2284 stbtt_PackEnd(&spc); 2285 buf_rects.clear(); 2286 2287 // 9. Setup ImFont and glyphs for runtime 2288 for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) 2289 { 2290 ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; 2291 if (src_tmp.GlyphsCount == 0) 2292 continue; 2293 2294 // When merging fonts with MergeMode=true: 2295 // - We can have multiple input fonts writing into a same destination font. 2296 // - dst_font->ConfigData is != from cfg which is our source configuration. 2297 ImFontConfig& cfg = atlas->ConfigData[src_i]; 2298 ImFont* dst_font = cfg.DstFont; 2299 2300 const float font_scale = stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels); 2301 int unscaled_ascent, unscaled_descent, unscaled_line_gap; 2302 stbtt_GetFontVMetrics(&src_tmp.FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap); 2303 2304 const float ascent = ImFloor(unscaled_ascent * font_scale + ((unscaled_ascent > 0.0f) ? +1 : -1)); 2305 const float descent = ImFloor(unscaled_descent * font_scale + ((unscaled_descent > 0.0f) ? +1 : -1)); 2306 ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent); 2307 const float font_off_x = cfg.GlyphOffset.x; 2308 const float font_off_y = cfg.GlyphOffset.y + IM_ROUND(dst_font->Ascent); 2309 2310 for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++) 2311 { 2312 // Register glyph 2313 const int codepoint = src_tmp.GlyphsList[glyph_i]; 2314 const stbtt_packedchar& pc = src_tmp.PackedChars[glyph_i]; 1858 2315 stbtt_aligned_quad q; 1859 float dummy_x = 0.0f, dummy_y = 0.0f; 1860 stbtt_GetPackedQuad(range.chardata_for_range, atlas->TexWidth, atlas->TexHeight, char_idx, &dummy_x, &dummy_y, &q, 0); 1861 dst_font->AddGlyph((ImWchar)codepoint, q.x0 + off_x, q.y0 + off_y, q.x1 + off_x, q.y1 + off_y, q.s0, q.t0, q.s1, q.t1, pc.xadvance); 1862 } 1863 } 1864 } 1865 1866 // Cleanup temporaries 1867 ImGui::MemFree(buf_packedchars); 1868 ImGui::MemFree(buf_ranges); 1869 ImGui::MemFree(tmp_array); 1870 1871 ImFontAtlasBuildFinish(atlas); 1872 1873 return true; 1874 } 1875 1876 void ImFontAtlasBuildRegisterDefaultCustomRects(ImFontAtlas* atlas) 1877 { 1878 if (atlas->CustomRectIds[0] >= 0) 1879 return; 1880 if (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors)) 1881 atlas->CustomRectIds[0] = atlas->AddCustomRectRegular(FONT_ATLAS_DEFAULT_TEX_DATA_ID, FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF * 2 + 1, FONT_ATLAS_DEFAULT_TEX_DATA_H); 1882 else 1883 atlas->CustomRectIds[0] = atlas->AddCustomRectRegular(FONT_ATLAS_DEFAULT_TEX_DATA_ID, 2, 2); 2316 float unused_x = 0.0f, unused_y = 0.0f; 2317 stbtt_GetPackedQuad(src_tmp.PackedChars, atlas->TexWidth, atlas->TexHeight, glyph_i, &unused_x, &unused_y, &q, 0); 2318 dst_font->AddGlyph(&cfg, (ImWchar)codepoint, q.x0 + font_off_x, q.y0 + font_off_y, q.x1 + font_off_x, q.y1 + font_off_y, q.s0, q.t0, q.s1, q.t1, pc.xadvance); 2319 } 2320 } 2321 2322 // Cleanup temporary (ImVector doesn't honor destructor) 2323 for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) 2324 src_tmp_array[src_i].~ImFontBuildSrcData(); 2325 2326 ImFontAtlasBuildFinish(atlas); 2327 return true; 1884 2328 } 1885 2329 1886 2330 void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent) 1887 2331 { 1888 if (!font_config->MergeMode) 1889 { 1890 font->ClearOutputData(); 1891 font->FontSize = font_config->SizePixels; 1892 font->ConfigData = font_config; 1893 font->ContainerAtlas = atlas; 1894 font->Ascent = ascent; 1895 font->Descent = descent; 1896 } 1897 font->ConfigDataCount++; 1898 } 1899 1900 void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* pack_context_opaque) 1901 { 1902 stbrp_context* pack_context = (stbrp_context*)pack_context_opaque; 1903 1904 ImVector<ImFontAtlas::CustomRect>& user_rects = atlas->CustomRects; 1905 IM_ASSERT(user_rects.Size >= 1); // We expect at least the default custom rects to be registered, else something went wrong. 1906 1907 ImVector<stbrp_rect> pack_rects; 1908 pack_rects.resize(user_rects.Size); 1909 memset(pack_rects.Data, 0, sizeof(stbrp_rect) * user_rects.Size); 1910 for (int i = 0; i < user_rects.Size; i++) 1911 { 1912 pack_rects[i].w = user_rects[i].Width; 1913 pack_rects[i].h = user_rects[i].Height; 1914 } 1915 stbrp_pack_rects(pack_context, &pack_rects[0], pack_rects.Size); 1916 for (int i = 0; i < pack_rects.Size; i++) 1917 if (pack_rects[i].was_packed) 1918 { 1919 user_rects[i].X = pack_rects[i].x; 1920 user_rects[i].Y = pack_rects[i].y; 1921 IM_ASSERT(pack_rects[i].w == user_rects[i].Width && pack_rects[i].h == user_rects[i].Height); 1922 atlas->TexHeight = ImMax(atlas->TexHeight, pack_rects[i].y + pack_rects[i].h); 1923 } 2332 if (!font_config->MergeMode) 2333 { 2334 font->ClearOutputData(); 2335 font->FontSize = font_config->SizePixels; 2336 font->ConfigData = font_config; 2337 font->ConfigDataCount = 0; 2338 font->ContainerAtlas = atlas; 2339 font->Ascent = ascent; 2340 font->Descent = descent; 2341 } 2342 font->ConfigDataCount++; 2343 } 2344 2345 void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque) 2346 { 2347 stbrp_context* pack_context = (stbrp_context*)stbrp_context_opaque; 2348 IM_ASSERT(pack_context != NULL); 2349 2350 ImVector<ImFontAtlasCustomRect>& user_rects = atlas->CustomRects; 2351 IM_ASSERT(user_rects.Size >= 1); // We expect at least the default custom rects to be registered, else something went wrong. 2352 2353 ImVector<stbrp_rect> pack_rects; 2354 pack_rects.resize(user_rects.Size); 2355 memset(pack_rects.Data, 0, (size_t)pack_rects.size_in_bytes()); 2356 for (int i = 0; i < user_rects.Size; i++) 2357 { 2358 pack_rects[i].w = user_rects[i].Width; 2359 pack_rects[i].h = user_rects[i].Height; 2360 } 2361 stbrp_pack_rects(pack_context, &pack_rects[0], pack_rects.Size); 2362 for (int i = 0; i < pack_rects.Size; i++) 2363 if (pack_rects[i].was_packed) 2364 { 2365 user_rects[i].X = pack_rects[i].x; 2366 user_rects[i].Y = pack_rects[i].y; 2367 IM_ASSERT(pack_rects[i].w == user_rects[i].Width && pack_rects[i].h == user_rects[i].Height); 2368 atlas->TexHeight = ImMax(atlas->TexHeight, pack_rects[i].y + pack_rects[i].h); 2369 } 2370 } 2371 2372 void ImFontAtlasBuildRender1bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned char in_marker_pixel_value) 2373 { 2374 IM_ASSERT(x >= 0 && x + w <= atlas->TexWidth); 2375 IM_ASSERT(y >= 0 && y + h <= atlas->TexHeight); 2376 unsigned char* out_pixel = atlas->TexPixelsAlpha8 + x + (y * atlas->TexWidth); 2377 for (int off_y = 0; off_y < h; off_y++, out_pixel += atlas->TexWidth, in_str += w) 2378 for (int off_x = 0; off_x < w; off_x++) 2379 out_pixel[off_x] = (in_str[off_x] == in_marker_char) ? in_marker_pixel_value : 0x00; 1924 2380 } 1925 2381 1926 2382 static void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas) 1927 2383 { 1928 IM_ASSERT(atlas->CustomRectIds[0] >= 0); 1929 IM_ASSERT(atlas->TexPixelsAlpha8 != NULL); 1930 ImFontAtlas::CustomRect& r = atlas->CustomRects[atlas->CustomRectIds[0]]; 1931 IM_ASSERT(r.ID == FONT_ATLAS_DEFAULT_TEX_DATA_ID); 1932 IM_ASSERT(r.IsPacked()); 1933 1934 const int w = atlas->TexWidth; 1935 if (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors)) 1936 { 1937 // Render/copy pixels 1938 IM_ASSERT(r.Width == FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF * 2 + 1 && r.Height == FONT_ATLAS_DEFAULT_TEX_DATA_H); 1939 for (int y = 0, n = 0; y < FONT_ATLAS_DEFAULT_TEX_DATA_H; y++) 1940 for (int x = 0; x < FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF; x++, n++) 1941 { 1942 const int offset0 = (int)(r.X + x) + (int)(r.Y + y) * w; 1943 const int offset1 = offset0 + FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF + 1; 1944 atlas->TexPixelsAlpha8[offset0] = FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[n] == '.' ? 0xFF : 0x00; 1945 atlas->TexPixelsAlpha8[offset1] = FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[n] == 'X' ? 0xFF : 0x00; 1946 } 1947 } 1948 else 1949 { 1950 IM_ASSERT(r.Width == 2 && r.Height == 2); 1951 const int offset = (int)(r.X) + (int)(r.Y) * w; 1952 atlas->TexPixelsAlpha8[offset] = atlas->TexPixelsAlpha8[offset + 1] = atlas->TexPixelsAlpha8[offset + w] = atlas->TexPixelsAlpha8[offset + w + 1] = 0xFF; 1953 } 1954 atlas->TexUvWhitePixel = ImVec2((r.X + 0.5f) * atlas->TexUvScale.x, (r.Y + 0.5f) * atlas->TexUvScale.y); 1955 } 1956 2384 ImFontAtlasCustomRect* r = atlas->GetCustomRectByIndex(atlas->PackIdMouseCursors); 2385 IM_ASSERT(r->IsPacked()); 2386 2387 const int w = atlas->TexWidth; 2388 if (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors)) 2389 { 2390 // Render/copy pixels 2391 IM_ASSERT(r->Width == FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1 && r->Height == FONT_ATLAS_DEFAULT_TEX_DATA_H); 2392 const int x_for_white = r->X; 2393 const int x_for_black = r->X + FONT_ATLAS_DEFAULT_TEX_DATA_W + 1; 2394 ImFontAtlasBuildRender1bppRectFromString(atlas, x_for_white, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.', 0xFF); 2395 ImFontAtlasBuildRender1bppRectFromString(atlas, x_for_black, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X', 0xFF); 2396 } 2397 else 2398 { 2399 // Render 4 white pixels 2400 IM_ASSERT(r->Width == 2 && r->Height == 2); 2401 const int offset = (int)r->X + (int)r->Y * w; 2402 atlas->TexPixelsAlpha8[offset] = atlas->TexPixelsAlpha8[offset + 1] = atlas->TexPixelsAlpha8[offset + w] = atlas->TexPixelsAlpha8[offset + w + 1] = 0xFF; 2403 } 2404 atlas->TexUvWhitePixel = ImVec2((r->X + 0.5f) * atlas->TexUvScale.x, (r->Y + 0.5f) * atlas->TexUvScale.y); 2405 } 2406 2407 static void ImFontAtlasBuildRenderLinesTexData(ImFontAtlas* atlas) 2408 { 2409 if (atlas->Flags & ImFontAtlasFlags_NoBakedLines) 2410 return; 2411 2412 // This generates a triangular shape in the texture, with the various line widths stacked on top of each other to allow interpolation between them 2413 ImFontAtlasCustomRect* r = atlas->GetCustomRectByIndex(atlas->PackIdLines); 2414 IM_ASSERT(r->IsPacked()); 2415 for (unsigned int n = 0; n < IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1; n++) // +1 because of the zero-width row 2416 { 2417 // Each line consists of at least two empty pixels at the ends, with a line of solid pixels in the middle 2418 unsigned int y = n; 2419 unsigned int line_width = n; 2420 unsigned int pad_left = (r->Width - line_width) / 2; 2421 unsigned int pad_right = r->Width - (pad_left + line_width); 2422 2423 // Write each slice 2424 IM_ASSERT(pad_left + line_width + pad_right == r->Width && y < r->Height); // Make sure we're inside the texture bounds before we start writing pixels 2425 unsigned char* write_ptr = &atlas->TexPixelsAlpha8[r->X + ((r->Y + y) * atlas->TexWidth)]; 2426 memset(write_ptr, 0x00, pad_left); 2427 memset(write_ptr + pad_left, 0xFF, line_width); 2428 memset(write_ptr + pad_left + line_width, 0x00, pad_right); 2429 2430 // Calculate UVs for this line 2431 ImVec2 uv0 = ImVec2((float)(r->X + pad_left - 1), (float)(r->Y + y)) * atlas->TexUvScale; 2432 ImVec2 uv1 = ImVec2((float)(r->X + pad_left + line_width + 1), (float)(r->Y + y + 1)) * atlas->TexUvScale; 2433 float half_v = (uv0.y + uv1.y) * 0.5f; // Calculate a constant V in the middle of the row to avoid sampling artifacts 2434 atlas->TexUvLines[n] = ImVec4(uv0.x, half_v, uv1.x, half_v); 2435 } 2436 } 2437 2438 // Note: this is called / shared by both the stb_truetype and the FreeType builder 2439 void ImFontAtlasBuildInit(ImFontAtlas* atlas) 2440 { 2441 // Register texture region for mouse cursors or standard white pixels 2442 if (atlas->PackIdMouseCursors < 0) 2443 { 2444 if (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors)) 2445 atlas->PackIdMouseCursors = atlas->AddCustomRectRegular(FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1, FONT_ATLAS_DEFAULT_TEX_DATA_H); 2446 else 2447 atlas->PackIdMouseCursors = atlas->AddCustomRectRegular(2, 2); 2448 } 2449 2450 // Register texture region for thick lines 2451 // The +2 here is to give space for the end caps, whilst height +1 is to accommodate the fact we have a zero-width row 2452 if (atlas->PackIdLines < 0) 2453 { 2454 if (!(atlas->Flags & ImFontAtlasFlags_NoBakedLines)) 2455 atlas->PackIdLines = atlas->AddCustomRectRegular(IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 2, IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1); 2456 } 2457 } 2458 2459 // This is called/shared by both the stb_truetype and the FreeType builder. 1957 2460 void ImFontAtlasBuildFinish(ImFontAtlas* atlas) 1958 2461 { 1959 // Render into our custom data block 1960 ImFontAtlasBuildRenderDefaultTexData(atlas); 1961 1962 // Register custom rectangle glyphs 1963 for (int i = 0; i < atlas->CustomRects.Size; i++) 1964 { 1965 const ImFontAtlas::CustomRect& r = atlas->CustomRects[i]; 1966 if (r.Font == NULL || r.ID > 0x10000) 1967 continue; 1968 1969 IM_ASSERT(r.Font->ContainerAtlas == atlas); 1970 ImVec2 uv0, uv1; 1971 atlas->CalcCustomRectUV(&r, &uv0, &uv1); 1972 r.Font->AddGlyph((ImWchar)r.ID, r.GlyphOffset.x, r.GlyphOffset.y, r.GlyphOffset.x + r.Width, r.GlyphOffset.y + r.Height, uv0.x, uv0.y, uv1.x, uv1.y, r.GlyphAdvanceX); 1973 } 1974 1975 // Build all fonts lookup tables 1976 for (int i = 0; i < atlas->Fonts.Size; i++) 1977 if (atlas->Fonts[i]->DirtyLookupTables) 1978 atlas->Fonts[i]->BuildLookupTable(); 2462 // Render into our custom data blocks 2463 IM_ASSERT(atlas->TexPixelsAlpha8 != NULL); 2464 ImFontAtlasBuildRenderDefaultTexData(atlas); 2465 ImFontAtlasBuildRenderLinesTexData(atlas); 2466 2467 // Register custom rectangle glyphs 2468 for (int i = 0; i < atlas->CustomRects.Size; i++) 2469 { 2470 const ImFontAtlasCustomRect* r = &atlas->CustomRects[i]; 2471 if (r->Font == NULL || r->GlyphID == 0) 2472 continue; 2473 2474 // Will ignore ImFontConfig settings: GlyphMinAdvanceX, GlyphMinAdvanceY, GlyphExtraSpacing, PixelSnapH 2475 IM_ASSERT(r->Font->ContainerAtlas == atlas); 2476 ImVec2 uv0, uv1; 2477 atlas->CalcCustomRectUV(r, &uv0, &uv1); 2478 r->Font->AddGlyph(NULL, (ImWchar)r->GlyphID, r->GlyphOffset.x, r->GlyphOffset.y, r->GlyphOffset.x + r->Width, r->GlyphOffset.y + r->Height, uv0.x, uv0.y, uv1.x, uv1.y, r->GlyphAdvanceX); 2479 } 2480 2481 // Build all fonts lookup tables 2482 for (int i = 0; i < atlas->Fonts.Size; i++) 2483 if (atlas->Fonts[i]->DirtyLookupTables) 2484 atlas->Fonts[i]->BuildLookupTable(); 2485 2486 // Ellipsis character is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis). 2487 // However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character. 2488 // FIXME: Also note that 0x2026 is currently seldom included in our font ranges. Because of this we are more likely to use three individual dots. 2489 for (int i = 0; i < atlas->Fonts.size(); i++) 2490 { 2491 ImFont* font = atlas->Fonts[i]; 2492 if (font->EllipsisChar != (ImWchar)-1) 2493 continue; 2494 const ImWchar ellipsis_variants[] = { (ImWchar)0x2026, (ImWchar)0x0085 }; 2495 for (int j = 0; j < IM_ARRAYSIZE(ellipsis_variants); j++) 2496 if (font->FindGlyphNoFallback(ellipsis_variants[j]) != NULL) // Verify glyph exists 2497 { 2498 font->EllipsisChar = ellipsis_variants[j]; 2499 break; 2500 } 2501 } 1979 2502 } 1980 2503 … … 1982 2505 const ImWchar* ImFontAtlas::GetGlyphRangesDefault() 1983 2506 { 1984 static const ImWchar ranges[] =1985 {1986 0x0020, 0x00FF, // Basic Latin + Latin Supplement1987 0,1988 };1989 return &ranges[0];2507 static const ImWchar ranges[] = 2508 { 2509 0x0020, 0x00FF, // Basic Latin + Latin Supplement 2510 0, 2511 }; 2512 return &ranges[0]; 1990 2513 } 1991 2514 1992 2515 const ImWchar* ImFontAtlas::GetGlyphRangesKorean() 1993 2516 { 1994 static const ImWchar ranges[] = 1995 { 1996 0x0020, 0x00FF, // Basic Latin + Latin Supplement 1997 0x3131, 0x3163, // Korean alphabets 1998 0xAC00, 0xD79D, // Korean characters 1999 0, 2000 }; 2001 return &ranges[0]; 2002 } 2003 2004 const ImWchar* ImFontAtlas::GetGlyphRangesChinese() 2005 { 2006 static const ImWchar ranges[] = 2007 { 2008 0x0020, 0x00FF, // Basic Latin + Latin Supplement 2009 0x3000, 0x30FF, // Punctuations, Hiragana, Katakana 2010 0x31F0, 0x31FF, // Katakana Phonetic Extensions 2011 0xFF00, 0xFFEF, // Half-width characters 2012 0x4e00, 0x9FAF, // CJK Ideograms 2013 0, 2014 }; 2015 return &ranges[0]; 2517 static const ImWchar ranges[] = 2518 { 2519 0x0020, 0x00FF, // Basic Latin + Latin Supplement 2520 0x3131, 0x3163, // Korean alphabets 2521 0xAC00, 0xD7A3, // Korean characters 2522 0, 2523 }; 2524 return &ranges[0]; 2525 } 2526 2527 const ImWchar* ImFontAtlas::GetGlyphRangesChineseFull() 2528 { 2529 static const ImWchar ranges[] = 2530 { 2531 0x0020, 0x00FF, // Basic Latin + Latin Supplement 2532 0x2000, 0x206F, // General Punctuation 2533 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana 2534 0x31F0, 0x31FF, // Katakana Phonetic Extensions 2535 0xFF00, 0xFFEF, // Half-width characters 2536 0x4e00, 0x9FAF, // CJK Ideograms 2537 0, 2538 }; 2539 return &ranges[0]; 2540 } 2541 2542 static void UnpackAccumulativeOffsetsIntoRanges(int base_codepoint, const short* accumulative_offsets, int accumulative_offsets_count, ImWchar* out_ranges) 2543 { 2544 for (int n = 0; n < accumulative_offsets_count; n++, out_ranges += 2) 2545 { 2546 out_ranges[0] = out_ranges[1] = (ImWchar)(base_codepoint + accumulative_offsets[n]); 2547 base_codepoint += accumulative_offsets[n]; 2548 } 2549 out_ranges[0] = 0; 2550 } 2551 2552 //------------------------------------------------------------------------- 2553 // [SECTION] ImFontAtlas glyph ranges helpers 2554 //------------------------------------------------------------------------- 2555 2556 const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon() 2557 { 2558 // Store 2500 regularly used characters for Simplified Chinese. 2559 // Sourced from https://zh.wiktionary.org/wiki/%E9%99%84%E5%BD%95:%E7%8E%B0%E4%BB%A3%E6%B1%89%E8%AF%AD%E5%B8%B8%E7%94%A8%E5%AD%97%E8%A1%A8 2560 // This table covers 97.97% of all characters used during the month in July, 1987. 2561 // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters. 2562 // (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.) 2563 static const short accumulative_offsets_from_0x4E00[] = 2564 { 2565 0,1,2,4,1,1,1,1,2,1,3,2,1,2,2,1,1,1,1,1,5,2,1,2,3,3,3,2,2,4,1,1,1,2,1,5,2,3,1,2,1,2,1,1,2,1,1,2,2,1,4,1,1,1,1,5,10,1,2,19,2,1,2,1,2,1,2,1,2, 2566 1,5,1,6,3,2,1,2,2,1,1,1,4,8,5,1,1,4,1,1,3,1,2,1,5,1,2,1,1,1,10,1,1,5,2,4,6,1,4,2,2,2,12,2,1,1,6,1,1,1,4,1,1,4,6,5,1,4,2,2,4,10,7,1,1,4,2,4, 2567 2,1,4,3,6,10,12,5,7,2,14,2,9,1,1,6,7,10,4,7,13,1,5,4,8,4,1,1,2,28,5,6,1,1,5,2,5,20,2,2,9,8,11,2,9,17,1,8,6,8,27,4,6,9,20,11,27,6,68,2,2,1,1, 2568 1,2,1,2,2,7,6,11,3,3,1,1,3,1,2,1,1,1,1,1,3,1,1,8,3,4,1,5,7,2,1,4,4,8,4,2,1,2,1,1,4,5,6,3,6,2,12,3,1,3,9,2,4,3,4,1,5,3,3,1,3,7,1,5,1,1,1,1,2, 2569 3,4,5,2,3,2,6,1,1,2,1,7,1,7,3,4,5,15,2,2,1,5,3,22,19,2,1,1,1,1,2,5,1,1,1,6,1,1,12,8,2,9,18,22,4,1,1,5,1,16,1,2,7,10,15,1,1,6,2,4,1,2,4,1,6, 2570 1,1,3,2,4,1,6,4,5,1,2,1,1,2,1,10,3,1,3,2,1,9,3,2,5,7,2,19,4,3,6,1,1,1,1,1,4,3,2,1,1,1,2,5,3,1,1,1,2,2,1,1,2,1,1,2,1,3,1,1,1,3,7,1,4,1,1,2,1, 2571 1,2,1,2,4,4,3,8,1,1,1,2,1,3,5,1,3,1,3,4,6,2,2,14,4,6,6,11,9,1,15,3,1,28,5,2,5,5,3,1,3,4,5,4,6,14,3,2,3,5,21,2,7,20,10,1,2,19,2,4,28,28,2,3, 2572 2,1,14,4,1,26,28,42,12,40,3,52,79,5,14,17,3,2,2,11,3,4,6,3,1,8,2,23,4,5,8,10,4,2,7,3,5,1,1,6,3,1,2,2,2,5,28,1,1,7,7,20,5,3,29,3,17,26,1,8,4, 2573 27,3,6,11,23,5,3,4,6,13,24,16,6,5,10,25,35,7,3,2,3,3,14,3,6,2,6,1,4,2,3,8,2,1,1,3,3,3,4,1,1,13,2,2,4,5,2,1,14,14,1,2,2,1,4,5,2,3,1,14,3,12, 2574 3,17,2,16,5,1,2,1,8,9,3,19,4,2,2,4,17,25,21,20,28,75,1,10,29,103,4,1,2,1,1,4,2,4,1,2,3,24,2,2,2,1,1,2,1,3,8,1,1,1,2,1,1,3,1,1,1,6,1,5,3,1,1, 2575 1,3,4,1,1,5,2,1,5,6,13,9,16,1,1,1,1,3,2,3,2,4,5,2,5,2,2,3,7,13,7,2,2,1,1,1,1,2,3,3,2,1,6,4,9,2,1,14,2,14,2,1,18,3,4,14,4,11,41,15,23,15,23, 2576 176,1,3,4,1,1,1,1,5,3,1,2,3,7,3,1,1,2,1,2,4,4,6,2,4,1,9,7,1,10,5,8,16,29,1,1,2,2,3,1,3,5,2,4,5,4,1,1,2,2,3,3,7,1,6,10,1,17,1,44,4,6,2,1,1,6, 2577 5,4,2,10,1,6,9,2,8,1,24,1,2,13,7,8,8,2,1,4,1,3,1,3,3,5,2,5,10,9,4,9,12,2,1,6,1,10,1,1,7,7,4,10,8,3,1,13,4,3,1,6,1,3,5,2,1,2,17,16,5,2,16,6, 2578 1,4,2,1,3,3,6,8,5,11,11,1,3,3,2,4,6,10,9,5,7,4,7,4,7,1,1,4,2,1,3,6,8,7,1,6,11,5,5,3,24,9,4,2,7,13,5,1,8,82,16,61,1,1,1,4,2,2,16,10,3,8,1,1, 2579 6,4,2,1,3,1,1,1,4,3,8,4,2,2,1,1,1,1,1,6,3,5,1,1,4,6,9,2,1,1,1,2,1,7,2,1,6,1,5,4,4,3,1,8,1,3,3,1,3,2,2,2,2,3,1,6,1,2,1,2,1,3,7,1,8,2,1,2,1,5, 2580 2,5,3,5,10,1,2,1,1,3,2,5,11,3,9,3,5,1,1,5,9,1,2,1,5,7,9,9,8,1,3,3,3,6,8,2,3,2,1,1,32,6,1,2,15,9,3,7,13,1,3,10,13,2,14,1,13,10,2,1,3,10,4,15, 2581 2,15,15,10,1,3,9,6,9,32,25,26,47,7,3,2,3,1,6,3,4,3,2,8,5,4,1,9,4,2,2,19,10,6,2,3,8,1,2,2,4,2,1,9,4,4,4,6,4,8,9,2,3,1,1,1,1,3,5,5,1,3,8,4,6, 2582 2,1,4,12,1,5,3,7,13,2,5,8,1,6,1,2,5,14,6,1,5,2,4,8,15,5,1,23,6,62,2,10,1,1,8,1,2,2,10,4,2,2,9,2,1,1,3,2,3,1,5,3,3,2,1,3,8,1,1,1,11,3,1,1,4, 2583 3,7,1,14,1,2,3,12,5,2,5,1,6,7,5,7,14,11,1,3,1,8,9,12,2,1,11,8,4,4,2,6,10,9,13,1,1,3,1,5,1,3,2,4,4,1,18,2,3,14,11,4,29,4,2,7,1,3,13,9,2,2,5, 2584 3,5,20,7,16,8,5,72,34,6,4,22,12,12,28,45,36,9,7,39,9,191,1,1,1,4,11,8,4,9,2,3,22,1,1,1,1,4,17,1,7,7,1,11,31,10,2,4,8,2,3,2,1,4,2,16,4,32,2, 2585 3,19,13,4,9,1,5,2,14,8,1,1,3,6,19,6,5,1,16,6,2,10,8,5,1,2,3,1,5,5,1,11,6,6,1,3,3,2,6,3,8,1,1,4,10,7,5,7,7,5,8,9,2,1,3,4,1,1,3,1,3,3,2,6,16, 2586 1,4,6,3,1,10,6,1,3,15,2,9,2,10,25,13,9,16,6,2,2,10,11,4,3,9,1,2,6,6,5,4,30,40,1,10,7,12,14,33,6,3,6,7,3,1,3,1,11,14,4,9,5,12,11,49,18,51,31, 2587 140,31,2,2,1,5,1,8,1,10,1,4,4,3,24,1,10,1,3,6,6,16,3,4,5,2,1,4,2,57,10,6,22,2,22,3,7,22,6,10,11,36,18,16,33,36,2,5,5,1,1,1,4,10,1,4,13,2,7, 2588 5,2,9,3,4,1,7,43,3,7,3,9,14,7,9,1,11,1,1,3,7,4,18,13,1,14,1,3,6,10,73,2,2,30,6,1,11,18,19,13,22,3,46,42,37,89,7,3,16,34,2,2,3,9,1,7,1,1,1,2, 2589 2,4,10,7,3,10,3,9,5,28,9,2,6,13,7,3,1,3,10,2,7,2,11,3,6,21,54,85,2,1,4,2,2,1,39,3,21,2,2,5,1,1,1,4,1,1,3,4,15,1,3,2,4,4,2,3,8,2,20,1,8,7,13, 2590 4,1,26,6,2,9,34,4,21,52,10,4,4,1,5,12,2,11,1,7,2,30,12,44,2,30,1,1,3,6,16,9,17,39,82,2,2,24,7,1,7,3,16,9,14,44,2,1,2,1,2,3,5,2,4,1,6,7,5,3, 2591 2,6,1,11,5,11,2,1,18,19,8,1,3,24,29,2,1,3,5,2,2,1,13,6,5,1,46,11,3,5,1,1,5,8,2,10,6,12,6,3,7,11,2,4,16,13,2,5,1,1,2,2,5,2,28,5,2,23,10,8,4, 2592 4,22,39,95,38,8,14,9,5,1,13,5,4,3,13,12,11,1,9,1,27,37,2,5,4,4,63,211,95,2,2,2,1,3,5,2,1,1,2,2,1,1,1,3,2,4,1,2,1,1,5,2,2,1,1,2,3,1,3,1,1,1, 2593 3,1,4,2,1,3,6,1,1,3,7,15,5,3,2,5,3,9,11,4,2,22,1,6,3,8,7,1,4,28,4,16,3,3,25,4,4,27,27,1,4,1,2,2,7,1,3,5,2,28,8,2,14,1,8,6,16,25,3,3,3,14,3, 2594 3,1,1,2,1,4,6,3,8,4,1,1,1,2,3,6,10,6,2,3,18,3,2,5,5,4,3,1,5,2,5,4,23,7,6,12,6,4,17,11,9,5,1,1,10,5,12,1,1,11,26,33,7,3,6,1,17,7,1,5,12,1,11, 2595 2,4,1,8,14,17,23,1,2,1,7,8,16,11,9,6,5,2,6,4,16,2,8,14,1,11,8,9,1,1,1,9,25,4,11,19,7,2,15,2,12,8,52,7,5,19,2,16,4,36,8,1,16,8,24,26,4,6,2,9, 2596 5,4,36,3,28,12,25,15,37,27,17,12,59,38,5,32,127,1,2,9,17,14,4,1,2,1,1,8,11,50,4,14,2,19,16,4,17,5,4,5,26,12,45,2,23,45,104,30,12,8,3,10,2,2, 2597 3,3,1,4,20,7,2,9,6,15,2,20,1,3,16,4,11,15,6,134,2,5,59,1,2,2,2,1,9,17,3,26,137,10,211,59,1,2,4,1,4,1,1,1,2,6,2,3,1,1,2,3,2,3,1,3,4,4,2,3,3, 2598 1,4,3,1,7,2,2,3,1,2,1,3,3,3,2,2,3,2,1,3,14,6,1,3,2,9,6,15,27,9,34,145,1,1,2,1,1,1,1,2,1,1,1,1,2,2,2,3,1,2,1,1,1,2,3,5,8,3,5,2,4,1,3,2,2,2,12, 2599 4,1,1,1,10,4,5,1,20,4,16,1,15,9,5,12,2,9,2,5,4,2,26,19,7,1,26,4,30,12,15,42,1,6,8,172,1,1,4,2,1,1,11,2,2,4,2,1,2,1,10,8,1,2,1,4,5,1,2,5,1,8, 2600 4,1,3,4,2,1,6,2,1,3,4,1,2,1,1,1,1,12,5,7,2,4,3,1,1,1,3,3,6,1,2,2,3,3,3,2,1,2,12,14,11,6,6,4,12,2,8,1,7,10,1,35,7,4,13,15,4,3,23,21,28,52,5, 2601 26,5,6,1,7,10,2,7,53,3,2,1,1,1,2,163,532,1,10,11,1,3,3,4,8,2,8,6,2,2,23,22,4,2,2,4,2,1,3,1,3,3,5,9,8,2,1,2,8,1,10,2,12,21,20,15,105,2,3,1,1, 2602 3,2,3,1,1,2,5,1,4,15,11,19,1,1,1,1,5,4,5,1,1,2,5,3,5,12,1,2,5,1,11,1,1,15,9,1,4,5,3,26,8,2,1,3,1,1,15,19,2,12,1,2,5,2,7,2,19,2,20,6,26,7,5, 2603 2,2,7,34,21,13,70,2,128,1,1,2,1,1,2,1,1,3,2,2,2,15,1,4,1,3,4,42,10,6,1,49,85,8,1,2,1,1,4,4,2,3,6,1,5,7,4,3,211,4,1,2,1,2,5,1,2,4,2,2,6,5,6, 2604 10,3,4,48,100,6,2,16,296,5,27,387,2,2,3,7,16,8,5,38,15,39,21,9,10,3,7,59,13,27,21,47,5,21,6 2605 }; 2606 static ImWchar base_ranges[] = // not zero-terminated 2607 { 2608 0x0020, 0x00FF, // Basic Latin + Latin Supplement 2609 0x2000, 0x206F, // General Punctuation 2610 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana 2611 0x31F0, 0x31FF, // Katakana Phonetic Extensions 2612 0xFF00, 0xFFEF // Half-width characters 2613 }; 2614 static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00) * 2 + 1] = { 0 }; 2615 if (!full_ranges[0]) 2616 { 2617 memcpy(full_ranges, base_ranges, sizeof(base_ranges)); 2618 UnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00, IM_ARRAYSIZE(accumulative_offsets_from_0x4E00), full_ranges + IM_ARRAYSIZE(base_ranges)); 2619 } 2620 return &full_ranges[0]; 2016 2621 } 2017 2622 2018 2623 const ImWchar* ImFontAtlas::GetGlyphRangesJapanese() 2019 2624 { 2020 // Store the 1946 ideograms code points as successive offsets from the initial unicode codepoint 0x4E00. Each offset has an implicit +1. 2021 // This encoding is designed to helps us reduce the source code size. 2022 // FIXME: Source a list of the revised 2136 joyo kanji list from 2010 and rebuild this. 2023 // The current list was sourced from http://theinstructionlimit.com/author/renaudbedardrenaudbedard/page/3 2024 // Note that you may use ImFontAtlas::GlyphRangesBuilder to create your own ranges, by merging existing ranges or adding new characters. 2025 static const short offsets_from_0x4E00[] = 2026 { 2027 -1,0,1,3,0,0,0,0,1,0,5,1,1,0,7,4,6,10,0,1,9,9,7,1,3,19,1,10,7,1,0,1,0,5,1,0,6,4,2,6,0,0,12,6,8,0,3,5,0,1,0,9,0,0,8,1,1,3,4,5,13,0,0,8,2,17, 2028 4,3,1,1,9,6,0,0,0,2,1,3,2,22,1,9,11,1,13,1,3,12,0,5,9,2,0,6,12,5,3,12,4,1,2,16,1,1,4,6,5,3,0,6,13,15,5,12,8,14,0,0,6,15,3,6,0,18,8,1,6,14,1, 2029 5,4,12,24,3,13,12,10,24,0,0,0,1,0,1,1,2,9,10,2,2,0,0,3,3,1,0,3,8,0,3,2,4,4,1,6,11,10,14,6,15,3,4,15,1,0,0,5,2,2,0,0,1,6,5,5,6,0,3,6,5,0,0,1,0, 2030 11,2,2,8,4,7,0,10,0,1,2,17,19,3,0,2,5,0,6,2,4,4,6,1,1,11,2,0,3,1,2,1,2,10,7,6,3,16,0,8,24,0,0,3,1,1,3,0,1,6,0,0,0,2,0,1,5,15,0,1,0,0,2,11,19, 2031 1,4,19,7,6,5,1,0,0,0,0,5,1,0,1,9,0,0,5,0,2,0,1,0,3,0,11,3,0,2,0,0,0,0,0,9,3,6,4,12,0,14,0,0,29,10,8,0,14,37,13,0,31,16,19,0,8,30,1,20,8,3,48, 2032 21,1,0,12,0,10,44,34,42,54,11,18,82,0,2,1,2,12,1,0,6,2,17,2,12,7,0,7,17,4,2,6,24,23,8,23,39,2,16,23,1,0,5,1,2,15,14,5,6,2,11,0,8,6,2,2,2,14, 2033 20,4,15,3,4,11,10,10,2,5,2,1,30,2,1,0,0,22,5,5,0,3,1,5,4,1,0,0,2,2,21,1,5,1,2,16,2,1,3,4,0,8,4,0,0,5,14,11,2,16,1,13,1,7,0,22,15,3,1,22,7,14, 2034 22,19,11,24,18,46,10,20,64,45,3,2,0,4,5,0,1,4,25,1,0,0,2,10,0,0,0,1,0,1,2,0,0,9,1,2,0,0,0,2,5,2,1,1,5,5,8,1,1,1,5,1,4,9,1,3,0,1,0,1,1,2,0,0, 2035 2,0,1,8,22,8,1,0,0,0,0,4,2,1,0,9,8,5,0,9,1,30,24,2,6,4,39,0,14,5,16,6,26,179,0,2,1,1,0,0,0,5,2,9,6,0,2,5,16,7,5,1,1,0,2,4,4,7,15,13,14,0,0, 2036 3,0,1,0,0,0,2,1,6,4,5,1,4,9,0,3,1,8,0,0,10,5,0,43,0,2,6,8,4,0,2,0,0,9,6,0,9,3,1,6,20,14,6,1,4,0,7,2,3,0,2,0,5,0,3,1,0,3,9,7,0,3,4,0,4,9,1,6,0, 2037 9,0,0,2,3,10,9,28,3,6,2,4,1,2,32,4,1,18,2,0,3,1,5,30,10,0,2,2,2,0,7,9,8,11,10,11,7,2,13,7,5,10,0,3,40,2,0,1,6,12,0,4,5,1,5,11,11,21,4,8,3,7, 2038 8,8,33,5,23,0,0,19,8,8,2,3,0,6,1,1,1,5,1,27,4,2,5,0,3,5,6,3,1,0,3,1,12,5,3,3,2,0,7,7,2,1,0,4,0,1,1,2,0,10,10,6,2,5,9,7,5,15,15,21,6,11,5,20, 2039 4,3,5,5,2,5,0,2,1,0,1,7,28,0,9,0,5,12,5,5,18,30,0,12,3,3,21,16,25,32,9,3,14,11,24,5,66,9,1,2,0,5,9,1,5,1,8,0,8,3,3,0,1,15,1,4,8,1,2,7,0,7,2, 2040 8,3,7,5,3,7,10,2,1,0,0,2,25,0,6,4,0,10,0,4,2,4,1,12,5,38,4,0,4,1,10,5,9,4,0,14,4,2,5,18,20,21,1,3,0,5,0,7,0,3,7,1,3,1,1,8,1,0,0,0,3,2,5,2,11, 2041 6,0,13,1,3,9,1,12,0,16,6,2,1,0,2,1,12,6,13,11,2,0,28,1,7,8,14,13,8,13,0,2,0,5,4,8,10,2,37,42,19,6,6,7,4,14,11,18,14,80,7,6,0,4,72,12,36,27, 2042 7,7,0,14,17,19,164,27,0,5,10,7,3,13,6,14,0,2,2,5,3,0,6,13,0,0,10,29,0,4,0,3,13,0,3,1,6,51,1,5,28,2,0,8,0,20,2,4,0,25,2,10,13,10,0,16,4,0,1,0, 2043 2,1,7,0,1,8,11,0,0,1,2,7,2,23,11,6,6,4,16,2,2,2,0,22,9,3,3,5,2,0,15,16,21,2,9,20,15,15,5,3,9,1,0,0,1,7,7,5,4,2,2,2,38,24,14,0,0,15,5,6,24,14, 2044 5,5,11,0,21,12,0,3,8,4,11,1,8,0,11,27,7,2,4,9,21,59,0,1,39,3,60,62,3,0,12,11,0,3,30,11,0,13,88,4,15,5,28,13,1,4,48,17,17,4,28,32,46,0,16,0, 2045 18,11,1,8,6,38,11,2,6,11,38,2,0,45,3,11,2,7,8,4,30,14,17,2,1,1,65,18,12,16,4,2,45,123,12,56,33,1,4,3,4,7,0,0,0,3,2,0,16,4,2,4,2,0,7,4,5,2,26, 2046 2,25,6,11,6,1,16,2,6,17,77,15,3,35,0,1,0,5,1,0,38,16,6,3,12,3,3,3,0,9,3,1,3,5,2,9,0,18,0,25,1,3,32,1,72,46,6,2,7,1,3,14,17,0,28,1,40,13,0,20, 2047 15,40,6,38,24,12,43,1,1,9,0,12,6,0,6,2,4,19,3,7,1,48,0,9,5,0,5,6,9,6,10,15,2,11,19,3,9,2,0,1,10,1,27,8,1,3,6,1,14,0,26,0,27,16,3,4,9,6,2,23, 2048 9,10,5,25,2,1,6,1,1,48,15,9,15,14,3,4,26,60,29,13,37,21,1,6,4,0,2,11,22,23,16,16,2,2,1,3,0,5,1,6,4,0,0,4,0,0,8,3,0,2,5,0,7,1,7,3,13,2,4,10, 2049 3,0,2,31,0,18,3,0,12,10,4,1,0,7,5,7,0,5,4,12,2,22,10,4,2,15,2,8,9,0,23,2,197,51,3,1,1,4,13,4,3,21,4,19,3,10,5,40,0,4,1,1,10,4,1,27,34,7,21, 2050 2,17,2,9,6,4,2,3,0,4,2,7,8,2,5,1,15,21,3,4,4,2,2,17,22,1,5,22,4,26,7,0,32,1,11,42,15,4,1,2,5,0,19,3,1,8,6,0,10,1,9,2,13,30,8,2,24,17,19,1,4, 2051 4,25,13,0,10,16,11,39,18,8,5,30,82,1,6,8,18,77,11,13,20,75,11,112,78,33,3,0,0,60,17,84,9,1,1,12,30,10,49,5,32,158,178,5,5,6,3,3,1,3,1,4,7,6, 2052 19,31,21,0,2,9,5,6,27,4,9,8,1,76,18,12,1,4,0,3,3,6,3,12,2,8,30,16,2,25,1,5,5,4,3,0,6,10,2,3,1,0,5,1,19,3,0,8,1,5,2,6,0,0,0,19,1,2,0,5,1,2,5, 2053 1,3,7,0,4,12,7,3,10,22,0,9,5,1,0,2,20,1,1,3,23,30,3,9,9,1,4,191,14,3,15,6,8,50,0,1,0,0,4,0,0,1,0,2,4,2,0,2,3,0,2,0,2,2,8,7,0,1,1,1,3,3,17,11, 2054 91,1,9,3,2,13,4,24,15,41,3,13,3,1,20,4,125,29,30,1,0,4,12,2,21,4,5,5,19,11,0,13,11,86,2,18,0,7,1,8,8,2,2,22,1,2,6,5,2,0,1,2,8,0,2,0,5,2,1,0, 2055 2,10,2,0,5,9,2,1,2,0,1,0,4,0,0,10,2,5,3,0,6,1,0,1,4,4,33,3,13,17,3,18,6,4,7,1,5,78,0,4,1,13,7,1,8,1,0,35,27,15,3,0,0,0,1,11,5,41,38,15,22,6, 2056 14,14,2,1,11,6,20,63,5,8,27,7,11,2,2,40,58,23,50,54,56,293,8,8,1,5,1,14,0,1,12,37,89,8,8,8,2,10,6,0,0,0,4,5,2,1,0,1,1,2,7,0,3,3,0,4,6,0,3,2, 2057 19,3,8,0,0,0,4,4,16,0,4,1,5,1,3,0,3,4,6,2,17,10,10,31,6,4,3,6,10,126,7,3,2,2,0,9,0,0,5,20,13,0,15,0,6,0,2,5,8,64,50,3,2,12,2,9,0,0,11,8,20, 2058 109,2,18,23,0,0,9,61,3,0,28,41,77,27,19,17,81,5,2,14,5,83,57,252,14,154,263,14,20,8,13,6,57,39,38, 2059 }; 2060 static ImWchar base_ranges[] = 2061 { 2062 0x0020, 0x00FF, // Basic Latin + Latin Supplement 2063 0x3000, 0x30FF, // Punctuations, Hiragana, Katakana 2064 0x31F0, 0x31FF, // Katakana Phonetic Extensions 2065 0xFF00, 0xFFEF, // Half-width characters 2066 }; 2067 static bool full_ranges_unpacked = false; 2068 static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(offsets_from_0x4E00) * 2 + 1]; 2069 if (!full_ranges_unpacked) 2070 { 2071 // Unpack 2072 int codepoint = 0x4e00; 2073 memcpy(full_ranges, base_ranges, sizeof(base_ranges)); 2074 ImWchar* dst = full_ranges + IM_ARRAYSIZE(base_ranges); 2075 for (int n = 0; n < IM_ARRAYSIZE(offsets_from_0x4E00); n++, dst += 2) 2076 dst[0] = dst[1] = (ImWchar)(codepoint += (offsets_from_0x4E00[n] + 1)); 2077 dst[0] = 0; 2078 full_ranges_unpacked = true; 2079 } 2080 return &full_ranges[0]; 2625 // 1946 common ideograms code points for Japanese 2626 // Sourced from http://theinstructionlimit.com/common-kanji-character-ranges-for-xna-spritefont-rendering 2627 // FIXME: Source a list of the revised 2136 Joyo Kanji list from 2010 and rebuild this. 2628 // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters. 2629 // (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.) 2630 static const short accumulative_offsets_from_0x4E00[] = 2631 { 2632 0,1,2,4,1,1,1,1,2,1,6,2,2,1,8,5,7,11,1,2,10,10,8,2,4,20,2,11,8,2,1,2,1,6,2,1,7,5,3,7,1,1,13,7,9,1,4,6,1,2,1,10,1,1,9,2,2,4,5,6,14,1,1,9,3,18, 2633 5,4,2,2,10,7,1,1,1,3,2,4,3,23,2,10,12,2,14,2,4,13,1,6,10,3,1,7,13,6,4,13,5,2,3,17,2,2,5,7,6,4,1,7,14,16,6,13,9,15,1,1,7,16,4,7,1,19,9,2,7,15, 2634 2,6,5,13,25,4,14,13,11,25,1,1,1,2,1,2,2,3,10,11,3,3,1,1,4,4,2,1,4,9,1,4,3,5,5,2,7,12,11,15,7,16,4,5,16,2,1,1,6,3,3,1,1,2,7,6,6,7,1,4,7,6,1,1, 2635 2,1,12,3,3,9,5,8,1,11,1,2,3,18,20,4,1,3,6,1,7,3,5,5,7,2,2,12,3,1,4,2,3,2,3,11,8,7,4,17,1,9,25,1,1,4,2,2,4,1,2,7,1,1,1,3,1,2,6,16,1,2,1,1,3,12, 2636 20,2,5,20,8,7,6,2,1,1,1,1,6,2,1,2,10,1,1,6,1,3,1,2,1,4,1,12,4,1,3,1,1,1,1,1,10,4,7,5,13,1,15,1,1,30,11,9,1,15,38,14,1,32,17,20,1,9,31,2,21,9, 2637 4,49,22,2,1,13,1,11,45,35,43,55,12,19,83,1,3,2,3,13,2,1,7,3,18,3,13,8,1,8,18,5,3,7,25,24,9,24,40,3,17,24,2,1,6,2,3,16,15,6,7,3,12,1,9,7,3,3, 2638 3,15,21,5,16,4,5,12,11,11,3,6,3,2,31,3,2,1,1,23,6,6,1,4,2,6,5,2,1,1,3,3,22,2,6,2,3,17,3,2,4,5,1,9,5,1,1,6,15,12,3,17,2,14,2,8,1,23,16,4,2,23, 2639 8,15,23,20,12,25,19,47,11,21,65,46,4,3,1,5,6,1,2,5,26,2,1,1,3,11,1,1,1,2,1,2,3,1,1,10,2,3,1,1,1,3,6,3,2,2,6,6,9,2,2,2,6,2,5,10,2,4,1,2,1,2,2, 2640 3,1,1,3,1,2,9,23,9,2,1,1,1,1,5,3,2,1,10,9,6,1,10,2,31,25,3,7,5,40,1,15,6,17,7,27,180,1,3,2,2,1,1,1,6,3,10,7,1,3,6,17,8,6,2,2,1,3,5,5,8,16,14, 2641 15,1,1,4,1,2,1,1,1,3,2,7,5,6,2,5,10,1,4,2,9,1,1,11,6,1,44,1,3,7,9,5,1,3,1,1,10,7,1,10,4,2,7,21,15,7,2,5,1,8,3,4,1,3,1,6,1,4,2,1,4,10,8,1,4,5, 2642 1,5,10,2,7,1,10,1,1,3,4,11,10,29,4,7,3,5,2,3,33,5,2,19,3,1,4,2,6,31,11,1,3,3,3,1,8,10,9,12,11,12,8,3,14,8,6,11,1,4,41,3,1,2,7,13,1,5,6,2,6,12, 2643 12,22,5,9,4,8,9,9,34,6,24,1,1,20,9,9,3,4,1,7,2,2,2,6,2,28,5,3,6,1,4,6,7,4,2,1,4,2,13,6,4,4,3,1,8,8,3,2,1,5,1,2,2,3,1,11,11,7,3,6,10,8,6,16,16, 2644 22,7,12,6,21,5,4,6,6,3,6,1,3,2,1,2,8,29,1,10,1,6,13,6,6,19,31,1,13,4,4,22,17,26,33,10,4,15,12,25,6,67,10,2,3,1,6,10,2,6,2,9,1,9,4,4,1,2,16,2, 2645 5,9,2,3,8,1,8,3,9,4,8,6,4,8,11,3,2,1,1,3,26,1,7,5,1,11,1,5,3,5,2,13,6,39,5,1,5,2,11,6,10,5,1,15,5,3,6,19,21,22,2,4,1,6,1,8,1,4,8,2,4,2,2,9,2, 2646 1,1,1,4,3,6,3,12,7,1,14,2,4,10,2,13,1,17,7,3,2,1,3,2,13,7,14,12,3,1,29,2,8,9,15,14,9,14,1,3,1,6,5,9,11,3,38,43,20,7,7,8,5,15,12,19,15,81,8,7, 2647 1,5,73,13,37,28,8,8,1,15,18,20,165,28,1,6,11,8,4,14,7,15,1,3,3,6,4,1,7,14,1,1,11,30,1,5,1,4,14,1,4,2,7,52,2,6,29,3,1,9,1,21,3,5,1,26,3,11,14, 2648 11,1,17,5,1,2,1,3,2,8,1,2,9,12,1,1,2,3,8,3,24,12,7,7,5,17,3,3,3,1,23,10,4,4,6,3,1,16,17,22,3,10,21,16,16,6,4,10,2,1,1,2,8,8,6,5,3,3,3,39,25, 2649 15,1,1,16,6,7,25,15,6,6,12,1,22,13,1,4,9,5,12,2,9,1,12,28,8,3,5,10,22,60,1,2,40,4,61,63,4,1,13,12,1,4,31,12,1,14,89,5,16,6,29,14,2,5,49,18,18, 2650 5,29,33,47,1,17,1,19,12,2,9,7,39,12,3,7,12,39,3,1,46,4,12,3,8,9,5,31,15,18,3,2,2,66,19,13,17,5,3,46,124,13,57,34,2,5,4,5,8,1,1,1,4,3,1,17,5, 2651 3,5,3,1,8,5,6,3,27,3,26,7,12,7,2,17,3,7,18,78,16,4,36,1,2,1,6,2,1,39,17,7,4,13,4,4,4,1,10,4,2,4,6,3,10,1,19,1,26,2,4,33,2,73,47,7,3,8,2,4,15, 2652 18,1,29,2,41,14,1,21,16,41,7,39,25,13,44,2,2,10,1,13,7,1,7,3,5,20,4,8,2,49,1,10,6,1,6,7,10,7,11,16,3,12,20,4,10,3,1,2,11,2,28,9,2,4,7,2,15,1, 2653 27,1,28,17,4,5,10,7,3,24,10,11,6,26,3,2,7,2,2,49,16,10,16,15,4,5,27,61,30,14,38,22,2,7,5,1,3,12,23,24,17,17,3,3,2,4,1,6,2,7,5,1,1,5,1,1,9,4, 2654 1,3,6,1,8,2,8,4,14,3,5,11,4,1,3,32,1,19,4,1,13,11,5,2,1,8,6,8,1,6,5,13,3,23,11,5,3,16,3,9,10,1,24,3,198,52,4,2,2,5,14,5,4,22,5,20,4,11,6,41, 2655 1,5,2,2,11,5,2,28,35,8,22,3,18,3,10,7,5,3,4,1,5,3,8,9,3,6,2,16,22,4,5,5,3,3,18,23,2,6,23,5,27,8,1,33,2,12,43,16,5,2,3,6,1,20,4,2,9,7,1,11,2, 2656 10,3,14,31,9,3,25,18,20,2,5,5,26,14,1,11,17,12,40,19,9,6,31,83,2,7,9,19,78,12,14,21,76,12,113,79,34,4,1,1,61,18,85,10,2,2,13,31,11,50,6,33,159, 2657 179,6,6,7,4,4,2,4,2,5,8,7,20,32,22,1,3,10,6,7,28,5,10,9,2,77,19,13,2,5,1,4,4,7,4,13,3,9,31,17,3,26,2,6,6,5,4,1,7,11,3,4,2,1,6,2,20,4,1,9,2,6, 2658 3,7,1,1,1,20,2,3,1,6,2,3,6,2,4,8,1,5,13,8,4,11,23,1,10,6,2,1,3,21,2,2,4,24,31,4,10,10,2,5,192,15,4,16,7,9,51,1,2,1,1,5,1,1,2,1,3,5,3,1,3,4,1, 2659 3,1,3,3,9,8,1,2,2,2,4,4,18,12,92,2,10,4,3,14,5,25,16,42,4,14,4,2,21,5,126,30,31,2,1,5,13,3,22,5,6,6,20,12,1,14,12,87,3,19,1,8,2,9,9,3,3,23,2, 2660 3,7,6,3,1,2,3,9,1,3,1,6,3,2,1,3,11,3,1,6,10,3,2,3,1,2,1,5,1,1,11,3,6,4,1,7,2,1,2,5,5,34,4,14,18,4,19,7,5,8,2,6,79,1,5,2,14,8,2,9,2,1,36,28,16, 2661 4,1,1,1,2,12,6,42,39,16,23,7,15,15,3,2,12,7,21,64,6,9,28,8,12,3,3,41,59,24,51,55,57,294,9,9,2,6,2,15,1,2,13,38,90,9,9,9,3,11,7,1,1,1,5,6,3,2, 2662 1,2,2,3,8,1,4,4,1,5,7,1,4,3,20,4,9,1,1,1,5,5,17,1,5,2,6,2,4,1,4,5,7,3,18,11,11,32,7,5,4,7,11,127,8,4,3,3,1,10,1,1,6,21,14,1,16,1,7,1,3,6,9,65, 2663 51,4,3,13,3,10,1,1,12,9,21,110,3,19,24,1,1,10,62,4,1,29,42,78,28,20,18,82,6,3,15,6,84,58,253,15,155,264,15,21,9,14,7,58,40,39, 2664 }; 2665 static ImWchar base_ranges[] = // not zero-terminated 2666 { 2667 0x0020, 0x00FF, // Basic Latin + Latin Supplement 2668 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana 2669 0x31F0, 0x31FF, // Katakana Phonetic Extensions 2670 0xFF00, 0xFFEF // Half-width characters 2671 }; 2672 static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00)*2 + 1] = { 0 }; 2673 if (!full_ranges[0]) 2674 { 2675 memcpy(full_ranges, base_ranges, sizeof(base_ranges)); 2676 UnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00, IM_ARRAYSIZE(accumulative_offsets_from_0x4E00), full_ranges + IM_ARRAYSIZE(base_ranges)); 2677 } 2678 return &full_ranges[0]; 2081 2679 } 2082 2680 2083 2681 const ImWchar* ImFontAtlas::GetGlyphRangesCyrillic() 2084 2682 { 2085 static const ImWchar ranges[] =2086 {2087 0x0020, 0x00FF, // Basic Latin + Latin Supplement2088 0x0400, 0x052F, // Cyrillic + Cyrillic Supplement2089 0x2DE0, 0x2DFF, // Cyrillic Extended-A2090 0xA640, 0xA69F, // Cyrillic Extended-B2091 0,2092 };2093 return &ranges[0];2683 static const ImWchar ranges[] = 2684 { 2685 0x0020, 0x00FF, // Basic Latin + Latin Supplement 2686 0x0400, 0x052F, // Cyrillic + Cyrillic Supplement 2687 0x2DE0, 0x2DFF, // Cyrillic Extended-A 2688 0xA640, 0xA69F, // Cyrillic Extended-B 2689 0, 2690 }; 2691 return &ranges[0]; 2094 2692 } 2095 2693 2096 2694 const ImWchar* ImFontAtlas::GetGlyphRangesThai() 2097 2695 { 2098 static const ImWchar ranges[] = 2099 { 2100 0x0020, 0x00FF, // Basic Latin 2101 0x2010, 0x205E, // Punctuations 2102 0x0E00, 0x0E7F, // Thai 2103 0, 2104 }; 2105 return &ranges[0]; 2696 static const ImWchar ranges[] = 2697 { 2698 0x0020, 0x00FF, // Basic Latin 2699 0x2010, 0x205E, // Punctuations 2700 0x0E00, 0x0E7F, // Thai 2701 0, 2702 }; 2703 return &ranges[0]; 2704 } 2705 2706 const ImWchar* ImFontAtlas::GetGlyphRangesVietnamese() 2707 { 2708 static const ImWchar ranges[] = 2709 { 2710 0x0020, 0x00FF, // Basic Latin 2711 0x0102, 0x0103, 2712 0x0110, 0x0111, 2713 0x0128, 0x0129, 2714 0x0168, 0x0169, 2715 0x01A0, 0x01A1, 2716 0x01AF, 0x01B0, 2717 0x1EA0, 0x1EF9, 2718 0, 2719 }; 2720 return &ranges[0]; 2106 2721 } 2107 2722 2108 2723 //----------------------------------------------------------------------------- 2109 // ImFontAtlas::GlyphRangesBuilder2724 // [SECTION] ImFontGlyphRangesBuilder 2110 2725 //----------------------------------------------------------------------------- 2111 2726 2112 void ImFont Atlas::GlyphRangesBuilder::AddText(const char* text, const char* text_end)2113 { 2114 while (text_end ? (text < text_end) : *text)2115 {2116 unsigned int c = 0;2117 int c_len = ImTextCharFromUtf8(&c, text, text_end);2118 text += c_len;2119 if (c_len == 0)2120 break;2121 if (c < 0x10000)2122 AddChar((ImWchar)c);2123 2124 } 2125 2126 void ImFontAtlas::GlyphRangesBuilder::AddRanges(const ImWchar* ranges) 2127 { 2128 for (; ranges[0]; ranges += 2)2129 for (ImWchar c = ranges[0]; c <= ranges[1]; c++)2130 AddChar(c); 2131 } 2132 2133 void ImFontAtlas::GlyphRangesBuilder::BuildRanges(ImVector<ImWchar>* out_ranges) 2134 { 2135 for (int n = 0; n < 0x10000; n++)2136 if (GetBit(n))2137 {2138 out_ranges->push_back((ImWchar)n);2139 while (n < 0x10000&& GetBit(n + 1))2140 n++;2141 out_ranges->push_back((ImWchar)n);2142 }2143 out_ranges->push_back(0);2727 void ImFontGlyphRangesBuilder::AddText(const char* text, const char* text_end) 2728 { 2729 while (text_end ? (text < text_end) : *text) 2730 { 2731 unsigned int c = 0; 2732 int c_len = ImTextCharFromUtf8(&c, text, text_end); 2733 text += c_len; 2734 if (c_len == 0) 2735 break; 2736 AddChar((ImWchar)c); 2737 } 2738 } 2739 2740 void ImFontGlyphRangesBuilder::AddRanges(const ImWchar* ranges) 2741 { 2742 for (; ranges[0]; ranges += 2) 2743 for (ImWchar c = ranges[0]; c <= ranges[1]; c++) 2744 AddChar(c); 2745 } 2746 2747 void ImFontGlyphRangesBuilder::BuildRanges(ImVector<ImWchar>* out_ranges) 2748 { 2749 const int max_codepoint = IM_UNICODE_CODEPOINT_MAX; 2750 for (int n = 0; n <= max_codepoint; n++) 2751 if (GetBit(n)) 2752 { 2753 out_ranges->push_back((ImWchar)n); 2754 while (n < max_codepoint && GetBit(n + 1)) 2755 n++; 2756 out_ranges->push_back((ImWchar)n); 2757 } 2758 out_ranges->push_back(0); 2144 2759 } 2145 2760 2146 2761 //----------------------------------------------------------------------------- 2147 // ImFont2762 // [SECTION] ImFont 2148 2763 //----------------------------------------------------------------------------- 2149 2764 2150 2765 ImFont::ImFont() 2151 2766 { 2152 Scale = 1.0f; 2153 FallbackChar = (ImWchar)'?'; 2154 DisplayOffset = ImVec2(0.0f, 0.0f); 2155 ClearOutputData(); 2767 FontSize = 0.0f; 2768 FallbackAdvanceX = 0.0f; 2769 FallbackChar = (ImWchar)'?'; 2770 EllipsisChar = (ImWchar)-1; 2771 FallbackGlyph = NULL; 2772 ContainerAtlas = NULL; 2773 ConfigData = NULL; 2774 ConfigDataCount = 0; 2775 DirtyLookupTables = false; 2776 Scale = 1.0f; 2777 Ascent = Descent = 0.0f; 2778 MetricsTotalSurface = 0; 2779 memset(Used4kPagesMap, 0, sizeof(Used4kPagesMap)); 2156 2780 } 2157 2781 2158 2782 ImFont::~ImFont() 2159 2783 { 2160 // Invalidate active font so that the user gets a clear crash instead of a dangling pointer. 2161 // If you want to delete fonts you need to do it between Render() and NewFrame(). 2162 // FIXME-CLEANUP 2163 /* 2164 ImGuiContext& g = *GImGui; 2165 if (g.Font == this) 2166 g.Font = NULL; 2167 */ 2168 ClearOutputData(); 2784 ClearOutputData(); 2169 2785 } 2170 2786 2171 2787 void ImFont::ClearOutputData() 2172 2788 { 2173 FontSize = 0.0f; 2174 Glyphs.clear(); 2175 IndexAdvanceX.clear(); 2176 IndexLookup.clear(); 2177 FallbackGlyph = NULL; 2178 FallbackAdvanceX = 0.0f; 2179 ConfigDataCount = 0; 2180 ConfigData = NULL; 2181 ContainerAtlas = NULL; 2182 Ascent = Descent = 0.0f; 2183 DirtyLookupTables = true; 2184 MetricsTotalSurface = 0; 2789 FontSize = 0.0f; 2790 FallbackAdvanceX = 0.0f; 2791 Glyphs.clear(); 2792 IndexAdvanceX.clear(); 2793 IndexLookup.clear(); 2794 FallbackGlyph = NULL; 2795 ContainerAtlas = NULL; 2796 DirtyLookupTables = true; 2797 Ascent = Descent = 0.0f; 2798 MetricsTotalSurface = 0; 2185 2799 } 2186 2800 2187 2801 void ImFont::BuildLookupTable() 2188 2802 { 2189 int max_codepoint = 0; 2190 for (int i = 0; i != Glyphs.Size; i++) 2191 max_codepoint = ImMax(max_codepoint, (int)Glyphs[i].Codepoint); 2192 2193 IM_ASSERT(Glyphs.Size < 0xFFFF); // -1 is reserved 2194 IndexAdvanceX.clear(); 2195 IndexLookup.clear(); 2196 DirtyLookupTables = false; 2197 GrowIndex(max_codepoint + 1); 2198 for (int i = 0; i < Glyphs.Size; i++) 2199 { 2200 int codepoint = (int)Glyphs[i].Codepoint; 2201 IndexAdvanceX[codepoint] = Glyphs[i].AdvanceX; 2202 IndexLookup[codepoint] = (unsigned short)i; 2203 } 2204 2205 // Create a glyph to handle TAB 2206 // FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?) 2207 if (FindGlyph((unsigned short)' ')) 2208 { 2209 if (Glyphs.back().Codepoint != '\t') // So we can call this function multiple times 2210 Glyphs.resize(Glyphs.Size + 1); 2211 ImFontGlyph& tab_glyph = Glyphs.back(); 2212 tab_glyph = *FindGlyph((unsigned short)' '); 2213 tab_glyph.Codepoint = '\t'; 2214 tab_glyph.AdvanceX *= 4; 2215 IndexAdvanceX[(int)tab_glyph.Codepoint] = (float)tab_glyph.AdvanceX; 2216 IndexLookup[(int)tab_glyph.Codepoint] = (unsigned short)(Glyphs.Size - 1); 2217 } 2218 2219 FallbackGlyph = FindGlyphNoFallback(FallbackChar); 2220 FallbackAdvanceX = FallbackGlyph ? FallbackGlyph->AdvanceX : 0.0f; 2221 for (int i = 0; i < max_codepoint + 1; i++) 2222 if (IndexAdvanceX[i] < 0.0f) 2223 IndexAdvanceX[i] = FallbackAdvanceX; 2803 int max_codepoint = 0; 2804 for (int i = 0; i != Glyphs.Size; i++) 2805 max_codepoint = ImMax(max_codepoint, (int)Glyphs[i].Codepoint); 2806 2807 // Build lookup table 2808 IM_ASSERT(Glyphs.Size < 0xFFFF); // -1 is reserved 2809 IndexAdvanceX.clear(); 2810 IndexLookup.clear(); 2811 DirtyLookupTables = false; 2812 memset(Used4kPagesMap, 0, sizeof(Used4kPagesMap)); 2813 GrowIndex(max_codepoint + 1); 2814 for (int i = 0; i < Glyphs.Size; i++) 2815 { 2816 int codepoint = (int)Glyphs[i].Codepoint; 2817 IndexAdvanceX[codepoint] = Glyphs[i].AdvanceX; 2818 IndexLookup[codepoint] = (ImWchar)i; 2819 2820 // Mark 4K page as used 2821 const int page_n = codepoint / 4096; 2822 Used4kPagesMap[page_n >> 3] |= 1 << (page_n & 7); 2823 } 2824 2825 // Create a glyph to handle TAB 2826 // FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?) 2827 if (FindGlyph((ImWchar)' ')) 2828 { 2829 if (Glyphs.back().Codepoint != '\t') // So we can call this function multiple times (FIXME: Flaky) 2830 Glyphs.resize(Glyphs.Size + 1); 2831 ImFontGlyph& tab_glyph = Glyphs.back(); 2832 tab_glyph = *FindGlyph((ImWchar)' '); 2833 tab_glyph.Codepoint = '\t'; 2834 tab_glyph.AdvanceX *= IM_TABSIZE; 2835 IndexAdvanceX[(int)tab_glyph.Codepoint] = (float)tab_glyph.AdvanceX; 2836 IndexLookup[(int)tab_glyph.Codepoint] = (ImWchar)(Glyphs.Size - 1); 2837 } 2838 2839 // Mark special glyphs as not visible (note that AddGlyph already mark as non-visible glyphs with zero-size polygons) 2840 SetGlyphVisible((ImWchar)' ', false); 2841 SetGlyphVisible((ImWchar)'\t', false); 2842 2843 // Setup fall-backs 2844 FallbackGlyph = FindGlyphNoFallback(FallbackChar); 2845 FallbackAdvanceX = FallbackGlyph ? FallbackGlyph->AdvanceX : 0.0f; 2846 for (int i = 0; i < max_codepoint + 1; i++) 2847 if (IndexAdvanceX[i] < 0.0f) 2848 IndexAdvanceX[i] = FallbackAdvanceX; 2849 } 2850 2851 // API is designed this way to avoid exposing the 4K page size 2852 // e.g. use with IsGlyphRangeUnused(0, 255) 2853 bool ImFont::IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last) 2854 { 2855 unsigned int page_begin = (c_begin / 4096); 2856 unsigned int page_last = (c_last / 4096); 2857 for (unsigned int page_n = page_begin; page_n <= page_last; page_n++) 2858 if ((page_n >> 3) < sizeof(Used4kPagesMap)) 2859 if (Used4kPagesMap[page_n >> 3] & (1 << (page_n & 7))) 2860 return false; 2861 return true; 2862 } 2863 2864 void ImFont::SetGlyphVisible(ImWchar c, bool visible) 2865 { 2866 if (ImFontGlyph* glyph = (ImFontGlyph*)(void*)FindGlyph((ImWchar)c)) 2867 glyph->Visible = visible ? 1 : 0; 2224 2868 } 2225 2869 2226 2870 void ImFont::SetFallbackChar(ImWchar c) 2227 2871 { 2228 FallbackChar = c;2229 BuildLookupTable();2872 FallbackChar = c; 2873 BuildLookupTable(); 2230 2874 } 2231 2875 2232 2876 void ImFont::GrowIndex(int new_size) 2233 2877 { 2234 IM_ASSERT(IndexAdvanceX.Size == IndexLookup.Size); 2235 if (new_size <= IndexLookup.Size) 2236 return; 2237 IndexAdvanceX.resize(new_size, -1.0f); 2238 IndexLookup.resize(new_size, (unsigned short)-1); 2239 } 2240 2241 void ImFont::AddGlyph(ImWchar codepoint, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x) 2242 { 2243 Glyphs.resize(Glyphs.Size + 1); 2244 ImFontGlyph& glyph = Glyphs.back(); 2245 glyph.Codepoint = (ImWchar)codepoint; 2246 glyph.X0 = x0; 2247 glyph.Y0 = y0; 2248 glyph.X1 = x1; 2249 glyph.Y1 = y1; 2250 glyph.U0 = u0; 2251 glyph.V0 = v0; 2252 glyph.U1 = u1; 2253 glyph.V1 = v1; 2254 glyph.AdvanceX = advance_x + ConfigData->GlyphExtraSpacing.x; // Bake spacing into AdvanceX 2255 2256 if (ConfigData->PixelSnapH) 2257 glyph.AdvanceX = (float)(int)(glyph.AdvanceX + 0.5f); 2258 2259 // Compute rough surface usage metrics (+1 to account for average padding, +0.99 to round) 2260 DirtyLookupTables = true; 2261 MetricsTotalSurface += (int)((glyph.U1 - glyph.U0) * ContainerAtlas->TexWidth + 1.99f) * (int)((glyph.V1 - glyph.V0) * ContainerAtlas->TexHeight + 1.99f); 2878 IM_ASSERT(IndexAdvanceX.Size == IndexLookup.Size); 2879 if (new_size <= IndexLookup.Size) 2880 return; 2881 IndexAdvanceX.resize(new_size, -1.0f); 2882 IndexLookup.resize(new_size, (ImWchar)-1); 2883 } 2884 2885 // x0/y0/x1/y1 are offset from the character upper-left layout position, in pixels. Therefore x0/y0 are often fairly close to zero. 2886 // Not to be mistaken with texture coordinates, which are held by u0/v0/u1/v1 in normalized format (0.0..1.0 on each texture axis). 2887 // 'cfg' is not necessarily == 'this->ConfigData' because multiple source fonts+configs can be used to build one target font. 2888 void ImFont::AddGlyph(const ImFontConfig* cfg, ImWchar codepoint, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x) 2889 { 2890 if (cfg != NULL) 2891 { 2892 // Clamp & recenter if needed 2893 const float advance_x_original = advance_x; 2894 advance_x = ImClamp(advance_x, cfg->GlyphMinAdvanceX, cfg->GlyphMaxAdvanceX); 2895 if (advance_x != advance_x_original) 2896 { 2897 float char_off_x = cfg->PixelSnapH ? ImFloor((advance_x - advance_x_original) * 0.5f) : (advance_x - advance_x_original) * 0.5f; 2898 x0 += char_off_x; 2899 x1 += char_off_x; 2900 } 2901 2902 // Snap to pixel 2903 if (cfg->PixelSnapH) 2904 advance_x = IM_ROUND(advance_x); 2905 2906 // Bake spacing 2907 advance_x += cfg->GlyphExtraSpacing.x; 2908 } 2909 2910 Glyphs.resize(Glyphs.Size + 1); 2911 ImFontGlyph& glyph = Glyphs.back(); 2912 glyph.Codepoint = (unsigned int)codepoint; 2913 glyph.Visible = (x0 != x1) && (y0 != y1); 2914 glyph.X0 = x0; 2915 glyph.Y0 = y0; 2916 glyph.X1 = x1; 2917 glyph.Y1 = y1; 2918 glyph.U0 = u0; 2919 glyph.V0 = v0; 2920 glyph.U1 = u1; 2921 glyph.V1 = v1; 2922 glyph.AdvanceX = advance_x; 2923 2924 // Compute rough surface usage metrics (+1 to account for average padding, +0.99 to round) 2925 // We use (U1-U0)*TexWidth instead of X1-X0 to account for oversampling. 2926 float pad = ContainerAtlas->TexGlyphPadding + 0.99f; 2927 DirtyLookupTables = true; 2928 MetricsTotalSurface += (int)((glyph.U1 - glyph.U0) * ContainerAtlas->TexWidth + pad) * (int)((glyph.V1 - glyph.V0) * ContainerAtlas->TexHeight + pad); 2262 2929 } 2263 2930 2264 2931 void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst) 2265 2932 { 2266 IM_ASSERT(IndexLookup.Size > 0); // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function.2267 int index_size =IndexLookup.Size;2268 2269 if (dst < index_size && IndexLookup.Data[dst] == (unsigned short)-1 && !overwrite_dst) // 'dst' already exists2270 return;2271 if (src >= index_size && dst >= index_size) // both 'dst' and 'src' don't exist -> no-op2272 return;2273 2274 GrowIndex(dst + 1);2275 IndexLookup[dst] = (src < index_size) ? IndexLookup.Data[src] : (unsigned short)-1;2276 IndexAdvanceX[dst] = (src < index_size) ? IndexAdvanceX.Data[src] : 1.0f;2933 IM_ASSERT(IndexLookup.Size > 0); // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function. 2934 unsigned int index_size = (unsigned int)IndexLookup.Size; 2935 2936 if (dst < index_size && IndexLookup.Data[dst] == (ImWchar)-1 && !overwrite_dst) // 'dst' already exists 2937 return; 2938 if (src >= index_size && dst >= index_size) // both 'dst' and 'src' don't exist -> no-op 2939 return; 2940 2941 GrowIndex(dst + 1); 2942 IndexLookup[dst] = (src < index_size) ? IndexLookup.Data[src] : (ImWchar)-1; 2943 IndexAdvanceX[dst] = (src < index_size) ? IndexAdvanceX.Data[src] : 1.0f; 2277 2944 } 2278 2945 2279 2946 const ImFontGlyph* ImFont::FindGlyph(ImWchar c) const 2280 2947 { 2281 if (c >=IndexLookup.Size)2282 return FallbackGlyph;2283 const unsigned short i = IndexLookup[c];2284 if (i == (unsigned short)-1)2285 return FallbackGlyph;2286 return &Glyphs.Data[i];2948 if (c >= (size_t)IndexLookup.Size) 2949 return FallbackGlyph; 2950 const ImWchar i = IndexLookup.Data[c]; 2951 if (i == (ImWchar)-1) 2952 return FallbackGlyph; 2953 return &Glyphs.Data[i]; 2287 2954 } 2288 2955 2289 2956 const ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) const 2290 2957 { 2291 if (c >=IndexLookup.Size)2292 return NULL;2293 const unsigned short i = IndexLookup[c];2294 if (i == (unsigned short)-1)2295 return NULL;2296 return &Glyphs.Data[i];2958 if (c >= (size_t)IndexLookup.Size) 2959 return NULL; 2960 const ImWchar i = IndexLookup.Data[c]; 2961 if (i == (ImWchar)-1) 2962 return NULL; 2963 return &Glyphs.Data[i]; 2297 2964 } 2298 2965 2299 2966 const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const 2300 2967 { 2301 // Simple word-wrapping for English, not full-featured. Please submit failing cases! 2302 // FIXME: Much possible improvements (don't cut things like "word !", "word!!!" but cut within "word,,,,", more sensible support for punctuations, support for Unicode punctuations, etc.) 2303 2304 // For references, possible wrap point marked with ^ 2305 // "aaa bbb, ccc,ddd. eee fff. ggg!" 2306 // ^ ^ ^ ^ ^__ ^ ^ 2307 2308 // List of hardcoded separators: .,;!?'" 2309 2310 // Skip extra blanks after a line returns (that includes not counting them in width computation) 2311 // e.g. "Hello world" --> "Hello" "World" 2312 2313 // Cut words that cannot possibly fit within one line. 2314 // e.g.: "The tropical fish" with ~5 characters worth of width --> "The tr" "opical" "fish" 2315 2316 float line_width = 0.0f; 2317 float word_width = 0.0f; 2318 float blank_width = 0.0f; 2319 wrap_width /= scale; // We work with unscaled widths to avoid scaling every characters 2320 2321 const char* word_end = text; 2322 const char* prev_word_end = NULL; 2323 bool inside_word = true; 2324 2325 const char* s = text; 2326 while (s < text_end) 2327 { 2328 unsigned int c = (unsigned int)*s; 2329 const char* next_s; 2330 if (c < 0x80) 2331 next_s = s + 1; 2332 else 2333 next_s = s + ImTextCharFromUtf8(&c, s, text_end); 2334 if (c == 0) 2335 break; 2336 2337 if (c < 32) 2338 { 2339 if (c == '\n') 2340 { 2341 line_width = word_width = blank_width = 0.0f; 2342 inside_word = true; 2343 s = next_s; 2968 // Simple word-wrapping for English, not full-featured. Please submit failing cases! 2969 // FIXME: Much possible improvements (don't cut things like "word !", "word!!!" but cut within "word,,,,", more sensible support for punctuations, support for Unicode punctuations, etc.) 2970 2971 // For references, possible wrap point marked with ^ 2972 // "aaa bbb, ccc,ddd. eee fff. ggg!" 2973 // ^ ^ ^ ^ ^__ ^ ^ 2974 2975 // List of hardcoded separators: .,;!?'" 2976 2977 // Skip extra blanks after a line returns (that includes not counting them in width computation) 2978 // e.g. "Hello world" --> "Hello" "World" 2979 2980 // Cut words that cannot possibly fit within one line. 2981 // e.g.: "The tropical fish" with ~5 characters worth of width --> "The tr" "opical" "fish" 2982 2983 float line_width = 0.0f; 2984 float word_width = 0.0f; 2985 float blank_width = 0.0f; 2986 wrap_width /= scale; // We work with unscaled widths to avoid scaling every characters 2987 2988 const char* word_end = text; 2989 const char* prev_word_end = NULL; 2990 bool inside_word = true; 2991 2992 const char* s = text; 2993 while (s < text_end) 2994 { 2995 unsigned int c = (unsigned int)*s; 2996 const char* next_s; 2997 if (c < 0x80) 2998 next_s = s + 1; 2999 else 3000 next_s = s + ImTextCharFromUtf8(&c, s, text_end); 3001 if (c == 0) 3002 break; 3003 3004 if (c < 32) 3005 { 3006 if (c == '\n') 3007 { 3008 line_width = word_width = blank_width = 0.0f; 3009 inside_word = true; 3010 s = next_s; 3011 continue; 3012 } 3013 if (c == '\r') 3014 { 3015 s = next_s; 3016 continue; 3017 } 3018 } 3019 3020 const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX); 3021 if (ImCharIsBlankW(c)) 3022 { 3023 if (inside_word) 3024 { 3025 line_width += blank_width; 3026 blank_width = 0.0f; 3027 word_end = s; 3028 } 3029 blank_width += char_width; 3030 inside_word = false; 3031 } 3032 else 3033 { 3034 word_width += char_width; 3035 if (inside_word) 3036 { 3037 word_end = next_s; 3038 } 3039 else 3040 { 3041 prev_word_end = word_end; 3042 line_width += word_width + blank_width; 3043 word_width = blank_width = 0.0f; 3044 } 3045 3046 // Allow wrapping after punctuation. 3047 inside_word = (c != '.' && c != ',' && c != ';' && c != '!' && c != '?' && c != '\"'); 3048 } 3049 3050 // We ignore blank width at the end of the line (they can be skipped) 3051 if (line_width + word_width > wrap_width) 3052 { 3053 // Words that cannot possibly fit within an entire line will be cut anywhere. 3054 if (word_width < wrap_width) 3055 s = prev_word_end ? prev_word_end : word_end; 3056 break; 3057 } 3058 3059 s = next_s; 3060 } 3061 3062 return s; 3063 } 3064 3065 ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end, const char** remaining) const 3066 { 3067 if (!text_end) 3068 text_end = text_begin + strlen(text_begin); // FIXME-OPT: Need to avoid this. 3069 3070 const float line_height = size; 3071 const float scale = size / FontSize; 3072 3073 ImVec2 text_size = ImVec2(0, 0); 3074 float line_width = 0.0f; 3075 3076 const bool word_wrap_enabled = (wrap_width > 0.0f); 3077 const char* word_wrap_eol = NULL; 3078 3079 const char* s = text_begin; 3080 while (s < text_end) 3081 { 3082 if (word_wrap_enabled) 3083 { 3084 // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature. 3085 if (!word_wrap_eol) 3086 { 3087 word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - line_width); 3088 if (word_wrap_eol == s) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity. 3089 word_wrap_eol++; // +1 may not be a character start point in UTF-8 but it's ok because we use s >= word_wrap_eol below 3090 } 3091 3092 if (s >= word_wrap_eol) 3093 { 3094 if (text_size.x < line_width) 3095 text_size.x = line_width; 3096 text_size.y += line_height; 3097 line_width = 0.0f; 3098 word_wrap_eol = NULL; 3099 3100 // Wrapping skips upcoming blanks 3101 while (s < text_end) 3102 { 3103 const char c = *s; 3104 if (ImCharIsBlankA(c)) { s++; } else if (c == '\n') { s++; break; } else { break; } 3105 } 3106 continue; 3107 } 3108 } 3109 3110 // Decode and advance source 3111 const char* prev_s = s; 3112 unsigned int c = (unsigned int)*s; 3113 if (c < 0x80) 3114 { 3115 s += 1; 3116 } 3117 else 3118 { 3119 s += ImTextCharFromUtf8(&c, s, text_end); 3120 if (c == 0) // Malformed UTF-8? 3121 break; 3122 } 3123 3124 if (c < 32) 3125 { 3126 if (c == '\n') 3127 { 3128 text_size.x = ImMax(text_size.x, line_width); 3129 text_size.y += line_height; 3130 line_width = 0.0f; 3131 continue; 3132 } 3133 if (c == '\r') 3134 continue; 3135 } 3136 3137 const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX) * scale; 3138 if (line_width + char_width >= max_width) 3139 { 3140 s = prev_s; 3141 break; 3142 } 3143 3144 line_width += char_width; 3145 } 3146 3147 if (text_size.x < line_width) 3148 text_size.x = line_width; 3149 3150 if (line_width > 0 || text_size.y == 0.0f) 3151 text_size.y += line_height; 3152 3153 if (remaining) 3154 *remaining = s; 3155 3156 return text_size; 3157 } 3158 3159 void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, ImWchar c) const 3160 { 3161 const ImFontGlyph* glyph = FindGlyph(c); 3162 if (!glyph || !glyph->Visible) 3163 return; 3164 float scale = (size >= 0.0f) ? (size / FontSize) : 1.0f; 3165 pos.x = IM_FLOOR(pos.x); 3166 pos.y = IM_FLOOR(pos.y); 3167 draw_list->PrimReserve(6, 4); 3168 draw_list->PrimRectUV(ImVec2(pos.x + glyph->X0 * scale, pos.y + glyph->Y0 * scale), ImVec2(pos.x + glyph->X1 * scale, pos.y + glyph->Y1 * scale), ImVec2(glyph->U0, glyph->V0), ImVec2(glyph->U1, glyph->V1), col); 3169 } 3170 3171 void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) const 3172 { 3173 if (!text_end) 3174 text_end = text_begin + strlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls. 3175 3176 // Align to be pixel perfect 3177 pos.x = IM_FLOOR(pos.x); 3178 pos.y = IM_FLOOR(pos.y); 3179 float x = pos.x; 3180 float y = pos.y; 3181 if (y > clip_rect.w) 3182 return; 3183 3184 const float scale = size / FontSize; 3185 const float line_height = FontSize * scale; 3186 const bool word_wrap_enabled = (wrap_width > 0.0f); 3187 const char* word_wrap_eol = NULL; 3188 3189 // Fast-forward to first visible line 3190 const char* s = text_begin; 3191 if (y + line_height < clip_rect.y && !word_wrap_enabled) 3192 while (y + line_height < clip_rect.y && s < text_end) 3193 { 3194 s = (const char*)memchr(s, '\n', text_end - s); 3195 s = s ? s + 1 : text_end; 3196 y += line_height; 3197 } 3198 3199 // For large text, scan for the last visible line in order to avoid over-reserving in the call to PrimReserve() 3200 // Note that very large horizontal line will still be affected by the issue (e.g. a one megabyte string buffer without a newline will likely crash atm) 3201 if (text_end - s > 10000 && !word_wrap_enabled) 3202 { 3203 const char* s_end = s; 3204 float y_end = y; 3205 while (y_end < clip_rect.w && s_end < text_end) 3206 { 3207 s_end = (const char*)memchr(s_end, '\n', text_end - s_end); 3208 s_end = s_end ? s_end + 1 : text_end; 3209 y_end += line_height; 3210 } 3211 text_end = s_end; 3212 } 3213 if (s == text_end) 3214 return; 3215 3216 // Reserve vertices for remaining worse case (over-reserving is useful and easily amortized) 3217 const int vtx_count_max = (int)(text_end - s) * 4; 3218 const int idx_count_max = (int)(text_end - s) * 6; 3219 const int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max; 3220 draw_list->PrimReserve(idx_count_max, vtx_count_max); 3221 3222 ImDrawVert* vtx_write = draw_list->_VtxWritePtr; 3223 ImDrawIdx* idx_write = draw_list->_IdxWritePtr; 3224 unsigned int vtx_current_idx = draw_list->_VtxCurrentIdx; 3225 3226 while (s < text_end) 3227 { 3228 if (word_wrap_enabled) 3229 { 3230 // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature. 3231 if (!word_wrap_eol) 3232 { 3233 word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - (x - pos.x)); 3234 if (word_wrap_eol == s) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity. 3235 word_wrap_eol++; // +1 may not be a character start point in UTF-8 but it's ok because we use s >= word_wrap_eol below 3236 } 3237 3238 if (s >= word_wrap_eol) 3239 { 3240 x = pos.x; 3241 y += line_height; 3242 word_wrap_eol = NULL; 3243 3244 // Wrapping skips upcoming blanks 3245 while (s < text_end) 3246 { 3247 const char c = *s; 3248 if (ImCharIsBlankA(c)) { s++; } else if (c == '\n') { s++; break; } else { break; } 3249 } 3250 continue; 3251 } 3252 } 3253 3254 // Decode and advance source 3255 unsigned int c = (unsigned int)*s; 3256 if (c < 0x80) 3257 { 3258 s += 1; 3259 } 3260 else 3261 { 3262 s += ImTextCharFromUtf8(&c, s, text_end); 3263 if (c == 0) // Malformed UTF-8? 3264 break; 3265 } 3266 3267 if (c < 32) 3268 { 3269 if (c == '\n') 3270 { 3271 x = pos.x; 3272 y += line_height; 3273 if (y > clip_rect.w) 3274 break; // break out of main loop 3275 continue; 3276 } 3277 if (c == '\r') 3278 continue; 3279 } 3280 3281 const ImFontGlyph* glyph = FindGlyph((ImWchar)c); 3282 if (glyph == NULL) 2344 3283 continue; 2345 } 2346 if (c == '\r') 2347 { 2348 s = next_s; 2349 continue; 2350 } 2351 } 2352 2353 const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX[(int)c] : FallbackAdvanceX); 2354 if (ImCharIsSpace(c)) 2355 { 2356 if (inside_word) 2357 { 2358 line_width += blank_width; 2359 blank_width = 0.0f; 2360 word_end = s; 2361 } 2362 blank_width += char_width; 2363 inside_word = false; 2364 } 2365 else 2366 { 2367 word_width += char_width; 2368 if (inside_word) 2369 { 2370 word_end = next_s; 2371 } 2372 else 2373 { 2374 prev_word_end = word_end; 2375 line_width += word_width + blank_width; 2376 word_width = blank_width = 0.0f; 2377 } 2378 2379 // Allow wrapping after punctuation. 2380 inside_word = !(c == '.' || c == ',' || c == ';' || c == '!' || c == '?' || c == '\"'); 2381 } 2382 2383 // We ignore blank width at the end of the line (they can be skipped) 2384 if (line_width + word_width >= wrap_width) 2385 { 2386 // Words that cannot possibly fit within an entire line will be cut anywhere. 2387 if (word_width < wrap_width) 2388 s = prev_word_end ? prev_word_end : word_end; 2389 break; 2390 } 2391 2392 s = next_s; 2393 } 2394 2395 return s; 2396 } 2397 2398 ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end, const char** remaining) const 2399 { 2400 if (!text_end) 2401 text_end = text_begin + strlen(text_begin); // FIXME-OPT: Need to avoid this. 2402 2403 const float line_height = size; 2404 const float scale = size / FontSize; 2405 2406 ImVec2 text_size = ImVec2(0, 0); 2407 float line_width = 0.0f; 2408 2409 const bool word_wrap_enabled = (wrap_width > 0.0f); 2410 const char* word_wrap_eol = NULL; 2411 2412 const char* s = text_begin; 2413 while (s < text_end) 2414 { 2415 if (word_wrap_enabled) 2416 { 2417 // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature. 2418 if (!word_wrap_eol) 2419 { 2420 word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - line_width); 2421 if (word_wrap_eol == s) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity. 2422 word_wrap_eol++; // +1 may not be a character start point in UTF-8 but it's ok because we use s >= word_wrap_eol below 2423 } 2424 2425 if (s >= word_wrap_eol) 2426 { 2427 if (text_size.x < line_width) 2428 text_size.x = line_width; 2429 text_size.y += line_height; 2430 line_width = 0.0f; 2431 word_wrap_eol = NULL; 2432 2433 // Wrapping skips upcoming blanks 2434 while (s < text_end) 2435 { 2436 const char c = *s; 2437 if (ImCharIsSpace((unsigned int)c)) { s++; } 2438 else if (c == '\n') { s++; break; } 2439 else { break; } 2440 } 2441 continue; 2442 } 2443 } 2444 2445 // Decode and advance source 2446 const char* prev_s = s; 2447 unsigned int c = (unsigned int)*s; 2448 if (c < 0x80) 2449 { 2450 s += 1; 2451 } 2452 else 2453 { 2454 s += ImTextCharFromUtf8(&c, s, text_end); 2455 if (c == 0) // Malformed UTF-8? 2456 break; 2457 } 2458 2459 if (c < 32) 2460 { 2461 if (c == '\n') 2462 { 2463 text_size.x = ImMax(text_size.x, line_width); 2464 text_size.y += line_height; 2465 line_width = 0.0f; 2466 continue; 2467 } 2468 if (c == '\r') 2469 continue; 2470 } 2471 2472 const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX[(int)c] : FallbackAdvanceX) * scale; 2473 if (line_width + char_width >= max_width) 2474 { 2475 s = prev_s; 2476 break; 2477 } 2478 2479 line_width += char_width; 2480 } 2481 2482 if (text_size.x < line_width) 2483 text_size.x = line_width; 2484 2485 if (line_width > 0 || text_size.y == 0.0f) 2486 text_size.y += line_height; 2487 2488 if (remaining) 2489 *remaining = s; 2490 2491 return text_size; 2492 } 2493 2494 void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, unsigned short c) const 2495 { 2496 if (c == ' ' || c == '\t' || c == '\n' || c == '\r') // Match behavior of RenderText(), those 4 codepoints are hard-coded. 2497 return; 2498 if (const ImFontGlyph* glyph = FindGlyph(c)) 2499 { 2500 float scale = (size >= 0.0f) ? (size / FontSize) : 1.0f; 2501 pos.x = (float)(int)pos.x + DisplayOffset.x; 2502 pos.y = (float)(int)pos.y + DisplayOffset.y; 2503 draw_list->PrimReserve(6, 4); 2504 draw_list->PrimRectUV(ImVec2(pos.x + glyph->X0 * scale, pos.y + glyph->Y0 * scale), ImVec2(pos.x + glyph->X1 * scale, pos.y + glyph->Y1 * scale), ImVec2(glyph->U0, glyph->V0), ImVec2(glyph->U1, glyph->V1), col); 2505 } 2506 } 2507 2508 void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) const 2509 { 2510 if (!text_end) 2511 text_end = text_begin + strlen(text_begin); // ImGui functions generally already provides a valid text_end, so this is merely to handle direct calls. 2512 2513 // Align to be pixel perfect 2514 pos.x = (float)(int)pos.x + DisplayOffset.x; 2515 pos.y = (float)(int)pos.y + DisplayOffset.y; 2516 float x = pos.x; 2517 float y = pos.y; 2518 if (y > clip_rect.w) 2519 return; 2520 2521 const float scale = size / FontSize; 2522 const float line_height = FontSize * scale; 2523 const bool word_wrap_enabled = (wrap_width > 0.0f); 2524 const char* word_wrap_eol = NULL; 2525 2526 // Skip non-visible lines 2527 const char* s = text_begin; 2528 if (!word_wrap_enabled && y + line_height < clip_rect.y) 2529 while (s < text_end && *s != '\n') // Fast-forward to next line 2530 s++; 2531 2532 // Reserve vertices for remaining worse case (over-reserving is useful and easily amortized) 2533 const int vtx_count_max = (int)(text_end - s) * 4; 2534 const int idx_count_max = (int)(text_end - s) * 6; 2535 const int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max; 2536 draw_list->PrimReserve(idx_count_max, vtx_count_max); 2537 2538 ImDrawVert* vtx_write = draw_list->_VtxWritePtr; 2539 ImDrawIdx* idx_write = draw_list->_IdxWritePtr; 2540 unsigned int vtx_current_idx = draw_list->_VtxCurrentIdx; 2541 2542 while (s < text_end) 2543 { 2544 if (word_wrap_enabled) 2545 { 2546 // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature. 2547 if (!word_wrap_eol) 2548 { 2549 word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - (x - pos.x)); 2550 if (word_wrap_eol == s) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity. 2551 word_wrap_eol++; // +1 may not be a character start point in UTF-8 but it's ok because we use s >= word_wrap_eol below 2552 } 2553 2554 if (s >= word_wrap_eol) 2555 { 2556 x = pos.x; 2557 y += line_height; 2558 word_wrap_eol = NULL; 2559 2560 // Wrapping skips upcoming blanks 2561 while (s < text_end) 2562 { 2563 const char c = *s; 2564 if (ImCharIsSpace((unsigned int)c)) { s++; } 2565 else if (c == '\n') { s++; break; } 2566 else { break; } 2567 } 2568 continue; 2569 } 2570 } 2571 2572 // Decode and advance source 2573 unsigned int c = (unsigned int)*s; 2574 if (c < 0x80) 2575 { 2576 s += 1; 2577 } 2578 else 2579 { 2580 s += ImTextCharFromUtf8(&c, s, text_end); 2581 if (c == 0) // Malformed UTF-8? 2582 break; 2583 } 2584 2585 if (c < 32) 2586 { 2587 if (c == '\n') 2588 { 2589 x = pos.x; 2590 y += line_height; 2591 2592 if (y > clip_rect.w) 2593 break; 2594 if (!word_wrap_enabled && y + line_height < clip_rect.y) 2595 while (s < text_end && *s != '\n') // Fast-forward to next line 2596 s++; 2597 continue; 2598 } 2599 if (c == '\r') 2600 continue; 2601 } 2602 2603 float char_width = 0.0f; 2604 if (const ImFontGlyph* glyph = FindGlyph((unsigned short)c)) 2605 { 2606 char_width = glyph->AdvanceX * scale; 2607 2608 // Arbitrarily assume that both space and tabs are empty glyphs as an optimization 2609 if (c != ' ' && c != '\t') 2610 { 3284 3285 float char_width = glyph->AdvanceX * scale; 3286 if (glyph->Visible) 3287 { 2611 3288 // We don't do a second finer clipping test on the Y axis as we've already skipped anything before clip_rect.y and exit once we pass clip_rect.w 2612 3289 float x1 = x + glyph->X0 * scale; … … 2616 3293 if (x1 <= clip_rect.z && x2 >= clip_rect.x) 2617 3294 { 2618 // Render a character2619 float u1 = glyph->U0;2620 float v1 = glyph->V0;2621 float u2 = glyph->U1;2622 float v2 = glyph->V1;2623 2624 // CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for axis aligned quads.2625 if (cpu_fine_clip)2626 {2627 if (x1 < clip_rect.x)2628 {2629 u1 = u1 + (1.0f - (x2 - clip_rect.x) / (x2 - x1)) * (u2 - u1);2630 x1 = clip_rect.x;2631 }2632 if (y1 < clip_rect.y)2633 {2634 v1 = v1 + (1.0f - (y2 - clip_rect.y) / (y2 - y1)) * (v2 - v1);2635 y1 = clip_rect.y;2636 }2637 if (x2 > clip_rect.z)2638 {2639 u2 = u1 + ((clip_rect.z - x1) / (x2 - x1)) * (u2 - u1);2640 x2 = clip_rect.z;2641 }2642 if (y2 > clip_rect.w)2643 {2644 v2 = v1 + ((clip_rect.w - y1) / (y2 - y1)) * (v2 - v1);2645 y2 = clip_rect.w;2646 }2647 if (y1 >= y2)2648 {2649 x += char_width;2650 continue;2651 }2652 }2653 2654 // We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug builds. Inlined here:2655 {2656 idx_write[0] = (ImDrawIdx)(vtx_current_idx); idx_write[1] = (ImDrawIdx)(vtx_current_idx + 1); idx_write[2] = (ImDrawIdx)(vtx_current_idx +2);2657 idx_write[3] = (ImDrawIdx)(vtx_current_idx); idx_write[4] = (ImDrawIdx)(vtx_current_idx + 2); idx_write[5] = (ImDrawIdx)(vtx_current_idx +3);2658 vtx_write[0].pos.x = x1; vtx_write[0].pos.y = y1; vtx_write[0].col = col; vtx_write[0].uv.x = u1; vtx_write[0].uv.y = v1;2659 vtx_write[1].pos.x = x2; vtx_write[1].pos.y = y1; vtx_write[1].col = col; vtx_write[1].uv.x = u2; vtx_write[1].uv.y = v1;2660 vtx_write[2].pos.x = x2; vtx_write[2].pos.y = y2; vtx_write[2].col = col; vtx_write[2].uv.x = u2; vtx_write[2].uv.y = v2;2661 vtx_write[3].pos.x = x1; vtx_write[3].pos.y = y2; vtx_write[3].col = col; vtx_write[3].uv.x = u1; vtx_write[3].uv.y = v2;2662 vtx_write += 4;2663 vtx_current_idx += 4;2664 idx_write += 6;2665 }3295 // Render a character 3296 float u1 = glyph->U0; 3297 float v1 = glyph->V0; 3298 float u2 = glyph->U1; 3299 float v2 = glyph->V1; 3300 3301 // CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for axis aligned quads. 3302 if (cpu_fine_clip) 3303 { 3304 if (x1 < clip_rect.x) 3305 { 3306 u1 = u1 + (1.0f - (x2 - clip_rect.x) / (x2 - x1)) * (u2 - u1); 3307 x1 = clip_rect.x; 3308 } 3309 if (y1 < clip_rect.y) 3310 { 3311 v1 = v1 + (1.0f - (y2 - clip_rect.y) / (y2 - y1)) * (v2 - v1); 3312 y1 = clip_rect.y; 3313 } 3314 if (x2 > clip_rect.z) 3315 { 3316 u2 = u1 + ((clip_rect.z - x1) / (x2 - x1)) * (u2 - u1); 3317 x2 = clip_rect.z; 3318 } 3319 if (y2 > clip_rect.w) 3320 { 3321 v2 = v1 + ((clip_rect.w - y1) / (y2 - y1)) * (v2 - v1); 3322 y2 = clip_rect.w; 3323 } 3324 if (y1 >= y2) 3325 { 3326 x += char_width; 3327 continue; 3328 } 3329 } 3330 3331 // We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug builds. Inlined here: 3332 { 3333 idx_write[0] = (ImDrawIdx)(vtx_current_idx); idx_write[1] = (ImDrawIdx)(vtx_current_idx+1); idx_write[2] = (ImDrawIdx)(vtx_current_idx+2); 3334 idx_write[3] = (ImDrawIdx)(vtx_current_idx); idx_write[4] = (ImDrawIdx)(vtx_current_idx+2); idx_write[5] = (ImDrawIdx)(vtx_current_idx+3); 3335 vtx_write[0].pos.x = x1; vtx_write[0].pos.y = y1; vtx_write[0].col = col; vtx_write[0].uv.x = u1; vtx_write[0].uv.y = v1; 3336 vtx_write[1].pos.x = x2; vtx_write[1].pos.y = y1; vtx_write[1].col = col; vtx_write[1].uv.x = u2; vtx_write[1].uv.y = v1; 3337 vtx_write[2].pos.x = x2; vtx_write[2].pos.y = y2; vtx_write[2].col = col; vtx_write[2].uv.x = u2; vtx_write[2].uv.y = v2; 3338 vtx_write[3].pos.x = x1; vtx_write[3].pos.y = y2; vtx_write[3].col = col; vtx_write[3].uv.x = u1; vtx_write[3].uv.y = v2; 3339 vtx_write += 4; 3340 vtx_current_idx += 4; 3341 idx_write += 6; 3342 } 2666 3343 } 2667 } 2668 } 2669 2670 x += char_width; 2671 } 2672 2673 // Give back unused vertices 2674 draw_list->VtxBuffer.resize((int)(vtx_write - draw_list->VtxBuffer.Data)); 2675 draw_list->IdxBuffer.resize((int)(idx_write - draw_list->IdxBuffer.Data)); 2676 draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ElemCount -= (idx_expected_size - draw_list->IdxBuffer.Size); 2677 draw_list->_VtxWritePtr = vtx_write; 2678 draw_list->_IdxWritePtr = idx_write; 2679 draw_list->_VtxCurrentIdx = (unsigned int)draw_list->VtxBuffer.Size; 3344 } 3345 x += char_width; 3346 } 3347 3348 // Give back unused vertices (clipped ones, blanks) ~ this is essentially a PrimUnreserve() action. 3349 draw_list->VtxBuffer.Size = (int)(vtx_write - draw_list->VtxBuffer.Data); // Same as calling shrink() 3350 draw_list->IdxBuffer.Size = (int)(idx_write - draw_list->IdxBuffer.Data); 3351 draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ElemCount -= (idx_expected_size - draw_list->IdxBuffer.Size); 3352 draw_list->_VtxWritePtr = vtx_write; 3353 draw_list->_IdxWritePtr = idx_write; 3354 draw_list->_VtxCurrentIdx = vtx_current_idx; 2680 3355 } 2681 3356 2682 3357 //----------------------------------------------------------------------------- 2683 // Internals DrawingHelpers3358 // [SECTION] ImGui Internal Render Helpers 2684 3359 //----------------------------------------------------------------------------- 3360 // Vaguely redesigned to stop accessing ImGui global state: 3361 // - RenderArrow() 3362 // - RenderBullet() 3363 // - RenderCheckMark() 3364 // - RenderMouseCursor() 3365 // - RenderArrowPointingAt() 3366 // - RenderRectFilledRangeH() 3367 //----------------------------------------------------------------------------- 3368 // Function in need of a redesign (legacy mess) 3369 // - RenderColorRectWithAlphaCheckerboard() 3370 //----------------------------------------------------------------------------- 3371 3372 // 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 3373 void ImGui::RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir dir, float scale) 3374 { 3375 const float h = draw_list->_Data->FontSize * 1.00f; 3376 float r = h * 0.40f * scale; 3377 ImVec2 center = pos + ImVec2(h * 0.50f, h * 0.50f * scale); 3378 3379 ImVec2 a, b, c; 3380 switch (dir) 3381 { 3382 case ImGuiDir_Up: 3383 case ImGuiDir_Down: 3384 if (dir == ImGuiDir_Up) r = -r; 3385 a = ImVec2(+0.000f, +0.750f) * r; 3386 b = ImVec2(-0.866f, -0.750f) * r; 3387 c = ImVec2(+0.866f, -0.750f) * r; 3388 break; 3389 case ImGuiDir_Left: 3390 case ImGuiDir_Right: 3391 if (dir == ImGuiDir_Left) r = -r; 3392 a = ImVec2(+0.750f, +0.000f) * r; 3393 b = ImVec2(-0.750f, +0.866f) * r; 3394 c = ImVec2(-0.750f, -0.866f) * r; 3395 break; 3396 case ImGuiDir_None: 3397 case ImGuiDir_COUNT: 3398 IM_ASSERT(0); 3399 break; 3400 } 3401 draw_list->AddTriangleFilled(center + a, center + b, center + c, col); 3402 } 3403 3404 void ImGui::RenderBullet(ImDrawList* draw_list, ImVec2 pos, ImU32 col) 3405 { 3406 draw_list->AddCircleFilled(pos, draw_list->_Data->FontSize * 0.20f, col, 8); 3407 } 3408 3409 void ImGui::RenderCheckMark(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz) 3410 { 3411 float thickness = ImMax(sz / 5.0f, 1.0f); 3412 sz -= thickness * 0.5f; 3413 pos += ImVec2(thickness * 0.25f, thickness * 0.25f); 3414 3415 float third = sz / 3.0f; 3416 float bx = pos.x + third; 3417 float by = pos.y + sz - third * 0.5f; 3418 draw_list->PathLineTo(ImVec2(bx - third, by - third)); 3419 draw_list->PathLineTo(ImVec2(bx, by)); 3420 draw_list->PathLineTo(ImVec2(bx + third * 2.0f, by - third * 2.0f)); 3421 draw_list->PathStroke(col, false, thickness); 3422 } 3423 3424 void ImGui::RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow) 3425 { 3426 if (mouse_cursor == ImGuiMouseCursor_None) 3427 return; 3428 IM_ASSERT(mouse_cursor > ImGuiMouseCursor_None && mouse_cursor < ImGuiMouseCursor_COUNT); 3429 3430 ImFontAtlas* font_atlas = draw_list->_Data->Font->ContainerAtlas; 3431 ImVec2 offset, size, uv[4]; 3432 if (font_atlas->GetMouseCursorTexData(mouse_cursor, &offset, &size, &uv[0], &uv[2])) 3433 { 3434 pos -= offset; 3435 const ImTextureID tex_id = font_atlas->TexID; 3436 draw_list->PushTextureID(tex_id); 3437 draw_list->AddImage(tex_id, pos + ImVec2(1, 0) * scale, pos + (ImVec2(1, 0) + size) * scale, uv[2], uv[3], col_shadow); 3438 draw_list->AddImage(tex_id, pos + ImVec2(2, 0) * scale, pos + (ImVec2(2, 0) + size) * scale, uv[2], uv[3], col_shadow); 3439 draw_list->AddImage(tex_id, pos, pos + size * scale, uv[2], uv[3], col_border); 3440 draw_list->AddImage(tex_id, pos, pos + size * scale, uv[0], uv[1], col_fill); 3441 draw_list->PopTextureID(); 3442 } 3443 } 3444 3445 // Render an arrow. 'pos' is position of the arrow tip. half_sz.x is length from base to tip. half_sz.y is length on each side. 3446 void ImGui::RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col) 3447 { 3448 switch (direction) 3449 { 3450 case ImGuiDir_Left: draw_list->AddTriangleFilled(ImVec2(pos.x + half_sz.x, pos.y - half_sz.y), ImVec2(pos.x + half_sz.x, pos.y + half_sz.y), pos, col); return; 3451 case ImGuiDir_Right: draw_list->AddTriangleFilled(ImVec2(pos.x - half_sz.x, pos.y + half_sz.y), ImVec2(pos.x - half_sz.x, pos.y - half_sz.y), pos, col); return; 3452 case ImGuiDir_Up: draw_list->AddTriangleFilled(ImVec2(pos.x + half_sz.x, pos.y + half_sz.y), ImVec2(pos.x - half_sz.x, pos.y + half_sz.y), pos, col); return; 3453 case ImGuiDir_Down: draw_list->AddTriangleFilled(ImVec2(pos.x - half_sz.x, pos.y - half_sz.y), ImVec2(pos.x + half_sz.x, pos.y - half_sz.y), pos, col); return; 3454 case ImGuiDir_None: case ImGuiDir_COUNT: break; // Fix warnings 3455 } 3456 } 2685 3457 2686 3458 static inline float ImAcos01(float x) 2687 3459 { 2688 if (x <= 0.0f) return IM_PI * 0.5f;2689 if (x >= 1.0f) return 0.0f;2690 return acosf(x);2691 //return (-0.69813170079773212f * x * x - 0.87266462599716477f) * x + 1.5707963267948966f; // Cheap approximation, may be enough for what we do.3460 if (x <= 0.0f) return IM_PI * 0.5f; 3461 if (x >= 1.0f) return 0.0f; 3462 return ImAcos(x); 3463 //return (-0.69813170079773212f * x * x - 0.87266462599716477f) * x + 1.5707963267948966f; // Cheap approximation, may be enough for what we do. 2692 3464 } 2693 3465 … … 2695 3467 void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding) 2696 3468 { 2697 if (x_end_norm == x_start_norm) 2698 return; 2699 if (x_start_norm > x_end_norm) 2700 ImSwap(x_start_norm, x_end_norm); 2701 2702 ImVec2 p0 = ImVec2(ImLerp(rect.Min.x, rect.Max.x, x_start_norm), rect.Min.y); 2703 ImVec2 p1 = ImVec2(ImLerp(rect.Min.x, rect.Max.x, x_end_norm), rect.Max.y); 2704 if (rounding == 0.0f) 2705 { 2706 draw_list->AddRectFilled(p0, p1, col, 0.0f); 2707 return; 2708 } 2709 2710 rounding = ImClamp(ImMin((rect.Max.x - rect.Min.x) * 0.5f, (rect.Max.y - rect.Min.y) * 0.5f) - 1.0f, 0.0f, rounding); 2711 const float inv_rounding = 1.0f / rounding; 2712 const float arc0_b = ImAcos01(1.0f - (p0.x - rect.Min.x) * inv_rounding); 2713 const float arc0_e = ImAcos01(1.0f - (p1.x - rect.Min.x) * inv_rounding); 2714 const float x0 = ImMax(p0.x, rect.Min.x + rounding); 2715 if (arc0_b == arc0_e) 2716 { 2717 draw_list->PathLineTo(ImVec2(x0, p1.y)); 2718 draw_list->PathLineTo(ImVec2(x0, p0.y)); 2719 } 2720 else if (arc0_b == 0.0f && arc0_e == IM_PI * 0.5f) 2721 { 2722 draw_list->PathArcToFast(ImVec2(x0, p1.y - rounding), rounding, 3, 6); // BL 2723 draw_list->PathArcToFast(ImVec2(x0, p0.y + rounding), rounding, 6, 9); // TR 2724 } 2725 else 2726 { 2727 draw_list->PathArcTo(ImVec2(x0, p1.y - rounding), rounding, IM_PI - arc0_e, IM_PI - arc0_b, 3); // BL 2728 draw_list->PathArcTo(ImVec2(x0, p0.y + rounding), rounding, IM_PI + arc0_b, IM_PI + arc0_e, 3); // TR 2729 } 2730 if (p1.x > rect.Min.x + rounding) 2731 { 2732 const float arc1_b = ImAcos01(1.0f - (rect.Max.x - p1.x) * inv_rounding); 2733 const float arc1_e = ImAcos01(1.0f - (rect.Max.x - p0.x) * inv_rounding); 2734 const float x1 = ImMin(p1.x, rect.Max.x - rounding); 2735 if (arc1_b == arc1_e) 2736 { 2737 draw_list->PathLineTo(ImVec2(x1, p0.y)); 2738 draw_list->PathLineTo(ImVec2(x1, p1.y)); 2739 } 2740 else if (arc1_b == 0.0f && arc1_e == IM_PI * 0.5f) 2741 { 2742 draw_list->PathArcToFast(ImVec2(x1, p0.y + rounding), rounding, 9, 12); // TR 2743 draw_list->PathArcToFast(ImVec2(x1, p1.y - rounding), rounding, 0, 3); // BR 2744 } 2745 else 2746 { 2747 draw_list->PathArcTo(ImVec2(x1, p0.y + rounding), rounding, -arc1_e, -arc1_b, 3); // TR 2748 draw_list->PathArcTo(ImVec2(x1, p1.y - rounding), rounding, +arc1_b, +arc1_e, 3); // BR 2749 } 2750 } 2751 draw_list->PathFillConvex(col); 3469 if (x_end_norm == x_start_norm) 3470 return; 3471 if (x_start_norm > x_end_norm) 3472 ImSwap(x_start_norm, x_end_norm); 3473 3474 ImVec2 p0 = ImVec2(ImLerp(rect.Min.x, rect.Max.x, x_start_norm), rect.Min.y); 3475 ImVec2 p1 = ImVec2(ImLerp(rect.Min.x, rect.Max.x, x_end_norm), rect.Max.y); 3476 if (rounding == 0.0f) 3477 { 3478 draw_list->AddRectFilled(p0, p1, col, 0.0f); 3479 return; 3480 } 3481 3482 rounding = ImClamp(ImMin((rect.Max.x - rect.Min.x) * 0.5f, (rect.Max.y - rect.Min.y) * 0.5f) - 1.0f, 0.0f, rounding); 3483 const float inv_rounding = 1.0f / rounding; 3484 const float arc0_b = ImAcos01(1.0f - (p0.x - rect.Min.x) * inv_rounding); 3485 const float arc0_e = ImAcos01(1.0f - (p1.x - rect.Min.x) * inv_rounding); 3486 const float half_pi = IM_PI * 0.5f; // We will == compare to this because we know this is the exact value ImAcos01 can return. 3487 const float x0 = ImMax(p0.x, rect.Min.x + rounding); 3488 if (arc0_b == arc0_e) 3489 { 3490 draw_list->PathLineTo(ImVec2(x0, p1.y)); 3491 draw_list->PathLineTo(ImVec2(x0, p0.y)); 3492 } 3493 else if (arc0_b == 0.0f && arc0_e == half_pi) 3494 { 3495 draw_list->PathArcToFast(ImVec2(x0, p1.y - rounding), rounding, 3, 6); // BL 3496 draw_list->PathArcToFast(ImVec2(x0, p0.y + rounding), rounding, 6, 9); // TR 3497 } 3498 else 3499 { 3500 draw_list->PathArcTo(ImVec2(x0, p1.y - rounding), rounding, IM_PI - arc0_e, IM_PI - arc0_b, 3); // BL 3501 draw_list->PathArcTo(ImVec2(x0, p0.y + rounding), rounding, IM_PI + arc0_b, IM_PI + arc0_e, 3); // TR 3502 } 3503 if (p1.x > rect.Min.x + rounding) 3504 { 3505 const float arc1_b = ImAcos01(1.0f - (rect.Max.x - p1.x) * inv_rounding); 3506 const float arc1_e = ImAcos01(1.0f - (rect.Max.x - p0.x) * inv_rounding); 3507 const float x1 = ImMin(p1.x, rect.Max.x - rounding); 3508 if (arc1_b == arc1_e) 3509 { 3510 draw_list->PathLineTo(ImVec2(x1, p0.y)); 3511 draw_list->PathLineTo(ImVec2(x1, p1.y)); 3512 } 3513 else if (arc1_b == 0.0f && arc1_e == half_pi) 3514 { 3515 draw_list->PathArcToFast(ImVec2(x1, p0.y + rounding), rounding, 9, 12); // TR 3516 draw_list->PathArcToFast(ImVec2(x1, p1.y - rounding), rounding, 0, 3); // BR 3517 } 3518 else 3519 { 3520 draw_list->PathArcTo(ImVec2(x1, p0.y + rounding), rounding, -arc1_e, -arc1_b, 3); // TR 3521 draw_list->PathArcTo(ImVec2(x1, p1.y - rounding), rounding, +arc1_b, +arc1_e, 3); // BR 3522 } 3523 } 3524 draw_list->PathFillConvex(col); 3525 } 3526 3527 void ImGui::RenderRectFilledWithHole(ImDrawList* draw_list, ImRect outer, ImRect inner, ImU32 col, float rounding) 3528 { 3529 const bool fill_L = (inner.Min.x > outer.Min.x); 3530 const bool fill_R = (inner.Max.x < outer.Max.x); 3531 const bool fill_U = (inner.Min.y > outer.Min.y); 3532 const bool fill_D = (inner.Max.y < outer.Max.y); 3533 if (fill_L) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Min.y), ImVec2(inner.Min.x, inner.Max.y), col, rounding, (fill_U ? 0 : ImDrawCornerFlags_TopLeft) | (fill_D ? 0 : ImDrawCornerFlags_BotLeft)); 3534 if (fill_R) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Min.y), ImVec2(outer.Max.x, inner.Max.y), col, rounding, (fill_U ? 0 : ImDrawCornerFlags_TopRight) | (fill_D ? 0 : ImDrawCornerFlags_BotRight)); 3535 if (fill_U) draw_list->AddRectFilled(ImVec2(inner.Min.x, outer.Min.y), ImVec2(inner.Max.x, inner.Min.y), col, rounding, (fill_L ? 0 : ImDrawCornerFlags_TopLeft) | (fill_R ? 0 : ImDrawCornerFlags_TopRight)); 3536 if (fill_D) draw_list->AddRectFilled(ImVec2(inner.Min.x, inner.Max.y), ImVec2(inner.Max.x, outer.Max.y), col, rounding, (fill_L ? 0 : ImDrawCornerFlags_BotLeft) | (fill_R ? 0 : ImDrawCornerFlags_BotRight)); 3537 if (fill_L && fill_U) draw_list->AddRectFilled(ImVec2(outer.Min.x, outer.Min.y), ImVec2(inner.Min.x, inner.Min.y), col, rounding, ImDrawCornerFlags_TopLeft); 3538 if (fill_R && fill_U) draw_list->AddRectFilled(ImVec2(inner.Max.x, outer.Min.y), ImVec2(outer.Max.x, inner.Min.y), col, rounding, ImDrawCornerFlags_TopRight); 3539 if (fill_L && fill_D) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Max.y), ImVec2(inner.Min.x, outer.Max.y), col, rounding, ImDrawCornerFlags_BotLeft); 3540 if (fill_R && fill_D) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Max.y), ImVec2(outer.Max.x, outer.Max.y), col, rounding, ImDrawCornerFlags_BotRight); 3541 } 3542 3543 // Helper for ColorPicker4() 3544 // NB: This is rather brittle and will show artifact when rounding this enabled if rounded corners overlap multiple cells. Caller currently responsible for avoiding that. 3545 // Spent a non reasonable amount of time trying to getting this right for ColorButton with rounding+anti-aliasing+ImGuiColorEditFlags_HalfAlphaPreview flag + various grid sizes and offsets, and eventually gave up... probably more reasonable to disable rounding altogether. 3546 // FIXME: uses ImGui::GetColorU32 3547 void ImGui::RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 col, float grid_step, ImVec2 grid_off, float rounding, int rounding_corners_flags) 3548 { 3549 if (((col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT) < 0xFF) 3550 { 3551 ImU32 col_bg1 = ImGui::GetColorU32(ImAlphaBlendColors(IM_COL32(204, 204, 204, 255), col)); 3552 ImU32 col_bg2 = ImGui::GetColorU32(ImAlphaBlendColors(IM_COL32(128, 128, 128, 255), col)); 3553 draw_list->AddRectFilled(p_min, p_max, col_bg1, rounding, rounding_corners_flags); 3554 3555 int yi = 0; 3556 for (float y = p_min.y + grid_off.y; y < p_max.y; y += grid_step, yi++) 3557 { 3558 float y1 = ImClamp(y, p_min.y, p_max.y), y2 = ImMin(y + grid_step, p_max.y); 3559 if (y2 <= y1) 3560 continue; 3561 for (float x = p_min.x + grid_off.x + (yi & 1) * grid_step; x < p_max.x; x += grid_step * 2.0f) 3562 { 3563 float x1 = ImClamp(x, p_min.x, p_max.x), x2 = ImMin(x + grid_step, p_max.x); 3564 if (x2 <= x1) 3565 continue; 3566 int rounding_corners_flags_cell = 0; 3567 if (y1 <= p_min.y) { if (x1 <= p_min.x) rounding_corners_flags_cell |= ImDrawCornerFlags_TopLeft; if (x2 >= p_max.x) rounding_corners_flags_cell |= ImDrawCornerFlags_TopRight; } 3568 if (y2 >= p_max.y) { if (x1 <= p_min.x) rounding_corners_flags_cell |= ImDrawCornerFlags_BotLeft; if (x2 >= p_max.x) rounding_corners_flags_cell |= ImDrawCornerFlags_BotRight; } 3569 rounding_corners_flags_cell &= rounding_corners_flags; 3570 draw_list->AddRectFilled(ImVec2(x1, y1), ImVec2(x2, y2), col_bg2, rounding_corners_flags_cell ? rounding : 0.0f, rounding_corners_flags_cell); 3571 } 3572 } 3573 } 3574 else 3575 { 3576 draw_list->AddRectFilled(p_min, p_max, col, rounding, rounding_corners_flags); 3577 } 2752 3578 } 2753 3579 2754 3580 //----------------------------------------------------------------------------- 2755 // DEFAULT FONT DATA3581 // [SECTION] Decompression code 2756 3582 //----------------------------------------------------------------------------- 2757 // Compressed with stb_compress() then converted to a C array .3583 // Compressed with stb_compress() then converted to a C array and encoded as base85. 2758 3584 // Use the program in misc/fonts/binary_to_compressed_c.cpp to create the array from a TTF file. 3585 // The purpose of encoding as base85 instead of "0x00,0x01,..." style is only save on _source code_ size. 2759 3586 // Decompression from stb.h (public domain) by Sean Barrett https://github.com/nothings/stb/blob/master/stb.h 2760 3587 //----------------------------------------------------------------------------- … … 2762 3589 static unsigned int stb_decompress_length(const unsigned char *input) 2763 3590 { 2764 return (input[8] << 24) + (input[9] << 16) + (input[10] << 8) + input[11];3591 return (input[8] << 24) + (input[9] << 16) + (input[10] << 8) + input[11]; 2765 3592 } 2766 3593 … … 2770 3597 static void stb__match(const unsigned char *data, unsigned int length) 2771 3598 { 2772 // INVERSE of memmove... write each byte before copying the next...2773 IM_ASSERT(stb__dout + length <= stb__barrier_out_e);2774 if (stb__dout + length > stb__barrier_out_e) { stb__dout += length; return; }2775 if (data < stb__barrier_out_b) { stb__dout = stb__barrier_out_e +1; return; }2776 while (length--) *stb__dout++ = *data++;3599 // INVERSE of memmove... write each byte before copying the next... 3600 IM_ASSERT(stb__dout + length <= stb__barrier_out_e); 3601 if (stb__dout + length > stb__barrier_out_e) { stb__dout += length; return; } 3602 if (data < stb__barrier_out_b) { stb__dout = stb__barrier_out_e+1; return; } 3603 while (length--) *stb__dout++ = *data++; 2777 3604 } 2778 3605 2779 3606 static void stb__lit(const unsigned char *data, unsigned int length) 2780 3607 { 2781 IM_ASSERT(stb__dout + length <= stb__barrier_out_e);2782 if (stb__dout + length > stb__barrier_out_e) { stb__dout += length; return; }2783 if (data < stb__barrier_in_b) { stb__dout = stb__barrier_out_e +1; return; }2784 memcpy(stb__dout, data, length);2785 stb__dout += length;3608 IM_ASSERT(stb__dout + length <= stb__barrier_out_e); 3609 if (stb__dout + length > stb__barrier_out_e) { stb__dout += length; return; } 3610 if (data < stb__barrier_in_b) { stb__dout = stb__barrier_out_e+1; return; } 3611 memcpy(stb__dout, data, length); 3612 stb__dout += length; 2786 3613 } 2787 3614 … … 2792 3619 static const unsigned char *stb_decompress_token(const unsigned char *i) 2793 3620 { 2794 if (*i >= 0x20) { // use fewer if's for cases that expand small 2795 if (*i >= 0x80) stb__match(stb__dout - i[1] - 1, i[0] - 0x80 + 1), i += 2; 2796 else if (*i >= 0x40) stb__match(stb__dout - (stb__in2(0) - 0x4000 + 1), i[2] + 1), i += 3; 2797 else /* *i >= 0x20 */ stb__lit(i + 1, i[0] - 0x20 + 1), i += 1 + (i[0] - 0x20 + 1); 2798 } 2799 else { // more ifs for cases that expand large, since overhead is amortized 2800 if (*i >= 0x18) stb__match(stb__dout - (stb__in3(0) - 0x180000 + 1), i[3] + 1), i += 4; 2801 else if (*i >= 0x10) stb__match(stb__dout - (stb__in3(0) - 0x100000 + 1), stb__in2(3) + 1), i += 5; 2802 else if (*i >= 0x08) stb__lit(i + 2, stb__in2(0) - 0x0800 + 1), i += 2 + (stb__in2(0) - 0x0800 + 1); 2803 else if (*i == 0x07) stb__lit(i + 3, stb__in2(1) + 1), i += 3 + (stb__in2(1) + 1); 2804 else if (*i == 0x06) stb__match(stb__dout - (stb__in3(1) + 1), i[4] + 1), i += 5; 2805 else if (*i == 0x04) stb__match(stb__dout - (stb__in3(1) + 1), stb__in2(4) + 1), i += 6; 2806 } 2807 return i; 3621 if (*i >= 0x20) { // use fewer if's for cases that expand small 3622 if (*i >= 0x80) stb__match(stb__dout-i[1]-1, i[0] - 0x80 + 1), i += 2; 3623 else if (*i >= 0x40) stb__match(stb__dout-(stb__in2(0) - 0x4000 + 1), i[2]+1), i += 3; 3624 else /* *i >= 0x20 */ stb__lit(i+1, i[0] - 0x20 + 1), i += 1 + (i[0] - 0x20 + 1); 3625 } else { // more ifs for cases that expand large, since overhead is amortized 3626 if (*i >= 0x18) stb__match(stb__dout-(stb__in3(0) - 0x180000 + 1), i[3]+1), i += 4; 3627 else if (*i >= 0x10) stb__match(stb__dout-(stb__in3(0) - 0x100000 + 1), stb__in2(3)+1), i += 5; 3628 else if (*i >= 0x08) stb__lit(i+2, stb__in2(0) - 0x0800 + 1), i += 2 + (stb__in2(0) - 0x0800 + 1); 3629 else if (*i == 0x07) stb__lit(i+3, stb__in2(1) + 1), i += 3 + (stb__in2(1) + 1); 3630 else if (*i == 0x06) stb__match(stb__dout-(stb__in3(1)+1), i[4]+1), i += 5; 3631 else if (*i == 0x04) stb__match(stb__dout-(stb__in3(1)+1), stb__in2(4)+1), i += 6; 3632 } 3633 return i; 2808 3634 } 2809 3635 2810 3636 static unsigned int stb_adler32(unsigned int adler32, unsigned char *buffer, unsigned int buflen) 2811 3637 { 2812 const unsigned long ADLER_MOD = 65521;2813 unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16;2814 unsigned long blocklen, i;2815 2816 blocklen = buflen % 5552;2817 while (buflen) {2818 for (i =0; i + 7 < blocklen; i += 8) {2819 s1 += buffer[0], s2 += s1;2820 s1 += buffer[1], s2 += s1;2821 s1 += buffer[2], s2 += s1;2822 s1 += buffer[3], s2 += s1;2823 s1 += buffer[4], s2 += s1;2824 s1 += buffer[5], s2 += s1;2825 s1 += buffer[6], s2 += s1;2826 s1 += buffer[7], s2 += s1;2827 2828 buffer += 8;2829 }2830 2831 for (; i < blocklen; ++i)2832 s1 += *buffer++, s2 += s1;2833 2834 s1 %= ADLER_MOD, s2 %= ADLER_MOD;2835 buflen -= blocklen;2836 blocklen = 5552;2837 }2838 return (unsigned int)(s2 << 16) + (unsigned int)s1;3638 const unsigned long ADLER_MOD = 65521; 3639 unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16; 3640 unsigned long blocklen = buflen % 5552; 3641 3642 unsigned long i; 3643 while (buflen) { 3644 for (i=0; i + 7 < blocklen; i += 8) { 3645 s1 += buffer[0], s2 += s1; 3646 s1 += buffer[1], s2 += s1; 3647 s1 += buffer[2], s2 += s1; 3648 s1 += buffer[3], s2 += s1; 3649 s1 += buffer[4], s2 += s1; 3650 s1 += buffer[5], s2 += s1; 3651 s1 += buffer[6], s2 += s1; 3652 s1 += buffer[7], s2 += s1; 3653 3654 buffer += 8; 3655 } 3656 3657 for (; i < blocklen; ++i) 3658 s1 += *buffer++, s2 += s1; 3659 3660 s1 %= ADLER_MOD, s2 %= ADLER_MOD; 3661 buflen -= blocklen; 3662 blocklen = 5552; 3663 } 3664 return (unsigned int)(s2 << 16) + (unsigned int)s1; 2839 3665 } 2840 3666 2841 3667 static unsigned int stb_decompress(unsigned char *output, const unsigned char *i, unsigned int /*length*/) 2842 3668 { 2843 unsigned int olen; 2844 if (stb__in4(0) != 0x57bC0000) return 0; 2845 if (stb__in4(4) != 0) return 0; // error! stream is > 4GB 2846 olen = stb_decompress_length(i); 2847 stb__barrier_in_b = i; 2848 stb__barrier_out_e = output + olen; 2849 stb__barrier_out_b = output; 2850 i += 16; 2851 2852 stb__dout = output; 2853 for (;;) { 2854 const unsigned char *old_i = i; 2855 i = stb_decompress_token(i); 2856 if (i == old_i) { 2857 if (*i == 0x05 && i[1] == 0xfa) { 2858 IM_ASSERT(stb__dout == output + olen); 2859 if (stb__dout != output + olen) return 0; 2860 if (stb_adler32(1, output, olen) != (unsigned int)stb__in4(2)) 2861 return 0; 2862 return olen; 2863 } 2864 else { 2865 IM_ASSERT(0); /* NOTREACHED */ 3669 if (stb__in4(0) != 0x57bC0000) return 0; 3670 if (stb__in4(4) != 0) return 0; // error! stream is > 4GB 3671 const unsigned int olen = stb_decompress_length(i); 3672 stb__barrier_in_b = i; 3673 stb__barrier_out_e = output + olen; 3674 stb__barrier_out_b = output; 3675 i += 16; 3676 3677 stb__dout = output; 3678 for (;;) { 3679 const unsigned char *old_i = i; 3680 i = stb_decompress_token(i); 3681 if (i == old_i) { 3682 if (*i == 0x05 && i[1] == 0xfa) { 3683 IM_ASSERT(stb__dout == output + olen); 3684 if (stb__dout != output + olen) return 0; 3685 if (stb_adler32(1, output, olen) != (unsigned int) stb__in4(2)) 3686 return 0; 3687 return olen; 3688 } else { 3689 IM_ASSERT(0); /* NOTREACHED */ 3690 return 0; 3691 } 3692 } 3693 IM_ASSERT(stb__dout <= output + olen); 3694 if (stb__dout > output + olen) 2866 3695 return 0; 2867 } 2868 } 2869 IM_ASSERT(stb__dout <= output + olen); 2870 if (stb__dout > output + olen) 2871 return 0; 2872 } 2873 } 2874 3696 } 3697 } 3698 3699 //----------------------------------------------------------------------------- 3700 // [SECTION] Default font data (ProggyClean.ttf) 2875 3701 //----------------------------------------------------------------------------- 2876 3702 // ProggyClean.ttf … … 2880 3706 //----------------------------------------------------------------------------- 2881 3707 // File: 'ProggyClean.ttf' (41208 bytes) 2882 // Exported using binary_to_compressed_c.cpp 3708 // Exported using misc/fonts/binary_to_compressed_c.cpp (with compression + base85 string encoding). 3709 // The purpose of encoding as base85 instead of "0x00,0x01,..." style is only save on _source code_ size. 2883 3710 //----------------------------------------------------------------------------- 2884 3711 static const char proggy_clean_ttf_compressed_data_base85[11980 + 1] = 2885 "7])#######hV0qs'/###[),##/l:$#Q6>##5[n42>c-TH`->>#/e>11NNV=Bv(*:.F?uu#(gRU.o0XGH`$vhLG1hxt9?W`#,5LsCp#-i>.r$<$6pD>Lb';9Crc6tgXmKVeU2cD4Eo3R/"2886 "2*>]b(MC;$jPfY.;h^`IWM9<Lh2TlS+f-s$o6Q<BWH`YiU.xfLq$N;$0iR/GX:U(jcW2p/W*q?-qmnUCI;jHSAiFWM.R*kU@C=GH?a9wp8f$e.-4^Qg1)Q-GL(lf(r/7GrRgwV%MS=C#"2887 "`8ND>Qo#t'X#(v#Y9w0#1D$CIf;W'#pWUPXOuxXuU(H9M(1<q-UE31#^-V'8IRUo7Qf./L>=Ke$$'5F%)]0^#[email protected]<r:QLtFsLcL6##lOj)#.Y5<-R&KgLwqJfLgN&;Q?gI^#DY2uL"2888 "i@^rMl9t=cWq6##weg>$FBjVQTSDgEKnIS7EM9>ZY9w0#L;>>#Mx&4Mvt//L[MkA#[email protected]'[0#7RL_&#w+F%HtG9M#XL`N&.,GM4Pg;-<nLENhvx>-VsM.M0rJfLH2eTM`*oJMHRC`N"2889 "kfimM2J,W-jXS:)r0wK#@Fge$U>`w'N7G#$#fB#$E^$#:9:hk+eOe--6x)F7*E%?76%^GMHePW-Z5l'&GiF#$956:rS?dA#fiK:)Yr+`�j@'DbG&#^$PG.Ll+DNa<XCMKEV*N)LN/N"2890 "*b=%Q6pia-Xg8I$<MR&,VdJe$<(7G;Ckl'&hF;;$<_=X(b.RS%%)###MPBuuE1V:v&cXm#(&cV]`k9OhLMbn%s$G2,B$BfD3X*sp5#l,$R#]x_X1xKX%b5U*[r5iMfUo9U`N99hG)"2891 "tm+/Us9pG)XPu`<0s-)WTt(gCRxIg(%6sfh=ktMKn3j)<6<b5Sk_/0(^]AaN#(p/L>&VZ>1i%h1S9u5o@YaaW$e+b<TWFn/Z:Oh(Cx2$lNEoN^e)#CFY@@I;BOQ*sRwZtZxRcU7uW6CX"2892 "ow0i(?$Q[cjOd[P4d)]>ROPOpxTO7Stwi1::iB1q)C_=dV26J;2,]7op$]uQr@_V7$q^%lQwtuHY]=DX,n3L#0PHDO4f9>dC@O>HBuKPpP*E,N+b3L#lpR/MrTEH.IAQk.a>D[.e;mc."2893 "x]Ip.PH^'/aqUO/$1WxLoW0[iLA<QT;5HKD+@qQ'NQ(3_PLhE48R.qAPSwQ0/WK?Z,[x?-J;jQTWA0X@KJ(_Y8N-:/M74:/-ZpKrUss?d#dZq]DAbkU*JqkL+nwX@@47`5>w=4h(9.`G"2894 "CRUxHPeR`5Mjol(dUWxZa(>STrPkrJiWx`5U7F#.g*jrohGg`cg:lSTvEY/EV_7H4Q9[Z%cnv;JQYZ5q.l7Zeas:HOIZOB?G<Nald$qs]@]L<J7bR*>gv:[7MI2k).'2($5FNP&EQ(,)"2895 "U]W]+fh18.vsai00);D3@4ku5P?DP8aJt+;qUM]=+b'8@;mViBKx0DE[-auGl8:PJ&Dj+M6OC]O^((##]`0i)drT;-7X`=-H3[igUnPG-NZlo.#k@h#=Ork$m>a>$-?Tm$UV(?#P6YY#"2896 "'/###xe7q.73rI3*pP/$1>s9)W,JrM7SN]'/4C#v$U`0#V.[0>xQsH$fEmPMgY2u7Kh(G%siIfLSoS+MK2eTM$=5,M8p`A.;_R%#u[K#$x4AG8.kK/HSB==-'Ie/QTtG?-.*^N-4B/ZM"2897 "_3YlQC7(p7q)&](`6_c)$/*JL(L-^(]$wIM`dPtOdGA,U3:w2M-0<q-]L_?^)1vw'.,MRsqVr.L;aN&#/EgJ)PBc[-f>+WomX2u7lqM2iEumMTcsF?-aT=Z-97UEnXglEn1K-bnEO`gu"2898 "Ft(c%=;Am_Qs@jLooI&NX;]0#j4#F14;gl8-GQpgwhrq8'=l_f-b49'UOqkLu7-##oDY2L(te+Mch&gLYtJ,MEtJfLh'x'M=$CS-ZZ%P]8bZ>#S?YY#%Q&q'3^Fw&?D)UDNrocM3A76/"2899 "/oL?#h7gl85[qW/NDOk%16ij;+:1a'iNIdb-ou8.P*w,v5#EI$TWS>Pot-R*H'-SEpA:g)f+O$%%`kA#G=8RMmG1&O`>to8bC]T&$,n.LoO>29sp3dt-52U%VM#q7'DHpg+#Z9%H[K<L"2900 "%a2E-grWVM3@2=-k22tL]4$##6We'8UJCKE[d_=%wI;'6X-GsLX4j^SgJ$##R*w,vP3wK#iiW&#*h^D&R?jp7+/u&#(AP##XU8c$fSYW-J95_-Dp[g9wcO&#M-h1OcJlc-*vpw0xUX&#"2901 "OQFKNX@QI'IoPp7nb,QU//MQ&ZDkKP)X<WSVL(68uVl&#c'[0#(s1X&xm$Y%B7*K:eDA323j998GXbA#pwMs-jgD$9QISB-A_(aN4xoFM^@C58D0+Q+q3n0#3U1InDjF682-SjMXJK)("2902 "h$hxua_K]ul92%'BOU&#BRRh-slg8KDlr:%L71Ka:.A;%YULjDPmL<LYs8i#XwJOYaKPKc1h:'9Ke,g)b),78=I39B;xiY$bgGw-&.Zi9InXDuYa%G*f2Bq7mn9^#p1vv%#(Wi-;/Z5h"2903 "o;#2:;%d	v68C5g?ntX0X)pT`;%pB3q7mgGN)3%(P8nTd5L7GeA-GL@+%J3u2:(Yf>et`e;)f#Km8&+DC$I46>#Kr]]u-[=99tts1.qb#q72g1WJO81q+eN'03'eM>&1XxY-caEnO"2904 "j%2n8)),?ILR5^.Ibn<-X-Mq7[a82Lq:F&#ce+S9wsCK*x`569E8ew'He]h:sI[2LM$[guka3ZRd6:t%IG:;$%YiJ:Nq=?eAw;/:nnDq0(CYcMpG)qLN4$##&J<j$UpK<Q4a1]MupW^-"2905 "sj_$%[HK%'F####QRZJ::Y3EGl4'@%FkiAOg#p[##O`gukTfBHagL<LHw%q&OV0##F=6/:chIm0@eCP8X]:kFI%hl8hgO@RcBhS-@Qb$%+m=hPDLg*%K8ln(wcf3/'DW-$.lR?n[nCH-"2906 "eXOONTJlh:.RYF%3'p6sq:UIMA945&^HFS87@$EP2iG<-lCO$%c`uKGD3rC$x0BL8aFn--`ke%#HMP'vh1/R&O_J9'um,.<tx[@%wsJk&bUT2`0uMv7gg#qp/ij.L56'hl;.s5CUrxjO"2907 "M7-##.l+Au'A&O:-T72L]P`&=;ctp'XScX*rU.>-XTt,%OVU4)S1+R-#dg0/Nn?Ku1^0f$B*P:Rowwm-`0PKjYDDM'3]d39VZHEl4,.j']Pk-M.h^&:0FACm$maq-&sgw0t7/6(^xtk%"2908 "LuH88Fj-ekm>GA#_>568x6(OFRl-IZp`&b,_P'$M<Jnq79VsJW/mWS*PUiq76;]/NM_>hLbxfc$mj`,O;&%W2m`Zh:/)Uetw:aJ%]K9h:TcF]u_-Sj9,VK3M.*'&0D[Ca]J9gp8,kAW]"2909 "%(?A%R$f<->Zts'^kn=-^@c4%-pY6qI%J%1IGxfLU9CP8cbPlXv);C=b),<2mOvP8up,UVf3839acAWAW-W?#ao/^#%KYo8fRULNd2.>%m]UK:n%r$'sw]J;5pAoO_#2mO3n,'=H5(et"2910 "Hg*`+RLgv>=4U8guD$I%D:W>-r5V*%j*W:Kvej.Lp$<M-SGZ':+Q_k+uvOSLiEo(<aD/K<CCc`'Lx>'?;++O'>()jLR-^u68PHm8ZFWe+ej8h:9r6L*0//c&iH&R8pRbA#Kjm%upV1g:"2911 "a_#Ur7FuA#(tRh#.Y5K+@?3<-8m0$PEn;J:rh6?I6uG<-`wMU'ircp0LaE_OtlMb&1#6T.#FDKu#1Lw%u%+GM+X'e?YLfjM[VO0MbuFp7;>Q&#WIo)0@F%q7c#4XAXN-U&VB<HFF*qL("2912 "$/V,;(kXZejWO`<[5?\?ewY(*9=%wDc;,u<'9t3W-(H1th3+G]ucQ]kLs7df($/*JL]@*t7Bu_G3_7mp7<[email protected];x3B0lqp7Hf,^Ze7-##@/c58Mo(3;knp0%)A7?-W+eI'o8)b<"2913 "nKnw'Ho8C=Y>pqB>0ie&jhZ[?iLR@@_AvA-iQC(=ksRZRVp7`.=+NpBC%rh&3]R:8XDmE5^V8O(x<<aG/1N$#FX$0V5Y6x'aErI3I$7x%E`v<-BY,)%-?Psf*l?%C3.mM(=/M0:JxG'?"2914 "7WhH%o'a<-80g0NBxoO(GH<dM]n.+%q@jH?f.UsJ2Ggs&4<-e47&Kl+f//9@`b+?.TeN_&B8Ss?v;^Trk;f#YvJkl&w$]>-+k?'(<S:68tq*WoDfZu';mM?8X[ma8W%*`-=;D.(nc7/;"2915 ")g:T1=^J$&BRV(-lTmNB6xqB[@0*o.erM*<SWF]u2=st-*(6v>^](H.aREZSi,#1:[IXaZFOm<-ui#qUq2$##Ri;u75OK#(RtaW-K-F`S+cF]uN`-KMQ%rP/Xri.LRcB##=YL3BgM/3M"2916 "D?@f&1'BW-)Ju<L25gl8uhVm1hL$##*8###'A3/LkKW+(^rWX?5W_8g)a(m&K8P>#bmmWCMkk&#TR`C,5d>g)F;t,4:@_l8G/5h4vUd%&%950:VXD'QdWoY-F$BtUwmfe$YqL'8(PWX("2917 "P?^@Po3$##`MSs?DWBZ/S>+4%>fX,VWv/w'KD`LP5IbH;rTV>n3cEK8U#bX]l-/V+^lj3;vlMb&[5YQ8#pekX9JP3XUC72L,,?+Ni&co7ApnO*5NK,((W-i:$,kp'UDAO(G0Sq7MVjJs"2918 "bIu)'Z,*[>br5fX^:FPAWr-m2KgL<LUN098kTF&#lvo58=/vjDo;.;)Ka*hLR#/k=rKbxuV`>Q_nN6'8uTGT5g)uLv:873UpTLgH+#FgpH'_o1780Ph8KmxQJ8#H72L4@768@Tm&Q"2919 "h4CB/5OvmA&,Q&QbUoi$a_%3M01H)4x7I^&KQVgtFnV+;[Pc>[m4k//,]1?#`VY[Jr*3&&slRfLiVZJ:]?=K3Sw=[$=uRB?3xk48@aeg<Z'<$#4H)6,>e0jT6'N#(q%.O=?2S]u*(m<-"2920 "V8J'(1)G][68hW$5'q[GC&5j`TE?m'esFGNRM)j,ffZ?-qx8;->g4t*:CIP/[Qap7/9'#(1sao7w-.qNUdkJ)tCF&#B^;[email protected]$m%#QvQS8U@)2Z+3K:AKM5i"2921 "sZ88+dKQ)W6>J%CL<KE>`.d*(B`-n8D9oK<Up]c$X$(,)M8Zt7/[rdkqTgl-0cuGMv'?>-XV1q['-5k'cAZ69e;D_?$ZPP&s^+7])$*$#@QYi9,5P	r+$%CE=68>K8r0=dSC%%(@p7"2922 ".m7jilQ02'0-VWAg<a/''3u.=4L$Y)6k/K:_[3=&jvL<L0C/2'v:^;-DIBW,B4E68:kZ;%?8(Q8BH=kO65BW?xSG&#@uU,DS*,?.+(o(#1vCS8#CHF>TlGW'b)Tq7VT9q^*^$$.:&N@@"2923 "$&)WHtPm*5_rO0&e%K&#-30j(E4#'Zb.o/(Tpm$>K'f@[PvFl,hfINTNU6u'0pao7%XUp9]5.>%h`8_=VYbxuel.NTSsJfLacFu3B'lQSu/m6-Oqem8T+oE--$0a/k]uj9EwsG>%veR*"2924 "hv^BFpQj:K'#SJ,sB-'#](j.Lg92rTw-*n%@/;39rrJF,l#qV%OrtBeC6/,;qB3ebNW[?,Hqj2L.1NP&GjUR=1D8QaS3Up&@*9wP?+lo7b?@%'k4`p0Z$22%K3+iCZj?XJN4Nm&+YF]u"2925 "@-W$U%VEQ/,,>>#)D<h#`)h0:<Q6909ua+&VU%n2:cG3FJ-%@Bj-DgLr`Hw&HAKjKjseK</xKT*)B,N9X3]krc12t'pgTV(Lv-tL[xg_%=M_q7a^x?7Ubd>#%8cY#YZ?=,`Wdxu/ae&#"2926 "w6)R89tI#6@s'(6Bf7a&?S=^ZI_kS&ai`&=tE72L_D,;^R)7[$s<Eh#c&)q.MXI%#v9ROa5FZO%sF7q7Nwb&#ptUJ:aqJe$Sl68%.D###EC><?-aF&#RNQv>o8lKN%5/$(vdfq7+ebA#"2927 "u1p]ovUKW&Y%q]'>$1@-[xfn$7ZTp7mM,G,Ko7a&Gu%G[RMxJs[0MM%wci.LFDK)(<c`Q8N)jEIF*+?P2a8g%)$q]o2aH8C&<SibC/q,(e:v;-b#6[$NtDZ84Je2KNvB#$P5?tQ3nt(0"2928 "d=j.LQf./Ll33+(;q3L-w=8dX$#WF&uIJ@-bfI>%:_i2B5CsR8&9Z&#=mPEnm0f`<&c)QL5uJ#%u%lJj+D-r;BoFDoS97h5g)E#o:&S4weDF,9^Hoe`h*L+_a*NrLW-1pG_&2UdB8"2929 "6e%B/:=>)N4xeW.*wft-;$'58-ESqr<b?UI(_%@[P46>#U`'6AQ]m&6/`Z>#S?YY#Vc;r7U2&326d=w&H####?TZ`*4?&.MK?LP8Vxg>$[QXc%QJv92.(Db*B)gb*BM9dM*hJMAo*c&#"2930 "b0v=Pjer]$gG&JXDf->'StvU7505l9$AFvgYRI^&<^b68?j#q9QX4SM'RO#&sL1IM.rJfLUAj221]d##DW=m83u5;'bYx,*Sl0hL(W;;$doB&O/TQ:(Z^xBdLjL<Lni;''X.`$#8+1GD"2931 ":k$YUWsbn8ogh6rxZ2Z9]%nd+>V#*8U_72Lh+2Q8Cj0i:6hp&$C/:p(HK>T8Y[gHQ4`4)'$Ab(Nof%V'8hL&#<NEdtg(n'=S1A(Q1/I&4([%dM`,Iu'1:_hL>SfD07&6D<fp8dHM7/g+"2932 "tlPN9J*rKaPct&?'uBCem^jn%9_K)<,C5K3s=5g&GmJb*[SYq7K;TRLGCsM-$$;S%:Y@r7AK0pprpL<Lrh,q7e/%KWK:50I^+m'vi`3?%Zp+<-d+$L-Sv:@.o19n$s0&39;kn;S%BSq*"2933 "$3WoJSCLweV[aZ'MQIjO<7;X-X;&+dMLvu#^UsGEC9WEc[X(wI7#2.(F0jV*eZf<-Qv3J-c+J5AlrB#$p(H68LvEA'q3n0#m,[`*8Ft)FcYgEud]CWfm68,(aLA$@EFTgLXoBq/UPlp7"2934 ":d[/;r_ix=:TF`S5H-b<LI&HY(K=h#)]Lk$K14lVfm:x$H<3^Ql<M`$OhapBnkup'D#L$Pb_`N*g]2e;X/Dtg,bsj&K#2[-:iYr'_wgH)NUIR8a1n#S?Yej'h8^58UbZd+^FKD*T@;6A"2935 "7aQC[K8d-(v6GI$x:T<&'Gp5Uf>@M.*J:;$-rv29'M]8qMv-tLp,'886iaC=Hb*YJoKJ,(j%K=H`K.v9HggqBIiZu'QvBT.#=)0ukruV&.)3=(^1`o*Pj4<-<aN((^7('#Z0wK#5GX@7"2936 "u][`*S^43933A4rl][`*O4CgLEl]v$1Q3AeF37dbXk,.)vj#x'd`;qgbQR%FW,2(?LO=s%Sc68%NP'##Aotl8x=BE#j1UD([3$M(]UI2LX3RpKN@;/#f'f/&_mt&F)XdF<9t4)Qa.*kT"2937 "LwQ'(TTB9.xH'>#MJ+gLq9-##@HuZPN0]u:h7.T..G:;$/Usj(T7`Q8tT72LnYl<-qx8;-HV7Q-&Xdx%1a,hC=0u+HlsV>nuIQL-5<N?)NBS)QN*_I,?&)2'IM%L3I)X((e/dl2&8'<M"2938 ":^#M*Q+[T.Xri.LYS3v%fF`68h;b-X[/En'CR.q7E)p'/kle2HM,u;^%OKC-N+Ll%F9CF<Nf'^#t2L,;27W:0O@6##U6W7:$rJfLWHj$#)woqBefIZ.PK<b*t7ed;p*_m;4ExK#h@&]>"2939 "_>@kXQtMacfD.m-VAb8;IReM3$wf0''hra*so568'Ip&vRs849'MRYSp%:t:h5qSgwpEr$B>Q,;s(C#$)`svQuF$##-D,##,g68@2[T;.XSdN9Qe)rpt._K-#5wF)sP'##p#C0c%-Gb%"2940 "hd+<-j'Ai*x&&HMkT]C'OSl##5RG[JXaHN;d'uA#x._U;.`PU@(Z3dt4r152@:v,'R.Sj'w#0<-;kPI)FfJ&#AYJ&#//)>-k=m=*XnK$>=)72L]0I%>.G690a:$##<,);?;72#?x9+d;"2941 "^V'9;jY@;)br#q^YQpx:X#Te$Z^'=-=bGhLf:D6&bNwZ9-ZD#n^9HhLMr5G;']d&6'wYmTFmL<LD)F^%[tC'8;+9E#C$g%#5Y>q9wI>P(9mI[>kC-ekLC/R&CH+s'B;K-M6$EB%is00:"2942 "+A4[7xks.LrNk0&E)wILYF@2L'0Nb$+pv<(2.768/FrY&h$^3i&@+G%JT'<-,v`3;_)I9M^AE]CN?Cl2AZg+%4iTpT3<n-&%H%b<FDj2M<hH=&Eh<2Len$b*aTX=-8QxN)k11IM1c^j%"2943 "9s<L<NFSo)B?+<-(GxsF,^-Eh@$4dXhN$+#rxK8'je'D7k`e;)2pYwPA'_p9&@^18ml1^[@g4t*[JOa*[=Qp7(qJ_oOL^('7fB&Hq-:sf,sNj8xq^>$U4O]GKx'm9)b@p7YsvK3w^YR-"2944 "CdQ*:Ir<($u&)#(&?L9Rg3H)4fiEp^iI9O8KnTj,]H?D*r7'M;PwZ9K0E^k&-cpI;.p/6_vwoFMV<->#%Xi.LxVnrU(4&8/P+:hLSKj$#U%]49t'I:rgMi'FL@a:0Y-uA[39',(vbma*"2945 "hU%<-SRF`Tt:542R_VV$p@[p8DV[A,?1839FWdF<TddF<9Ah-6&9tWoDlh]&1SpGMq>Ti1O*H&#(AL8[_P%.M>v^-))qOT*F5Cq0`Ye%+$B6i:7@0IX<N+T+0MlMBPQ*Vj>SsD<U4JHY"2946 "8kD2)2fU/M#$e.)T4,_=8hLim[&);?UkK'-x?'(:siIfL<$pFM`i<?%W(mGDHM%>iWP,##P`%/L<eXi:@Z9C.7o=@(pXdAO/NLQ8lPl+HPOQa8wD8=^GlPa8TKI1CjhsCTSLJM'/Wl>-"2947 "S(qw%sf/@%#B6;/U7K]uZbi^Oc^2n<bhPmUkMw>%t<)'mEVE''n`WnJra$^TKvX5B>;_aSEK',(hwa0:i4G?.Bci.(X[?b*($,=-n<.Q%`(X=?+@Am*Js0&=3bh8K]mL<LoNs'6,'85`"2948 "0?t/'_U59@]ddF<#LdF<eWdF<OuN/45rY<-L@&#+fm>69=Lb,OcZV/);TTm8VI;?%OtJ<(b4mq7M6:u?KRdF<gR@2L=FNU-<b[(9c/ML3m;Z[$oF3g)GAWqpARc=<ROu7cL5l;-[A]%/"2949 "+fsd;l#SafT/f*W]0=O'$(Tb<[)*@e775R-:Yob%g*>l*:xP?Yb.5)%w_I?7uk5JC+FS(m#i'k.'a0i)9<7b'fs'59hq$*5Uhv##pi^8+hIEBF`nvo`;'l0.^S1<-wUK2/Coh58KKhLj"2950 "M=SO*rfO`+qC`W-On.=AJ56>>i2@2LH6A:&5q`?9I3@@'04&p2/LVa*T-4<-i3;M9UvZd+N7>b*eIwg:CC)c<>nO&#<IGe;__.thjZl<%w(Wk2xmp4Q@I#I9,DF]u7-P=.-_:YJ]aS@V"2951 "?6*C()dOp7:WL,b&3Rg/.cmM9&r^>$(>.Z-I&J(Q0Hd5Q%7Co-b`-c<N(6r@ip+AurK<m86QIth*#v;-OBqi+L7wDE-Ir8K['m+DDSLwK&/.?-V%U_%3:qKNu$_b*B-kp7NaD'QdWQPK"2952 "Yq[@>P)hI;*_F]u`Rb[.j8_Q/<&>uu+VsH$sM9TA%?)(vmJ80),P7E>)tjD%2L=-t#fK[%`v=Q8<FfNkgg^oIbah*#8/Qt$F&:K*-(N/'+1vMB,u()-a.VUU*#[e%gAAO(S>WlA2);Sa"2953 ">gXm8YB`1d@K#n]76-a$U,mF<fX]idqd)<3,]J7JmW4`6]uks=4-72L(jEk+:bJ0M^q-8Dm_Z?0olP1C9Sa&H[d&c$ooQUj]Exd*3ZM@-WGW2%s',B-_M%>%Ul:#/'xoFM9QX-$.QN'>"2954 "[%$Z$uF6pA6Ki2O5:8w*vP1<-1`[G,)-m#>0`P&#eb#.3i)rtB61(o'$?X3B</R90;eZ]%Ncq;-Tl]#F>2Qft^ae_5tKL9MUe9b*sLEQ95C&`=G?@Mj=wh*'3E>=-<)Gt*Iw)'QG:`@I"2955 "wOf7&]1i'S01B+Ev/Nac#9S;=;YQpg_6U`*kVY39xK,[/6Aj7:'1Bm-_1EYfa1+o&o4hp7KN_Q(OlIo@S%;jVdn0'1<Vc52=u`3^o-n1'g4v58Hj&6_t7$##?M)c<$bgQ_'SY((-xkA#"2956 "Y(,p'H9rIVY-b,'%bCPF7.J<Up^,(dU1VY*5#WkTU>h19w,WQhLI)3S#f$2(eb,jr*b;3Vw]*7NH%$c4Vs,eD9>XW8?N]o+(*pgC%/72LV-u<Hp,3@e^9UB1J+ak9-TN/mhKPg+AJYd$"2957 "MlvAF_jCK*.O-^(63adMT->W%iewS8W6m2rtCpo'RS1R84=@paTKt)>=%&1[)*vp'u+x,VrwN;&]kuO9JDbg=pO$J*.jVe;u'm0dr9l,<*wMK*Oe=g8lV_KEBFkO'oU]^=[-792#ok,)"2958 "i]lR8qQ2oA8wcRCZ^7w/Njh;?.stX?Q1>S1q4Bn$)K1<-rGdO'$Wr.Lc.CG)$/*JL4tNR/,SVO3,aUw'DJN:)Ss;wGn9A32ijw%FL+Z0Fn.U9;reSq)bmI32U==5ALuG&#Vf1398/pVo"2959 "1*c-(aY168o<`JsSbk-,1N;$>0:OUas(3:8Z972LSfF8eb=c-;>SPw7.6hn3m`9^Xkn(r.qS[0;T%&Qc=+STRxX'q1BNk3&*eu2;&8q$&x>Q#Q7^Tf+6<(d%ZVmj2bDi%.3L2n+4W'$P"2960 "iDDG)g,r%+?,$@?uou5tSe2aN_AQU*<h`e-GI7)?OK2A.d7_c)?wQ5AS@DL3r#7fSkgl6-++D:'A,uq7SvlB$pcpH'q3n0#_%dY#xCpr-l<F0NR@-##FEV6NTF6##$l84N1w?AO>'IAO"2961 "URQ##V^Fv-XFbGM7Fl(N<3DhLGF%q.1rC$#:T__&Pi68%0xi_&[qFJ(77j_&JWoF.V735&T,[R*:xFR*K5>>#`bW-?4Ne_&6Ne_&6Ne_&n`kr-#GJcM6X;uM6X;uM(.a..^2TkL%oR(#"2962 ";u.T%fAr%4tJ8&><1=GHZ_+m9/#H1F^R#SC#*N=BA9(D?v[UiFY>>^8p,KKF.W]L29uLkLlu/+4T<XoIB&hx=T1PcDaB&;HH+-AFr?(m9HZV)FKS8JCw;SD=6[^/DZUL`EUDf]GGlG&>"2963 "w$)F./^n3+rlo+DB;5sIYGNk+i1t-69Jg--0pao7Sm#K)pdHW&;LuDNH@H>#/X-TI(;P>#,Gc>#0Su>#4`1?#8lC?#<xU?#@.i?#D:%@#HF7@#LRI@#P_[@#Tkn@#Xw*A#]-=A#a9OA#"2964 "d<F&#*;G##.GY##2Sl##6`($#:l:$#>xL$#B.`$#F:r$#JF.%#NR@%#R_R%#Vke%#Zww%#_-4^Rh%Sflr-k'MS.o?.5/sWel/wpEM0%3'/1)K^f1-d>G21&v(35>V`39V7A4=onx4"2965 "A1OY5EI0;6Ibgr6M$HS7Q<)58C5w,;WoA*#[%T*#`1g*#d=#+#hI5+#lUG+#pbY+#tnl+#x$),#&1;,#*=M,#.I`,#2Ur,#6b.-#;w[H#iQtA#m^0B#qjBB#uvTB##-hB#'9$C#+E6C#"2966 "/QHC#3^ZC#7jmC#;v)D#?,<D#C8ND#GDaD#KPsD#O]/E#g1A5#KA*1#gC17#MGd;#8(02#L-d3#rWM4#Hga1#,<w0#T.j<#O#'2#CYN1#qa^:#_4m3#o@/=#eG8=#t8J5#`+78#4uI-#"2967 "m3B2#SB[8#Q0@8#i[*9#iOn8#1Nm;#^sN9#qh<9#:=x-#P;K2#$%X9#bC+.#Rg;<#mN=.#MTF.#RZO.#2?)4#Y#(/#[)1/#b;L/#dAU/#0Sv;#lY$0#n`-0#sf60#(F24#wrH0#%/e0#"2968 "TmD<#%JSMFove:CTBEXI:<eh2g)B,3h2^G3i;#d3jD>)4kMYD4lVu`4m`:&5niUA5@(A5BA1]PBB:xlBCC=2CDLXMCEUtiCf&0g2'tN?PGT4CPGT4CPGT4CPGT4CPGT4CPGT4CPGT4CP"2969 "GT4CPGT4CPGT4CPGT4CPGT4CPGT4CP-qekC`.9kEg^+F$kwViFJTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5o,^<-28ZI'O?;xp"2970 "O?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xp;7q-#lLYI:xvD=#";3712 "7])#######hV0qs'/###[),##/l:$#Q6>##5[n42>c-TH`->>#/e>11NNV=Bv(*:.F?uu#(gRU.o0XGH`$vhLG1hxt9?W`#,5LsCp#-i>.r$<$6pD>Lb';9Crc6tgXmKVeU2cD4Eo3R/" 3713 "2*>]b(MC;$jPfY.;h^`IWM9<Lh2TlS+f-s$o6Q<BWH`YiU.xfLq$N;$0iR/GX:U(jcW2p/W*q?-qmnUCI;jHSAiFWM.R*kU@C=GH?a9wp8f$e.-4^Qg1)Q-GL(lf(r/7GrRgwV%MS=C#" 3714 "`8ND>Qo#t'X#(v#Y9w0#1D$CIf;W'#pWUPXOuxXuU(H9M(1<q-UE31#^-V'8IRUo7Qf./L>=Ke$$'5F%)]0^#[email protected]<r:QLtFsLcL6##lOj)#.Y5<-R&KgLwqJfLgN&;Q?gI^#DY2uL" 3715 "i@^rMl9t=cWq6##weg>$FBjVQTSDgEKnIS7EM9>ZY9w0#L;>>#Mx&4Mvt//L[MkA#[email protected]'[0#7RL_&#w+F%HtG9M#XL`N&.,GM4Pg;-<nLENhvx>-VsM.M0rJfLH2eTM`*oJMHRC`N" 3716 "kfimM2J,W-jXS:)r0wK#@Fge$U>`w'N7G#$#fB#$E^$#:9:hk+eOe--6x)F7*E%?76%^GMHePW-Z5l'&GiF#$956:rS?dA#fiK:)Yr+`�j@'DbG&#^$PG.Ll+DNa<XCMKEV*N)LN/N" 3717 "*b=%Q6pia-Xg8I$<MR&,VdJe$<(7G;Ckl'&hF;;$<_=X(b.RS%%)###MPBuuE1V:v&cXm#(&cV]`k9OhLMbn%s$G2,B$BfD3X*sp5#l,$R#]x_X1xKX%b5U*[r5iMfUo9U`N99hG)" 3718 "tm+/Us9pG)XPu`<0s-)WTt(gCRxIg(%6sfh=ktMKn3j)<6<b5Sk_/0(^]AaN#(p/L>&VZ>1i%h1S9u5o@YaaW$e+b<TWFn/Z:Oh(Cx2$lNEoN^e)#CFY@@I;BOQ*sRwZtZxRcU7uW6CX" 3719 "ow0i(?$Q[cjOd[P4d)]>ROPOpxTO7Stwi1::iB1q)C_=dV26J;2,]7op$]uQr@_V7$q^%lQwtuHY]=DX,n3L#0PHDO4f9>dC@O>HBuKPpP*E,N+b3L#lpR/MrTEH.IAQk.a>D[.e;mc." 3720 "x]Ip.PH^'/aqUO/$1WxLoW0[iLA<QT;5HKD+@qQ'NQ(3_PLhE48R.qAPSwQ0/WK?Z,[x?-J;jQTWA0X@KJ(_Y8N-:/M74:/-ZpKrUss?d#dZq]DAbkU*JqkL+nwX@@47`5>w=4h(9.`G" 3721 "CRUxHPeR`5Mjol(dUWxZa(>STrPkrJiWx`5U7F#.g*jrohGg`cg:lSTvEY/EV_7H4Q9[Z%cnv;JQYZ5q.l7Zeas:HOIZOB?G<Nald$qs]@]L<J7bR*>gv:[7MI2k).'2($5FNP&EQ(,)" 3722 "U]W]+fh18.vsai00);D3@4ku5P?DP8aJt+;qUM]=+b'8@;mViBKx0DE[-auGl8:PJ&Dj+M6OC]O^((##]`0i)drT;-7X`=-H3[igUnPG-NZlo.#k@h#=Ork$m>a>$-?Tm$UV(?#P6YY#" 3723 "'/###xe7q.73rI3*pP/$1>s9)W,JrM7SN]'/4C#v$U`0#V.[0>xQsH$fEmPMgY2u7Kh(G%siIfLSoS+MK2eTM$=5,M8p`A.;_R%#u[K#$x4AG8.kK/HSB==-'Ie/QTtG?-.*^N-4B/ZM" 3724 "_3YlQC7(p7q)&](`6_c)$/*JL(L-^(]$wIM`dPtOdGA,U3:w2M-0<q-]L_?^)1vw'.,MRsqVr.L;aN&#/EgJ)PBc[-f>+WomX2u7lqM2iEumMTcsF?-aT=Z-97UEnXglEn1K-bnEO`gu" 3725 "Ft(c%=;Am_Qs@jLooI&NX;]0#j4#F14;gl8-GQpgwhrq8'=l_f-b49'UOqkLu7-##oDY2L(te+Mch&gLYtJ,MEtJfLh'x'M=$CS-ZZ%P]8bZ>#S?YY#%Q&q'3^Fw&?D)UDNrocM3A76/" 3726 "/oL?#h7gl85[qW/NDOk%16ij;+:1a'iNIdb-ou8.P*w,v5#EI$TWS>Pot-R*H'-SEpA:g)f+O$%%`kA#G=8RMmG1&O`>to8bC]T&$,n.LoO>29sp3dt-52U%VM#q7'DHpg+#Z9%H[K<L" 3727 "%a2E-grWVM3@2=-k22tL]4$##6We'8UJCKE[d_=%wI;'6X-GsLX4j^SgJ$##R*w,vP3wK#iiW&#*h^D&R?jp7+/u&#(AP##XU8c$fSYW-J95_-Dp[g9wcO&#M-h1OcJlc-*vpw0xUX&#" 3728 "OQFKNX@QI'IoPp7nb,QU//MQ&ZDkKP)X<WSVL(68uVl&#c'[0#(s1X&xm$Y%B7*K:eDA323j998GXbA#pwMs-jgD$9QISB-A_(aN4xoFM^@C58D0+Q+q3n0#3U1InDjF682-SjMXJK)(" 3729 "h$hxua_K]ul92%'BOU&#BRRh-slg8KDlr:%L71Ka:.A;%YULjDPmL<LYs8i#XwJOYaKPKc1h:'9Ke,g)b),78=I39B;xiY$bgGw-&.Zi9InXDuYa%G*f2Bq7mn9^#p1vv%#(Wi-;/Z5h" 3730 "o;#2:;%d	v68C5g?ntX0X)pT`;%pB3q7mgGN)3%(P8nTd5L7GeA-GL@+%J3u2:(Yf>et`e;)f#Km8&+DC$I46>#Kr]]u-[=99tts1.qb#q72g1WJO81q+eN'03'eM>&1XxY-caEnO" 3731 "j%2n8)),?ILR5^.Ibn<-X-Mq7[a82Lq:F&#ce+S9wsCK*x`569E8ew'He]h:sI[2LM$[guka3ZRd6:t%IG:;$%YiJ:Nq=?eAw;/:nnDq0(CYcMpG)qLN4$##&J<j$UpK<Q4a1]MupW^-" 3732 "sj_$%[HK%'F####QRZJ::Y3EGl4'@%FkiAOg#p[##O`gukTfBHagL<LHw%q&OV0##F=6/:chIm0@eCP8X]:kFI%hl8hgO@RcBhS-@Qb$%+m=hPDLg*%K8ln(wcf3/'DW-$.lR?n[nCH-" 3733 "eXOONTJlh:.RYF%3'p6sq:UIMA945&^HFS87@$EP2iG<-lCO$%c`uKGD3rC$x0BL8aFn--`ke%#HMP'vh1/R&O_J9'um,.<tx[@%wsJk&bUT2`0uMv7gg#qp/ij.L56'hl;.s5CUrxjO" 3734 "M7-##.l+Au'A&O:-T72L]P`&=;ctp'XScX*rU.>-XTt,%OVU4)S1+R-#dg0/Nn?Ku1^0f$B*P:Rowwm-`0PKjYDDM'3]d39VZHEl4,.j']Pk-M.h^&:0FACm$maq-&sgw0t7/6(^xtk%" 3735 "LuH88Fj-ekm>GA#_>568x6(OFRl-IZp`&b,_P'$M<Jnq79VsJW/mWS*PUiq76;]/NM_>hLbxfc$mj`,O;&%W2m`Zh:/)Uetw:aJ%]K9h:TcF]u_-Sj9,VK3M.*'&0D[Ca]J9gp8,kAW]" 3736 "%(?A%R$f<->Zts'^kn=-^@c4%-pY6qI%J%1IGxfLU9CP8cbPlXv);C=b),<2mOvP8up,UVf3839acAWAW-W?#ao/^#%KYo8fRULNd2.>%m]UK:n%r$'sw]J;5pAoO_#2mO3n,'=H5(et" 3737 "Hg*`+RLgv>=4U8guD$I%D:W>-r5V*%j*W:Kvej.Lp$<M-SGZ':+Q_k+uvOSLiEo(<aD/K<CCc`'Lx>'?;++O'>()jLR-^u68PHm8ZFWe+ej8h:9r6L*0//c&iH&R8pRbA#Kjm%upV1g:" 3738 "a_#Ur7FuA#(tRh#.Y5K+@?3<-8m0$PEn;J:rh6?I6uG<-`wMU'ircp0LaE_OtlMb&1#6T.#FDKu#1Lw%u%+GM+X'e?YLfjM[VO0MbuFp7;>Q&#WIo)0@F%q7c#4XAXN-U&VB<HFF*qL(" 3739 "$/V,;(kXZejWO`<[5?\?ewY(*9=%wDc;,u<'9t3W-(H1th3+G]ucQ]kLs7df($/*JL]@*t7Bu_G3_7mp7<[email protected];x3B0lqp7Hf,^Ze7-##@/c58Mo(3;knp0%)A7?-W+eI'o8)b<" 3740 "nKnw'Ho8C=Y>pqB>0ie&jhZ[?iLR@@_AvA-iQC(=ksRZRVp7`.=+NpBC%rh&3]R:8XDmE5^V8O(x<<aG/1N$#FX$0V5Y6x'aErI3I$7x%E`v<-BY,)%-?Psf*l?%C3.mM(=/M0:JxG'?" 3741 "7WhH%o'a<-80g0NBxoO(GH<dM]n.+%q@jH?f.UsJ2Ggs&4<-e47&Kl+f//9@`b+?.TeN_&B8Ss?v;^Trk;f#YvJkl&w$]>-+k?'(<S:68tq*WoDfZu';mM?8X[ma8W%*`-=;D.(nc7/;" 3742 ")g:T1=^J$&BRV(-lTmNB6xqB[@0*o.erM*<SWF]u2=st-*(6v>^](H.aREZSi,#1:[IXaZFOm<-ui#qUq2$##Ri;u75OK#(RtaW-K-F`S+cF]uN`-KMQ%rP/Xri.LRcB##=YL3BgM/3M" 3743 "D?@f&1'BW-)Ju<L25gl8uhVm1hL$##*8###'A3/LkKW+(^rWX?5W_8g)a(m&K8P>#bmmWCMkk&#TR`C,5d>g)F;t,4:@_l8G/5h4vUd%&%950:VXD'QdWoY-F$BtUwmfe$YqL'8(PWX(" 3744 "P?^@Po3$##`MSs?DWBZ/S>+4%>fX,VWv/w'KD`LP5IbH;rTV>n3cEK8U#bX]l-/V+^lj3;vlMb&[5YQ8#pekX9JP3XUC72L,,?+Ni&co7ApnO*5NK,((W-i:$,kp'UDAO(G0Sq7MVjJs" 3745 "bIu)'Z,*[>br5fX^:FPAWr-m2KgL<LUN098kTF&#lvo58=/vjDo;.;)Ka*hLR#/k=rKbxuV`>Q_nN6'8uTGT5g)uLv:873UpTLgH+#FgpH'_o1780Ph8KmxQJ8#H72L4@768@Tm&Q" 3746 "h4CB/5OvmA&,Q&QbUoi$a_%3M01H)4x7I^&KQVgtFnV+;[Pc>[m4k//,]1?#`VY[Jr*3&&slRfLiVZJ:]?=K3Sw=[$=uRB?3xk48@aeg<Z'<$#4H)6,>e0jT6'N#(q%.O=?2S]u*(m<-" 3747 "V8J'(1)G][68hW$5'q[GC&5j`TE?m'esFGNRM)j,ffZ?-qx8;->g4t*:CIP/[Qap7/9'#(1sao7w-.qNUdkJ)tCF&#B^;[email protected]$m%#QvQS8U@)2Z+3K:AKM5i" 3748 "sZ88+dKQ)W6>J%CL<KE>`.d*(B`-n8D9oK<Up]c$X$(,)M8Zt7/[rdkqTgl-0cuGMv'?>-XV1q['-5k'cAZ69e;D_?$ZPP&s^+7])$*$#@QYi9,5P	r+$%CE=68>K8r0=dSC%%(@p7" 3749 ".m7jilQ02'0-VWAg<a/''3u.=4L$Y)6k/K:_[3=&jvL<L0C/2'v:^;-DIBW,B4E68:kZ;%?8(Q8BH=kO65BW?xSG&#@uU,DS*,?.+(o(#1vCS8#CHF>TlGW'b)Tq7VT9q^*^$$.:&N@@" 3750 "$&)WHtPm*5_rO0&e%K&#-30j(E4#'Zb.o/(Tpm$>K'f@[PvFl,hfINTNU6u'0pao7%XUp9]5.>%h`8_=VYbxuel.NTSsJfLacFu3B'lQSu/m6-Oqem8T+oE--$0a/k]uj9EwsG>%veR*" 3751 "hv^BFpQj:K'#SJ,sB-'#](j.Lg92rTw-*n%@/;39rrJF,l#qV%OrtBeC6/,;qB3ebNW[?,Hqj2L.1NP&GjUR=1D8QaS3Up&@*9wP?+lo7b?@%'k4`p0Z$22%K3+iCZj?XJN4Nm&+YF]u" 3752 "@-W$U%VEQ/,,>>#)D<h#`)h0:<Q6909ua+&VU%n2:cG3FJ-%@Bj-DgLr`Hw&HAKjKjseK</xKT*)B,N9X3]krc12t'pgTV(Lv-tL[xg_%=M_q7a^x?7Ubd>#%8cY#YZ?=,`Wdxu/ae&#" 3753 "w6)R89tI#6@s'(6Bf7a&?S=^ZI_kS&ai`&=tE72L_D,;^R)7[$s<Eh#c&)q.MXI%#v9ROa5FZO%sF7q7Nwb&#ptUJ:aqJe$Sl68%.D###EC><?-aF&#RNQv>o8lKN%5/$(vdfq7+ebA#" 3754 "u1p]ovUKW&Y%q]'>$1@-[xfn$7ZTp7mM,G,Ko7a&Gu%G[RMxJs[0MM%wci.LFDK)(<c`Q8N)jEIF*+?P2a8g%)$q]o2aH8C&<SibC/q,(e:v;-b#6[$NtDZ84Je2KNvB#$P5?tQ3nt(0" 3755 "d=j.LQf./Ll33+(;q3L-w=8dX$#WF&uIJ@-bfI>%:_i2B5CsR8&9Z&#=mPEnm0f`<&c)QL5uJ#%u%lJj+D-r;BoFDoS97h5g)E#o:&S4weDF,9^Hoe`h*L+_a*NrLW-1pG_&2UdB8" 3756 "6e%B/:=>)N4xeW.*wft-;$'58-ESqr<b?UI(_%@[P46>#U`'6AQ]m&6/`Z>#S?YY#Vc;r7U2&326d=w&H####?TZ`*4?&.MK?LP8Vxg>$[QXc%QJv92.(Db*B)gb*BM9dM*hJMAo*c&#" 3757 "b0v=Pjer]$gG&JXDf->'StvU7505l9$AFvgYRI^&<^b68?j#q9QX4SM'RO#&sL1IM.rJfLUAj221]d##DW=m83u5;'bYx,*Sl0hL(W;;$doB&O/TQ:(Z^xBdLjL<Lni;''X.`$#8+1GD" 3758 ":k$YUWsbn8ogh6rxZ2Z9]%nd+>V#*8U_72Lh+2Q8Cj0i:6hp&$C/:p(HK>T8Y[gHQ4`4)'$Ab(Nof%V'8hL&#<NEdtg(n'=S1A(Q1/I&4([%dM`,Iu'1:_hL>SfD07&6D<fp8dHM7/g+" 3759 "tlPN9J*rKaPct&?'uBCem^jn%9_K)<,C5K3s=5g&GmJb*[SYq7K;TRLGCsM-$$;S%:Y@r7AK0pprpL<Lrh,q7e/%KWK:50I^+m'vi`3?%Zp+<-d+$L-Sv:@.o19n$s0&39;kn;S%BSq*" 3760 "$3WoJSCLweV[aZ'MQIjO<7;X-X;&+dMLvu#^UsGEC9WEc[X(wI7#2.(F0jV*eZf<-Qv3J-c+J5AlrB#$p(H68LvEA'q3n0#m,[`*8Ft)FcYgEud]CWfm68,(aLA$@EFTgLXoBq/UPlp7" 3761 ":d[/;r_ix=:TF`S5H-b<LI&HY(K=h#)]Lk$K14lVfm:x$H<3^Ql<M`$OhapBnkup'D#L$Pb_`N*g]2e;X/Dtg,bsj&K#2[-:iYr'_wgH)NUIR8a1n#S?Yej'h8^58UbZd+^FKD*T@;6A" 3762 "7aQC[K8d-(v6GI$x:T<&'Gp5Uf>@M.*J:;$-rv29'M]8qMv-tLp,'886iaC=Hb*YJoKJ,(j%K=H`K.v9HggqBIiZu'QvBT.#=)0ukruV&.)3=(^1`o*Pj4<-<aN((^7('#Z0wK#5GX@7" 3763 "u][`*S^43933A4rl][`*O4CgLEl]v$1Q3AeF37dbXk,.)vj#x'd`;qgbQR%FW,2(?LO=s%Sc68%NP'##Aotl8x=BE#j1UD([3$M(]UI2LX3RpKN@;/#f'f/&_mt&F)XdF<9t4)Qa.*kT" 3764 "LwQ'(TTB9.xH'>#MJ+gLq9-##@HuZPN0]u:h7.T..G:;$/Usj(T7`Q8tT72LnYl<-qx8;-HV7Q-&Xdx%1a,hC=0u+HlsV>nuIQL-5<N?)NBS)QN*_I,?&)2'IM%L3I)X((e/dl2&8'<M" 3765 ":^#M*Q+[T.Xri.LYS3v%fF`68h;b-X[/En'CR.q7E)p'/kle2HM,u;^%OKC-N+Ll%F9CF<Nf'^#t2L,;27W:0O@6##U6W7:$rJfLWHj$#)woqBefIZ.PK<b*t7ed;p*_m;4ExK#h@&]>" 3766 "_>@kXQtMacfD.m-VAb8;IReM3$wf0''hra*so568'Ip&vRs849'MRYSp%:t:h5qSgwpEr$B>Q,;s(C#$)`svQuF$##-D,##,g68@2[T;.XSdN9Qe)rpt._K-#5wF)sP'##p#C0c%-Gb%" 3767 "hd+<-j'Ai*x&&HMkT]C'OSl##5RG[JXaHN;d'uA#x._U;.`PU@(Z3dt4r152@:v,'R.Sj'w#0<-;kPI)FfJ&#AYJ&#//)>-k=m=*XnK$>=)72L]0I%>.G690a:$##<,);?;72#?x9+d;" 3768 "^V'9;jY@;)br#q^YQpx:X#Te$Z^'=-=bGhLf:D6&bNwZ9-ZD#n^9HhLMr5G;']d&6'wYmTFmL<LD)F^%[tC'8;+9E#C$g%#5Y>q9wI>P(9mI[>kC-ekLC/R&CH+s'B;K-M6$EB%is00:" 3769 "+A4[7xks.LrNk0&E)wILYF@2L'0Nb$+pv<(2.768/FrY&h$^3i&@+G%JT'<-,v`3;_)I9M^AE]CN?Cl2AZg+%4iTpT3<n-&%H%b<FDj2M<hH=&Eh<2Len$b*aTX=-8QxN)k11IM1c^j%" 3770 "9s<L<NFSo)B?+<-(GxsF,^-Eh@$4dXhN$+#rxK8'je'D7k`e;)2pYwPA'_p9&@^18ml1^[@g4t*[JOa*[=Qp7(qJ_oOL^('7fB&Hq-:sf,sNj8xq^>$U4O]GKx'm9)b@p7YsvK3w^YR-" 3771 "CdQ*:Ir<($u&)#(&?L9Rg3H)4fiEp^iI9O8KnTj,]H?D*r7'M;PwZ9K0E^k&-cpI;.p/6_vwoFMV<->#%Xi.LxVnrU(4&8/P+:hLSKj$#U%]49t'I:rgMi'FL@a:0Y-uA[39',(vbma*" 3772 "hU%<-SRF`Tt:542R_VV$p@[p8DV[A,?1839FWdF<TddF<9Ah-6&9tWoDlh]&1SpGMq>Ti1O*H&#(AL8[_P%.M>v^-))qOT*F5Cq0`Ye%+$B6i:7@0IX<N+T+0MlMBPQ*Vj>SsD<U4JHY" 3773 "8kD2)2fU/M#$e.)T4,_=8hLim[&);?UkK'-x?'(:siIfL<$pFM`i<?%W(mGDHM%>iWP,##P`%/L<eXi:@Z9C.7o=@(pXdAO/NLQ8lPl+HPOQa8wD8=^GlPa8TKI1CjhsCTSLJM'/Wl>-" 3774 "S(qw%sf/@%#B6;/U7K]uZbi^Oc^2n<bhPmUkMw>%t<)'mEVE''n`WnJra$^TKvX5B>;_aSEK',(hwa0:i4G?.Bci.(X[?b*($,=-n<.Q%`(X=?+@Am*Js0&=3bh8K]mL<LoNs'6,'85`" 3775 "0?t/'_U59@]ddF<#LdF<eWdF<OuN/45rY<-L@&#+fm>69=Lb,OcZV/);TTm8VI;?%OtJ<(b4mq7M6:u?KRdF<gR@2L=FNU-<b[(9c/ML3m;Z[$oF3g)GAWqpARc=<ROu7cL5l;-[A]%/" 3776 "+fsd;l#SafT/f*W]0=O'$(Tb<[)*@e775R-:Yob%g*>l*:xP?Yb.5)%w_I?7uk5JC+FS(m#i'k.'a0i)9<7b'fs'59hq$*5Uhv##pi^8+hIEBF`nvo`;'l0.^S1<-wUK2/Coh58KKhLj" 3777 "M=SO*rfO`+qC`W-On.=AJ56>>i2@2LH6A:&5q`?9I3@@'04&p2/LVa*T-4<-i3;M9UvZd+N7>b*eIwg:CC)c<>nO&#<IGe;__.thjZl<%w(Wk2xmp4Q@I#I9,DF]u7-P=.-_:YJ]aS@V" 3778 "?6*C()dOp7:WL,b&3Rg/.cmM9&r^>$(>.Z-I&J(Q0Hd5Q%7Co-b`-c<N(6r@ip+AurK<m86QIth*#v;-OBqi+L7wDE-Ir8K['m+DDSLwK&/.?-V%U_%3:qKNu$_b*B-kp7NaD'QdWQPK" 3779 "Yq[@>P)hI;*_F]u`Rb[.j8_Q/<&>uu+VsH$sM9TA%?)(vmJ80),P7E>)tjD%2L=-t#fK[%`v=Q8<FfNkgg^oIbah*#8/Qt$F&:K*-(N/'+1vMB,u()-a.VUU*#[e%gAAO(S>WlA2);Sa" 3780 ">gXm8YB`1d@K#n]76-a$U,mF<fX]idqd)<3,]J7JmW4`6]uks=4-72L(jEk+:bJ0M^q-8Dm_Z?0olP1C9Sa&H[d&c$ooQUj]Exd*3ZM@-WGW2%s',B-_M%>%Ul:#/'xoFM9QX-$.QN'>" 3781 "[%$Z$uF6pA6Ki2O5:8w*vP1<-1`[G,)-m#>0`P&#eb#.3i)rtB61(o'$?X3B</R90;eZ]%Ncq;-Tl]#F>2Qft^ae_5tKL9MUe9b*sLEQ95C&`=G?@Mj=wh*'3E>=-<)Gt*Iw)'QG:`@I" 3782 "wOf7&]1i'S01B+Ev/Nac#9S;=;YQpg_6U`*kVY39xK,[/6Aj7:'1Bm-_1EYfa1+o&o4hp7KN_Q(OlIo@S%;jVdn0'1<Vc52=u`3^o-n1'g4v58Hj&6_t7$##?M)c<$bgQ_'SY((-xkA#" 3783 "Y(,p'H9rIVY-b,'%bCPF7.J<Up^,(dU1VY*5#WkTU>h19w,WQhLI)3S#f$2(eb,jr*b;3Vw]*7NH%$c4Vs,eD9>XW8?N]o+(*pgC%/72LV-u<Hp,3@e^9UB1J+ak9-TN/mhKPg+AJYd$" 3784 "MlvAF_jCK*.O-^(63adMT->W%iewS8W6m2rtCpo'RS1R84=@paTKt)>=%&1[)*vp'u+x,VrwN;&]kuO9JDbg=pO$J*.jVe;u'm0dr9l,<*wMK*Oe=g8lV_KEBFkO'oU]^=[-792#ok,)" 3785 "i]lR8qQ2oA8wcRCZ^7w/Njh;?.stX?Q1>S1q4Bn$)K1<-rGdO'$Wr.Lc.CG)$/*JL4tNR/,SVO3,aUw'DJN:)Ss;wGn9A32ijw%FL+Z0Fn.U9;reSq)bmI32U==5ALuG&#Vf1398/pVo" 3786 "1*c-(aY168o<`JsSbk-,1N;$>0:OUas(3:8Z972LSfF8eb=c-;>SPw7.6hn3m`9^Xkn(r.qS[0;T%&Qc=+STRxX'q1BNk3&*eu2;&8q$&x>Q#Q7^Tf+6<(d%ZVmj2bDi%.3L2n+4W'$P" 3787 "iDDG)g,r%+?,$@?uou5tSe2aN_AQU*<h`e-GI7)?OK2A.d7_c)?wQ5AS@DL3r#7fSkgl6-++D:'A,uq7SvlB$pcpH'q3n0#_%dY#xCpr-l<F0NR@-##FEV6NTF6##$l84N1w?AO>'IAO" 3788 "URQ##V^Fv-XFbGM7Fl(N<3DhLGF%q.1rC$#:T__&Pi68%0xi_&[qFJ(77j_&JWoF.V735&T,[R*:xFR*K5>>#`bW-?4Ne_&6Ne_&6Ne_&n`kr-#GJcM6X;uM6X;uM(.a..^2TkL%oR(#" 3789 ";u.T%fAr%4tJ8&><1=GHZ_+m9/#H1F^R#SC#*N=BA9(D?v[UiFY>>^8p,KKF.W]L29uLkLlu/+4T<XoIB&hx=T1PcDaB&;HH+-AFr?(m9HZV)FKS8JCw;SD=6[^/DZUL`EUDf]GGlG&>" 3790 "w$)F./^n3+rlo+DB;5sIYGNk+i1t-69Jg--0pao7Sm#K)pdHW&;LuDNH@H>#/X-TI(;P>#,Gc>#0Su>#4`1?#8lC?#<xU?#@.i?#D:%@#HF7@#LRI@#P_[@#Tkn@#Xw*A#]-=A#a9OA#" 3791 "d<F&#*;G##.GY##2Sl##6`($#:l:$#>xL$#B.`$#F:r$#JF.%#NR@%#R_R%#Vke%#Zww%#_-4^Rh%Sflr-k'MS.o?.5/sWel/wpEM0%3'/1)K^f1-d>G21&v(35>V`39V7A4=onx4" 3792 "A1OY5EI0;6Ibgr6M$HS7Q<)58C5w,;WoA*#[%T*#`1g*#d=#+#hI5+#lUG+#pbY+#tnl+#x$),#&1;,#*=M,#.I`,#2Ur,#6b.-#;w[H#iQtA#m^0B#qjBB#uvTB##-hB#'9$C#+E6C#" 3793 "/QHC#3^ZC#7jmC#;v)D#?,<D#C8ND#GDaD#KPsD#O]/E#g1A5#KA*1#gC17#MGd;#8(02#L-d3#rWM4#Hga1#,<w0#T.j<#O#'2#CYN1#qa^:#_4m3#o@/=#eG8=#t8J5#`+78#4uI-#" 3794 "m3B2#SB[8#Q0@8#i[*9#iOn8#1Nm;#^sN9#qh<9#:=x-#P;K2#$%X9#bC+.#Rg;<#mN=.#MTF.#RZO.#2?)4#Y#(/#[)1/#b;L/#dAU/#0Sv;#lY$0#n`-0#sf60#(F24#wrH0#%/e0#" 3795 "TmD<#%JSMFove:CTBEXI:<eh2g)B,3h2^G3i;#d3jD>)4kMYD4lVu`4m`:&5niUA5@(A5BA1]PBB:xlBCC=2CDLXMCEUtiCf&0g2'tN?PGT4CPGT4CPGT4CPGT4CPGT4CPGT4CPGT4CP" 3796 "GT4CPGT4CPGT4CPGT4CPGT4CPGT4CP-qekC`.9kEg^+F$kwViFJTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5o,^<-28ZI'O?;xp" 3797 "O?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xp;7q-#lLYI:xvD=#"; 2971 3798 2972 3799 static const char* GetDefaultCompressedFontDataTTFBase85() 2973 3800 { 2974 return proggy_clean_ttf_compressed_data_base85; 2975 } 3801 return proggy_clean_ttf_compressed_data_base85; 3802 } 3803 3804 #endif // #ifndef IMGUI_DISABLE -
IMGUI/imgui_internal.h
r78c3045 re66fd66 1 // dear imgui, v1. 61 WIP2 // (internal s)1 // dear imgui, v1.79 2 // (internal structures/api) 3 3 4 4 // You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility! … … 7 7 // To implement maths operators for ImVec2 (disabled by default to not collide with using IM_VEC2_CLASS_EXTRA along with your own math types+operators) 8 8 9 /* 10 11 Index of this file: 12 13 // [SECTION] Header mess 14 // [SECTION] Forward declarations 15 // [SECTION] Context pointer 16 // [SECTION] STB libraries includes 17 // [SECTION] Macros 18 // [SECTION] Generic helpers 19 // [SECTION] ImDrawList support 20 // [SECTION] Widgets support: flags, enums, data structures 21 // [SECTION] Columns support 22 // [SECTION] Settings support 23 // [SECTION] Multi-select support 24 // [SECTION] Docking support 25 // [SECTION] Viewport support 26 // [SECTION] ImGuiContext (main imgui context) 27 // [SECTION] ImGuiWindowTempData, ImGuiWindow 28 // [SECTION] Tab bar, Tab item support 29 // [SECTION] Table support 30 // [SECTION] Internal API 31 // [SECTION] Test Engine Hooks (imgui_test_engine) 32 33 */ 34 9 35 #pragma once 36 #ifndef IMGUI_DISABLE 37 38 //----------------------------------------------------------------------------- 39 // [SECTION] Header mess 40 //----------------------------------------------------------------------------- 10 41 11 42 #ifndef IMGUI_VERSION … … 13 44 #endif 14 45 15 #include <stdio.h> // FILE* 46 #include <stdio.h> // FILE*, sscanf 47 #include <stdlib.h> // NULL, malloc, free, qsort, atoi, atof 16 48 #include <math.h> // sqrtf, fabsf, fmodf, powf, floorf, ceilf, cosf, sinf 17 49 #include <limits.h> // INT_MIN, INT_MAX 18 50 51 // Visual Studio warnings 19 52 #ifdef _MSC_VER 20 53 #pragma warning (push) … … 22 55 #endif 23 56 24 #ifdef __clang__ 57 // Clang/GCC warnings with -Weverything 58 #if defined(__clang__) 25 59 #pragma clang diagnostic push 26 #pragma clang diagnostic ignored "-Wunused-function" // for stb_textedit.h 27 #pragma clang diagnostic ignored "-Wmissing-prototypes" // for stb_textedit.h 60 #if __has_warning("-Wunknown-warning-option") 61 #pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' 62 #endif 63 #pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' 64 #pragma clang diagnostic ignored "-Wunused-function" // for stb_textedit.h 65 #pragma clang diagnostic ignored "-Wmissing-prototypes" // for stb_textedit.h 28 66 #pragma clang diagnostic ignored "-Wold-style-cast" 29 #endif 30 31 //----------------------------------------------------------------------------- 32 // Forward Declarations 33 //----------------------------------------------------------------------------- 34 35 struct ImRect; 36 struct ImGuiColMod; 37 struct ImGuiStyleMod; 38 struct ImGuiGroupData; 39 struct ImGuiMenuColumns; 40 struct ImGuiDrawContext; 41 struct ImGuiTextEditState; 42 struct ImGuiPopupRef; 43 struct ImGuiWindow; 44 struct ImGuiWindowSettings; 45 46 typedef int ImGuiLayoutType; // enum: horizontal or vertical // enum ImGuiLayoutType_ 47 typedef int ImGuiButtonFlags; // flags: for ButtonEx(), ButtonBehavior() // enum ImGuiButtonFlags_ 48 typedef int ImGuiItemFlags; // flags: for PushItemFlag() // enum ImGuiItemFlags_ 49 typedef int ImGuiItemStatusFlags; // flags: storage for DC.LastItemXXX // enum ImGuiItemStatusFlags_ 50 typedef int ImGuiNavHighlightFlags; // flags: for RenderNavHighlight() // enum ImGuiNavHighlightFlags_ 51 typedef int ImGuiNavDirSourceFlags; // flags: for GetNavInputAmount2d() // enum ImGuiNavDirSourceFlags_ 52 typedef int ImGuiSeparatorFlags; // flags: for Separator() - internal // enum ImGuiSeparatorFlags_ 53 typedef int ImGuiSliderFlags; // flags: for SliderBehavior() // enum ImGuiSliderFlags_ 54 55 //------------------------------------------------------------------------- 56 // STB libraries 57 //------------------------------------------------------------------------- 58 59 namespace ImGuiStb 67 #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" 68 #pragma clang diagnostic ignored "-Wdouble-promotion" 69 #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision 70 #elif defined(__GNUC__) 71 #pragma GCC diagnostic push 72 #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind 73 #pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead 74 #endif 75 76 // Legacy defines 77 #ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS // Renamed in 1.74 78 #error Use IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS 79 #endif 80 #ifdef IMGUI_DISABLE_MATH_FUNCTIONS // Renamed in 1.74 81 #error Use IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS 82 #endif 83 84 //----------------------------------------------------------------------------- 85 // [SECTION] Forward declarations 86 //----------------------------------------------------------------------------- 87 88 struct ImBitVector; // Store 1-bit per value 89 struct ImRect; // An axis-aligned rectangle (2 points) 90 struct ImDrawDataBuilder; // Helper to build a ImDrawData instance 91 struct ImDrawListSharedData; // Data shared between all ImDrawList instances 92 struct ImGuiColorMod; // Stacked color modifier, backup of modified data so we can restore it 93 struct ImGuiColumnData; // Storage data for a single column 94 struct ImGuiColumns; // Storage data for a columns set 95 struct ImGuiContext; // Main Dear ImGui context 96 struct ImGuiDataTypeInfo; // Type information associated to a ImGuiDataType enum 97 struct ImGuiGroupData; // Stacked storage data for BeginGroup()/EndGroup() 98 struct ImGuiInputTextState; // Internal state of the currently focused/edited text input box 99 struct ImGuiLastItemDataBackup; // Backup and restore IsItemHovered() internal data 100 struct ImGuiMenuColumns; // Simple column measurement, currently used for MenuItem() only 101 struct ImGuiNavMoveResult; // Result of a gamepad/keyboard directional navigation move query result 102 struct ImGuiNextWindowData; // Storage for SetNextWindow** functions 103 struct ImGuiNextItemData; // Storage for SetNextItem** functions 104 struct ImGuiPopupData; // Storage for current popup stack 105 struct ImGuiSettingsHandler; // Storage for one type registered in the .ini file 106 struct ImGuiStyleMod; // Stacked style modifier, backup of modified data so we can restore it 107 struct ImGuiTabBar; // Storage for a tab bar 108 struct ImGuiTabItem; // Storage for a tab item (within a tab bar) 109 struct ImGuiWindow; // Storage for one window 110 struct ImGuiWindowTempData; // Temporary storage for one window (that's the data which in theory we could ditch at the end of the frame) 111 struct ImGuiWindowSettings; // Storage for a window .ini settings (we keep one of those even if the actual window wasn't instanced during this session) 112 113 // Use your programming IDE "Go to definition" facility on the names of the center columns to find the actual flags/enum lists. 114 typedef int ImGuiLayoutType; // -> enum ImGuiLayoutType_ // Enum: Horizontal or vertical 115 typedef int ImGuiButtonFlags; // -> enum ImGuiButtonFlags_ // Flags: for ButtonEx(), ButtonBehavior() 116 typedef int ImGuiColumnsFlags; // -> enum ImGuiColumnsFlags_ // Flags: BeginColumns() 117 typedef int ImGuiItemFlags; // -> enum ImGuiItemFlags_ // Flags: for PushItemFlag() 118 typedef int ImGuiItemStatusFlags; // -> enum ImGuiItemStatusFlags_ // Flags: for DC.LastItemStatusFlags 119 typedef int ImGuiNavHighlightFlags; // -> enum ImGuiNavHighlightFlags_ // Flags: for RenderNavHighlight() 120 typedef int ImGuiNavDirSourceFlags; // -> enum ImGuiNavDirSourceFlags_ // Flags: for GetNavInputAmount2d() 121 typedef int ImGuiNavMoveFlags; // -> enum ImGuiNavMoveFlags_ // Flags: for navigation requests 122 typedef int ImGuiNextItemDataFlags; // -> enum ImGuiNextItemDataFlags_ // Flags: for SetNextItemXXX() functions 123 typedef int ImGuiNextWindowDataFlags; // -> enum ImGuiNextWindowDataFlags_// Flags: for SetNextWindowXXX() functions 124 typedef int ImGuiSeparatorFlags; // -> enum ImGuiSeparatorFlags_ // Flags: for SeparatorEx() 125 typedef int ImGuiTextFlags; // -> enum ImGuiTextFlags_ // Flags: for TextEx() 126 typedef int ImGuiTooltipFlags; // -> enum ImGuiTooltipFlags_ // Flags: for BeginTooltipEx() 127 128 //----------------------------------------------------------------------------- 129 // [SECTION] Context pointer 130 // See implementation of this variable in imgui.cpp for comments and details. 131 //----------------------------------------------------------------------------- 132 133 #ifndef GImGui 134 extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer 135 #endif 136 137 //------------------------------------------------------------------------- 138 // [SECTION] STB libraries includes 139 //------------------------------------------------------------------------- 140 141 namespace ImStb 60 142 { 61 143 62 144 #undef STB_TEXTEDIT_STRING 63 145 #undef STB_TEXTEDIT_CHARTYPE 64 #define STB_TEXTEDIT_STRING ImGui TextEditState146 #define STB_TEXTEDIT_STRING ImGuiInputTextState 65 147 #define STB_TEXTEDIT_CHARTYPE ImWchar 66 #define STB_TEXTEDIT_GETWIDTH_NEWLINE -1.0f 67 #include "stb_textedit.h" 68 69 } // namespace ImGuiStb 70 71 //----------------------------------------------------------------------------- 72 // Context 73 //----------------------------------------------------------------------------- 74 75 #ifndef GImGui 76 extern IMGUI_API ImGuiContext* GImGui; // Current implicit ImGui context pointer 77 #endif 78 79 //----------------------------------------------------------------------------- 80 // Helpers 81 //----------------------------------------------------------------------------- 82 83 #define IM_PI 3.14159265358979323846f 148 #define STB_TEXTEDIT_GETWIDTH_NEWLINE (-1.0f) 149 #define STB_TEXTEDIT_UNDOSTATECOUNT 99 150 #define STB_TEXTEDIT_UNDOCHARCOUNT 999 151 #include "imstb_textedit.h" 152 153 } // namespace ImStb 154 155 //----------------------------------------------------------------------------- 156 // [SECTION] Macros 157 //----------------------------------------------------------------------------- 158 159 // Debug Logging 160 #ifndef IMGUI_DEBUG_LOG 161 #define IMGUI_DEBUG_LOG(_FMT,...) printf("[%05d] " _FMT, GImGui->FrameCount, __VA_ARGS__) 162 #endif 163 164 // Debug Logging for selected systems. Remove the '((void)0) //' to enable. 165 //#define IMGUI_DEBUG_LOG_POPUP IMGUI_DEBUG_LOG // Enable log 166 //#define IMGUI_DEBUG_LOG_NAV IMGUI_DEBUG_LOG // Enable log 167 #define IMGUI_DEBUG_LOG_POPUP(...) ((void)0) // Disable log 168 #define IMGUI_DEBUG_LOG_NAV(...) ((void)0) // Disable log 169 170 // Static Asserts 171 #if (__cplusplus >= 201100) 172 #define IM_STATIC_ASSERT(_COND) static_assert(_COND, "") 173 #else 174 #define IM_STATIC_ASSERT(_COND) typedef char static_assertion_##__line__[(_COND)?1:-1] 175 #endif 176 177 // "Paranoid" Debug Asserts are meant to only be enabled during specific debugging/work, otherwise would slow down the code too much. 178 // We currently don't have many of those so the effect is currently negligible, but onward intent to add more aggressive ones in the code. 179 //#define IMGUI_DEBUG_PARANOID 180 #ifdef IMGUI_DEBUG_PARANOID 181 #define IM_ASSERT_PARANOID(_EXPR) IM_ASSERT(_EXPR) 182 #else 183 #define IM_ASSERT_PARANOID(_EXPR) 184 #endif 185 186 // Error handling 187 // Down the line in some frameworks/languages we would like to have a way to redirect those to the programmer and recover from more faults. 188 #ifndef IM_ASSERT_USER_ERROR 189 #define IM_ASSERT_USER_ERROR(_EXP,_MSG) IM_ASSERT((_EXP) && _MSG) // Recoverable User Error 190 #endif 191 192 // Misc Macros 193 #define IM_PI 3.14159265358979323846f 84 194 #ifdef _WIN32 85 #define IM_NEWLINE "\r\n" // Play it nice with Windows users (2018: Notepad _still_ doesn't display files properly when they use Unix-style carriage returns)195 #define IM_NEWLINE "\r\n" // Play it nice with Windows users (Update: since 2018-05, Notepad finally appears to support Unix-style carriage returns!) 86 196 #else 87 #define IM_NEWLINE "\n" 88 #endif 89 90 // Helpers: UTF-8 <> wchar 91 IMGUI_API int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count 92 IMGUI_API int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end); // return input UTF-8 bytes count 93 IMGUI_API int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_remaining = NULL); // return input UTF-8 bytes count 94 IMGUI_API int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end); // return number of UTF-8 code-points (NOT bytes count) 95 IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string as UTF-8 code-points 96 97 // Helpers: Misc 98 IMGUI_API ImU32 ImHash(const void* data, int data_size, ImU32 seed = 0); // Pass data_size==0 for zero-terminated strings 99 IMGUI_API void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, int* out_file_size = NULL, int padding_bytes = 0); 100 IMGUI_API FILE* ImFileOpen(const char* filename, const char* file_open_mode); 101 static inline bool ImCharIsSpace(unsigned int c) { return c == ' ' || c == '\t' || c == 0x3000; } 102 static inline bool ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; } 103 static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; } 104 105 // Helpers: Geometry 106 IMGUI_API ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p); 107 IMGUI_API bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p); 108 IMGUI_API ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p); 109 IMGUI_API void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w); 110 111 // Helpers: String 197 #define IM_NEWLINE "\n" 198 #endif 199 #define IM_TABSIZE (4) 200 #define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) // Unsaturated, for display purpose 201 #define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255 202 #define IM_FLOOR(_VAL) ((float)(int)(_VAL)) // ImFloor() is not inlined in MSVC debug builds 203 #define IM_ROUND(_VAL) ((float)(int)((_VAL) + 0.5f)) // 204 205 // Enforce cdecl calling convention for functions called by the standard library, in case compilation settings changed the default to e.g. __vectorcall 206 #ifdef _MSC_VER 207 #define IMGUI_CDECL __cdecl 208 #else 209 #define IMGUI_CDECL 210 #endif 211 212 // Debug Tools 213 // Use 'Metrics->Tools->Item Picker' to break into the call-stack of a specific item. 214 #ifndef IM_DEBUG_BREAK 215 #if defined(__clang__) 216 #define IM_DEBUG_BREAK() __builtin_debugtrap() 217 #elif defined (_MSC_VER) 218 #define IM_DEBUG_BREAK() __debugbreak() 219 #else 220 #define IM_DEBUG_BREAK() IM_ASSERT(0) // It is expected that you define IM_DEBUG_BREAK() into something that will break nicely in a debugger! 221 #endif 222 #endif // #ifndef IM_DEBUG_BREAK 223 224 //----------------------------------------------------------------------------- 225 // [SECTION] Generic helpers 226 // Note that the ImXXX helpers functions are lower-level than ImGui functions. 227 // ImGui functions or the ImGui context are never called/used from other ImXXX functions. 228 //----------------------------------------------------------------------------- 229 // - Helpers: Hashing 230 // - Helpers: Sorting 231 // - Helpers: Bit manipulation 232 // - Helpers: String, Formatting 233 // - Helpers: UTF-8 <> wchar conversions 234 // - Helpers: ImVec2/ImVec4 operators 235 // - Helpers: Maths 236 // - Helpers: Geometry 237 // - Helper: ImVec1 238 // - Helper: ImVec2ih 239 // - Helper: ImRect 240 // - Helper: ImBitArray 241 // - Helper: ImBitVector 242 // - Helper: ImPool<> 243 // - Helper: ImChunkStream<> 244 //----------------------------------------------------------------------------- 245 246 // Helpers: Hashing 247 IMGUI_API ImU32 ImHashData(const void* data, size_t data_size, ImU32 seed = 0); 248 IMGUI_API ImU32 ImHashStr(const char* data, size_t data_size = 0, ImU32 seed = 0); 249 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS 250 static inline ImU32 ImHash(const void* data, int size, ImU32 seed = 0) { return size ? ImHashData(data, (size_t)size, seed) : ImHashStr((const char*)data, 0, seed); } // [moved to ImHashStr/ImHashData in 1.68] 251 #endif 252 253 // Helpers: Sorting 254 #define ImQsort qsort 255 256 // Helpers: Color Blending 257 IMGUI_API ImU32 ImAlphaBlendColors(ImU32 col_a, ImU32 col_b); 258 259 // Helpers: Bit manipulation 260 static inline bool ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; } 261 static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; } 262 263 // Helpers: String, Formatting 112 264 IMGUI_API int ImStricmp(const char* str1, const char* str2); 113 265 IMGUI_API int ImStrnicmp(const char* str1, const char* str2, size_t count); 114 266 IMGUI_API void ImStrncpy(char* dst, const char* src, size_t count); 115 267 IMGUI_API char* ImStrdup(const char* str); 268 IMGUI_API char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* str); 116 269 IMGUI_API const char* ImStrchrRange(const char* str_begin, const char* str_end, char c); 117 270 IMGUI_API int ImStrlenW(const ImWchar* str); 118 IMGUI_API const ImWchar*ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin); // Find beginning-of-line 271 IMGUI_API const char* ImStreolRange(const char* str, const char* str_end); // End end-of-line 272 IMGUI_API const ImWchar*ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin); // Find beginning-of-line 119 273 IMGUI_API const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end); 274 IMGUI_API void ImStrTrimBlanks(char* str); 275 IMGUI_API const char* ImStrSkipBlank(const char* str); 120 276 IMGUI_API int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...) IM_FMTARGS(3); 121 277 IMGUI_API int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) IM_FMTLIST(3); 122 123 // Helpers: Math 124 // We are keeping those not leaking to the user by default, in the case the user has implicit cast operators between ImVec2 and its own types (when IM_VEC2_CLASS_EXTRA is defined) 278 IMGUI_API const char* ImParseFormatFindStart(const char* format); 279 IMGUI_API const char* ImParseFormatFindEnd(const char* format); 280 IMGUI_API const char* ImParseFormatTrimDecorations(const char* format, char* buf, size_t buf_size); 281 IMGUI_API int ImParseFormatPrecision(const char* format, int default_value); 282 static inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; } 283 static inline bool ImCharIsBlankW(unsigned int c) { return c == ' ' || c == '\t' || c == 0x3000; } 284 285 // Helpers: UTF-8 <> wchar conversions 286 IMGUI_API int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count 287 IMGUI_API int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end); // read one character. return input UTF-8 bytes count 288 IMGUI_API int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_remaining = NULL); // return input UTF-8 bytes count 289 IMGUI_API int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end); // return number of UTF-8 code-points (NOT bytes count) 290 IMGUI_API int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end); // return number of bytes to express one char in UTF-8 291 IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string in UTF-8 292 293 // Helpers: ImVec2/ImVec4 operators 294 // We are keeping those disabled by default so they don't leak in user space, to allow user enabling implicit cast operators between ImVec2 and their own types (using IM_VEC2_CLASS_EXTRA etc.) 295 // We unfortunately don't have a unary- operator for ImVec2 because this would needs to be defined inside the class itself. 125 296 #ifdef IMGUI_DEFINE_MATH_OPERATORS 126 static inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x*rhs, lhs.y*rhs); } 127 static inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x / rhs, lhs.y / rhs); } 128 static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); } 129 static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); } 130 static inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x*rhs.x, lhs.y*rhs.y); } 131 static inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x / rhs.x, lhs.y / rhs.y); } 132 static inline ImVec2& operator+=(ImVec2& lhs, const ImVec2& rhs) { lhs.x += rhs.x; lhs.y += rhs.y; return lhs; } 133 static inline ImVec2& operator-=(ImVec2& lhs, const ImVec2& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; return lhs; } 134 static inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; } 135 static inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; } 136 static inline ImVec4 operator+(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w); } 137 static inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w); } 138 static inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x*rhs.x, lhs.y*rhs.y, lhs.z*rhs.z, lhs.w*rhs.w); } 139 #endif 140 141 static inline int ImMin(int lhs, int rhs) { return lhs < rhs ? lhs : rhs; } 142 static inline int ImMax(int lhs, int rhs) { return lhs >= rhs ? lhs : rhs; } 143 static inline float ImMin(float lhs, float rhs) { return lhs < rhs ? lhs : rhs; } 144 static inline float ImMax(float lhs, float rhs) { return lhs >= rhs ? lhs : rhs; } 145 static inline ImVec2 ImMin(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x < rhs.x ? lhs.x : rhs.x, lhs.y < rhs.y ? lhs.y : rhs.y); } 146 static inline ImVec2 ImMax(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x >= rhs.x ? lhs.x : rhs.x, lhs.y >= rhs.y ? lhs.y : rhs.y); } 147 static inline int ImClamp(int v, int mn, int mx) { return (v < mn) ? mn : (v > mx) ? mx : v; } 148 static inline float ImClamp(float v, float mn, float mx) { return (v < mn) ? mn : (v > mx) ? mx : v; } 149 static inline ImVec2 ImClamp(const ImVec2& f, const ImVec2& mn, ImVec2 mx) { return ImVec2(ImClamp(f.x, mn.x, mx.x), ImClamp(f.y, mn.y, mx.y)); } 150 static inline float ImSaturate(float f) { return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : f; } 151 static inline void ImSwap(int& a, int& b) { int tmp = a; a = b; b = tmp; } 152 static inline void ImSwap(float& a, float& b) { float tmp = a; a = b; b = tmp; } 153 static inline int ImLerp(int a, int b, float t) { return (int)(a + (b - a) * t); } 154 static inline float ImLerp(float a, float b, float t) { return a + (b - a) * t; } 155 static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, float t) { return ImVec2(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t); } 156 static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, const ImVec2& t) { return ImVec2(a.x + (b.x - a.x) * t.x, a.y + (b.y - a.y) * t.y); } 157 static inline ImVec4 ImLerp(const ImVec4& a, const ImVec4& b, float t) { return ImVec4(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t, a.w + (b.w - a.w) * t); } 158 static inline float ImLengthSqr(const ImVec2& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y; } 159 static inline float ImLengthSqr(const ImVec4& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y + lhs.z*lhs.z + lhs.w*lhs.w; } 160 static inline float ImInvLength(const ImVec2& lhs, float fail_value) { float d = lhs.x*lhs.x + lhs.y*lhs.y; if (d > 0.0f) return 1.0f / sqrtf(d); return fail_value; } 161 static inline float ImFloor(float f) { return (float)(int)f; } 162 static inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2((float)(int)v.x, (float)(int)v.y); } 163 static inline float ImDot(const ImVec2& a, const ImVec2& b) { return a.x * b.x + a.y * b.y; } 164 static inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); } 165 static inline float ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; } 166 static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } 167 168 //----------------------------------------------------------------------------- 169 // Types 170 //----------------------------------------------------------------------------- 171 172 enum ImGuiButtonFlags_ 173 { 174 ImGuiButtonFlags_Repeat = 1 << 0, // hold to repeat 175 ImGuiButtonFlags_PressedOnClickRelease = 1 << 1, // return true on click + release on same item [DEFAULT if no PressedOn* flag is set] 176 ImGuiButtonFlags_PressedOnClick = 1 << 2, // return true on click (default requires click+release) 177 ImGuiButtonFlags_PressedOnRelease = 1 << 3, // return true on release (default requires click+release) 178 ImGuiButtonFlags_PressedOnDoubleClick = 1 << 4, // return true on double-click (default requires click+release) 179 ImGuiButtonFlags_FlattenChildren = 1 << 5, // allow interactions even if a child window is overlapping 180 ImGuiButtonFlags_AllowItemOverlap = 1 << 6, // require previous frame HoveredId to either match id or be null before being usable, use along with SetItemAllowOverlap() 181 ImGuiButtonFlags_DontClosePopups = 1 << 7, // disable automatically closing parent popup on press // [UNUSED] 182 ImGuiButtonFlags_Disabled = 1 << 8, // disable interactions 183 ImGuiButtonFlags_AlignTextBaseLine = 1 << 9, // vertically align button to match text baseline - ButtonEx() only // FIXME: Should be removed and handled by SmallButton(), not possible currently because of DC.CursorPosPrevLine 184 ImGuiButtonFlags_NoKeyModifiers = 1 << 10, // disable interaction if a key modifier is held 185 ImGuiButtonFlags_NoHoldingActiveID = 1 << 11, // don't set ActiveId while holding the mouse (ImGuiButtonFlags_PressedOnClick only) 186 ImGuiButtonFlags_PressedOnDragDropHold = 1 << 12, // press when held into while we are drag and dropping another item (used by e.g. tree nodes, collapsing headers) 187 ImGuiButtonFlags_NoNavFocus = 1 << 13 // don't override navigation focus when activated 188 }; 189 190 enum ImGuiSliderFlags_ 191 { 192 ImGuiSliderFlags_Vertical = 1 << 0 193 }; 194 195 enum ImGuiColumnsFlags_ 196 { 197 // Default: 0 198 ImGuiColumnsFlags_NoBorder = 1 << 0, // Disable column dividers 199 ImGuiColumnsFlags_NoResize = 1 << 1, // Disable resizing columns when clicking on the dividers 200 ImGuiColumnsFlags_NoPreserveWidths = 1 << 2, // Disable column width preservation when adjusting columns 201 ImGuiColumnsFlags_NoForceWithinWindow = 1 << 3, // Disable forcing columns to fit within window 202 ImGuiColumnsFlags_GrowParentContentsSize = 1 << 4 // (WIP) Restore pre-1.51 behavior of extending the parent window contents size but _without affecting the columns width at all_. Will eventually remove. 203 }; 204 205 enum ImGuiSelectableFlagsPrivate_ 206 { 207 // NB: need to be in sync with last value of ImGuiSelectableFlags_ 208 ImGuiSelectableFlags_Menu = 1 << 3, // -> PressedOnClick 209 ImGuiSelectableFlags_MenuItem = 1 << 4, // -> PressedOnRelease 210 ImGuiSelectableFlags_Disabled = 1 << 5, 211 ImGuiSelectableFlags_DrawFillAvailWidth = 1 << 6 212 }; 213 214 enum ImGuiSeparatorFlags_ 215 { 216 ImGuiSeparatorFlags_Horizontal = 1 << 0, // Axis default to current layout type, so generally Horizontal unless e.g. in a menu bar 217 ImGuiSeparatorFlags_Vertical = 1 << 1 218 }; 219 220 // Storage for LastItem data 221 enum ImGuiItemStatusFlags_ 222 { 223 ImGuiItemStatusFlags_HoveredRect = 1 << 0, 224 ImGuiItemStatusFlags_HasDisplayRect = 1 << 1 225 }; 226 227 // FIXME: this is in development, not exposed/functional as a generic feature yet. 228 enum ImGuiLayoutType_ 229 { 230 ImGuiLayoutType_Vertical, 231 ImGuiLayoutType_Horizontal 232 }; 233 234 enum ImGuiAxis 235 { 236 ImGuiAxis_None = -1, 237 ImGuiAxis_X = 0, 238 ImGuiAxis_Y = 1 239 }; 240 241 enum ImGuiPlotType 242 { 243 ImGuiPlotType_Lines, 244 ImGuiPlotType_Histogram 245 }; 246 247 enum ImGuiDataType 248 { 249 ImGuiDataType_Int32, 250 ImGuiDataType_Uint32, 251 ImGuiDataType_Float, 252 ImGuiDataType_Double, 253 ImGuiDataType_COUNT 254 }; 255 256 enum ImGuiInputSource 257 { 258 ImGuiInputSource_None = 0, 259 ImGuiInputSource_Mouse, 260 ImGuiInputSource_Nav, 261 ImGuiInputSource_NavKeyboard, // Only used occasionally for storage, not tested/handled by most code 262 ImGuiInputSource_NavGamepad, // " 263 ImGuiInputSource_COUNT 264 }; 265 266 // FIXME-NAV: Clarify/expose various repeat delay/rate 267 enum ImGuiInputReadMode 268 { 269 ImGuiInputReadMode_Down, 270 ImGuiInputReadMode_Pressed, 271 ImGuiInputReadMode_Released, 272 ImGuiInputReadMode_Repeat, 273 ImGuiInputReadMode_RepeatSlow, 274 ImGuiInputReadMode_RepeatFast 275 }; 276 277 enum ImGuiNavHighlightFlags_ 278 { 279 ImGuiNavHighlightFlags_TypeDefault = 1 << 0, 280 ImGuiNavHighlightFlags_TypeThin = 1 << 1, 281 ImGuiNavHighlightFlags_AlwaysDraw = 1 << 2, 282 ImGuiNavHighlightFlags_NoRounding = 1 << 3 283 }; 284 285 enum ImGuiNavDirSourceFlags_ 286 { 287 ImGuiNavDirSourceFlags_Keyboard = 1 << 0, 288 ImGuiNavDirSourceFlags_PadDPad = 1 << 1, 289 ImGuiNavDirSourceFlags_PadLStick = 1 << 2 290 }; 291 292 enum ImGuiNavForward 293 { 294 ImGuiNavForward_None, 295 ImGuiNavForward_ForwardQueued, 296 ImGuiNavForward_ForwardActive 297 }; 298 299 // 2D axis aligned bounding-box 300 // NB: we can't rely on ImVec2 math operators being available here 297 static inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x * rhs, lhs.y * rhs); } 298 static inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x / rhs, lhs.y / rhs); } 299 static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); } 300 static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); } 301 static inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } 302 static inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x / rhs.x, lhs.y / rhs.y); } 303 static inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; } 304 static inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; } 305 static inline ImVec2& operator+=(ImVec2& lhs, const ImVec2& rhs) { lhs.x += rhs.x; lhs.y += rhs.y; return lhs; } 306 static inline ImVec2& operator-=(ImVec2& lhs, const ImVec2& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; return lhs; } 307 static inline ImVec2& operator*=(ImVec2& lhs, const ImVec2& rhs) { lhs.x *= rhs.x; lhs.y *= rhs.y; return lhs; } 308 static inline ImVec2& operator/=(ImVec2& lhs, const ImVec2& rhs) { lhs.x /= rhs.x; lhs.y /= rhs.y; return lhs; } 309 static inline ImVec4 operator+(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w); } 310 static inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w); } 311 static inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z, lhs.w * rhs.w); } 312 #endif 313 314 // Helpers: File System 315 #ifdef IMGUI_DISABLE_FILE_FUNCTIONS 316 #define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS 317 typedef void* ImFileHandle; 318 static inline ImFileHandle ImFileOpen(const char*, const char*) { return NULL; } 319 static inline bool ImFileClose(ImFileHandle) { return false; } 320 static inline ImU64 ImFileGetSize(ImFileHandle) { return (ImU64)-1; } 321 static inline ImU64 ImFileRead(void*, ImU64, ImU64, ImFileHandle) { return 0; } 322 static inline ImU64 ImFileWrite(const void*, ImU64, ImU64, ImFileHandle) { return 0; } 323 #endif 324 #ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS 325 typedef FILE* ImFileHandle; 326 IMGUI_API ImFileHandle ImFileOpen(const char* filename, const char* mode); 327 IMGUI_API bool ImFileClose(ImFileHandle file); 328 IMGUI_API ImU64 ImFileGetSize(ImFileHandle file); 329 IMGUI_API ImU64 ImFileRead(void* data, ImU64 size, ImU64 count, ImFileHandle file); 330 IMGUI_API ImU64 ImFileWrite(const void* data, ImU64 size, ImU64 count, ImFileHandle file); 331 #else 332 #define IMGUI_DISABLE_TTY_FUNCTIONS // Can't use stdout, fflush if we are not using default file functions 333 #endif 334 IMGUI_API void* ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_file_size = NULL, int padding_bytes = 0); 335 336 // Helpers: Maths 337 // - Wrapper for standard libs functions. (Note that imgui_demo.cpp does _not_ use them to keep the code easy to copy) 338 #ifndef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS 339 #define ImFabs(X) fabsf(X) 340 #define ImSqrt(X) sqrtf(X) 341 #define ImFmod(X, Y) fmodf((X), (Y)) 342 #define ImCos(X) cosf(X) 343 #define ImSin(X) sinf(X) 344 #define ImAcos(X) acosf(X) 345 #define ImAtan2(Y, X) atan2f((Y), (X)) 346 #define ImAtof(STR) atof(STR) 347 #define ImFloorStd(X) floorf(X) // We already uses our own ImFloor() { return (float)(int)v } internally so the standard one wrapper is named differently (it's used by e.g. stb_truetype) 348 #define ImCeil(X) ceilf(X) 349 static inline float ImPow(float x, float y) { return powf(x, y); } // DragBehaviorT/SliderBehaviorT uses ImPow with either float/double and need the precision 350 static inline double ImPow(double x, double y) { return pow(x, y); } 351 static inline float ImLog(float x) { return logf(x); } // DragBehaviorT/SliderBehaviorT uses ImLog with either float/double and need the precision 352 static inline double ImLog(double x) { return log(x); } 353 static inline float ImAbs(float x) { return fabsf(x); } 354 static inline double ImAbs(double x) { return fabs(x); } 355 static inline float ImSign(float x) { return (x < 0.0f) ? -1.0f : ((x > 0.0f) ? 1.0f : 0.0f); } // Sign operator - returns -1, 0 or 1 based on sign of argument 356 static inline double ImSign(double x) { return (x < 0.0) ? -1.0 : ((x > 0.0) ? 1.0 : 0.0); } 357 #endif 358 // - ImMin/ImMax/ImClamp/ImLerp/ImSwap are used by widgets which support variety of types: signed/unsigned int/long long float/double 359 // (Exceptionally using templates here but we could also redefine them for those types) 360 template<typename T> static inline T ImMin(T lhs, T rhs) { return lhs < rhs ? lhs : rhs; } 361 template<typename T> static inline T ImMax(T lhs, T rhs) { return lhs >= rhs ? lhs : rhs; } 362 template<typename T> static inline T ImClamp(T v, T mn, T mx) { return (v < mn) ? mn : (v > mx) ? mx : v; } 363 template<typename T> static inline T ImLerp(T a, T b, float t) { return (T)(a + (b - a) * t); } 364 template<typename T> static inline void ImSwap(T& a, T& b) { T tmp = a; a = b; b = tmp; } 365 template<typename T> static inline T ImAddClampOverflow(T a, T b, T mn, T mx) { if (b < 0 && (a < mn - b)) return mn; if (b > 0 && (a > mx - b)) return mx; return a + b; } 366 template<typename T> static inline T ImSubClampOverflow(T a, T b, T mn, T mx) { if (b > 0 && (a < mn + b)) return mn; if (b < 0 && (a > mx + b)) return mx; return a - b; } 367 // - Misc maths helpers 368 static inline ImVec2 ImMin(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x < rhs.x ? lhs.x : rhs.x, lhs.y < rhs.y ? lhs.y : rhs.y); } 369 static inline ImVec2 ImMax(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x >= rhs.x ? lhs.x : rhs.x, lhs.y >= rhs.y ? lhs.y : rhs.y); } 370 static inline ImVec2 ImClamp(const ImVec2& v, const ImVec2& mn, ImVec2 mx) { return ImVec2((v.x < mn.x) ? mn.x : (v.x > mx.x) ? mx.x : v.x, (v.y < mn.y) ? mn.y : (v.y > mx.y) ? mx.y : v.y); } 371 static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, float t) { return ImVec2(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t); } 372 static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, const ImVec2& t) { return ImVec2(a.x + (b.x - a.x) * t.x, a.y + (b.y - a.y) * t.y); } 373 static inline ImVec4 ImLerp(const ImVec4& a, const ImVec4& b, float t) { return ImVec4(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t, a.w + (b.w - a.w) * t); } 374 static inline float ImSaturate(float f) { return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : f; } 375 static inline float ImLengthSqr(const ImVec2& lhs) { return (lhs.x * lhs.x) + (lhs.y * lhs.y); } 376 static inline float ImLengthSqr(const ImVec4& lhs) { return (lhs.x * lhs.x) + (lhs.y * lhs.y) + (lhs.z * lhs.z) + (lhs.w * lhs.w); } 377 static inline float ImInvLength(const ImVec2& lhs, float fail_value) { float d = (lhs.x * lhs.x) + (lhs.y * lhs.y); if (d > 0.0f) return 1.0f / ImSqrt(d); return fail_value; } 378 static inline float ImFloor(float f) { return (float)(int)(f); } 379 static inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2((float)(int)(v.x), (float)(int)(v.y)); } 380 static inline int ImModPositive(int a, int b) { return (a + b) % b; } 381 static inline float ImDot(const ImVec2& a, const ImVec2& b) { return a.x * b.x + a.y * b.y; } 382 static inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); } 383 static inline float ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; } 384 static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } 385 386 // Helpers: Geometry 387 IMGUI_API ImVec2 ImBezierCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, float t); // Cubic Bezier 388 IMGUI_API ImVec2 ImBezierClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, int num_segments); // For curves with explicit number of segments 389 IMGUI_API ImVec2 ImBezierClosestPointCasteljau(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float tess_tol);// For auto-tessellated curves you can use tess_tol = style.CurveTessellationTol 390 IMGUI_API ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p); 391 IMGUI_API bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p); 392 IMGUI_API ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p); 393 IMGUI_API void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w); 394 inline float ImTriangleArea(const ImVec2& a, const ImVec2& b, const ImVec2& c) { return ImFabs((a.x * (b.y - c.y)) + (b.x * (c.y - a.y)) + (c.x * (a.y - b.y))) * 0.5f; } 395 IMGUI_API ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy); 396 397 // Helper: ImVec1 (1D vector) 398 // (this odd construct is used to facilitate the transition between 1D and 2D, and the maintenance of some branches/patches) 399 struct ImVec1 400 { 401 float x; 402 ImVec1() { x = 0.0f; } 403 ImVec1(float _x) { x = _x; } 404 }; 405 406 // Helper: ImVec2ih (2D vector, half-size integer, for long-term packed storage) 407 struct ImVec2ih 408 { 409 short x, y; 410 ImVec2ih() { x = y = 0; } 411 ImVec2ih(short _x, short _y) { x = _x; y = _y; } 412 explicit ImVec2ih(const ImVec2& rhs) { x = (short)rhs.x; y = (short)rhs.y; } 413 }; 414 415 // Helper: ImRect (2D axis aligned bounding-box) 416 // NB: we can't rely on ImVec2 math operators being available here! 301 417 struct IMGUI_API ImRect 302 418 { 303 ImVec2 Min; // Upper-left 304 ImVec2 Max; // Lower-right 305 306 ImRect() : Min(FLT_MAX, FLT_MAX), Max(-FLT_MAX, -FLT_MAX) {} 307 ImRect(const ImVec2& min, const ImVec2& max) : Min(min), Max(max) {} 308 ImRect(const ImVec4& v) : Min(v.x, v.y), Max(v.z, v.w) {} 309 ImRect(float x1, float y1, float x2, float y2) : Min(x1, y1), Max(x2, y2) {} 310 311 ImVec2 GetCenter() const { return ImVec2((Min.x + Max.x) * 0.5f, (Min.y + Max.y) * 0.5f); } 312 ImVec2 GetSize() const { return ImVec2(Max.x - Min.x, Max.y - Min.y); } 313 float GetWidth() const { return Max.x - Min.x; } 314 float GetHeight() const { return Max.y - Min.y; } 315 ImVec2 GetTL() const { return Min; } // Top-left 316 ImVec2 GetTR() const { return ImVec2(Max.x, Min.y); } // Top-right 317 ImVec2 GetBL() const { return ImVec2(Min.x, Max.y); } // Bottom-left 318 ImVec2 GetBR() const { return Max; } // Bottom-right 319 bool Contains(const ImVec2& p) const { return p.x >= Min.x && p.y >= Min.y && p.x < Max.x && p.y < Max.y; } 320 bool Contains(const ImRect& r) const { return r.Min.x >= Min.x && r.Min.y >= Min.y && r.Max.x <= Max.x && r.Max.y <= Max.y; } 321 bool Overlaps(const ImRect& r) const { return r.Min.y < Max.y && r.Max.y > Min.y && r.Min.x < Max.x && r.Max.x > Min.x; } 322 void Add(const ImVec2& p) { if (Min.x > p.x) Min.x = p.x; if (Min.y > p.y) Min.y = p.y; if (Max.x < p.x) Max.x = p.x; if (Max.y < p.y) Max.y = p.y; } 323 void Add(const ImRect& r) { if (Min.x > r.Min.x) Min.x = r.Min.x; if (Min.y > r.Min.y) Min.y = r.Min.y; if (Max.x < r.Max.x) Max.x = r.Max.x; if (Max.y < r.Max.y) Max.y = r.Max.y; } 324 void Expand(const float amount) { Min.x -= amount; Min.y -= amount; Max.x += amount; Max.y += amount; } 325 void Expand(const ImVec2& amount) { Min.x -= amount.x; Min.y -= amount.y; Max.x += amount.x; Max.y += amount.y; } 326 void Translate(const ImVec2& d) { Min.x += d.x; Min.y += d.y; Max.x += d.x; Max.y += d.y; } 327 void ClipWith(const ImRect& r) { Min = ImMax(Min, r.Min); Max = ImMin(Max, r.Max); } // Simple version, may lead to an inverted rectangle, which is fine for Contains/Overlaps test but not for display. 328 void ClipWithFull(const ImRect& r) { Min = ImClamp(Min, r.Min, r.Max); Max = ImClamp(Max, r.Min, r.Max); } // Full version, ensure both points are fully clipped. 329 void Floor() { Min.x = (float)(int)Min.x; Min.y = (float)(int)Min.y; Max.x = (float)(int)Max.x; Max.y = (float)(int)Max.y; } 330 bool IsInverted() const { return Min.x > Max.x || Min.y > Max.y; } 331 }; 332 333 // Stacked color modifier, backup of modified data so we can restore it 334 struct ImGuiColMod 335 { 336 ImGuiCol Col; 337 ImVec4 BackupValue; 338 }; 339 340 // Stacked style modifier, backup of modified data so we can restore it. Data type inferred from the variable. 341 struct ImGuiStyleMod 342 { 343 ImGuiStyleVar VarIdx; 344 union { int BackupInt[2]; float BackupFloat[2]; }; 345 ImGuiStyleMod(ImGuiStyleVar idx, int v) { VarIdx = idx; BackupInt[0] = v; } 346 ImGuiStyleMod(ImGuiStyleVar idx, float v) { VarIdx = idx; BackupFloat[0] = v; } 347 ImGuiStyleMod(ImGuiStyleVar idx, ImVec2 v) { VarIdx = idx; BackupFloat[0] = v.x; BackupFloat[1] = v.y; } 348 }; 349 350 // Stacked data for BeginGroup()/EndGroup() 351 struct ImGuiGroupData 352 { 353 ImVec2 BackupCursorPos; 354 ImVec2 BackupCursorMaxPos; 355 float BackupIndentX; 356 float BackupGroupOffsetX; 357 float BackupCurrentLineHeight; 358 float BackupCurrentLineTextBaseOffset; 359 float BackupLogLinePosY; 360 bool BackupActiveIdIsAlive; 361 bool AdvanceCursor; 362 }; 363 364 // Simple column measurement currently used for MenuItem() only. This is very short-sighted/throw-away code and NOT a generic helper. 365 struct IMGUI_API ImGuiMenuColumns 366 { 367 int Count; 368 float Spacing; 369 float Width, NextWidth; 370 float Pos[4], NextWidths[4]; 371 372 ImGuiMenuColumns(); 373 void Update(int count, float spacing, bool clear); 374 float DeclColumns(float w0, float w1, float w2); 375 float CalcExtraSpace(float avail_w); 376 }; 377 378 // Internal state of the currently focused/edited text input box 379 struct IMGUI_API ImGuiTextEditState 380 { 381 ImGuiID Id; // widget id owning the text state 382 ImVector<ImWchar> Text; // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so we copy into own buffer. 383 ImVector<char> InitialText; // backup of end-user buffer at the time of focus (in UTF-8, unaltered) 384 ImVector<char> TempTextBuffer; 385 int CurLenA, CurLenW; // we need to maintain our buffer length in both UTF-8 and wchar format. 386 int BufSizeA; // end-user buffer size 387 float ScrollX; 388 ImGuiStb::STB_TexteditState StbState; 389 float CursorAnim; 390 bool CursorFollow; 391 bool SelectedAllMouseLock; 392 393 ImGuiTextEditState() { memset(this, 0, sizeof(*this)); } 394 void CursorAnimReset() { CursorAnim = -0.30f; } // After a user-input the cursor stays on for a while without blinking 395 void CursorClamp() { StbState.cursor = ImMin(StbState.cursor, CurLenW); StbState.select_start = ImMin(StbState.select_start, CurLenW); StbState.select_end = ImMin(StbState.select_end, CurLenW); } 396 bool HasSelection() const { return StbState.select_start != StbState.select_end; } 397 void ClearSelection() { StbState.select_start = StbState.select_end = StbState.cursor; } 398 void SelectAll() { StbState.select_start = 0; StbState.cursor = StbState.select_end = CurLenW; StbState.has_preferred_x = false; } 399 void OnKeyPressed(int key); 400 }; 401 402 // Data saved in imgui.ini file 403 struct ImGuiWindowSettings 404 { 405 char* Name; 406 ImGuiID Id; 407 ImVec2 Pos; 408 ImVec2 Size; 409 bool Collapsed; 410 411 ImGuiWindowSettings() { Name = NULL; Id = 0; Pos = Size = ImVec2(0, 0); Collapsed = false; } 412 }; 413 414 struct ImGuiSettingsHandler 415 { 416 const char* TypeName; // Short description stored in .ini file. Disallowed characters: '[' ']' 417 ImGuiID TypeHash; // == ImHash(TypeName, 0, 0) 418 void* (*ReadOpenFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, const char* name); // Read: Called when entering into a new ini entry e.g. "[Window][Name]" 419 void(*ReadLineFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line); // Read: Called for every line of text within an ini entry 420 void(*WriteAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* out_buf); // Write: Output every entries into 'out_buf' 421 void* UserData; 422 423 ImGuiSettingsHandler() { memset(this, 0, sizeof(*this)); } 424 }; 425 426 // Storage for current popup stack 427 struct ImGuiPopupRef 428 { 429 ImGuiID PopupId; // Set on OpenPopup() 430 ImGuiWindow* Window; // Resolved on BeginPopup() - may stay unresolved if user never calls OpenPopup() 431 ImGuiWindow* ParentWindow; // Set on OpenPopup() 432 int OpenFrameCount; // Set on OpenPopup() 433 ImGuiID OpenParentId; // Set on OpenPopup(), we need this to differenciate multiple menu sets from each others (e.g. inside menu bar vs loose menu items) 434 ImVec2 OpenPopupPos; // Set on OpenPopup(), preferred popup position (typically == OpenMousePos when using mouse) 435 ImVec2 OpenMousePos; // Set on OpenPopup(), copy of mouse position at the time of opening popup 436 }; 437 438 struct ImGuiColumnData 439 { 440 float OffsetNorm; // Column start offset, normalized 0.0 (far left) -> 1.0 (far right) 441 float OffsetNormBeforeResize; 442 ImGuiColumnsFlags Flags; // Not exposed 443 ImRect ClipRect; 444 445 ImGuiColumnData() { OffsetNorm = OffsetNormBeforeResize = 0.0f; Flags = 0; } 446 }; 447 448 struct ImGuiColumnsSet 449 { 450 ImGuiID ID; 451 ImGuiColumnsFlags Flags; 452 bool IsFirstFrame; 453 bool IsBeingResized; 454 int Current; 455 int Count; 456 float MinX, MaxX; 457 float LineMinY, LineMaxY; 458 float StartPosY; // Copy of CursorPos 459 float StartMaxPosX; // Copy of CursorMaxPos 460 ImVector<ImGuiColumnData> Columns; 461 462 ImGuiColumnsSet() { Clear(); } 463 void Clear() 464 { 465 ID = 0; 466 Flags = 0; 467 IsFirstFrame = false; 468 IsBeingResized = false; 469 Current = 0; 470 Count = 1; 471 MinX = MaxX = 0.0f; 472 LineMinY = LineMaxY = 0.0f; 473 StartPosY = 0.0f; 474 StartMaxPosX = 0.0f; 475 Columns.clear(); 476 } 477 }; 478 419 ImVec2 Min; // Upper-left 420 ImVec2 Max; // Lower-right 421 422 ImRect() : Min(0.0f, 0.0f), Max(0.0f, 0.0f) {} 423 ImRect(const ImVec2& min, const ImVec2& max) : Min(min), Max(max) {} 424 ImRect(const ImVec4& v) : Min(v.x, v.y), Max(v.z, v.w) {} 425 ImRect(float x1, float y1, float x2, float y2) : Min(x1, y1), Max(x2, y2) {} 426 427 ImVec2 GetCenter() const { return ImVec2((Min.x + Max.x) * 0.5f, (Min.y + Max.y) * 0.5f); } 428 ImVec2 GetSize() const { return ImVec2(Max.x - Min.x, Max.y - Min.y); } 429 float GetWidth() const { return Max.x - Min.x; } 430 float GetHeight() const { return Max.y - Min.y; } 431 ImVec2 GetTL() const { return Min; } // Top-left 432 ImVec2 GetTR() const { return ImVec2(Max.x, Min.y); } // Top-right 433 ImVec2 GetBL() const { return ImVec2(Min.x, Max.y); } // Bottom-left 434 ImVec2 GetBR() const { return Max; } // Bottom-right 435 bool Contains(const ImVec2& p) const { return p.x >= Min.x && p.y >= Min.y && p.x < Max.x && p.y < Max.y; } 436 bool Contains(const ImRect& r) const { return r.Min.x >= Min.x && r.Min.y >= Min.y && r.Max.x <= Max.x && r.Max.y <= Max.y; } 437 bool Overlaps(const ImRect& r) const { return r.Min.y < Max.y && r.Max.y > Min.y && r.Min.x < Max.x && r.Max.x > Min.x; } 438 void Add(const ImVec2& p) { if (Min.x > p.x) Min.x = p.x; if (Min.y > p.y) Min.y = p.y; if (Max.x < p.x) Max.x = p.x; if (Max.y < p.y) Max.y = p.y; } 439 void Add(const ImRect& r) { if (Min.x > r.Min.x) Min.x = r.Min.x; if (Min.y > r.Min.y) Min.y = r.Min.y; if (Max.x < r.Max.x) Max.x = r.Max.x; if (Max.y < r.Max.y) Max.y = r.Max.y; } 440 void Expand(const float amount) { Min.x -= amount; Min.y -= amount; Max.x += amount; Max.y += amount; } 441 void Expand(const ImVec2& amount) { Min.x -= amount.x; Min.y -= amount.y; Max.x += amount.x; Max.y += amount.y; } 442 void Translate(const ImVec2& d) { Min.x += d.x; Min.y += d.y; Max.x += d.x; Max.y += d.y; } 443 void TranslateX(float dx) { Min.x += dx; Max.x += dx; } 444 void TranslateY(float dy) { Min.y += dy; Max.y += dy; } 445 void ClipWith(const ImRect& r) { Min = ImMax(Min, r.Min); Max = ImMin(Max, r.Max); } // Simple version, may lead to an inverted rectangle, which is fine for Contains/Overlaps test but not for display. 446 void ClipWithFull(const ImRect& r) { Min = ImClamp(Min, r.Min, r.Max); Max = ImClamp(Max, r.Min, r.Max); } // Full version, ensure both points are fully clipped. 447 void Floor() { Min.x = IM_FLOOR(Min.x); Min.y = IM_FLOOR(Min.y); Max.x = IM_FLOOR(Max.x); Max.y = IM_FLOOR(Max.y); } 448 bool IsInverted() const { return Min.x > Max.x || Min.y > Max.y; } 449 ImVec4 ToVec4() const { return ImVec4(Min.x, Min.y, Max.x, Max.y); } 450 }; 451 452 // Helper: ImBitArray 453 inline bool ImBitArrayTestBit(const ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); return (arr[n >> 5] & mask) != 0; } 454 inline void ImBitArrayClearBit(ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); arr[n >> 5] &= ~mask; } 455 inline void ImBitArraySetBit(ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); arr[n >> 5] |= mask; } 456 inline void ImBitArraySetBitRange(ImU32* arr, int n, int n2) 457 { 458 while (n <= n2) 459 { 460 int a_mod = (n & 31); 461 int b_mod = ((n2 >= n + 31) ? 31 : (n2 & 31)) + 1; 462 ImU32 mask = (ImU32)(((ImU64)1 << b_mod) - 1) & ~(ImU32)(((ImU64)1 << a_mod) - 1); 463 arr[n >> 5] |= mask; 464 n = (n + 32) & ~31; 465 } 466 } 467 468 // Helper: ImBitVector 469 // Store 1-bit per value. 470 struct IMGUI_API ImBitVector 471 { 472 ImVector<ImU32> Storage; 473 void Create(int sz) { Storage.resize((sz + 31) >> 5); memset(Storage.Data, 0, (size_t)Storage.Size * sizeof(Storage.Data[0])); } 474 void Clear() { Storage.clear(); } 475 bool TestBit(int n) const { IM_ASSERT(n < (Storage.Size << 5)); return ImBitArrayTestBit(Storage.Data, n); } 476 void SetBit(int n) { IM_ASSERT(n < (Storage.Size << 5)); ImBitArraySetBit(Storage.Data, n); } 477 void ClearBit(int n) { IM_ASSERT(n < (Storage.Size << 5)); ImBitArrayClearBit(Storage.Data, n); } 478 }; 479 480 // Helper: ImPool<> 481 // Basic keyed storage for contiguous instances, slow/amortized insertion, O(1) indexable, O(Log N) queries by ID over a dense/hot buffer, 482 // Honor constructor/destructor. Add/remove invalidate all pointers. Indexes have the same lifetime as the associated object. 483 typedef int ImPoolIdx; 484 template<typename T> 485 struct IMGUI_API ImPool 486 { 487 ImVector<T> Buf; // Contiguous data 488 ImGuiStorage Map; // ID->Index 489 ImPoolIdx FreeIdx; // Next free idx to use 490 491 ImPool() { FreeIdx = 0; } 492 ~ImPool() { Clear(); } 493 T* GetByKey(ImGuiID key) { int idx = Map.GetInt(key, -1); return (idx != -1) ? &Buf[idx] : NULL; } 494 T* GetByIndex(ImPoolIdx n) { return &Buf[n]; } 495 ImPoolIdx GetIndex(const T* p) const { IM_ASSERT(p >= Buf.Data && p < Buf.Data + Buf.Size); return (ImPoolIdx)(p - Buf.Data); } 496 T* GetOrAddByKey(ImGuiID key) { int* p_idx = Map.GetIntRef(key, -1); if (*p_idx != -1) return &Buf[*p_idx]; *p_idx = FreeIdx; return Add(); } 497 bool Contains(const T* p) const { return (p >= Buf.Data && p < Buf.Data + Buf.Size); } 498 void Clear() { for (int n = 0; n < Map.Data.Size; n++) { int idx = Map.Data[n].val_i; if (idx != -1) Buf[idx].~T(); } Map.Clear(); Buf.clear(); FreeIdx = 0; } 499 T* Add() { int idx = FreeIdx; if (idx == Buf.Size) { Buf.resize(Buf.Size + 1); FreeIdx++; } else { FreeIdx = *(int*)&Buf[idx]; } IM_PLACEMENT_NEW(&Buf[idx]) T(); return &Buf[idx]; } 500 void Remove(ImGuiID key, const T* p) { Remove(key, GetIndex(p)); } 501 void Remove(ImGuiID key, ImPoolIdx idx) { Buf[idx].~T(); *(int*)&Buf[idx] = FreeIdx; FreeIdx = idx; Map.SetInt(key, -1); } 502 void Reserve(int capacity) { Buf.reserve(capacity); Map.Data.reserve(capacity); } 503 int GetSize() const { return Buf.Size; } 504 }; 505 506 // Helper: ImChunkStream<> 507 // Build and iterate a contiguous stream of variable-sized structures. 508 // This is used by Settings to store persistent data while reducing allocation count. 509 // We store the chunk size first, and align the final size on 4 bytes boundaries (this what the '(X + 3) & ~3' statement is for) 510 // The tedious/zealous amount of casting is to avoid -Wcast-align warnings. 511 template<typename T> 512 struct IMGUI_API ImChunkStream 513 { 514 ImVector<char> Buf; 515 516 void clear() { Buf.clear(); } 517 bool empty() const { return Buf.Size == 0; } 518 int size() const { return Buf.Size; } 519 T* alloc_chunk(size_t sz) { size_t HDR_SZ = 4; sz = ((HDR_SZ + sz) + 3u) & ~3u; int off = Buf.Size; Buf.resize(off + (int)sz); ((int*)(void*)(Buf.Data + off))[0] = (int)sz; return (T*)(void*)(Buf.Data + off + (int)HDR_SZ); } 520 T* begin() { size_t HDR_SZ = 4; if (!Buf.Data) return NULL; return (T*)(void*)(Buf.Data + HDR_SZ); } 521 T* next_chunk(T* p) { size_t HDR_SZ = 4; IM_ASSERT(p >= begin() && p < end()); p = (T*)(void*)((char*)(void*)p + chunk_size(p)); if (p == (T*)(void*)((char*)end() + HDR_SZ)) return (T*)0; IM_ASSERT(p < end()); return p; } 522 int chunk_size(const T* p) { return ((const int*)p)[-1]; } 523 T* end() { return (T*)(void*)(Buf.Data + Buf.Size); } 524 int offset_from_ptr(const T* p) { IM_ASSERT(p >= begin() && p < end()); const ptrdiff_t off = (const char*)p - Buf.Data; return (int)off; } 525 T* ptr_from_offset(int off) { IM_ASSERT(off >= 4 && off < Buf.Size); return (T*)(void*)(Buf.Data + off); } 526 }; 527 528 //----------------------------------------------------------------------------- 529 // [SECTION] ImDrawList support 530 //----------------------------------------------------------------------------- 531 532 // ImDrawList: Helper function to calculate a circle's segment count given its radius and a "maximum error" value. 533 #define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN 12 534 #define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX 512 535 #define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(_RAD,_MAXERROR) ImClamp((int)((IM_PI * 2.0f) / ImAcos(((_RAD) - (_MAXERROR)) / (_RAD))), IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX) 536 537 // ImDrawList: You may set this to higher values (e.g. 2 or 3) to increase tessellation of fast rounded corners path. 538 #ifndef IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER 539 #define IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER 1 540 #endif 541 542 // Data shared between all ImDrawList instances 543 // You may want to create your own instance of this if you want to use ImDrawList completely without ImGui. In that case, watch out for future changes to this structure. 479 544 struct IMGUI_API ImDrawListSharedData 480 545 { 481 ImVec2 TexUvWhitePixel; // UV of white pixel in the atlas 482 ImFont* Font; // Current/default font (optional, for simplified AddText overload) 483 float FontSize; // Current/default font size (optional, for simplified AddText overload) 484 float CurveTessellationTol; 485 ImVec4 ClipRectFullscreen; // Value for PushClipRectFullscreen() 486 487 // Const data 488 // FIXME: Bake rounded corners fill/borders in atlas 489 ImVec2 CircleVtx12[12]; 490 491 ImDrawListSharedData(); 546 ImVec2 TexUvWhitePixel; // UV of white pixel in the atlas 547 ImFont* Font; // Current/default font (optional, for simplified AddText overload) 548 float FontSize; // Current/default font size (optional, for simplified AddText overload) 549 float CurveTessellationTol; // Tessellation tolerance when using PathBezierCurveTo() 550 float CircleSegmentMaxError; // Number of circle segments to use per pixel of radius for AddCircle() etc 551 ImVec4 ClipRectFullscreen; // Value for PushClipRectFullscreen() 552 ImDrawListFlags InitialFlags; // Initial flags at the beginning of the frame (it is possible to alter flags on a per-drawlist basis afterwards) 553 554 // [Internal] Lookup tables 555 ImVec2 ArcFastVtx[12 * IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER]; // FIXME: Bake rounded corners fill/borders in atlas 556 ImU8 CircleSegmentCounts[64]; // Precomputed segment count for given radius (array index + 1) before we calculate it dynamically (to avoid calculation overhead) 557 const ImVec4* TexUvLines; // UV of anti-aliased lines in the atlas 558 559 ImDrawListSharedData(); 560 void SetCircleSegmentMaxError(float max_error); 492 561 }; 493 562 494 563 struct ImDrawDataBuilder 495 564 { 496 ImVector<ImDrawList*> Layers[2]; // Global layers for: regular, tooltip 497 498 void Clear() { for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) Layers[n].resize(0); } 499 void ClearFreeMemory() { for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) Layers[n].clear(); } 500 IMGUI_API void FlattenIntoSingleLayer(); 501 }; 502 503 struct ImGuiNavMoveResult 504 { 505 ImGuiID ID; // Best candidate 506 ImGuiID ParentID; // Best candidate window->IDStack.back() - to compare context 507 ImGuiWindow* Window; // Best candidate window 508 float DistBox; // Best candidate box distance to current NavId 509 float DistCenter; // Best candidate center distance to current NavId 510 float DistAxial; 511 ImRect RectRel; // Best candidate bounding box in window relative space 512 513 ImGuiNavMoveResult() { Clear(); } 514 void Clear() { ID = ParentID = 0; Window = NULL; DistBox = DistCenter = DistAxial = FLT_MAX; RectRel = ImRect(); } 515 }; 516 517 // Storage for SetNexWindow** functions 518 struct ImGuiNextWindowData 519 { 520 ImGuiCond PosCond; 521 ImGuiCond SizeCond; 522 ImGuiCond ContentSizeCond; 523 ImGuiCond CollapsedCond; 524 ImGuiCond SizeConstraintCond; 525 ImGuiCond FocusCond; 526 ImGuiCond BgAlphaCond; 527 ImVec2 PosVal; 528 ImVec2 PosPivotVal; 529 ImVec2 SizeVal; 530 ImVec2 ContentSizeVal; 531 bool CollapsedVal; 532 ImRect SizeConstraintRect; 533 ImGuiSizeCallback SizeCallback; 534 void* SizeCallbackUserData; 535 float BgAlphaVal; 536 ImVec2 MenuBarOffsetMinVal; // This is not exposed publicly, so we don't clear it. 537 538 ImGuiNextWindowData() 539 { 540 PosCond = SizeCond = ContentSizeCond = CollapsedCond = SizeConstraintCond = FocusCond = BgAlphaCond = 0; 541 PosVal = PosPivotVal = SizeVal = ImVec2(0.0f, 0.0f); 542 ContentSizeVal = ImVec2(0.0f, 0.0f); 543 CollapsedVal = false; 544 SizeConstraintRect = ImRect(); 545 SizeCallback = NULL; 546 SizeCallbackUserData = NULL; 547 BgAlphaVal = FLT_MAX; 548 MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f); 549 } 550 551 void Clear() 552 { 553 PosCond = SizeCond = ContentSizeCond = CollapsedCond = SizeConstraintCond = FocusCond = BgAlphaCond = 0; 554 } 555 }; 556 557 // Main state for ImGui 558 struct ImGuiContext 559 { 560 bool Initialized; 561 bool FontAtlasOwnedByContext; // Io.Fonts-> is owned by the ImGuiContext and will be destructed along with it. 562 ImGuiIO IO; 563 ImGuiStyle Style; 564 ImFont* Font; // (Shortcut) == FontStack.empty() ? IO.Font : FontStack.back() 565 float FontSize; // (Shortcut) == FontBaseSize * g.CurrentWindow->FontWindowScale == window->FontSize(). Text height for current window. 566 float FontBaseSize; // (Shortcut) == IO.FontGlobalScale * Font->Scale * Font->FontSize. Base text height. 567 ImDrawListSharedData DrawListSharedData; 568 569 float Time; 570 int FrameCount; 571 int FrameCountEnded; 572 int FrameCountRendered; 573 ImVector<ImGuiWindow*> Windows; 574 ImVector<ImGuiWindow*> WindowsSortBuffer; 575 ImVector<ImGuiWindow*> CurrentWindowStack; 576 ImGuiStorage WindowsById; 577 int WindowsActiveCount; 578 ImGuiWindow* CurrentWindow; // Being drawn into 579 ImGuiWindow* HoveredWindow; // Will catch mouse inputs 580 ImGuiWindow* HoveredRootWindow; // Will catch mouse inputs (for focus/move only) 581 ImGuiID HoveredId; // Hovered widget 582 bool HoveredIdAllowOverlap; 583 ImGuiID HoveredIdPreviousFrame; 584 float HoveredIdTimer; 585 ImGuiID ActiveId; // Active widget 586 ImGuiID ActiveIdPreviousFrame; 587 float ActiveIdTimer; 588 bool ActiveIdIsAlive; // Active widget has been seen this frame 589 bool ActiveIdIsJustActivated; // Set at the time of activation for one frame 590 bool ActiveIdAllowOverlap; // Active widget allows another widget to steal active id (generally for overlapping widgets, but not always) 591 int ActiveIdAllowNavDirFlags; // Active widget allows using directional navigation (e.g. can activate a button and move away from it) 592 ImVec2 ActiveIdClickOffset; // Clicked offset from upper-left corner, if applicable (currently only set by ButtonBehavior) 593 ImGuiWindow* ActiveIdWindow; 594 ImGuiInputSource ActiveIdSource; // Activating with mouse or nav (gamepad/keyboard) 595 ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actually window that is moved is generally MovingWindow->RootWindow. 596 ImVector<ImGuiColMod> ColorModifiers; // Stack for PushStyleColor()/PopStyleColor() 597 ImVector<ImGuiStyleMod> StyleModifiers; // Stack for PushStyleVar()/PopStyleVar() 598 ImVector<ImFont*> FontStack; // Stack for PushFont()/PopFont() 599 ImVector<ImGuiPopupRef> OpenPopupStack; // Which popups are open (persistent) 600 ImVector<ImGuiPopupRef> CurrentPopupStack; // Which level of BeginPopup() we are in (reset every frame) 601 ImGuiNextWindowData NextWindowData; // Storage for SetNextWindow** functions 602 bool NextTreeNodeOpenVal; // Storage for SetNextTreeNode** functions 603 ImGuiCond NextTreeNodeOpenCond; 604 605 // Navigation data (for gamepad/keyboard) 606 ImGuiWindow* NavWindow; // Focused window for navigation. Could be called 'FocusWindow' 607 ImGuiID NavId; // Focused item for navigation 608 ImGuiID NavActivateId; // ~~ (g.ActiveId == 0) && IsNavInputPressed(ImGuiNavInput_Activate) ? NavId : 0, also set when calling ActivateItem() 609 ImGuiID NavActivateDownId; // ~~ IsNavInputDown(ImGuiNavInput_Activate) ? NavId : 0 610 ImGuiID NavActivatePressedId; // ~~ IsNavInputPressed(ImGuiNavInput_Activate) ? NavId : 0 611 ImGuiID NavInputId; // ~~ IsNavInputPressed(ImGuiNavInput_Input) ? NavId : 0 612 ImGuiID NavJustTabbedId; // Just tabbed to this id. 613 ImGuiID NavJustMovedToId; // Just navigated to this id (result of a successfully MoveRequest) 614 ImGuiID NavNextActivateId; // Set by ActivateItem(), queued until next frame 615 ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode? 616 ImRect NavScoringRectScreen; // Rectangle used for scoring, in screen space. Based of window->DC.NavRefRectRel[], modified for directional navigation scoring. 617 int NavScoringCount; // Metrics for debugging 618 ImGuiWindow* NavWindowingTarget; // When selecting a window (holding Menu+FocusPrev/Next, or equivalent of CTRL-TAB) this window is temporarily displayed front-most. 619 float NavWindowingHighlightTimer; 620 float NavWindowingHighlightAlpha; 621 bool NavWindowingToggleLayer; 622 int NavLayer; // Layer we are navigating on. For now the system is hard-coded for 0=main contents and 1=menu/title bar, may expose layers later. 623 int NavIdTabCounter; // == NavWindow->DC.FocusIdxTabCounter at time of NavId processing 624 bool NavIdIsAlive; // Nav widget has been seen this frame ~~ NavRefRectRel is valid 625 bool NavMousePosDirty; // When set we will update mouse position if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) if set (NB: this not enabled by default) 626 bool NavDisableHighlight; // When user starts using mouse, we hide gamepad/keyboard highlight (NB: but they are still available, which is why NavDisableHighlight isn't always != NavDisableMouseHover) 627 bool NavDisableMouseHover; // When user starts using gamepad/keyboard, we hide mouse hovering highlight until mouse is touched again. 628 bool NavAnyRequest; // ~~ NavMoveRequest || NavInitRequest 629 bool NavInitRequest; // Init request for appearing window to select first item 630 bool NavInitRequestFromMove; 631 ImGuiID NavInitResultId; 632 ImRect NavInitResultRectRel; 633 bool NavMoveFromClampedRefRect; // Set by manual scrolling, if we scroll to a point where NavId isn't visible we reset navigation from visible items 634 bool NavMoveRequest; // Move request for this frame 635 ImGuiNavForward NavMoveRequestForward; // None / ForwardQueued / ForwardActive (this is used to navigate sibling parent menus from a child menu) 636 ImGuiDir NavMoveDir, NavMoveDirLast; // Direction of the move request (left/right/up/down), direction of the previous move request 637 ImGuiNavMoveResult NavMoveResultLocal; // Best move request candidate within NavWindow 638 ImGuiNavMoveResult NavMoveResultOther; // Best move request candidate within NavWindow's flattened hierarchy (when using the NavFlattened flag) 639 640 // Render 641 ImDrawData DrawData; // Main ImDrawData instance to pass render information to the user 642 ImDrawDataBuilder DrawDataBuilder; 643 float ModalWindowDarkeningRatio; 644 ImDrawList OverlayDrawList; // Optional software render of mouse cursors, if io.MouseDrawCursor is set + a few debug overlays 645 ImGuiMouseCursor MouseCursor; 646 647 // Drag and Drop 648 bool DragDropActive; 649 ImGuiDragDropFlags DragDropSourceFlags; 650 int DragDropMouseButton; 651 ImGuiPayload DragDropPayload; 652 ImRect DragDropTargetRect; 653 ImGuiID DragDropTargetId; 654 float DragDropAcceptIdCurrRectSurface; 655 ImGuiID DragDropAcceptIdCurr; // Target item id (set at the time of accepting the payload) 656 ImGuiID DragDropAcceptIdPrev; // Target item id from previous frame (we need to store this to allow for overlapping drag and drop targets) 657 int DragDropAcceptFrameCount; // Last time a target expressed a desire to accept the source 658 ImVector<unsigned char> DragDropPayloadBufHeap; // We don't expose the ImVector<> directly 659 unsigned char DragDropPayloadBufLocal[8]; // Local buffer for small payloads 660 661 // Widget state 662 ImGuiTextEditState InputTextState; 663 ImFont InputTextPasswordFont; 664 ImGuiID ScalarAsInputTextId; // Temporary text input when CTRL+clicking on a slider, etc. 665 ImGuiColorEditFlags ColorEditOptions; // Store user options for color edit widgets 666 ImVec4 ColorPickerRef; 667 float DragCurrentValue; // Currently dragged value, always float, not rounded by end-user precision settings 668 ImVec2 DragLastMouseDelta; 669 float DragSpeedDefaultRatio; // If speed == 0.0f, uses (max-min) * DragSpeedDefaultRatio 670 float DragSpeedScaleSlow; 671 float DragSpeedScaleFast; 672 ImVec2 ScrollbarClickDeltaToGrabCenter; // Distance between mouse and center of grab box, normalized in parent space. Use storage? 673 int TooltipOverrideCount; 674 ImVector<char> PrivateClipboard; // If no custom clipboard handler is defined 675 ImVec2 PlatformImePos, PlatformImeLastPos; // Cursor position request & last passed to the OS Input Method Editor 676 677 // Settings 678 bool SettingsLoaded; 679 float SettingsDirtyTimer; // Save .ini Settings on disk when time reaches zero 680 ImVector<ImGuiWindowSettings> SettingsWindows; // .ini settings for ImGuiWindow 681 ImVector<ImGuiSettingsHandler> SettingsHandlers; // List of .ini settings handlers 682 683 // Logging 684 bool LogEnabled; 685 FILE* LogFile; // If != NULL log to stdout/ file 686 ImGuiTextBuffer* LogClipboard; // Else log to clipboard. This is pointer so our GImGui static constructor doesn't call heap allocators. 687 int LogStartDepth; 688 int LogAutoExpandMaxDepth; 689 690 // Misc 691 float FramerateSecPerFrame[120]; // Calculate estimate of framerate for user over the last 2 seconds. 692 int FramerateSecPerFrameIdx; 693 float FramerateSecPerFrameAccum; 694 int WantCaptureMouseNextFrame; // Explicit capture via CaptureKeyboardFromApp()/CaptureMouseFromApp() sets those flags 695 int WantCaptureKeyboardNextFrame; 696 int WantTextInputNextFrame; 697 char TempBuffer[1024 * 3 + 1]; // Temporary text buffer 698 699 ImGuiContext(ImFontAtlas* shared_font_atlas) : OverlayDrawList(NULL) 700 { 701 Initialized = false; 702 Font = NULL; 703 FontSize = FontBaseSize = 0.0f; 704 FontAtlasOwnedByContext = shared_font_atlas ? false : true; 705 IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)(); 706 707 Time = 0.0f; 708 FrameCount = 0; 709 FrameCountEnded = FrameCountRendered = -1; 710 WindowsActiveCount = 0; 711 CurrentWindow = NULL; 712 HoveredWindow = NULL; 713 HoveredRootWindow = NULL; 714 HoveredId = 0; 715 HoveredIdAllowOverlap = false; 716 HoveredIdPreviousFrame = 0; 717 HoveredIdTimer = 0.0f; 718 ActiveId = 0; 719 ActiveIdPreviousFrame = 0; 720 ActiveIdTimer = 0.0f; 721 ActiveIdIsAlive = false; 722 ActiveIdIsJustActivated = false; 723 ActiveIdAllowOverlap = false; 724 ActiveIdAllowNavDirFlags = 0; 725 ActiveIdClickOffset = ImVec2(-1, -1); 726 ActiveIdWindow = NULL; 727 ActiveIdSource = ImGuiInputSource_None; 728 MovingWindow = NULL; 729 NextTreeNodeOpenVal = false; 730 NextTreeNodeOpenCond = 0; 731 732 NavWindow = NULL; 733 NavId = NavActivateId = NavActivateDownId = NavActivatePressedId = NavInputId = 0; 734 NavJustTabbedId = NavJustMovedToId = NavNextActivateId = 0; 735 NavInputSource = ImGuiInputSource_None; 736 NavScoringRectScreen = ImRect(); 737 NavScoringCount = 0; 738 NavWindowingTarget = NULL; 739 NavWindowingHighlightTimer = NavWindowingHighlightAlpha = 0.0f; 740 NavWindowingToggleLayer = false; 741 NavLayer = 0; 742 NavIdTabCounter = INT_MAX; 743 NavIdIsAlive = false; 744 NavMousePosDirty = false; 745 NavDisableHighlight = true; 746 NavDisableMouseHover = false; 747 NavAnyRequest = false; 748 NavInitRequest = false; 749 NavInitRequestFromMove = false; 750 NavInitResultId = 0; 751 NavMoveFromClampedRefRect = false; 752 NavMoveRequest = false; 753 NavMoveRequestForward = ImGuiNavForward_None; 754 NavMoveDir = NavMoveDirLast = ImGuiDir_None; 755 756 ModalWindowDarkeningRatio = 0.0f; 757 OverlayDrawList._Data = &DrawListSharedData; 758 OverlayDrawList._OwnerName = "##Overlay"; // Give it a name for debugging 759 MouseCursor = ImGuiMouseCursor_Arrow; 760 761 DragDropActive = false; 762 DragDropSourceFlags = 0; 763 DragDropMouseButton = -1; 764 DragDropTargetId = 0; 765 DragDropAcceptIdCurrRectSurface = 0.0f; 766 DragDropAcceptIdPrev = DragDropAcceptIdCurr = 0; 767 DragDropAcceptFrameCount = -1; 768 memset(DragDropPayloadBufLocal, 0, sizeof(DragDropPayloadBufLocal)); 769 770 ScalarAsInputTextId = 0; 771 ColorEditOptions = ImGuiColorEditFlags__OptionsDefault; 772 DragCurrentValue = 0.0f; 773 DragLastMouseDelta = ImVec2(0.0f, 0.0f); 774 DragSpeedDefaultRatio = 1.0f / 100.0f; 775 DragSpeedScaleSlow = 1.0f / 100.0f; 776 DragSpeedScaleFast = 10.0f; 777 ScrollbarClickDeltaToGrabCenter = ImVec2(0.0f, 0.0f); 778 TooltipOverrideCount = 0; 779 PlatformImePos = PlatformImeLastPos = ImVec2(FLT_MAX, FLT_MAX); 780 781 SettingsLoaded = false; 782 SettingsDirtyTimer = 0.0f; 783 784 LogEnabled = false; 785 LogFile = NULL; 786 LogClipboard = NULL; 787 LogStartDepth = 0; 788 LogAutoExpandMaxDepth = 2; 789 790 memset(FramerateSecPerFrame, 0, sizeof(FramerateSecPerFrame)); 791 FramerateSecPerFrameIdx = 0; 792 FramerateSecPerFrameAccum = 0.0f; 793 WantCaptureMouseNextFrame = WantCaptureKeyboardNextFrame = WantTextInputNextFrame = -1; 794 memset(TempBuffer, 0, sizeof(TempBuffer)); 795 } 796 }; 565 ImVector<ImDrawList*> Layers[2]; // Global layers for: regular, tooltip 566 567 void Clear() { for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) Layers[n].resize(0); } 568 void ClearFreeMemory() { for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) Layers[n].clear(); } 569 IMGUI_API void FlattenIntoSingleLayer(); 570 }; 571 572 //----------------------------------------------------------------------------- 573 // [SECTION] Widgets support: flags, enums, data structures 574 //----------------------------------------------------------------------------- 797 575 798 576 // Transient per-window flags, reset at the beginning of the frame. For child window, inherited from parent on first Begin(). … … 800 578 enum ImGuiItemFlags_ 801 579 { 802 ImGuiItemFlags_AllowKeyboardFocus = 1 << 0, // true 803 ImGuiItemFlags_ButtonRepeat = 1 << 1, // false // Button() will return true multiple times based on io.KeyRepeatDelay and io.KeyRepeatRate settings. 804 ImGuiItemFlags_Disabled = 1 << 2, // false // FIXME-WIP: Disable interactions but doesn't affect visuals. Should be: grey out and disable interactions with widgets that affect data + view widgets (WIP) 805 ImGuiItemFlags_NoNav = 1 << 3, // false 806 ImGuiItemFlags_NoNavDefaultFocus = 1 << 4, // false 807 ImGuiItemFlags_SelectableDontClosePopup = 1 << 5, // false // MenuItem/Selectable() automatically closes current Popup window 808 ImGuiItemFlags_Default_ = ImGuiItemFlags_AllowKeyboardFocus 809 }; 810 811 // Transient per-window data, reset at the beginning of the frame 812 // FIXME: That's theory, in practice the delimitation between ImGuiWindow and ImGuiDrawContext is quite tenuous and could be reconsidered. 813 struct IMGUI_API ImGuiDrawContext 814 { 815 ImVec2 CursorPos; 816 ImVec2 CursorPosPrevLine; 817 ImVec2 CursorStartPos; 818 ImVec2 CursorMaxPos; // Used to implicitly calculate the size of our contents, always growing during the frame. Turned into window->SizeContents at the beginning of next frame 819 float CurrentLineHeight; 820 float CurrentLineTextBaseOffset; 821 float PrevLineHeight; 822 float PrevLineTextBaseOffset; 823 float LogLinePosY; 824 int TreeDepth; 825 ImU32 TreeDepthMayJumpToParentOnPop; // Store a copy of !g.NavIdIsAlive for TreeDepth 0..31 826 ImGuiID LastItemId; 827 ImGuiItemStatusFlags LastItemStatusFlags; 828 ImRect LastItemRect; // Interaction rect 829 ImRect LastItemDisplayRect; // End-user display rect (only valid if LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect) 830 bool NavHideHighlightOneFrame; 831 bool NavHasScroll; // Set when scrolling can be used (ScrollMax > 0.0f) 832 int NavLayerCurrent; // Current layer, 0..31 (we currently only use 0..1) 833 int NavLayerCurrentMask; // = (1 << NavLayerCurrent) used by ItemAdd prior to clipping. 834 int NavLayerActiveMask; // Which layer have been written to (result from previous frame) 835 int NavLayerActiveMaskNext; // Which layer have been written to (buffer for current frame) 836 bool MenuBarAppending; // FIXME: Remove this 837 ImVec2 MenuBarOffset; // MenuBarOffset.x is sort of equivalent of a per-layer CursorPos.x, saved/restored as we switch to the menu bar. The only situation when MenuBarOffset.y is > 0 if when (SafeAreaPadding.y > FramePadding.y), often used on TVs. 838 ImVector<ImGuiWindow*> ChildWindows; 839 ImGuiStorage* StateStorage; 840 ImGuiLayoutType LayoutType; 841 ImGuiLayoutType ParentLayoutType; // Layout type of parent window at the time of Begin() 842 843 // We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings. 844 ImGuiItemFlags ItemFlags; // == ItemFlagsStack.back() [empty == ImGuiItemFlags_Default] 845 float ItemWidth; // == ItemWidthStack.back(). 0.0: default, >0.0: width in pixels, <0.0: align xx pixels to the right of window 846 float TextWrapPos; // == TextWrapPosStack.back() [empty == -1.0f] 847 ImVector<ImGuiItemFlags>ItemFlagsStack; 848 ImVector<float> ItemWidthStack; 849 ImVector<float> TextWrapPosStack; 850 ImVector<ImGuiGroupData>GroupStack; 851 int StackSizesBackup[6]; // Store size of various stacks for asserting 852 853 float IndentX; // Indentation / start position from left of window (increased by TreePush/TreePop, etc.) 854 float GroupOffsetX; 855 float ColumnsOffsetX; // Offset to the current column (if ColumnsCurrent > 0). FIXME: This and the above should be a stack to allow use cases like Tree->Column->Tree. Need revamp columns API. 856 ImGuiColumnsSet* ColumnsSet; // Current columns set 857 858 ImGuiDrawContext() 859 { 860 CursorPos = CursorPosPrevLine = CursorStartPos = CursorMaxPos = ImVec2(0.0f, 0.0f); 861 CurrentLineHeight = PrevLineHeight = 0.0f; 862 CurrentLineTextBaseOffset = PrevLineTextBaseOffset = 0.0f; 863 LogLinePosY = -1.0f; 864 TreeDepth = 0; 865 TreeDepthMayJumpToParentOnPop = 0x00; 866 LastItemId = 0; 867 LastItemStatusFlags = 0; 868 LastItemRect = LastItemDisplayRect = ImRect(); 869 NavHideHighlightOneFrame = false; 870 NavHasScroll = false; 871 NavLayerActiveMask = NavLayerActiveMaskNext = 0x00; 872 NavLayerCurrent = 0; 873 NavLayerCurrentMask = 1 << 0; 874 MenuBarAppending = false; 875 MenuBarOffset = ImVec2(0.0f, 0.0f); 876 StateStorage = NULL; 877 LayoutType = ParentLayoutType = ImGuiLayoutType_Vertical; 878 ItemWidth = 0.0f; 879 ItemFlags = ImGuiItemFlags_Default_; 880 TextWrapPos = -1.0f; 881 memset(StackSizesBackup, 0, sizeof(StackSizesBackup)); 882 883 IndentX = 0.0f; 884 GroupOffsetX = 0.0f; 885 ColumnsOffsetX = 0.0f; 886 ColumnsSet = NULL; 887 } 888 }; 889 890 // Windows data 580 ImGuiItemFlags_None = 0, 581 ImGuiItemFlags_NoTabStop = 1 << 0, // false 582 ImGuiItemFlags_ButtonRepeat = 1 << 1, // false // Button() will return true multiple times based on io.KeyRepeatDelay and io.KeyRepeatRate settings. 583 ImGuiItemFlags_Disabled = 1 << 2, // false // [BETA] Disable interactions but doesn't affect visuals yet. See github.com/ocornut/imgui/issues/211 584 ImGuiItemFlags_NoNav = 1 << 3, // false 585 ImGuiItemFlags_NoNavDefaultFocus = 1 << 4, // false 586 ImGuiItemFlags_SelectableDontClosePopup = 1 << 5, // false // MenuItem/Selectable() automatically closes current Popup window 587 ImGuiItemFlags_MixedValue = 1 << 6, // false // [BETA] Represent a mixed/indeterminate value, generally multi-selection where values differ. Currently only supported by Checkbox() (later should support all sorts of widgets) 588 ImGuiItemFlags_ReadOnly = 1 << 7, // false // [ALPHA] Allow hovering interactions but underlying value is not changed. 589 ImGuiItemFlags_Default_ = 0 590 }; 591 592 // Storage for LastItem data 593 enum ImGuiItemStatusFlags_ 594 { 595 ImGuiItemStatusFlags_None = 0, 596 ImGuiItemStatusFlags_HoveredRect = 1 << 0, 597 ImGuiItemStatusFlags_HasDisplayRect = 1 << 1, 598 ImGuiItemStatusFlags_Edited = 1 << 2, // Value exposed by item was edited in the current frame (should match the bool return value of most widgets) 599 ImGuiItemStatusFlags_ToggledSelection = 1 << 3, // Set when Selectable(), TreeNode() reports toggling a selection. We can't report "Selected" because reporting the change allows us to handle clipping with less issues. 600 ImGuiItemStatusFlags_ToggledOpen = 1 << 4, // Set when TreeNode() reports toggling their open state. 601 ImGuiItemStatusFlags_HasDeactivated = 1 << 5, // Set if the widget/group is able to provide data for the ImGuiItemStatusFlags_Deactivated flag. 602 ImGuiItemStatusFlags_Deactivated = 1 << 6 // Only valid if ImGuiItemStatusFlags_HasDeactivated is set. 603 604 #ifdef IMGUI_ENABLE_TEST_ENGINE 605 , // [imgui_tests only] 606 ImGuiItemStatusFlags_Openable = 1 << 10, // 607 ImGuiItemStatusFlags_Opened = 1 << 11, // 608 ImGuiItemStatusFlags_Checkable = 1 << 12, // 609 ImGuiItemStatusFlags_Checked = 1 << 13 // 610 #endif 611 }; 612 613 // Extend ImGuiButtonFlags_ 614 enum ImGuiButtonFlagsPrivate_ 615 { 616 ImGuiButtonFlags_PressedOnClick = 1 << 4, // return true on click (mouse down event) 617 ImGuiButtonFlags_PressedOnClickRelease = 1 << 5, // [Default] return true on click + release on same item <-- this is what the majority of Button are using 618 ImGuiButtonFlags_PressedOnClickReleaseAnywhere = 1 << 6, // return true on click + release even if the release event is not done while hovering the item 619 ImGuiButtonFlags_PressedOnRelease = 1 << 7, // return true on release (default requires click+release) 620 ImGuiButtonFlags_PressedOnDoubleClick = 1 << 8, // return true on double-click (default requires click+release) 621 ImGuiButtonFlags_PressedOnDragDropHold = 1 << 9, // return true when held into while we are drag and dropping another item (used by e.g. tree nodes, collapsing headers) 622 ImGuiButtonFlags_Repeat = 1 << 10, // hold to repeat 623 ImGuiButtonFlags_FlattenChildren = 1 << 11, // allow interactions even if a child window is overlapping 624 ImGuiButtonFlags_AllowItemOverlap = 1 << 12, // require previous frame HoveredId to either match id or be null before being usable, use along with SetItemAllowOverlap() 625 ImGuiButtonFlags_DontClosePopups = 1 << 13, // disable automatically closing parent popup on press // [UNUSED] 626 ImGuiButtonFlags_Disabled = 1 << 14, // disable interactions 627 ImGuiButtonFlags_AlignTextBaseLine = 1 << 15, // vertically align button to match text baseline - ButtonEx() only // FIXME: Should be removed and handled by SmallButton(), not possible currently because of DC.CursorPosPrevLine 628 ImGuiButtonFlags_NoKeyModifiers = 1 << 16, // disable mouse interaction if a key modifier is held 629 ImGuiButtonFlags_NoHoldingActiveId = 1 << 17, // don't set ActiveId while holding the mouse (ImGuiButtonFlags_PressedOnClick only) 630 ImGuiButtonFlags_NoNavFocus = 1 << 18, // don't override navigation focus when activated 631 ImGuiButtonFlags_NoHoveredOnFocus = 1 << 19, // don't report as hovered when nav focus is on this item 632 ImGuiButtonFlags_PressedOnMask_ = ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnClickReleaseAnywhere | ImGuiButtonFlags_PressedOnRelease | ImGuiButtonFlags_PressedOnDoubleClick | ImGuiButtonFlags_PressedOnDragDropHold, 633 ImGuiButtonFlags_PressedOnDefault_ = ImGuiButtonFlags_PressedOnClickRelease 634 }; 635 636 // Extend ImGuiSliderFlags_ 637 enum ImGuiSliderFlagsPrivate_ 638 { 639 ImGuiSliderFlags_Vertical = 1 << 20, // Should this slider be orientated vertically? 640 ImGuiSliderFlags_ReadOnly = 1 << 21 641 }; 642 643 // Extend ImGuiSelectableFlags_ 644 enum ImGuiSelectableFlagsPrivate_ 645 { 646 // NB: need to be in sync with last value of ImGuiSelectableFlags_ 647 ImGuiSelectableFlags_NoHoldingActiveID = 1 << 20, 648 ImGuiSelectableFlags_SelectOnClick = 1 << 21, // Override button behavior to react on Click (default is Click+Release) 649 ImGuiSelectableFlags_SelectOnRelease = 1 << 22, // Override button behavior to react on Release (default is Click+Release) 650 ImGuiSelectableFlags_SpanAvailWidth = 1 << 23, // Span all avail width even if we declared less for layout purpose. FIXME: We may be able to remove this (added in 6251d379, 2bcafc86 for menus) 651 ImGuiSelectableFlags_DrawHoveredWhenHeld = 1 << 24, // Always show active when held, even is not hovered. This concept could probably be renamed/formalized somehow. 652 ImGuiSelectableFlags_SetNavIdOnHover = 1 << 25, // Set Nav/Focus ID on mouse hover (used by MenuItem) 653 ImGuiSelectableFlags_NoPadWithHalfSpacing = 1 << 26 // Disable padding each side with ItemSpacing * 0.5f 654 }; 655 656 // Extend ImGuiTreeNodeFlags_ 657 enum ImGuiTreeNodeFlagsPrivate_ 658 { 659 ImGuiTreeNodeFlags_ClipLabelForTrailingButton = 1 << 20 660 }; 661 662 enum ImGuiSeparatorFlags_ 663 { 664 ImGuiSeparatorFlags_None = 0, 665 ImGuiSeparatorFlags_Horizontal = 1 << 0, // Axis default to current layout type, so generally Horizontal unless e.g. in a menu bar 666 ImGuiSeparatorFlags_Vertical = 1 << 1, 667 ImGuiSeparatorFlags_SpanAllColumns = 1 << 2 668 }; 669 670 enum ImGuiTextFlags_ 671 { 672 ImGuiTextFlags_None = 0, 673 ImGuiTextFlags_NoWidthForLargeClippedText = 1 << 0 674 }; 675 676 enum ImGuiTooltipFlags_ 677 { 678 ImGuiTooltipFlags_None = 0, 679 ImGuiTooltipFlags_OverridePreviousTooltip = 1 << 0 // Override will clear/ignore previously submitted tooltip (defaults to append) 680 }; 681 682 // FIXME: this is in development, not exposed/functional as a generic feature yet. 683 // Horizontal/Vertical enums are fixed to 0/1 so they may be used to index ImVec2 684 enum ImGuiLayoutType_ 685 { 686 ImGuiLayoutType_Horizontal = 0, 687 ImGuiLayoutType_Vertical = 1 688 }; 689 690 enum ImGuiLogType 691 { 692 ImGuiLogType_None = 0, 693 ImGuiLogType_TTY, 694 ImGuiLogType_File, 695 ImGuiLogType_Buffer, 696 ImGuiLogType_Clipboard 697 }; 698 699 // X/Y enums are fixed to 0/1 so they may be used to index ImVec2 700 enum ImGuiAxis 701 { 702 ImGuiAxis_None = -1, 703 ImGuiAxis_X = 0, 704 ImGuiAxis_Y = 1 705 }; 706 707 enum ImGuiPlotType 708 { 709 ImGuiPlotType_Lines, 710 ImGuiPlotType_Histogram 711 }; 712 713 enum ImGuiInputSource 714 { 715 ImGuiInputSource_None = 0, 716 ImGuiInputSource_Mouse, 717 ImGuiInputSource_Nav, 718 ImGuiInputSource_NavKeyboard, // Only used occasionally for storage, not tested/handled by most code 719 ImGuiInputSource_NavGamepad, // " 720 ImGuiInputSource_COUNT 721 }; 722 723 // FIXME-NAV: Clarify/expose various repeat delay/rate 724 enum ImGuiInputReadMode 725 { 726 ImGuiInputReadMode_Down, 727 ImGuiInputReadMode_Pressed, 728 ImGuiInputReadMode_Released, 729 ImGuiInputReadMode_Repeat, 730 ImGuiInputReadMode_RepeatSlow, 731 ImGuiInputReadMode_RepeatFast 732 }; 733 734 enum ImGuiNavHighlightFlags_ 735 { 736 ImGuiNavHighlightFlags_None = 0, 737 ImGuiNavHighlightFlags_TypeDefault = 1 << 0, 738 ImGuiNavHighlightFlags_TypeThin = 1 << 1, 739 ImGuiNavHighlightFlags_AlwaysDraw = 1 << 2, // Draw rectangular highlight if (g.NavId == id) _even_ when using the mouse. 740 ImGuiNavHighlightFlags_NoRounding = 1 << 3 741 }; 742 743 enum ImGuiNavDirSourceFlags_ 744 { 745 ImGuiNavDirSourceFlags_None = 0, 746 ImGuiNavDirSourceFlags_Keyboard = 1 << 0, 747 ImGuiNavDirSourceFlags_PadDPad = 1 << 1, 748 ImGuiNavDirSourceFlags_PadLStick = 1 << 2 749 }; 750 751 enum ImGuiNavMoveFlags_ 752 { 753 ImGuiNavMoveFlags_None = 0, 754 ImGuiNavMoveFlags_LoopX = 1 << 0, // On failed request, restart from opposite side 755 ImGuiNavMoveFlags_LoopY = 1 << 1, 756 ImGuiNavMoveFlags_WrapX = 1 << 2, // On failed request, request from opposite side one line down (when NavDir==right) or one line up (when NavDir==left) 757 ImGuiNavMoveFlags_WrapY = 1 << 3, // This is not super useful for provided for completeness 758 ImGuiNavMoveFlags_AllowCurrentNavId = 1 << 4, // Allow scoring and considering the current NavId as a move target candidate. This is used when the move source is offset (e.g. pressing PageDown actually needs to send a Up move request, if we are pressing PageDown from the bottom-most item we need to stay in place) 759 ImGuiNavMoveFlags_AlsoScoreVisibleSet = 1 << 5, // Store alternate result in NavMoveResultLocalVisibleSet that only comprise elements that are already fully visible. 760 ImGuiNavMoveFlags_ScrollToEdge = 1 << 6 761 }; 762 763 enum ImGuiNavForward 764 { 765 ImGuiNavForward_None, 766 ImGuiNavForward_ForwardQueued, 767 ImGuiNavForward_ForwardActive 768 }; 769 770 enum ImGuiNavLayer 771 { 772 ImGuiNavLayer_Main = 0, // Main scrolling layer 773 ImGuiNavLayer_Menu = 1, // Menu layer (access with Alt/ImGuiNavInput_Menu) 774 ImGuiNavLayer_COUNT 775 }; 776 777 enum ImGuiPopupPositionPolicy 778 { 779 ImGuiPopupPositionPolicy_Default, 780 ImGuiPopupPositionPolicy_ComboBox, 781 ImGuiPopupPositionPolicy_Tooltip 782 }; 783 784 struct ImGuiDataTypeTempStorage 785 { 786 ImU8 Data[8]; // Can fit any data up to ImGuiDataType_COUNT 787 }; 788 789 // Type information associated to one ImGuiDataType. Retrieve with DataTypeGetInfo(). 790 struct ImGuiDataTypeInfo 791 { 792 size_t Size; // Size in bytes 793 const char* Name; // Short descriptive name for the type, for debugging 794 const char* PrintFmt; // Default printf format for the type 795 const char* ScanFmt; // Default scanf format for the type 796 }; 797 798 // Extend ImGuiDataType_ 799 enum ImGuiDataTypePrivate_ 800 { 801 ImGuiDataType_String = ImGuiDataType_COUNT + 1, 802 ImGuiDataType_Pointer, 803 ImGuiDataType_ID 804 }; 805 806 // Stacked color modifier, backup of modified data so we can restore it 807 struct ImGuiColorMod 808 { 809 ImGuiCol Col; 810 ImVec4 BackupValue; 811 }; 812 813 // Stacked style modifier, backup of modified data so we can restore it. Data type inferred from the variable. 814 struct ImGuiStyleMod 815 { 816 ImGuiStyleVar VarIdx; 817 union { int BackupInt[2]; float BackupFloat[2]; }; 818 ImGuiStyleMod(ImGuiStyleVar idx, int v) { VarIdx = idx; BackupInt[0] = v; } 819 ImGuiStyleMod(ImGuiStyleVar idx, float v) { VarIdx = idx; BackupFloat[0] = v; } 820 ImGuiStyleMod(ImGuiStyleVar idx, ImVec2 v) { VarIdx = idx; BackupFloat[0] = v.x; BackupFloat[1] = v.y; } 821 }; 822 823 // Stacked storage data for BeginGroup()/EndGroup() 824 struct ImGuiGroupData 825 { 826 ImVec2 BackupCursorPos; 827 ImVec2 BackupCursorMaxPos; 828 ImVec1 BackupIndent; 829 ImVec1 BackupGroupOffset; 830 ImVec2 BackupCurrLineSize; 831 float BackupCurrLineTextBaseOffset; 832 ImGuiID BackupActiveIdIsAlive; 833 bool BackupActiveIdPreviousFrameIsAlive; 834 bool EmitItem; 835 }; 836 837 // Simple column measurement, currently used for MenuItem() only.. This is very short-sighted/throw-away code and NOT a generic helper. 838 struct IMGUI_API ImGuiMenuColumns 839 { 840 float Spacing; 841 float Width, NextWidth; 842 float Pos[3], NextWidths[3]; 843 844 ImGuiMenuColumns(); 845 void Update(int count, float spacing, bool clear); 846 float DeclColumns(float w0, float w1, float w2); 847 float CalcExtraSpace(float avail_w) const; 848 }; 849 850 // Internal state of the currently focused/edited text input box 851 // For a given item ID, access with ImGui::GetInputTextState() 852 struct IMGUI_API ImGuiInputTextState 853 { 854 ImGuiID ID; // widget id owning the text state 855 int CurLenW, CurLenA; // we need to maintain our buffer length in both UTF-8 and wchar format. UTF-8 length is valid even if TextA is not. 856 ImVector<ImWchar> TextW; // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so we copy into own buffer. 857 ImVector<char> TextA; // temporary UTF8 buffer for callbacks and other operations. this is not updated in every code-path! size=capacity. 858 ImVector<char> InitialTextA; // backup of end-user buffer at the time of focus (in UTF-8, unaltered) 859 bool TextAIsValid; // temporary UTF8 buffer is not initially valid before we make the widget active (until then we pull the data from user argument) 860 int BufCapacityA; // end-user buffer capacity 861 float ScrollX; // horizontal scrolling/offset 862 ImStb::STB_TexteditState Stb; // state for stb_textedit.h 863 float CursorAnim; // timer for cursor blink, reset on every user action so the cursor reappears immediately 864 bool CursorFollow; // set when we want scrolling to follow the current cursor position (not always!) 865 bool SelectedAllMouseLock; // after a double-click to select all, we ignore further mouse drags to update selection 866 bool Edited; // edited this frame 867 ImGuiInputTextFlags UserFlags; // Temporarily set while we call user's callback 868 ImGuiInputTextCallback UserCallback; // " 869 void* UserCallbackData; // " 870 871 ImGuiInputTextState() { memset(this, 0, sizeof(*this)); } 872 void ClearText() { CurLenW = CurLenA = 0; TextW[0] = 0; TextA[0] = 0; CursorClamp(); } 873 void ClearFreeMemory() { TextW.clear(); TextA.clear(); InitialTextA.clear(); } 874 int GetUndoAvailCount() const { return Stb.undostate.undo_point; } 875 int GetRedoAvailCount() const { return STB_TEXTEDIT_UNDOSTATECOUNT - Stb.undostate.redo_point; } 876 void OnKeyPressed(int key); // Cannot be inline because we call in code in stb_textedit.h implementation 877 878 // Cursor & Selection 879 void CursorAnimReset() { CursorAnim = -0.30f; } // After a user-input the cursor stays on for a while without blinking 880 void CursorClamp() { Stb.cursor = ImMin(Stb.cursor, CurLenW); Stb.select_start = ImMin(Stb.select_start, CurLenW); Stb.select_end = ImMin(Stb.select_end, CurLenW); } 881 bool HasSelection() const { return Stb.select_start != Stb.select_end; } 882 void ClearSelection() { Stb.select_start = Stb.select_end = Stb.cursor; } 883 void SelectAll() { Stb.select_start = 0; Stb.cursor = Stb.select_end = CurLenW; Stb.has_preferred_x = 0; } 884 }; 885 886 // Storage for current popup stack 887 struct ImGuiPopupData 888 { 889 ImGuiID PopupId; // Set on OpenPopup() 890 ImGuiWindow* Window; // Resolved on BeginPopup() - may stay unresolved if user never calls OpenPopup() 891 ImGuiWindow* SourceWindow; // Set on OpenPopup() copy of NavWindow at the time of opening the popup 892 int OpenFrameCount; // Set on OpenPopup() 893 ImGuiID OpenParentId; // Set on OpenPopup(), we need this to differentiate multiple menu sets from each others (e.g. inside menu bar vs loose menu items) 894 ImVec2 OpenPopupPos; // Set on OpenPopup(), preferred popup position (typically == OpenMousePos when using mouse) 895 ImVec2 OpenMousePos; // Set on OpenPopup(), copy of mouse position at the time of opening popup 896 897 ImGuiPopupData() { PopupId = 0; Window = SourceWindow = NULL; OpenFrameCount = -1; OpenParentId = 0; } 898 }; 899 900 struct ImGuiNavMoveResult 901 { 902 ImGuiWindow* Window; // Best candidate window 903 ImGuiID ID; // Best candidate ID 904 ImGuiID FocusScopeId; // Best candidate focus scope ID 905 float DistBox; // Best candidate box distance to current NavId 906 float DistCenter; // Best candidate center distance to current NavId 907 float DistAxial; 908 ImRect RectRel; // Best candidate bounding box in window relative space 909 910 ImGuiNavMoveResult() { Clear(); } 911 void Clear() { Window = NULL; ID = FocusScopeId = 0; DistBox = DistCenter = DistAxial = FLT_MAX; RectRel = ImRect(); } 912 }; 913 914 enum ImGuiNextWindowDataFlags_ 915 { 916 ImGuiNextWindowDataFlags_None = 0, 917 ImGuiNextWindowDataFlags_HasPos = 1 << 0, 918 ImGuiNextWindowDataFlags_HasSize = 1 << 1, 919 ImGuiNextWindowDataFlags_HasContentSize = 1 << 2, 920 ImGuiNextWindowDataFlags_HasCollapsed = 1 << 3, 921 ImGuiNextWindowDataFlags_HasSizeConstraint = 1 << 4, 922 ImGuiNextWindowDataFlags_HasFocus = 1 << 5, 923 ImGuiNextWindowDataFlags_HasBgAlpha = 1 << 6, 924 ImGuiNextWindowDataFlags_HasScroll = 1 << 7 925 }; 926 927 // Storage for SetNexWindow** functions 928 struct ImGuiNextWindowData 929 { 930 ImGuiNextWindowDataFlags Flags; 931 ImGuiCond PosCond; 932 ImGuiCond SizeCond; 933 ImGuiCond CollapsedCond; 934 ImVec2 PosVal; 935 ImVec2 PosPivotVal; 936 ImVec2 SizeVal; 937 ImVec2 ContentSizeVal; 938 ImVec2 ScrollVal; 939 bool CollapsedVal; 940 ImRect SizeConstraintRect; 941 ImGuiSizeCallback SizeCallback; 942 void* SizeCallbackUserData; 943 float BgAlphaVal; // Override background alpha 944 ImVec2 MenuBarOffsetMinVal; // *Always on* This is not exposed publicly, so we don't clear it. 945 946 ImGuiNextWindowData() { memset(this, 0, sizeof(*this)); } 947 inline void ClearFlags() { Flags = ImGuiNextWindowDataFlags_None; } 948 }; 949 950 enum ImGuiNextItemDataFlags_ 951 { 952 ImGuiNextItemDataFlags_None = 0, 953 ImGuiNextItemDataFlags_HasWidth = 1 << 0, 954 ImGuiNextItemDataFlags_HasOpen = 1 << 1 955 }; 956 957 struct ImGuiNextItemData 958 { 959 ImGuiNextItemDataFlags Flags; 960 float Width; // Set by SetNextItemWidth() 961 ImGuiID FocusScopeId; // Set by SetNextItemMultiSelectData() (!= 0 signify value has been set, so it's an alternate version of HasSelectionData, we don't use Flags for this because they are cleared too early. This is mostly used for debugging) 962 ImGuiCond OpenCond; 963 bool OpenVal; // Set by SetNextItemOpen() 964 965 ImGuiNextItemData() { memset(this, 0, sizeof(*this)); } 966 inline void ClearFlags() { Flags = ImGuiNextItemDataFlags_None; } // Also cleared manually by ItemAdd()! 967 }; 968 969 struct ImGuiShrinkWidthItem 970 { 971 int Index; 972 float Width; 973 }; 974 975 struct ImGuiPtrOrIndex 976 { 977 void* Ptr; // Either field can be set, not both. e.g. Dock node tab bars are loose while BeginTabBar() ones are in a pool. 978 int Index; // Usually index in a main pool. 979 980 ImGuiPtrOrIndex(void* ptr) { Ptr = ptr; Index = -1; } 981 ImGuiPtrOrIndex(int index) { Ptr = NULL; Index = index; } 982 }; 983 984 //----------------------------------------------------------------------------- 985 // [SECTION] Columns support 986 //----------------------------------------------------------------------------- 987 988 enum ImGuiColumnsFlags_ 989 { 990 // Default: 0 991 ImGuiColumnsFlags_None = 0, 992 ImGuiColumnsFlags_NoBorder = 1 << 0, // Disable column dividers 993 ImGuiColumnsFlags_NoResize = 1 << 1, // Disable resizing columns when clicking on the dividers 994 ImGuiColumnsFlags_NoPreserveWidths = 1 << 2, // Disable column width preservation when adjusting columns 995 ImGuiColumnsFlags_NoForceWithinWindow = 1 << 3, // Disable forcing columns to fit within window 996 ImGuiColumnsFlags_GrowParentContentsSize= 1 << 4 // (WIP) Restore pre-1.51 behavior of extending the parent window contents size but _without affecting the columns width at all_. Will eventually remove. 997 }; 998 999 struct ImGuiColumnData 1000 { 1001 float OffsetNorm; // Column start offset, normalized 0.0 (far left) -> 1.0 (far right) 1002 float OffsetNormBeforeResize; 1003 ImGuiColumnsFlags Flags; // Not exposed 1004 ImRect ClipRect; 1005 1006 ImGuiColumnData() { OffsetNorm = OffsetNormBeforeResize = 0.0f; Flags = ImGuiColumnsFlags_None; } 1007 }; 1008 1009 struct ImGuiColumns 1010 { 1011 ImGuiID ID; 1012 ImGuiColumnsFlags Flags; 1013 bool IsFirstFrame; 1014 bool IsBeingResized; 1015 int Current; 1016 int Count; 1017 float OffMinX, OffMaxX; // Offsets from HostWorkRect.Min.x 1018 float LineMinY, LineMaxY; 1019 float HostCursorPosY; // Backup of CursorPos at the time of BeginColumns() 1020 float HostCursorMaxPosX; // Backup of CursorMaxPos at the time of BeginColumns() 1021 ImRect HostInitialClipRect; // Backup of ClipRect at the time of BeginColumns() 1022 ImRect HostBackupClipRect; // Backup of ClipRect during PushColumnsBackground()/PopColumnsBackground() 1023 ImRect HostBackupParentWorkRect;//Backup of WorkRect at the time of BeginColumns() 1024 ImVector<ImGuiColumnData> Columns; 1025 ImDrawListSplitter Splitter; 1026 1027 ImGuiColumns() { Clear(); } 1028 void Clear() 1029 { 1030 ID = 0; 1031 Flags = ImGuiColumnsFlags_None; 1032 IsFirstFrame = false; 1033 IsBeingResized = false; 1034 Current = 0; 1035 Count = 1; 1036 OffMinX = OffMaxX = 0.0f; 1037 LineMinY = LineMaxY = 0.0f; 1038 HostCursorPosY = 0.0f; 1039 HostCursorMaxPosX = 0.0f; 1040 Columns.clear(); 1041 } 1042 }; 1043 1044 //----------------------------------------------------------------------------- 1045 // [SECTION] Multi-select support 1046 //----------------------------------------------------------------------------- 1047 1048 #ifdef IMGUI_HAS_MULTI_SELECT 1049 // <this is filled in 'range_select' branch> 1050 #endif // #ifdef IMGUI_HAS_MULTI_SELECT 1051 1052 //----------------------------------------------------------------------------- 1053 // [SECTION] Docking support 1054 //----------------------------------------------------------------------------- 1055 1056 #ifdef IMGUI_HAS_DOCK 1057 // <this is filled in 'docking' branch> 1058 #endif // #ifdef IMGUI_HAS_DOCK 1059 1060 //----------------------------------------------------------------------------- 1061 // [SECTION] Viewport support 1062 //----------------------------------------------------------------------------- 1063 1064 #ifdef IMGUI_HAS_VIEWPORT 1065 // <this is filled in 'docking' branch> 1066 #endif // #ifdef IMGUI_HAS_VIEWPORT 1067 1068 //----------------------------------------------------------------------------- 1069 // [SECTION] Settings support 1070 //----------------------------------------------------------------------------- 1071 1072 // Windows data saved in imgui.ini file 1073 // Because we never destroy or rename ImGuiWindowSettings, we can store the names in a separate buffer easily. 1074 // (this is designed to be stored in a ImChunkStream buffer, with the variable-length Name following our structure) 1075 struct ImGuiWindowSettings 1076 { 1077 ImGuiID ID; 1078 ImVec2ih Pos; 1079 ImVec2ih Size; 1080 bool Collapsed; 1081 bool WantApply; // Set when loaded from .ini data (to enable merging/loading .ini data into an already running context) 1082 1083 ImGuiWindowSettings() { ID = 0; Pos = Size = ImVec2ih(0, 0); Collapsed = WantApply = false; } 1084 char* GetName() { return (char*)(this + 1); } 1085 }; 1086 1087 struct ImGuiSettingsHandler 1088 { 1089 const char* TypeName; // Short description stored in .ini file. Disallowed characters: '[' ']' 1090 ImGuiID TypeHash; // == ImHashStr(TypeName) 1091 void (*ClearAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler); // Clear all settings data 1092 void (*ReadInitFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler); // Read: Called before reading (in registration order) 1093 void* (*ReadOpenFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, const char* name); // Read: Called when entering into a new ini entry e.g. "[Window][Name]" 1094 void (*ReadLineFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line); // Read: Called for every line of text within an ini entry 1095 void (*ApplyAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler); // Read: Called after reading (in registration order) 1096 void (*WriteAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* out_buf); // Write: Output every entries into 'out_buf' 1097 void* UserData; 1098 1099 ImGuiSettingsHandler() { memset(this, 0, sizeof(*this)); } 1100 }; 1101 1102 //----------------------------------------------------------------------------- 1103 // [SECTION] ImGuiContext (main imgui context) 1104 //----------------------------------------------------------------------------- 1105 1106 struct ImGuiContext 1107 { 1108 bool Initialized; 1109 bool FontAtlasOwnedByContext; // IO.Fonts-> is owned by the ImGuiContext and will be destructed along with it. 1110 ImGuiIO IO; 1111 ImGuiStyle Style; 1112 ImFont* Font; // (Shortcut) == FontStack.empty() ? IO.Font : FontStack.back() 1113 float FontSize; // (Shortcut) == FontBaseSize * g.CurrentWindow->FontWindowScale == window->FontSize(). Text height for current window. 1114 float FontBaseSize; // (Shortcut) == IO.FontGlobalScale * Font->Scale * Font->FontSize. Base text height. 1115 ImDrawListSharedData DrawListSharedData; 1116 double Time; 1117 int FrameCount; 1118 int FrameCountEnded; 1119 int FrameCountRendered; 1120 bool WithinFrameScope; // Set by NewFrame(), cleared by EndFrame() 1121 bool WithinFrameScopeWithImplicitWindow; // Set by NewFrame(), cleared by EndFrame() when the implicit debug window has been pushed 1122 bool WithinEndChild; // Set within EndChild() 1123 bool TestEngineHookItems; // Will call test engine hooks: ImGuiTestEngineHook_ItemAdd(), ImGuiTestEngineHook_ItemInfo(), ImGuiTestEngineHook_Log() 1124 ImGuiID TestEngineHookIdInfo; // Will call test engine hooks: ImGuiTestEngineHook_IdInfo() from GetID() 1125 void* TestEngine; // Test engine user data 1126 1127 // Windows state 1128 ImVector<ImGuiWindow*> Windows; // Windows, sorted in display order, back to front 1129 ImVector<ImGuiWindow*> WindowsFocusOrder; // Windows, sorted in focus order, back to front. (FIXME: We could only store root windows here! Need to sort out the Docking equivalent which is RootWindowDockStop and is unfortunately a little more dynamic) 1130 ImVector<ImGuiWindow*> WindowsTempSortBuffer; // Temporary buffer used in EndFrame() to reorder windows so parents are kept before their child 1131 ImVector<ImGuiWindow*> CurrentWindowStack; 1132 ImGuiStorage WindowsById; // Map window's ImGuiID to ImGuiWindow* 1133 int WindowsActiveCount; // Number of unique windows submitted by frame 1134 ImGuiWindow* CurrentWindow; // Window being drawn into 1135 ImGuiWindow* HoveredWindow; // Window the mouse is hovering. Will typically catch mouse inputs. 1136 ImGuiWindow* HoveredRootWindow; // == HoveredWindow ? HoveredWindow->RootWindow : NULL, merely a shortcut to avoid null test in some situation. 1137 ImGuiWindow* HoveredWindowUnderMovingWindow; // Hovered window ignoring MovingWindow. Only set if MovingWindow is set. 1138 ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actual window that is moved is generally MovingWindow->RootWindow. 1139 ImGuiWindow* WheelingWindow; // Track the window we started mouse-wheeling on. Until a timer elapse or mouse has moved, generally keep scrolling the same window even if during the course of scrolling the mouse ends up hovering a child window. 1140 ImVec2 WheelingWindowRefMousePos; 1141 float WheelingWindowTimer; 1142 1143 // Item/widgets state and tracking information 1144 ImGuiID HoveredId; // Hovered widget 1145 ImGuiID HoveredIdPreviousFrame; 1146 bool HoveredIdAllowOverlap; 1147 bool HoveredIdDisabled; // At least one widget passed the rect test, but has been discarded by disabled flag or popup inhibit. May be true even if HoveredId == 0. 1148 float HoveredIdTimer; // Measure contiguous hovering time 1149 float HoveredIdNotActiveTimer; // Measure contiguous hovering time where the item has not been active 1150 ImGuiID ActiveId; // Active widget 1151 ImGuiID ActiveIdIsAlive; // Active widget has been seen this frame (we can't use a bool as the ActiveId may change within the frame) 1152 float ActiveIdTimer; 1153 bool ActiveIdIsJustActivated; // Set at the time of activation for one frame 1154 bool ActiveIdAllowOverlap; // Active widget allows another widget to steal active id (generally for overlapping widgets, but not always) 1155 bool ActiveIdNoClearOnFocusLoss; // Disable losing active id if the active id window gets unfocused. 1156 bool ActiveIdHasBeenPressedBefore; // Track whether the active id led to a press (this is to allow changing between PressOnClick and PressOnRelease without pressing twice). Used by range_select branch. 1157 bool ActiveIdHasBeenEditedBefore; // Was the value associated to the widget Edited over the course of the Active state. 1158 bool ActiveIdHasBeenEditedThisFrame; 1159 ImU32 ActiveIdUsingNavDirMask; // Active widget will want to read those nav move requests (e.g. can activate a button and move away from it) 1160 ImU32 ActiveIdUsingNavInputMask; // Active widget will want to read those nav inputs. 1161 ImU64 ActiveIdUsingKeyInputMask; // Active widget will want to read those key inputs. When we grow the ImGuiKey enum we'll need to either to order the enum to make useful keys come first, either redesign this into e.g. a small array. 1162 ImVec2 ActiveIdClickOffset; // Clicked offset from upper-left corner, if applicable (currently only set by ButtonBehavior) 1163 ImGuiWindow* ActiveIdWindow; 1164 ImGuiInputSource ActiveIdSource; // Activating with mouse or nav (gamepad/keyboard) 1165 int ActiveIdMouseButton; 1166 ImGuiID ActiveIdPreviousFrame; 1167 bool ActiveIdPreviousFrameIsAlive; 1168 bool ActiveIdPreviousFrameHasBeenEditedBefore; 1169 ImGuiWindow* ActiveIdPreviousFrameWindow; 1170 ImGuiID LastActiveId; // Store the last non-zero ActiveId, useful for animation. 1171 float LastActiveIdTimer; // Store the last non-zero ActiveId timer since the beginning of activation, useful for animation. 1172 1173 // Next window/item data 1174 ImGuiNextWindowData NextWindowData; // Storage for SetNextWindow** functions 1175 ImGuiNextItemData NextItemData; // Storage for SetNextItem** functions 1176 1177 // Shared stacks 1178 ImVector<ImGuiColorMod> ColorModifiers; // Stack for PushStyleColor()/PopStyleColor() 1179 ImVector<ImGuiStyleMod> StyleModifiers; // Stack for PushStyleVar()/PopStyleVar() 1180 ImVector<ImFont*> FontStack; // Stack for PushFont()/PopFont() 1181 ImVector<ImGuiPopupData>OpenPopupStack; // Which popups are open (persistent) 1182 ImVector<ImGuiPopupData>BeginPopupStack; // Which level of BeginPopup() we are in (reset every frame) 1183 1184 // Gamepad/keyboard Navigation 1185 ImGuiWindow* NavWindow; // Focused window for navigation. Could be called 'FocusWindow' 1186 ImGuiID NavId; // Focused item for navigation 1187 ImGuiID NavFocusScopeId; // Identify a selection scope (selection code often wants to "clear other items" when landing on an item of the selection set) 1188 ImGuiID NavActivateId; // ~~ (g.ActiveId == 0) && IsNavInputPressed(ImGuiNavInput_Activate) ? NavId : 0, also set when calling ActivateItem() 1189 ImGuiID NavActivateDownId; // ~~ IsNavInputDown(ImGuiNavInput_Activate) ? NavId : 0 1190 ImGuiID NavActivatePressedId; // ~~ IsNavInputPressed(ImGuiNavInput_Activate) ? NavId : 0 1191 ImGuiID NavInputId; // ~~ IsNavInputPressed(ImGuiNavInput_Input) ? NavId : 0 1192 ImGuiID NavJustTabbedId; // Just tabbed to this id. 1193 ImGuiID NavJustMovedToId; // Just navigated to this id (result of a successfully MoveRequest). 1194 ImGuiID NavJustMovedToFocusScopeId; // Just navigated to this focus scope id (result of a successfully MoveRequest). 1195 ImGuiKeyModFlags NavJustMovedToKeyMods; 1196 ImGuiID NavNextActivateId; // Set by ActivateItem(), queued until next frame. 1197 ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode? THIS WILL ONLY BE None or NavGamepad or NavKeyboard. 1198 ImRect NavScoringRect; // Rectangle used for scoring, in screen space. Based of window->NavRectRel[], modified for directional navigation scoring. 1199 int NavScoringCount; // Metrics for debugging 1200 ImGuiNavLayer NavLayer; // Layer we are navigating on. For now the system is hard-coded for 0=main contents and 1=menu/title bar, may expose layers later. 1201 int NavIdTabCounter; // == NavWindow->DC.FocusIdxTabCounter at time of NavId processing 1202 bool NavIdIsAlive; // Nav widget has been seen this frame ~~ NavRectRel is valid 1203 bool NavMousePosDirty; // When set we will update mouse position if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) if set (NB: this not enabled by default) 1204 bool NavDisableHighlight; // When user starts using mouse, we hide gamepad/keyboard highlight (NB: but they are still available, which is why NavDisableHighlight isn't always != NavDisableMouseHover) 1205 bool NavDisableMouseHover; // When user starts using gamepad/keyboard, we hide mouse hovering highlight until mouse is touched again. 1206 bool NavAnyRequest; // ~~ NavMoveRequest || NavInitRequest 1207 bool NavInitRequest; // Init request for appearing window to select first item 1208 bool NavInitRequestFromMove; 1209 ImGuiID NavInitResultId; // Init request result (first item of the window, or one for which SetItemDefaultFocus() was called) 1210 ImRect NavInitResultRectRel; // Init request result rectangle (relative to parent window) 1211 bool NavMoveRequest; // Move request for this frame 1212 ImGuiNavMoveFlags NavMoveRequestFlags; 1213 ImGuiNavForward NavMoveRequestForward; // None / ForwardQueued / ForwardActive (this is used to navigate sibling parent menus from a child menu) 1214 ImGuiKeyModFlags NavMoveRequestKeyMods; 1215 ImGuiDir NavMoveDir, NavMoveDirLast; // Direction of the move request (left/right/up/down), direction of the previous move request 1216 ImGuiDir NavMoveClipDir; // FIXME-NAV: Describe the purpose of this better. Might want to rename? 1217 ImGuiNavMoveResult NavMoveResultLocal; // Best move request candidate within NavWindow 1218 ImGuiNavMoveResult NavMoveResultLocalVisibleSet; // Best move request candidate within NavWindow that are mostly visible (when using ImGuiNavMoveFlags_AlsoScoreVisibleSet flag) 1219 ImGuiNavMoveResult NavMoveResultOther; // Best move request candidate within NavWindow's flattened hierarchy (when using ImGuiWindowFlags_NavFlattened flag) 1220 ImGuiWindow* NavWrapRequestWindow; // Window which requested trying nav wrap-around. 1221 ImGuiNavMoveFlags NavWrapRequestFlags; // Wrap-around operation flags. 1222 1223 // Navigation: Windowing (CTRL+TAB for list, or Menu button + keys or directional pads to move/resize) 1224 ImGuiWindow* NavWindowingTarget; // Target window when doing CTRL+Tab (or Pad Menu + FocusPrev/Next), this window is temporarily displayed top-most! 1225 ImGuiWindow* NavWindowingTargetAnim; // Record of last valid NavWindowingTarget until DimBgRatio and NavWindowingHighlightAlpha becomes 0.0f, so the fade-out can stay on it. 1226 ImGuiWindow* NavWindowingListWindow; // Internal window actually listing the CTRL+Tab contents 1227 float NavWindowingTimer; 1228 float NavWindowingHighlightAlpha; 1229 bool NavWindowingToggleLayer; 1230 1231 // Legacy Focus/Tabbing system (older than Nav, active even if Nav is disabled, misnamed. FIXME-NAV: This needs a redesign!) 1232 ImGuiWindow* FocusRequestCurrWindow; // 1233 ImGuiWindow* FocusRequestNextWindow; // 1234 int FocusRequestCurrCounterRegular; // Any item being requested for focus, stored as an index (we on layout to be stable between the frame pressing TAB and the next frame, semi-ouch) 1235 int FocusRequestCurrCounterTabStop; // Tab item being requested for focus, stored as an index 1236 int FocusRequestNextCounterRegular; // Stored for next frame 1237 int FocusRequestNextCounterTabStop; // " 1238 bool FocusTabPressed; // 1239 1240 // Render 1241 ImDrawData DrawData; // Main ImDrawData instance to pass render information to the user 1242 ImDrawDataBuilder DrawDataBuilder; 1243 float DimBgRatio; // 0.0..1.0 animation when fading in a dimming background (for modal window and CTRL+TAB list) 1244 ImDrawList BackgroundDrawList; // First draw list to be rendered. 1245 ImDrawList ForegroundDrawList; // Last draw list to be rendered. This is where we the render software mouse cursor (if io.MouseDrawCursor is set) and most debug overlays. 1246 ImGuiMouseCursor MouseCursor; 1247 1248 // Drag and Drop 1249 bool DragDropActive; 1250 bool DragDropWithinSource; // Set when within a BeginDragDropXXX/EndDragDropXXX block for a drag source. 1251 bool DragDropWithinTarget; // Set when within a BeginDragDropXXX/EndDragDropXXX block for a drag target. 1252 ImGuiDragDropFlags DragDropSourceFlags; 1253 int DragDropSourceFrameCount; 1254 int DragDropMouseButton; 1255 ImGuiPayload DragDropPayload; 1256 ImRect DragDropTargetRect; // Store rectangle of current target candidate (we favor small targets when overlapping) 1257 ImGuiID DragDropTargetId; 1258 ImGuiDragDropFlags DragDropAcceptFlags; 1259 float DragDropAcceptIdCurrRectSurface; // Target item surface (we resolve overlapping targets by prioritizing the smaller surface) 1260 ImGuiID DragDropAcceptIdCurr; // Target item id (set at the time of accepting the payload) 1261 ImGuiID DragDropAcceptIdPrev; // Target item id from previous frame (we need to store this to allow for overlapping drag and drop targets) 1262 int DragDropAcceptFrameCount; // Last time a target expressed a desire to accept the source 1263 ImGuiID DragDropHoldJustPressedId; // Set when holding a payload just made ButtonBehavior() return a press. 1264 ImVector<unsigned char> DragDropPayloadBufHeap; // We don't expose the ImVector<> directly, ImGuiPayload only holds pointer+size 1265 unsigned char DragDropPayloadBufLocal[16]; // Local buffer for small payloads 1266 1267 // Tab bars 1268 ImGuiTabBar* CurrentTabBar; 1269 ImPool<ImGuiTabBar> TabBars; 1270 ImVector<ImGuiPtrOrIndex> CurrentTabBarStack; 1271 ImVector<ImGuiShrinkWidthItem> ShrinkWidthBuffer; 1272 1273 // Widget state 1274 ImVec2 LastValidMousePos; 1275 ImGuiInputTextState InputTextState; 1276 ImFont InputTextPasswordFont; 1277 ImGuiID TempInputId; // Temporary text input when CTRL+clicking on a slider, etc. 1278 ImGuiColorEditFlags ColorEditOptions; // Store user options for color edit widgets 1279 float ColorEditLastHue; // Backup of last Hue associated to LastColor[3], so we can restore Hue in lossy RGB<>HSV round trips 1280 float ColorEditLastSat; // Backup of last Saturation associated to LastColor[3], so we can restore Saturation in lossy RGB<>HSV round trips 1281 float ColorEditLastColor[3]; 1282 ImVec4 ColorPickerRef; // Initial/reference color at the time of opening the color picker. 1283 float SliderCurrentAccum; // Accumulated slider delta when using navigation controls. 1284 bool SliderCurrentAccumDirty; // Has the accumulated slider delta changed since last time we tried to apply it? 1285 bool DragCurrentAccumDirty; 1286 float DragCurrentAccum; // Accumulator for dragging modification. Always high-precision, not rounded by end-user precision settings 1287 float DragSpeedDefaultRatio; // If speed == 0.0f, uses (max-min) * DragSpeedDefaultRatio 1288 float ScrollbarClickDeltaToGrabCenter; // Distance between mouse and center of grab box, normalized in parent space. Use storage? 1289 int TooltipOverrideCount; 1290 ImVector<char> ClipboardHandlerData; // If no custom clipboard handler is defined 1291 ImVector<ImGuiID> MenusIdSubmittedThisFrame; // A list of menu IDs that were rendered at least once 1292 1293 // Platform support 1294 ImVec2 PlatformImePos; // Cursor position request & last passed to the OS Input Method Editor 1295 ImVec2 PlatformImeLastPos; 1296 char PlatformLocaleDecimalPoint; // '.' or *localeconv()->decimal_point 1297 1298 // Settings 1299 bool SettingsLoaded; 1300 float SettingsDirtyTimer; // Save .ini Settings to memory when time reaches zero 1301 ImGuiTextBuffer SettingsIniData; // In memory .ini settings 1302 ImVector<ImGuiSettingsHandler> SettingsHandlers; // List of .ini settings handlers 1303 ImChunkStream<ImGuiWindowSettings> SettingsWindows; // ImGuiWindow .ini settings entries 1304 1305 // Capture/Logging 1306 bool LogEnabled; // Currently capturing 1307 ImGuiLogType LogType; // Capture target 1308 ImFileHandle LogFile; // If != NULL log to stdout/ file 1309 ImGuiTextBuffer LogBuffer; // Accumulation buffer when log to clipboard. This is pointer so our GImGui static constructor doesn't call heap allocators. 1310 float LogLinePosY; 1311 bool LogLineFirstItem; 1312 int LogDepthRef; 1313 int LogDepthToExpand; 1314 int LogDepthToExpandDefault; // Default/stored value for LogDepthMaxExpand if not specified in the LogXXX function call. 1315 1316 // Debug Tools 1317 bool DebugItemPickerActive; // Item picker is active (started with DebugStartItemPicker()) 1318 ImGuiID DebugItemPickerBreakId; // Will call IM_DEBUG_BREAK() when encountering this id 1319 1320 // Misc 1321 float FramerateSecPerFrame[120]; // Calculate estimate of framerate for user over the last 2 seconds. 1322 int FramerateSecPerFrameIdx; 1323 float FramerateSecPerFrameAccum; 1324 int WantCaptureMouseNextFrame; // Explicit capture via CaptureKeyboardFromApp()/CaptureMouseFromApp() sets those flags 1325 int WantCaptureKeyboardNextFrame; 1326 int WantTextInputNextFrame; 1327 char TempBuffer[1024 * 3 + 1]; // Temporary text buffer 1328 1329 ImGuiContext(ImFontAtlas* shared_font_atlas) : BackgroundDrawList(&DrawListSharedData), ForegroundDrawList(&DrawListSharedData) 1330 { 1331 Initialized = false; 1332 FontAtlasOwnedByContext = shared_font_atlas ? false : true; 1333 Font = NULL; 1334 FontSize = FontBaseSize = 0.0f; 1335 IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)(); 1336 Time = 0.0f; 1337 FrameCount = 0; 1338 FrameCountEnded = FrameCountRendered = -1; 1339 WithinFrameScope = WithinFrameScopeWithImplicitWindow = WithinEndChild = false; 1340 TestEngineHookItems = false; 1341 TestEngineHookIdInfo = 0; 1342 TestEngine = NULL; 1343 1344 WindowsActiveCount = 0; 1345 CurrentWindow = NULL; 1346 HoveredWindow = NULL; 1347 HoveredRootWindow = NULL; 1348 HoveredWindowUnderMovingWindow = NULL; 1349 MovingWindow = NULL; 1350 WheelingWindow = NULL; 1351 WheelingWindowTimer = 0.0f; 1352 1353 HoveredId = HoveredIdPreviousFrame = 0; 1354 HoveredIdAllowOverlap = false; 1355 HoveredIdDisabled = false; 1356 HoveredIdTimer = HoveredIdNotActiveTimer = 0.0f; 1357 ActiveId = 0; 1358 ActiveIdIsAlive = 0; 1359 ActiveIdTimer = 0.0f; 1360 ActiveIdIsJustActivated = false; 1361 ActiveIdAllowOverlap = false; 1362 ActiveIdNoClearOnFocusLoss = false; 1363 ActiveIdHasBeenPressedBefore = false; 1364 ActiveIdHasBeenEditedBefore = false; 1365 ActiveIdHasBeenEditedThisFrame = false; 1366 ActiveIdUsingNavDirMask = 0x00; 1367 ActiveIdUsingNavInputMask = 0x00; 1368 ActiveIdUsingKeyInputMask = 0x00; 1369 ActiveIdClickOffset = ImVec2(-1, -1); 1370 ActiveIdWindow = NULL; 1371 ActiveIdSource = ImGuiInputSource_None; 1372 ActiveIdMouseButton = 0; 1373 ActiveIdPreviousFrame = 0; 1374 ActiveIdPreviousFrameIsAlive = false; 1375 ActiveIdPreviousFrameHasBeenEditedBefore = false; 1376 ActiveIdPreviousFrameWindow = NULL; 1377 LastActiveId = 0; 1378 LastActiveIdTimer = 0.0f; 1379 1380 NavWindow = NULL; 1381 NavId = NavFocusScopeId = NavActivateId = NavActivateDownId = NavActivatePressedId = NavInputId = 0; 1382 NavJustTabbedId = NavJustMovedToId = NavJustMovedToFocusScopeId = NavNextActivateId = 0; 1383 NavJustMovedToKeyMods = ImGuiKeyModFlags_None; 1384 NavInputSource = ImGuiInputSource_None; 1385 NavScoringRect = ImRect(); 1386 NavScoringCount = 0; 1387 NavLayer = ImGuiNavLayer_Main; 1388 NavIdTabCounter = INT_MAX; 1389 NavIdIsAlive = false; 1390 NavMousePosDirty = false; 1391 NavDisableHighlight = true; 1392 NavDisableMouseHover = false; 1393 NavAnyRequest = false; 1394 NavInitRequest = false; 1395 NavInitRequestFromMove = false; 1396 NavInitResultId = 0; 1397 NavMoveRequest = false; 1398 NavMoveRequestFlags = ImGuiNavMoveFlags_None; 1399 NavMoveRequestForward = ImGuiNavForward_None; 1400 NavMoveRequestKeyMods = ImGuiKeyModFlags_None; 1401 NavMoveDir = NavMoveDirLast = NavMoveClipDir = ImGuiDir_None; 1402 NavWrapRequestWindow = NULL; 1403 NavWrapRequestFlags = ImGuiNavMoveFlags_None; 1404 1405 NavWindowingTarget = NavWindowingTargetAnim = NavWindowingListWindow = NULL; 1406 NavWindowingTimer = NavWindowingHighlightAlpha = 0.0f; 1407 NavWindowingToggleLayer = false; 1408 1409 FocusRequestCurrWindow = FocusRequestNextWindow = NULL; 1410 FocusRequestCurrCounterRegular = FocusRequestCurrCounterTabStop = INT_MAX; 1411 FocusRequestNextCounterRegular = FocusRequestNextCounterTabStop = INT_MAX; 1412 FocusTabPressed = false; 1413 1414 DimBgRatio = 0.0f; 1415 BackgroundDrawList._OwnerName = "##Background"; // Give it a name for debugging 1416 ForegroundDrawList._OwnerName = "##Foreground"; // Give it a name for debugging 1417 MouseCursor = ImGuiMouseCursor_Arrow; 1418 1419 DragDropActive = DragDropWithinSource = DragDropWithinTarget = false; 1420 DragDropSourceFlags = ImGuiDragDropFlags_None; 1421 DragDropSourceFrameCount = -1; 1422 DragDropMouseButton = -1; 1423 DragDropTargetId = 0; 1424 DragDropAcceptFlags = ImGuiDragDropFlags_None; 1425 DragDropAcceptIdCurrRectSurface = 0.0f; 1426 DragDropAcceptIdPrev = DragDropAcceptIdCurr = 0; 1427 DragDropAcceptFrameCount = -1; 1428 DragDropHoldJustPressedId = 0; 1429 memset(DragDropPayloadBufLocal, 0, sizeof(DragDropPayloadBufLocal)); 1430 1431 CurrentTabBar = NULL; 1432 1433 LastValidMousePos = ImVec2(0.0f, 0.0f); 1434 TempInputId = 0; 1435 ColorEditOptions = ImGuiColorEditFlags__OptionsDefault; 1436 ColorEditLastHue = ColorEditLastSat = 0.0f; 1437 ColorEditLastColor[0] = ColorEditLastColor[1] = ColorEditLastColor[2] = FLT_MAX; 1438 SliderCurrentAccum = 0.0f; 1439 SliderCurrentAccumDirty = false; 1440 DragCurrentAccumDirty = false; 1441 DragCurrentAccum = 0.0f; 1442 DragSpeedDefaultRatio = 1.0f / 100.0f; 1443 ScrollbarClickDeltaToGrabCenter = 0.0f; 1444 TooltipOverrideCount = 0; 1445 1446 PlatformImePos = PlatformImeLastPos = ImVec2(FLT_MAX, FLT_MAX); 1447 PlatformLocaleDecimalPoint = '.'; 1448 1449 SettingsLoaded = false; 1450 SettingsDirtyTimer = 0.0f; 1451 1452 LogEnabled = false; 1453 LogType = ImGuiLogType_None; 1454 LogFile = NULL; 1455 LogLinePosY = FLT_MAX; 1456 LogLineFirstItem = false; 1457 LogDepthRef = 0; 1458 LogDepthToExpand = LogDepthToExpandDefault = 2; 1459 1460 DebugItemPickerActive = false; 1461 DebugItemPickerBreakId = 0; 1462 1463 memset(FramerateSecPerFrame, 0, sizeof(FramerateSecPerFrame)); 1464 FramerateSecPerFrameIdx = 0; 1465 FramerateSecPerFrameAccum = 0.0f; 1466 WantCaptureMouseNextFrame = WantCaptureKeyboardNextFrame = WantTextInputNextFrame = -1; 1467 memset(TempBuffer, 0, sizeof(TempBuffer)); 1468 } 1469 }; 1470 1471 //----------------------------------------------------------------------------- 1472 // [SECTION] ImGuiWindowTempData, ImGuiWindow 1473 //----------------------------------------------------------------------------- 1474 1475 // Transient per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the DC variable name in ImGuiWindow. 1476 // FIXME: That's theory, in practice the delimitation between ImGuiWindow and ImGuiWindowTempData is quite tenuous and could be reconsidered. 1477 struct IMGUI_API ImGuiWindowTempData 1478 { 1479 // Layout 1480 ImVec2 CursorPos; // Current emitting position, in absolute coordinates. 1481 ImVec2 CursorPosPrevLine; 1482 ImVec2 CursorStartPos; // Initial position after Begin(), generally ~ window position + WindowPadding. 1483 ImVec2 CursorMaxPos; // Used to implicitly calculate the size of our contents, always growing during the frame. Used to calculate window->ContentSize at the beginning of next frame 1484 ImVec2 CurrLineSize; 1485 ImVec2 PrevLineSize; 1486 float CurrLineTextBaseOffset; // Baseline offset (0.0f by default on a new line, generally == style.FramePadding.y when a framed item has been added). 1487 float PrevLineTextBaseOffset; 1488 ImVec1 Indent; // Indentation / start position from left of window (increased by TreePush/TreePop, etc.) 1489 ImVec1 ColumnsOffset; // Offset to the current column (if ColumnsCurrent > 0). FIXME: This and the above should be a stack to allow use cases like Tree->Column->Tree. Need revamp columns API. 1490 ImVec1 GroupOffset; 1491 1492 // Last item status 1493 ImGuiID LastItemId; // ID for last item 1494 ImGuiItemStatusFlags LastItemStatusFlags; // Status flags for last item (see ImGuiItemStatusFlags_) 1495 ImRect LastItemRect; // Interaction rect for last item 1496 ImRect LastItemDisplayRect; // End-user display rect for last item (only valid if LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect) 1497 1498 // Keyboard/Gamepad navigation 1499 ImGuiNavLayer NavLayerCurrent; // Current layer, 0..31 (we currently only use 0..1) 1500 int NavLayerActiveMask; // Which layers have been written to (result from previous frame) 1501 int NavLayerActiveMaskNext; // Which layers have been written to (accumulator for current frame) 1502 ImGuiID NavFocusScopeIdCurrent; // Current focus scope ID while appending 1503 bool NavHideHighlightOneFrame; 1504 bool NavHasScroll; // Set when scrolling can be used (ScrollMax > 0.0f) 1505 1506 // Miscellaneous 1507 bool MenuBarAppending; // FIXME: Remove this 1508 ImVec2 MenuBarOffset; // MenuBarOffset.x is sort of equivalent of a per-layer CursorPos.x, saved/restored as we switch to the menu bar. The only situation when MenuBarOffset.y is > 0 if when (SafeAreaPadding.y > FramePadding.y), often used on TVs. 1509 ImGuiMenuColumns MenuColumns; // Simplified columns storage for menu items measurement 1510 int TreeDepth; // Current tree depth. 1511 ImU32 TreeJumpToParentOnPopMask; // Store a copy of !g.NavIdIsAlive for TreeDepth 0..31.. Could be turned into a ImU64 if necessary. 1512 ImVector<ImGuiWindow*> ChildWindows; 1513 ImGuiStorage* StateStorage; // Current persistent per-window storage (store e.g. tree node open/close state) 1514 ImGuiColumns* CurrentColumns; // Current columns set 1515 ImGuiLayoutType LayoutType; 1516 ImGuiLayoutType ParentLayoutType; // Layout type of parent window at the time of Begin() 1517 int FocusCounterRegular; // (Legacy Focus/Tabbing system) Sequential counter, start at -1 and increase as assigned via FocusableItemRegister() (FIXME-NAV: Needs redesign) 1518 int FocusCounterTabStop; // (Legacy Focus/Tabbing system) Same, but only count widgets which you can Tab through. 1519 1520 // Local parameters stacks 1521 // We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings. 1522 ImGuiItemFlags ItemFlags; // == ItemFlagsStack.back() [empty == ImGuiItemFlags_Default] 1523 float ItemWidth; // == ItemWidthStack.back(). 0.0: default, >0.0: width in pixels, <0.0: align xx pixels to the right of window 1524 float TextWrapPos; // == TextWrapPosStack.back() [empty == -1.0f] 1525 ImVector<ImGuiItemFlags>ItemFlagsStack; 1526 ImVector<float> ItemWidthStack; 1527 ImVector<float> TextWrapPosStack; 1528 ImVector<ImGuiGroupData>GroupStack; 1529 short StackSizesBackup[6]; // Store size of various stacks for asserting 1530 1531 ImGuiWindowTempData() 1532 { 1533 CursorPos = CursorPosPrevLine = CursorStartPos = CursorMaxPos = ImVec2(0.0f, 0.0f); 1534 CurrLineSize = PrevLineSize = ImVec2(0.0f, 0.0f); 1535 CurrLineTextBaseOffset = PrevLineTextBaseOffset = 0.0f; 1536 Indent = ImVec1(0.0f); 1537 ColumnsOffset = ImVec1(0.0f); 1538 GroupOffset = ImVec1(0.0f); 1539 1540 LastItemId = 0; 1541 LastItemStatusFlags = ImGuiItemStatusFlags_None; 1542 LastItemRect = LastItemDisplayRect = ImRect(); 1543 1544 NavLayerActiveMask = NavLayerActiveMaskNext = 0x00; 1545 NavLayerCurrent = ImGuiNavLayer_Main; 1546 NavFocusScopeIdCurrent = 0; 1547 NavHideHighlightOneFrame = false; 1548 NavHasScroll = false; 1549 1550 MenuBarAppending = false; 1551 MenuBarOffset = ImVec2(0.0f, 0.0f); 1552 TreeDepth = 0; 1553 TreeJumpToParentOnPopMask = 0x00; 1554 StateStorage = NULL; 1555 CurrentColumns = NULL; 1556 LayoutType = ParentLayoutType = ImGuiLayoutType_Vertical; 1557 FocusCounterRegular = FocusCounterTabStop = -1; 1558 1559 ItemFlags = ImGuiItemFlags_Default_; 1560 ItemWidth = 0.0f; 1561 TextWrapPos = -1.0f; 1562 memset(StackSizesBackup, 0, sizeof(StackSizesBackup)); 1563 } 1564 }; 1565 1566 // Storage for one window 891 1567 struct IMGUI_API ImGuiWindow 892 1568 { 893 char* Name; 894 ImGuiID ID; // == ImHash(Name) 895 ImGuiWindowFlags Flags; // See enum ImGuiWindowFlags_ 896 ImVec2 Pos; // Position (always rounded-up to nearest pixel) 897 ImVec2 Size; // Current size (==SizeFull or collapsed title bar size) 898 ImVec2 SizeFull; // Size when non collapsed 899 ImVec2 SizeFullAtLastBegin; // Copy of SizeFull at the end of Begin. This is the reference value we'll use on the next frame to decide if we need scrollbars. 900 ImVec2 SizeContents; // Size of contents (== extents reach of the drawing cursor) from previous frame. Include decoration, window title, border, menu, etc. 901 ImVec2 SizeContentsExplicit; // Size of contents explicitly set by the user via SetNextWindowContentSize() 902 ImRect ContentsRegionRect; // Maximum visible content position in window coordinates. ~~ (SizeContentsExplicit ? SizeContentsExplicit : Size - ScrollbarSizes) - CursorStartPos, per axis 903 ImVec2 WindowPadding; // Window padding at the time of begin. 904 float WindowRounding; // Window rounding at the time of begin. 905 float WindowBorderSize; // Window border size at the time of begin. 906 ImGuiID MoveId; // == window->GetID("#MOVE") 907 ImGuiID ChildId; // Id of corresponding item in parent window (for child windows) 908 ImVec2 Scroll; 909 ImVec2 ScrollTarget; // target scroll position. stored as cursor position with scrolling canceled out, so the highest point is always 0.0f. (FLT_MAX for no change) 910 ImVec2 ScrollTargetCenterRatio; // 0.0f = scroll so that target position is at top, 0.5f = scroll so that target position is centered 911 ImVec2 ScrollbarSizes; 912 bool ScrollbarX, ScrollbarY; 913 bool Active; // Set to true on Begin(), unless Collapsed 914 bool WasActive; 915 bool WriteAccessed; // Set to true when any widget access the current window 916 bool Collapsed; // Set when collapsing window to become only title-bar 917 bool CollapseToggleWanted; 918 bool SkipItems; // Set when items can safely be all clipped (e.g. window not visible or collapsed) 919 bool Appearing; // Set during the frame where the window is appearing (or re-appearing) 920 bool CloseButton; // Set when the window has a close button (p_open != NULL) 921 int BeginOrderWithinParent; // Order within immediate parent window, if we are a child window. Otherwise 0. 922 int BeginOrderWithinContext; // Order within entire imgui context. This is mostly used for debugging submission order related issues. 923 int BeginCount; // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs) 924 ImGuiID PopupId; // ID in the popup stack when this window is used as a popup/menu (because we use generic Name/ID for recycling) 925 int AutoFitFramesX, AutoFitFramesY; 926 bool AutoFitOnlyGrows; 927 int AutoFitChildAxises; 928 ImGuiDir AutoPosLastDirection; 929 int HiddenFrames; 930 ImGuiCond SetWindowPosAllowFlags; // store acceptable condition flags for SetNextWindowPos() use. 931 ImGuiCond SetWindowSizeAllowFlags; // store acceptable condition flags for SetNextWindowSize() use. 932 ImGuiCond SetWindowCollapsedAllowFlags; // store acceptable condition flags for SetNextWindowCollapsed() use. 933 ImVec2 SetWindowPosVal; // store window position when using a non-zero Pivot (position set needs to be processed when we know the window size) 934 ImVec2 SetWindowPosPivot; // store window pivot for positioning. ImVec2(0,0) when positioning from top-left corner; ImVec2(0.5f,0.5f) for centering; ImVec2(1,1) for bottom right. 935 936 ImGuiDrawContext DC; // Temporary per-window data, reset at the beginning of the frame 937 ImVector<ImGuiID> IDStack; // ID stack. ID are hashes seeded with the value at the top of the stack 938 ImRect ClipRect; // = DrawList->clip_rect_stack.back(). Scissoring / clipping rectangle. x1, y1, x2, y2. 939 ImRect WindowRectClipped; // = WindowRect just after setup in Begin(). == window->Rect() for root window. 940 ImRect InnerRect, InnerClipRect; 941 int LastFrameActive; 942 float ItemWidthDefault; 943 ImGuiMenuColumns MenuColumns; // Simplified columns storage for menu items 944 ImGuiStorage StateStorage; 945 ImVector<ImGuiColumnsSet> ColumnsStorage; 946 float FontWindowScale; // User scale multiplier per-window 947 948 ImDrawList* DrawList; // == &DrawListInst (for backward compatibility reason with code using imgui_internal.h we keep this a pointer) 949 ImDrawList DrawListInst; 950 ImGuiWindow* ParentWindow; // If we are a child _or_ popup window, this is pointing to our parent. Otherwise NULL. 951 ImGuiWindow* RootWindow; // Point to ourself or first ancestor that is not a child window. 952 ImGuiWindow* RootWindowForTitleBarHighlight; // Point to ourself or first ancestor which will display TitleBgActive color when this window is active. 953 ImGuiWindow* RootWindowForTabbing; // Point to ourself or first ancestor which can be CTRL-Tabbed into. 954 ImGuiWindow* RootWindowForNav; // Point to ourself or first ancestor which doesn't have the NavFlattened flag. 955 956 ImGuiWindow* NavLastChildNavWindow; // When going to the menu bar, we remember the child window we came from. (This could probably be made implicit if we kept g.Windows sorted by last focused including child window.) 957 ImGuiID NavLastIds[2]; // Last known NavId for this window, per layer (0/1) 958 ImRect NavRectRel[2]; // Reference rectangle, in window relative space 959 960 // Navigation / Focus 961 // FIXME-NAV: Merge all this with the new Nav system, at least the request variables should be moved to ImGuiContext 962 int FocusIdxAllCounter; // Start at -1 and increase as assigned via FocusItemRegister() 963 int FocusIdxTabCounter; // (same, but only count widgets which you can Tab through) 964 int FocusIdxAllRequestCurrent; // Item being requested for focus 965 int FocusIdxTabRequestCurrent; // Tab-able item being requested for focus 966 int FocusIdxAllRequestNext; // Item being requested for focus, for next update (relies on layout to be stable between the frame pressing TAB and the next frame) 967 int FocusIdxTabRequestNext; // " 1569 char* Name; // Window name, owned by the window. 1570 ImGuiID ID; // == ImHashStr(Name) 1571 ImGuiWindowFlags Flags; // See enum ImGuiWindowFlags_ 1572 ImVec2 Pos; // Position (always rounded-up to nearest pixel) 1573 ImVec2 Size; // Current size (==SizeFull or collapsed title bar size) 1574 ImVec2 SizeFull; // Size when non collapsed 1575 ImVec2 ContentSize; // Size of contents/scrollable client area (calculated from the extents reach of the cursor) from previous frame. Does not include window decoration or window padding. 1576 ImVec2 ContentSizeExplicit; // Size of contents/scrollable client area explicitly request by the user via SetNextWindowContentSize(). 1577 ImVec2 WindowPadding; // Window padding at the time of Begin(). 1578 float WindowRounding; // Window rounding at the time of Begin(). May be clamped lower to avoid rendering artifacts with title bar, menu bar etc. 1579 float WindowBorderSize; // Window border size at the time of Begin(). 1580 int NameBufLen; // Size of buffer storing Name. May be larger than strlen(Name)! 1581 ImGuiID MoveId; // == window->GetID("#MOVE") 1582 ImGuiID ChildId; // ID of corresponding item in parent window (for navigation to return from child window to parent window) 1583 ImVec2 Scroll; 1584 ImVec2 ScrollMax; 1585 ImVec2 ScrollTarget; // target scroll position. stored as cursor position with scrolling canceled out, so the highest point is always 0.0f. (FLT_MAX for no change) 1586 ImVec2 ScrollTargetCenterRatio; // 0.0f = scroll so that target position is at top, 0.5f = scroll so that target position is centered 1587 ImVec2 ScrollTargetEdgeSnapDist; // 0.0f = no snapping, >0.0f snapping threshold 1588 ImVec2 ScrollbarSizes; // Size taken by each scrollbars on their smaller axis. Pay attention! ScrollbarSizes.x == width of the vertical scrollbar, ScrollbarSizes.y = height of the horizontal scrollbar. 1589 bool ScrollbarX, ScrollbarY; // Are scrollbars visible? 1590 bool Active; // Set to true on Begin(), unless Collapsed 1591 bool WasActive; 1592 bool WriteAccessed; // Set to true when any widget access the current window 1593 bool Collapsed; // Set when collapsing window to become only title-bar 1594 bool WantCollapseToggle; 1595 bool SkipItems; // Set when items can safely be all clipped (e.g. window not visible or collapsed) 1596 bool Appearing; // Set during the frame where the window is appearing (or re-appearing) 1597 bool Hidden; // Do not display (== HiddenFrames*** > 0) 1598 bool IsFallbackWindow; // Set on the "Debug##Default" window. 1599 bool HasCloseButton; // Set when the window has a close button (p_open != NULL) 1600 signed char ResizeBorderHeld; // Current border being held for resize (-1: none, otherwise 0-3) 1601 short BeginCount; // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs) 1602 short BeginOrderWithinParent; // Order within immediate parent window, if we are a child window. Otherwise 0. 1603 short BeginOrderWithinContext; // Order within entire imgui context. This is mostly used for debugging submission order related issues. 1604 ImGuiID PopupId; // ID in the popup stack when this window is used as a popup/menu (because we use generic Name/ID for recycling) 1605 ImS8 AutoFitFramesX, AutoFitFramesY; 1606 ImS8 AutoFitChildAxises; 1607 bool AutoFitOnlyGrows; 1608 ImGuiDir AutoPosLastDirection; 1609 int HiddenFramesCanSkipItems; // Hide the window for N frames 1610 int HiddenFramesCannotSkipItems; // Hide the window for N frames while allowing items to be submitted so we can measure their size 1611 ImGuiCond SetWindowPosAllowFlags; // store acceptable condition flags for SetNextWindowPos() use. 1612 ImGuiCond SetWindowSizeAllowFlags; // store acceptable condition flags for SetNextWindowSize() use. 1613 ImGuiCond SetWindowCollapsedAllowFlags; // store acceptable condition flags for SetNextWindowCollapsed() use. 1614 ImVec2 SetWindowPosVal; // store window position when using a non-zero Pivot (position set needs to be processed when we know the window size) 1615 ImVec2 SetWindowPosPivot; // store window pivot for positioning. ImVec2(0, 0) when positioning from top-left corner; ImVec2(0.5f, 0.5f) for centering; ImVec2(1, 1) for bottom right. 1616 1617 ImVector<ImGuiID> IDStack; // ID stack. ID are hashes seeded with the value at the top of the stack. (In theory this should be in the TempData structure) 1618 ImGuiWindowTempData DC; // Temporary per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the "DC" variable name. 1619 1620 // The best way to understand what those rectangles are is to use the 'Metrics -> Tools -> Show windows rectangles' viewer. 1621 // The main 'OuterRect', omitted as a field, is window->Rect(). 1622 ImRect OuterRectClipped; // == Window->Rect() just after setup in Begin(). == window->Rect() for root window. 1623 ImRect InnerRect; // Inner rectangle (omit title bar, menu bar, scroll bar) 1624 ImRect InnerClipRect; // == InnerRect shrunk by WindowPadding*0.5f on each side, clipped within viewport or parent clip rect. 1625 ImRect WorkRect; // Initially covers the whole scrolling region. Reduced by containers e.g columns/tables when active. Shrunk by WindowPadding*1.0f on each side. This is meant to replace ContentRegionRect over time (from 1.71+ onward). 1626 ImRect ParentWorkRect; // Backup of WorkRect before entering a container such as columns/tables. Used by e.g. SpanAllColumns functions to easily access. Stacked containers are responsible for maintaining this. // FIXME-WORKRECT: Could be a stack? 1627 ImRect ClipRect; // Current clipping/scissoring rectangle, evolve as we are using PushClipRect(), etc. == DrawList->clip_rect_stack.back(). 1628 ImRect ContentRegionRect; // FIXME: This is currently confusing/misleading. It is essentially WorkRect but not handling of scrolling. We currently rely on it as right/bottom aligned sizing operation need some size to rely on. 1629 ImVec2ih HitTestHoleSize; // Define an optional rectangular hole where mouse will pass-through the window. 1630 ImVec2ih HitTestHoleOffset; 1631 1632 int LastFrameActive; // Last frame number the window was Active. 1633 float LastTimeActive; // Last timestamp the window was Active (using float as we don't need high precision there) 1634 float ItemWidthDefault; 1635 ImGuiStorage StateStorage; 1636 ImVector<ImGuiColumns> ColumnsStorage; 1637 float FontWindowScale; // User scale multiplier per-window, via SetWindowFontScale() 1638 int SettingsOffset; // Offset into SettingsWindows[] (offsets are always valid as we only grow the array from the back) 1639 1640 ImDrawList* DrawList; // == &DrawListInst (for backward compatibility reason with code using imgui_internal.h we keep this a pointer) 1641 ImDrawList DrawListInst; 1642 ImGuiWindow* ParentWindow; // If we are a child _or_ popup window, this is pointing to our parent. Otherwise NULL. 1643 ImGuiWindow* RootWindow; // Point to ourself or first ancestor that is not a child window == Top-level window. 1644 ImGuiWindow* RootWindowForTitleBarHighlight; // Point to ourself or first ancestor which will display TitleBgActive color when this window is active. 1645 ImGuiWindow* RootWindowForNav; // Point to ourself or first ancestor which doesn't have the NavFlattened flag. 1646 1647 ImGuiWindow* NavLastChildNavWindow; // When going to the menu bar, we remember the child window we came from. (This could probably be made implicit if we kept g.Windows sorted by last focused including child window.) 1648 ImGuiID NavLastIds[ImGuiNavLayer_COUNT]; // Last known NavId for this window, per layer (0/1) 1649 ImRect NavRectRel[ImGuiNavLayer_COUNT]; // Reference rectangle, in window relative space 1650 1651 bool MemoryCompacted; // Set when window extraneous data have been garbage collected 1652 int MemoryDrawListIdxCapacity; // Backup of last idx/vtx count, so when waking up the window we can preallocate and avoid iterative alloc/copy 1653 int MemoryDrawListVtxCapacity; 968 1654 969 1655 public: 970 ImGuiWindow(ImGuiContext* context, const char* name); 971 ~ImGuiWindow(); 972 973 ImGuiID GetID(const char* str, const char* str_end = NULL); 974 ImGuiID GetID(const void* ptr); 975 ImGuiID GetIDNoKeepAlive(const char* str, const char* str_end = NULL); 976 ImGuiID GetIDFromRectangle(const ImRect& r_abs); 977 978 // We don't use g.FontSize because the window may be != g.CurrentWidow. 979 ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } 980 float CalcFontSize() const { return GImGui->FontBaseSize * FontWindowScale; } 981 float TitleBarHeight() const { return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f; } 982 ImRect TitleBarRect() const { return ImRect(Pos, ImVec2(Pos.x + SizeFull.x, Pos.y + TitleBarHeight())); } 983 float MenuBarHeight() const { return (Flags & ImGuiWindowFlags_MenuBar) ? DC.MenuBarOffset.y + CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f : 0.0f; } 984 ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight(); return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight()); } 985 }; 986 987 // Backup and restore just enough data to be able to use IsItemHovered() on item A after another B in the same window has overwritten the data. 988 struct ImGuiItemHoveredDataBackup 989 { 990 ImGuiID LastItemId; 991 ImGuiItemStatusFlags LastItemStatusFlags; 992 ImRect LastItemRect; 993 ImRect LastItemDisplayRect; 994 995 ImGuiItemHoveredDataBackup() { Backup(); } 996 void Backup() { ImGuiWindow* window = GImGui->CurrentWindow; LastItemId = window->DC.LastItemId; LastItemStatusFlags = window->DC.LastItemStatusFlags; LastItemRect = window->DC.LastItemRect; LastItemDisplayRect = window->DC.LastItemDisplayRect; } 997 void Restore() const { ImGuiWindow* window = GImGui->CurrentWindow; window->DC.LastItemId = LastItemId; window->DC.LastItemStatusFlags = LastItemStatusFlags; window->DC.LastItemRect = LastItemRect; window->DC.LastItemDisplayRect = LastItemDisplayRect; } 998 }; 999 1000 //----------------------------------------------------------------------------- 1001 // Internal API 1002 // No guarantee of forward compatibility here. 1656 ImGuiWindow(ImGuiContext* context, const char* name); 1657 ~ImGuiWindow(); 1658 1659 ImGuiID GetID(const char* str, const char* str_end = NULL); 1660 ImGuiID GetID(const void* ptr); 1661 ImGuiID GetID(int n); 1662 ImGuiID GetIDNoKeepAlive(const char* str, const char* str_end = NULL); 1663 ImGuiID GetIDNoKeepAlive(const void* ptr); 1664 ImGuiID GetIDNoKeepAlive(int n); 1665 ImGuiID GetIDFromRectangle(const ImRect& r_abs); 1666 1667 // We don't use g.FontSize because the window may be != g.CurrentWidow. 1668 ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } 1669 float CalcFontSize() const { ImGuiContext& g = *GImGui; float scale = g.FontBaseSize * FontWindowScale; if (ParentWindow) scale *= ParentWindow->FontWindowScale; return scale; } 1670 float TitleBarHeight() const { ImGuiContext& g = *GImGui; return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : CalcFontSize() + g.Style.FramePadding.y * 2.0f; } 1671 ImRect TitleBarRect() const { return ImRect(Pos, ImVec2(Pos.x + SizeFull.x, Pos.y + TitleBarHeight())); } 1672 float MenuBarHeight() const { ImGuiContext& g = *GImGui; return (Flags & ImGuiWindowFlags_MenuBar) ? DC.MenuBarOffset.y + CalcFontSize() + g.Style.FramePadding.y * 2.0f : 0.0f; } 1673 ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight(); return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight()); } 1674 }; 1675 1676 // Backup and restore just enough data to be able to use IsItemHovered() on item A after another B in the same window has overwritten the data. 1677 struct ImGuiLastItemDataBackup 1678 { 1679 ImGuiID LastItemId; 1680 ImGuiItemStatusFlags LastItemStatusFlags; 1681 ImRect LastItemRect; 1682 ImRect LastItemDisplayRect; 1683 1684 ImGuiLastItemDataBackup() { Backup(); } 1685 void Backup() { ImGuiWindow* window = GImGui->CurrentWindow; LastItemId = window->DC.LastItemId; LastItemStatusFlags = window->DC.LastItemStatusFlags; LastItemRect = window->DC.LastItemRect; LastItemDisplayRect = window->DC.LastItemDisplayRect; } 1686 void Restore() const { ImGuiWindow* window = GImGui->CurrentWindow; window->DC.LastItemId = LastItemId; window->DC.LastItemStatusFlags = LastItemStatusFlags; window->DC.LastItemRect = LastItemRect; window->DC.LastItemDisplayRect = LastItemDisplayRect; } 1687 }; 1688 1689 //----------------------------------------------------------------------------- 1690 // [SECTION] Tab bar, Tab item support 1691 //----------------------------------------------------------------------------- 1692 1693 // Extend ImGuiTabBarFlags_ 1694 enum ImGuiTabBarFlagsPrivate_ 1695 { 1696 ImGuiTabBarFlags_DockNode = 1 << 20, // Part of a dock node [we don't use this in the master branch but it facilitate branch syncing to keep this around] 1697 ImGuiTabBarFlags_IsFocused = 1 << 21, 1698 ImGuiTabBarFlags_SaveSettings = 1 << 22 // FIXME: Settings are handled by the docking system, this only request the tab bar to mark settings dirty when reordering tabs 1699 }; 1700 1701 // Extend ImGuiTabItemFlags_ 1702 enum ImGuiTabItemFlagsPrivate_ 1703 { 1704 ImGuiTabItemFlags_NoCloseButton = 1 << 20, // Track whether p_open was set or not (we'll need this info on the next frame to recompute ContentWidth during layout) 1705 ImGuiTabItemFlags_Button = 1 << 21 // Used by TabItemButton, change the tab item behavior to mimic a button 1706 }; 1707 1708 // Storage for one active tab item (sizeof() 28~32 bytes) 1709 struct ImGuiTabItem 1710 { 1711 ImGuiID ID; 1712 ImGuiTabItemFlags Flags; 1713 int LastFrameVisible; 1714 int LastFrameSelected; // This allows us to infer an ordered list of the last activated tabs with little maintenance 1715 float Offset; // Position relative to beginning of tab 1716 float Width; // Width currently displayed 1717 float ContentWidth; // Width of label, stored during BeginTabItem() call 1718 ImS16 NameOffset; // When Window==NULL, offset to name within parent ImGuiTabBar::TabsNames 1719 ImS8 BeginOrder; // BeginTabItem() order, used to re-order tabs after toggling ImGuiTabBarFlags_Reorderable 1720 ImS8 IndexDuringLayout; // Index only used during TabBarLayout() 1721 bool WantClose; // Marked as closed by SetTabItemClosed() 1722 1723 ImGuiTabItem() { ID = 0; Flags = ImGuiTabItemFlags_None; LastFrameVisible = LastFrameSelected = -1; NameOffset = -1; Offset = Width = ContentWidth = 0.0f; BeginOrder = -1; IndexDuringLayout = -1; WantClose = false; } 1724 }; 1725 1726 // Storage for a tab bar (sizeof() 92~96 bytes) 1727 struct ImGuiTabBar 1728 { 1729 ImVector<ImGuiTabItem> Tabs; 1730 ImGuiID ID; // Zero for tab-bars used by docking 1731 ImGuiID SelectedTabId; // Selected tab/window 1732 ImGuiID NextSelectedTabId; 1733 ImGuiID VisibleTabId; // Can occasionally be != SelectedTabId (e.g. when previewing contents for CTRL+TAB preview) 1734 int CurrFrameVisible; 1735 int PrevFrameVisible; 1736 ImRect BarRect; 1737 float LastTabContentHeight; // Record the height of contents submitted below the tab bar 1738 float WidthAllTabs; // Actual width of all tabs (locked during layout) 1739 float WidthAllTabsIdeal; // Ideal width if all tabs were visible and not clipped 1740 float ScrollingAnim; 1741 float ScrollingTarget; 1742 float ScrollingTargetDistToVisibility; 1743 float ScrollingSpeed; 1744 float ScrollingRectMinX; 1745 float ScrollingRectMaxX; 1746 ImGuiTabBarFlags Flags; 1747 ImGuiID ReorderRequestTabId; 1748 ImS8 ReorderRequestDir; 1749 ImS8 TabsActiveCount; // Number of tabs submitted this frame. 1750 bool WantLayout; 1751 bool VisibleTabWasSubmitted; 1752 bool TabsAddedNew; // Set to true when a new tab item or button has been added to the tab bar during last frame 1753 short LastTabItemIdx; // Index of last BeginTabItem() tab for use by EndTabItem() 1754 ImVec2 FramePadding; // style.FramePadding locked at the time of BeginTabBar() 1755 ImGuiTextBuffer TabsNames; // For non-docking tab bar we re-append names in a contiguous buffer. 1756 1757 ImGuiTabBar(); 1758 int GetTabOrder(const ImGuiTabItem* tab) const { return Tabs.index_from_ptr(tab); } 1759 const char* GetTabName(const ImGuiTabItem* tab) const 1760 { 1761 IM_ASSERT(tab->NameOffset != -1 && (int)tab->NameOffset < TabsNames.Buf.Size); 1762 return TabsNames.Buf.Data + tab->NameOffset; 1763 } 1764 }; 1765 1766 //----------------------------------------------------------------------------- 1767 // [SECTION] Table support 1768 //----------------------------------------------------------------------------- 1769 1770 #ifdef IMGUI_HAS_TABLE 1771 // <this is filled in 'tables' branch> 1772 #endif // #ifdef IMGUI_HAS_TABLE 1773 1774 //----------------------------------------------------------------------------- 1775 // [SECTION] Internal API 1776 // No guarantee of forward compatibility here! 1003 1777 //----------------------------------------------------------------------------- 1004 1778 1005 1779 namespace ImGui 1006 1780 { 1007 // We should always have a CurrentWindow in the stack (there is an implicit "Debug" window) 1008 // If this ever crash because g.CurrentWindow is NULL it means that either 1009 // - ImGui::NewFrame() has never been called, which is illegal. 1010 // - You are calling ImGui functions after ImGui::Render() and before the next ImGui::NewFrame(), which is also illegal. 1011 inline ImGuiWindow* GetCurrentWindowRead() { ImGuiContext& g = *GImGui; return g.CurrentWindow; } 1012 inline ImGuiWindow* GetCurrentWindow() { ImGuiContext& g = *GImGui; g.CurrentWindow->WriteAccessed = true; return g.CurrentWindow; } 1013 IMGUI_API ImGuiWindow* FindWindowByName(const char* name); 1014 IMGUI_API void FocusWindow(ImGuiWindow* window); 1015 IMGUI_API void BringWindowToFront(ImGuiWindow* window); 1016 IMGUI_API void BringWindowToBack(ImGuiWindow* window); 1017 IMGUI_API bool IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent); 1018 IMGUI_API bool IsWindowNavFocusable(ImGuiWindow* window); 1019 1020 IMGUI_API void Initialize(ImGuiContext* context); 1021 IMGUI_API void Shutdown(ImGuiContext* context); // Since 1.60 this is a _private_ function. You can call DestroyContext() to destroy the context created by CreateContext(). 1022 1023 IMGUI_API void NewFrameUpdateHoveredWindowAndCaptureFlags(); 1024 1025 IMGUI_API void MarkIniSettingsDirty(); 1026 IMGUI_API ImGuiSettingsHandler* FindSettingsHandler(const char* type_name); 1027 IMGUI_API ImGuiWindowSettings* FindWindowSettings(ImGuiID id); 1028 1029 IMGUI_API void SetActiveID(ImGuiID id, ImGuiWindow* window); 1030 IMGUI_API ImGuiID GetActiveID(); 1031 IMGUI_API void SetFocusID(ImGuiID id, ImGuiWindow* window); 1032 IMGUI_API void ClearActiveID(); 1033 IMGUI_API void SetHoveredID(ImGuiID id); 1034 IMGUI_API ImGuiID GetHoveredID(); 1035 IMGUI_API void KeepAliveID(ImGuiID id); 1036 1037 IMGUI_API void ItemSize(const ImVec2& size, float text_offset_y = 0.0f); 1038 IMGUI_API void ItemSize(const ImRect& bb, float text_offset_y = 0.0f); 1039 IMGUI_API bool ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb = NULL); 1040 IMGUI_API bool ItemHoverable(const ImRect& bb, ImGuiID id); 1041 IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged); 1042 IMGUI_API bool FocusableItemRegister(ImGuiWindow* window, ImGuiID id, bool tab_stop = true); // Return true if focus is requested 1043 IMGUI_API void FocusableItemUnregister(ImGuiWindow* window); 1044 IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_x, float default_y); 1045 IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x); 1046 IMGUI_API void PushMultiItemsWidths(int components, float width_full = 0.0f); 1047 IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled); 1048 IMGUI_API void PopItemFlag(); 1049 1050 IMGUI_API void SetCurrentFont(ImFont* font); 1051 1052 IMGUI_API void OpenPopupEx(ImGuiID id); 1053 IMGUI_API void ClosePopup(ImGuiID id); 1054 IMGUI_API void ClosePopupsOverWindow(ImGuiWindow* ref_window); 1055 IMGUI_API bool IsPopupOpen(ImGuiID id); 1056 IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags); 1057 IMGUI_API void BeginTooltipEx(ImGuiWindowFlags extra_flags, bool override_previous_tooltip = true); 1058 IMGUI_API ImGuiWindow* GetFrontMostPopupModal(); 1059 1060 IMGUI_API void NavInitWindow(ImGuiWindow* window, bool force_reinit); 1061 IMGUI_API void NavMoveRequestCancel(); 1062 IMGUI_API void ActivateItem(ImGuiID id); // Remotely activate a button, checkbox, tree node etc. given its unique ID. activation is queued and processed on the next frame when the item is encountered again. 1063 1064 IMGUI_API float GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode); 1065 IMGUI_API ImVec2 GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor = 0.0f, float fast_factor = 0.0f); 1066 IMGUI_API int CalcTypematicPressedRepeatAmount(float t, float t_prev, float repeat_delay, float repeat_rate); 1067 1068 IMGUI_API void Scrollbar(ImGuiLayoutType direction); 1069 IMGUI_API void VerticalSeparator(); // Vertical separator, for menu bars (use current line height). not exposed because it is misleading what it doesn't have an effect on regular layout. 1070 IMGUI_API bool SplitterBehavior(ImGuiID id, const ImRect& bb, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend = 0.0f); 1071 1072 IMGUI_API bool BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id); 1073 IMGUI_API void ClearDragDrop(); 1074 IMGUI_API bool IsDragDropPayloadBeingAccepted(); 1075 1076 // FIXME-WIP: New Columns API 1077 IMGUI_API void BeginColumns(const char* str_id, int count, ImGuiColumnsFlags flags = 0); // setup number of columns. use an identifier to distinguish multiple column sets. close with EndColumns(). 1078 IMGUI_API void EndColumns(); // close columns 1079 IMGUI_API void PushColumnClipRect(int column_index = -1); 1080 1081 // NB: All position are in absolute pixels coordinates (never using window coordinates internally) 1082 // AVOID USING OUTSIDE OF IMGUI.CPP! NOT FOR PUBLIC CONSUMPTION. THOSE FUNCTIONS ARE A MESS. THEIR SIGNATURE AND BEHAVIOR WILL CHANGE, THEY NEED TO BE REFACTORED INTO SOMETHING DECENT. 1083 IMGUI_API void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true); 1084 IMGUI_API void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width); 1085 IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL); 1086 IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); 1087 IMGUI_API void RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding = 0.0f); 1088 IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, int rounding_corners_flags = ~0); 1089 IMGUI_API void RenderArrow(ImVec2 pos, ImGuiDir dir, float scale = 1.0f); 1090 IMGUI_API void RenderBullet(ImVec2 pos); 1091 IMGUI_API void RenderCheckMark(ImVec2 pos, ImU32 col, float sz); 1092 IMGUI_API void RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags = ImGuiNavHighlightFlags_TypeDefault); // Navigation highlight 1093 IMGUI_API void RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding); 1094 IMGUI_API const char* FindRenderedTextEnd(const char* text, const char* text_end = NULL); // Find the optional ## from which we stop displaying text. 1095 1096 IMGUI_API bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags = 0); 1097 IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0); 1098 IMGUI_API bool CloseButton(ImGuiID id, const ImVec2& pos, float radius); 1099 1100 IMGUI_API bool SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_min, float v_max, const char* format, float power, ImGuiSliderFlags flags = 0); 1101 IMGUI_API bool SliderFloatN(const char* label, float* v, int components, float v_min, float v_max, const char* format, float power); 1102 IMGUI_API bool SliderIntN(const char* label, int* v, int components, int v_min, int v_max, const char* format); 1103 1104 IMGUI_API bool DragBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_speed, float v_min, float v_max, const char* format, float power); 1105 IMGUI_API bool DragFloatN(const char* label, float* v, int components, float v_speed, float v_min, float v_max, const char* format, float power); 1106 IMGUI_API bool DragIntN(const char* label, int* v, int components, float v_speed, int v_min, int v_max, const char* format); 1107 1108 IMGUI_API bool InputTextEx(const char* label, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback = NULL, void* user_data = NULL); 1109 IMGUI_API bool InputFloatN(const char* label, float* v, int components, const char* format, ImGuiInputTextFlags extra_flags); 1110 IMGUI_API bool InputIntN(const char* label, int* v, int components, ImGuiInputTextFlags extra_flags); 1111 IMGUI_API bool InputScalarEx(const char* label, ImGuiDataType data_type, void* data_ptr, void* step_ptr, void* step_fast_ptr, const char* format, ImGuiInputTextFlags extra_flags = 0); 1112 IMGUI_API bool InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* data_ptr, const char* format); 1113 1114 IMGUI_API void ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags); 1115 IMGUI_API void ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags); 1116 1117 IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL); 1118 IMGUI_API bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0); // Consume previous SetNextTreeNodeOpened() data, if any. May return true when logging 1119 IMGUI_API void TreePushRawID(ImGuiID id); 1120 1121 IMGUI_API void PlotEx(ImGuiPlotType plot_type, const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size); 1122 1123 IMGUI_API const char* ParseFormatTrimDecorationsLeading(const char* format); 1124 IMGUI_API const char* ParseFormatTrimDecorations(const char* format, char* buf, int buf_size); 1125 IMGUI_API int ParseFormatPrecision(const char* format, int default_value); 1126 IMGUI_API float RoundScalarWithFormat(const char* format, float value); 1127 1128 // Shade functions (write over already created vertices) 1129 IMGUI_API void ShadeVertsLinearColorGradientKeepAlpha(ImDrawVert* vert_start, ImDrawVert* vert_end, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1); 1130 IMGUI_API void ShadeVertsLinearAlphaGradientForLeftToRightText(ImDrawVert* vert_start, ImDrawVert* vert_end, float gradient_p0_x, float gradient_p1_x); 1131 IMGUI_API void ShadeVertsLinearUV(ImDrawVert* vert_start, ImDrawVert* vert_end, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp); 1781 // Windows 1782 // We should always have a CurrentWindow in the stack (there is an implicit "Debug" window) 1783 // If this ever crash because g.CurrentWindow is NULL it means that either 1784 // - ImGui::NewFrame() has never been called, which is illegal. 1785 // - You are calling ImGui functions after ImGui::EndFrame()/ImGui::Render() and before the next ImGui::NewFrame(), which is also illegal. 1786 inline ImGuiWindow* GetCurrentWindowRead() { ImGuiContext& g = *GImGui; return g.CurrentWindow; } 1787 inline ImGuiWindow* GetCurrentWindow() { ImGuiContext& g = *GImGui; g.CurrentWindow->WriteAccessed = true; return g.CurrentWindow; } 1788 IMGUI_API ImGuiWindow* FindWindowByID(ImGuiID id); 1789 IMGUI_API ImGuiWindow* FindWindowByName(const char* name); 1790 IMGUI_API void UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window); 1791 IMGUI_API ImVec2 CalcWindowExpectedSize(ImGuiWindow* window); 1792 IMGUI_API bool IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent); 1793 IMGUI_API bool IsWindowNavFocusable(ImGuiWindow* window); 1794 IMGUI_API ImRect GetWindowAllowedExtentRect(ImGuiWindow* window); 1795 IMGUI_API void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond = 0); 1796 IMGUI_API void SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond = 0); 1797 IMGUI_API void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond = 0); 1798 IMGUI_API void SetWindowHitTestHole(ImGuiWindow* window, const ImVec2& pos, const ImVec2& size); 1799 1800 // Windows: Display Order and Focus Order 1801 IMGUI_API void FocusWindow(ImGuiWindow* window); 1802 IMGUI_API void FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window); 1803 IMGUI_API void BringWindowToFocusFront(ImGuiWindow* window); 1804 IMGUI_API void BringWindowToDisplayFront(ImGuiWindow* window); 1805 IMGUI_API void BringWindowToDisplayBack(ImGuiWindow* window); 1806 1807 // Fonts, drawing 1808 IMGUI_API void SetCurrentFont(ImFont* font); 1809 inline ImFont* GetDefaultFont() { ImGuiContext& g = *GImGui; return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; } 1810 inline ImDrawList* GetForegroundDrawList(ImGuiWindow* window) { IM_UNUSED(window); ImGuiContext& g = *GImGui; return &g.ForegroundDrawList; } // This seemingly unnecessary wrapper simplifies compatibility between the 'master' and 'docking' branches. 1811 1812 // Init 1813 IMGUI_API void Initialize(ImGuiContext* context); 1814 IMGUI_API void Shutdown(ImGuiContext* context); // Since 1.60 this is a _private_ function. You can call DestroyContext() to destroy the context created by CreateContext(). 1815 1816 // NewFrame 1817 IMGUI_API void UpdateHoveredWindowAndCaptureFlags(); 1818 IMGUI_API void StartMouseMovingWindow(ImGuiWindow* window); 1819 IMGUI_API void UpdateMouseMovingWindowNewFrame(); 1820 IMGUI_API void UpdateMouseMovingWindowEndFrame(); 1821 1822 // Settings 1823 IMGUI_API void MarkIniSettingsDirty(); 1824 IMGUI_API void MarkIniSettingsDirty(ImGuiWindow* window); 1825 IMGUI_API void ClearIniSettings(); 1826 IMGUI_API ImGuiWindowSettings* CreateNewWindowSettings(const char* name); 1827 IMGUI_API ImGuiWindowSettings* FindWindowSettings(ImGuiID id); 1828 IMGUI_API ImGuiWindowSettings* FindOrCreateWindowSettings(const char* name); 1829 IMGUI_API ImGuiSettingsHandler* FindSettingsHandler(const char* type_name); 1830 1831 // Scrolling 1832 IMGUI_API void SetNextWindowScroll(const ImVec2& scroll); // Use -1.0f on one axis to leave as-is 1833 IMGUI_API void SetScrollX(ImGuiWindow* window, float scroll_x); 1834 IMGUI_API void SetScrollY(ImGuiWindow* window, float scroll_y); 1835 IMGUI_API void SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio); 1836 IMGUI_API void SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio); 1837 IMGUI_API ImVec2 ScrollToBringRectIntoView(ImGuiWindow* window, const ImRect& item_rect); 1838 1839 // Basic Accessors 1840 inline ImGuiID GetItemID() { ImGuiContext& g = *GImGui; return g.CurrentWindow->DC.LastItemId; } // Get ID of last item (~~ often same ImGui::GetID(label) beforehand) 1841 inline ImGuiItemStatusFlags GetItemStatusFlags() { ImGuiContext& g = *GImGui; return g.CurrentWindow->DC.LastItemStatusFlags; } 1842 inline ImGuiID GetActiveID() { ImGuiContext& g = *GImGui; return g.ActiveId; } 1843 inline ImGuiID GetFocusID() { ImGuiContext& g = *GImGui; return g.NavId; } 1844 IMGUI_API void SetActiveID(ImGuiID id, ImGuiWindow* window); 1845 IMGUI_API void SetFocusID(ImGuiID id, ImGuiWindow* window); 1846 IMGUI_API void ClearActiveID(); 1847 IMGUI_API ImGuiID GetHoveredID(); 1848 IMGUI_API void SetHoveredID(ImGuiID id); 1849 IMGUI_API void KeepAliveID(ImGuiID id); 1850 IMGUI_API void MarkItemEdited(ImGuiID id); // Mark data associated to given item as "edited", used by IsItemDeactivatedAfterEdit() function. 1851 IMGUI_API void PushOverrideID(ImGuiID id); // Push given value as-is at the top of the ID stack (whereas PushID combines old and new hashes) 1852 IMGUI_API ImGuiID GetIDWithSeed(const char* str_id_begin, const char* str_id_end, ImGuiID seed); 1853 1854 // Basic Helpers for widget code 1855 IMGUI_API void ItemSize(const ImVec2& size, float text_baseline_y = -1.0f); 1856 IMGUI_API void ItemSize(const ImRect& bb, float text_baseline_y = -1.0f); 1857 IMGUI_API bool ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb = NULL); 1858 IMGUI_API bool ItemHoverable(const ImRect& bb, ImGuiID id); 1859 IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged); 1860 IMGUI_API void SetLastItemData(ImGuiWindow* window, ImGuiID item_id, ImGuiItemStatusFlags status_flags, const ImRect& item_rect); 1861 IMGUI_API bool FocusableItemRegister(ImGuiWindow* window, ImGuiID id); // Return true if focus is requested 1862 IMGUI_API void FocusableItemUnregister(ImGuiWindow* window); 1863 IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_w, float default_h); 1864 IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x); 1865 IMGUI_API void PushMultiItemsWidths(int components, float width_full); 1866 IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled); 1867 IMGUI_API void PopItemFlag(); 1868 IMGUI_API bool IsItemToggledSelection(); // Was the last item selection toggled? (after Selectable(), TreeNode() etc. We only returns toggle _event_ in order to handle clipping correctly) 1869 IMGUI_API ImVec2 GetContentRegionMaxAbs(); 1870 IMGUI_API void ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess); 1871 1872 // Logging/Capture 1873 IMGUI_API void LogBegin(ImGuiLogType type, int auto_open_depth); // -> BeginCapture() when we design v2 api, for now stay under the radar by using the old name. 1874 IMGUI_API void LogToBuffer(int auto_open_depth = -1); // Start logging/capturing to internal buffer 1875 1876 // Popups, Modals, Tooltips 1877 IMGUI_API bool BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags); 1878 IMGUI_API void OpenPopupEx(ImGuiID id, ImGuiPopupFlags popup_flags = ImGuiPopupFlags_None); 1879 IMGUI_API void ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup); 1880 IMGUI_API void ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup); 1881 IMGUI_API bool IsPopupOpen(ImGuiID id, ImGuiPopupFlags popup_flags); 1882 IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags); 1883 IMGUI_API void BeginTooltipEx(ImGuiWindowFlags extra_flags, ImGuiTooltipFlags tooltip_flags); 1884 IMGUI_API ImGuiWindow* GetTopMostPopupModal(); 1885 IMGUI_API ImVec2 FindBestWindowPosForPopup(ImGuiWindow* window); 1886 IMGUI_API ImVec2 FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy); 1887 1888 // Gamepad/Keyboard Navigation 1889 IMGUI_API void NavInitWindow(ImGuiWindow* window, bool force_reinit); 1890 IMGUI_API bool NavMoveRequestButNoResultYet(); 1891 IMGUI_API void NavMoveRequestCancel(); 1892 IMGUI_API void NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, const ImRect& bb_rel, ImGuiNavMoveFlags move_flags); 1893 IMGUI_API void NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags); 1894 IMGUI_API float GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode); 1895 IMGUI_API ImVec2 GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor = 0.0f, float fast_factor = 0.0f); 1896 IMGUI_API int CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate); 1897 IMGUI_API void ActivateItem(ImGuiID id); // Remotely activate a button, checkbox, tree node etc. given its unique ID. activation is queued and processed on the next frame when the item is encountered again. 1898 IMGUI_API void SetNavID(ImGuiID id, int nav_layer, ImGuiID focus_scope_id); 1899 IMGUI_API void SetNavIDWithRectRel(ImGuiID id, int nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel); 1900 1901 // Focus Scope (WIP) 1902 // This is generally used to identify a selection set (multiple of which may be in the same window), as selection 1903 // patterns generally need to react (e.g. clear selection) when landing on an item of the set. 1904 IMGUI_API void PushFocusScope(ImGuiID id); 1905 IMGUI_API void PopFocusScope(); 1906 inline ImGuiID GetFocusScopeID() { ImGuiContext& g = *GImGui; return g.NavFocusScopeId; } 1907 1908 // Inputs 1909 // FIXME: Eventually we should aim to move e.g. IsActiveIdUsingKey() into IsKeyXXX functions. 1910 inline bool IsActiveIdUsingNavDir(ImGuiDir dir) { ImGuiContext& g = *GImGui; return (g.ActiveIdUsingNavDirMask & (1 << dir)) != 0; } 1911 inline bool IsActiveIdUsingNavInput(ImGuiNavInput input) { ImGuiContext& g = *GImGui; return (g.ActiveIdUsingNavInputMask & (1 << input)) != 0; } 1912 inline bool IsActiveIdUsingKey(ImGuiKey key) { ImGuiContext& g = *GImGui; IM_ASSERT(key < 64); return (g.ActiveIdUsingKeyInputMask & ((ImU64)1 << key)) != 0; } 1913 IMGUI_API bool IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold = -1.0f); 1914 inline bool IsKeyPressedMap(ImGuiKey key, bool repeat = true) { ImGuiContext& g = *GImGui; const int key_index = g.IO.KeyMap[key]; return (key_index >= 0) ? IsKeyPressed(key_index, repeat) : false; } 1915 inline bool IsNavInputDown(ImGuiNavInput n) { ImGuiContext& g = *GImGui; return g.IO.NavInputs[n] > 0.0f; } 1916 inline bool IsNavInputTest(ImGuiNavInput n, ImGuiInputReadMode rm) { return (GetNavInputAmount(n, rm) > 0.0f); } 1917 IMGUI_API ImGuiKeyModFlags GetMergedKeyModFlags(); 1918 1919 // Drag and Drop 1920 IMGUI_API bool BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id); 1921 IMGUI_API void ClearDragDrop(); 1922 IMGUI_API bool IsDragDropPayloadBeingAccepted(); 1923 1924 // Internal Columns API (this is not exposed because we will encourage transitioning to the Tables API) 1925 IMGUI_API void SetWindowClipRectBeforeSetChannel(ImGuiWindow* window, const ImRect& clip_rect); 1926 IMGUI_API void BeginColumns(const char* str_id, int count, ImGuiColumnsFlags flags = 0); // setup number of columns. use an identifier to distinguish multiple column sets. close with EndColumns(). 1927 IMGUI_API void EndColumns(); // close columns 1928 IMGUI_API void PushColumnClipRect(int column_index); 1929 IMGUI_API void PushColumnsBackground(); 1930 IMGUI_API void PopColumnsBackground(); 1931 IMGUI_API ImGuiID GetColumnsID(const char* str_id, int count); 1932 IMGUI_API ImGuiColumns* FindOrCreateColumns(ImGuiWindow* window, ImGuiID id); 1933 IMGUI_API float GetColumnOffsetFromNorm(const ImGuiColumns* columns, float offset_norm); 1934 IMGUI_API float GetColumnNormFromOffset(const ImGuiColumns* columns, float offset); 1935 1936 // Tab Bars 1937 IMGUI_API bool BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags); 1938 IMGUI_API ImGuiTabItem* TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id); 1939 IMGUI_API void TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id); 1940 IMGUI_API void TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); 1941 IMGUI_API void TabBarQueueReorder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int dir); 1942 IMGUI_API bool TabBarProcessReorder(ImGuiTabBar* tab_bar); 1943 IMGUI_API bool TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags); 1944 IMGUI_API ImVec2 TabItemCalcSize(const char* label, bool has_close_button); 1945 IMGUI_API void TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col); 1946 IMGUI_API bool TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImVec2 frame_padding, const char* label, ImGuiID tab_id, ImGuiID close_button_id, bool is_contents_visible); 1947 1948 // Render helpers 1949 // AVOID USING OUTSIDE OF IMGUI.CPP! NOT FOR PUBLIC CONSUMPTION. THOSE FUNCTIONS ARE A MESS. THEIR SIGNATURE AND BEHAVIOR WILL CHANGE, THEY NEED TO BE REFACTORED INTO SOMETHING DECENT. 1950 // NB: All position are in absolute pixels coordinates (we are never using window coordinates internally) 1951 IMGUI_API void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true); 1952 IMGUI_API void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width); 1953 IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL); 1954 IMGUI_API void RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL); 1955 IMGUI_API void RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end, const ImVec2* text_size_if_known); 1956 IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); 1957 IMGUI_API void RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding = 0.0f); 1958 IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, int rounding_corners_flags = ~0); 1959 IMGUI_API void RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags = ImGuiNavHighlightFlags_TypeDefault); // Navigation highlight 1960 IMGUI_API const char* FindRenderedTextEnd(const char* text, const char* text_end = NULL); // Find the optional ## from which we stop displaying text. 1961 IMGUI_API void LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end = NULL); 1962 1963 // Render helpers (those functions don't access any ImGui state!) 1964 IMGUI_API void RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir dir, float scale = 1.0f); 1965 IMGUI_API void RenderBullet(ImDrawList* draw_list, ImVec2 pos, ImU32 col); 1966 IMGUI_API void RenderCheckMark(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz); 1967 IMGUI_API void RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow); 1968 IMGUI_API void RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col); 1969 IMGUI_API void RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding); 1970 IMGUI_API void RenderRectFilledWithHole(ImDrawList* draw_list, ImRect outer, ImRect inner, ImU32 col, float rounding); 1971 1972 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS 1973 // [1.71: 2019/06/07: Updating prototypes of some of the internal functions. Leaving those for reference for a short while] 1974 inline void RenderArrow(ImVec2 pos, ImGuiDir dir, float scale=1.0f) { ImGuiWindow* window = GetCurrentWindow(); RenderArrow(window->DrawList, pos, GetColorU32(ImGuiCol_Text), dir, scale); } 1975 inline void RenderBullet(ImVec2 pos) { ImGuiWindow* window = GetCurrentWindow(); RenderBullet(window->DrawList, pos, GetColorU32(ImGuiCol_Text)); } 1976 #endif 1977 1978 // Widgets 1979 IMGUI_API void TextEx(const char* text, const char* text_end = NULL, ImGuiTextFlags flags = 0); 1980 IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0); 1981 IMGUI_API bool CloseButton(ImGuiID id, const ImVec2& pos); 1982 IMGUI_API bool CollapseButton(ImGuiID id, const ImVec2& pos); 1983 IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags = 0); 1984 IMGUI_API void Scrollbar(ImGuiAxis axis); 1985 IMGUI_API bool ScrollbarEx(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* p_scroll_v, float avail_v, float contents_v, ImDrawCornerFlags rounding_corners); 1986 IMGUI_API bool ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec2& padding, const ImVec4& bg_col, const ImVec4& tint_col); 1987 IMGUI_API ImRect GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis); 1988 IMGUI_API ImGuiID GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis); 1989 IMGUI_API ImGuiID GetWindowResizeID(ImGuiWindow* window, int n); // 0..3: corners, 4..7: borders 1990 IMGUI_API void SeparatorEx(ImGuiSeparatorFlags flags); 1991 1992 // Widgets low-level behaviors 1993 IMGUI_API bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags = 0); 1994 IMGUI_API bool DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags); 1995 IMGUI_API bool SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* p_v, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb); 1996 IMGUI_API bool SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend = 0.0f, float hover_visibility_delay = 0.0f); 1997 IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL); 1998 IMGUI_API bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0); // Consume previous SetNextItemOpen() data, if any. May return true when logging 1999 IMGUI_API void TreePushOverrideID(ImGuiID id); 2000 2001 // Template functions are instantiated in imgui_widgets.cpp for a finite number of types. 2002 // To use them externally (for custom widget) you may need an "extern template" statement in your code in order to link to existing instances and silence Clang warnings (see #2036). 2003 // e.g. " extern template IMGUI_API float RoundScalarWithFormatT<float, float>(const char* format, ImGuiDataType data_type, float v); " 2004 template<typename T, typename SIGNED_T, typename FLOAT_T> IMGUI_API float ScaleRatioFromValueT(ImGuiDataType data_type, T v, T v_min, T v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_size); 2005 template<typename T, typename SIGNED_T, typename FLOAT_T> IMGUI_API T ScaleValueFromRatioT(ImGuiDataType data_type, float t, T v_min, T v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_size); 2006 template<typename T, typename SIGNED_T, typename FLOAT_T> IMGUI_API bool DragBehaviorT(ImGuiDataType data_type, T* v, float v_speed, T v_min, T v_max, const char* format, ImGuiSliderFlags flags); 2007 template<typename T, typename SIGNED_T, typename FLOAT_T> IMGUI_API bool SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, T* v, T v_min, T v_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb); 2008 template<typename T, typename SIGNED_T> IMGUI_API T RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, T v); 2009 2010 // Data type helpers 2011 IMGUI_API const ImGuiDataTypeInfo* DataTypeGetInfo(ImGuiDataType data_type); 2012 IMGUI_API int DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* p_data, const char* format); 2013 IMGUI_API void DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, const void* arg_1, const void* arg_2); 2014 IMGUI_API bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* p_data, const char* format); 2015 IMGUI_API int DataTypeCompare(ImGuiDataType data_type, const void* arg_1, const void* arg_2); 2016 IMGUI_API bool DataTypeClamp(ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max); 2017 2018 // InputText 2019 IMGUI_API bool InputTextEx(const char* label, const char* hint, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); 2020 IMGUI_API bool TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* buf, int buf_size, ImGuiInputTextFlags flags); 2021 IMGUI_API bool TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format, const void* p_clamp_min = NULL, const void* p_clamp_max = NULL); 2022 inline bool TempInputIsActive(ImGuiID id) { ImGuiContext& g = *GImGui; return (g.ActiveId == id && g.TempInputId == id); } 2023 inline ImGuiInputTextState* GetInputTextState(ImGuiID id) { ImGuiContext& g = *GImGui; return (g.InputTextState.ID == id) ? &g.InputTextState : NULL; } // Get input text state if active 2024 2025 // Color 2026 IMGUI_API void ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags); 2027 IMGUI_API void ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags); 2028 IMGUI_API void ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags flags); 2029 2030 // Plot 2031 IMGUI_API int PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 frame_size); 2032 2033 // Shade functions (write over already created vertices) 2034 IMGUI_API void ShadeVertsLinearColorGradientKeepAlpha(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1); 2035 IMGUI_API void ShadeVertsLinearUV(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp); 2036 2037 // Garbage collection 2038 IMGUI_API void GcCompactTransientWindowBuffers(ImGuiWindow* window); 2039 IMGUI_API void GcAwakeTransientWindowBuffers(ImGuiWindow* window); 2040 2041 // Debug Tools 2042 inline void DebugDrawItemRect(ImU32 col = IM_COL32(255,0,0,255)) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; GetForegroundDrawList(window)->AddRect(window->DC.LastItemRect.Min, window->DC.LastItemRect.Max, col); } 2043 inline void DebugStartItemPicker() { ImGuiContext& g = *GImGui; g.DebugItemPickerActive = true; } 1132 2044 1133 2045 } // namespace ImGui 1134 2046 1135 2047 // ImFontAtlas internals 1136 2048 IMGUI_API bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas); 1137 IMGUI_API void ImFontAtlasBuild RegisterDefaultCustomRects(ImFontAtlas* atlas);2049 IMGUI_API void ImFontAtlasBuildInit(ImFontAtlas* atlas); 1138 2050 IMGUI_API void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent); 1139 IMGUI_API void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* s pc);2051 IMGUI_API void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque); 1140 2052 IMGUI_API void ImFontAtlasBuildFinish(ImFontAtlas* atlas); 2053 IMGUI_API void ImFontAtlasBuildRender1bppRectFromString(ImFontAtlas* atlas, int atlas_x, int atlas_y, int w, int h, const char* in_str, char in_marker_char, unsigned char in_marker_pixel_value); 1141 2054 IMGUI_API void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_multiply_factor); 1142 2055 IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride); 1143 2056 1144 #ifdef __clang__ 2057 //----------------------------------------------------------------------------- 2058 // [SECTION] Test Engine Hooks (imgui_test_engine) 2059 //----------------------------------------------------------------------------- 2060 2061 #ifdef IMGUI_ENABLE_TEST_ENGINE 2062 extern void ImGuiTestEngineHook_Shutdown(ImGuiContext* ctx); 2063 extern void ImGuiTestEngineHook_PreNewFrame(ImGuiContext* ctx); 2064 extern void ImGuiTestEngineHook_PostNewFrame(ImGuiContext* ctx); 2065 extern void ImGuiTestEngineHook_ItemAdd(ImGuiContext* ctx, const ImRect& bb, ImGuiID id); 2066 extern void ImGuiTestEngineHook_ItemInfo(ImGuiContext* ctx, ImGuiID id, const char* label, ImGuiItemStatusFlags flags); 2067 extern void ImGuiTestEngineHook_IdInfo(ImGuiContext* ctx, ImGuiDataType data_type, ImGuiID id, const void* data_id); 2068 extern void ImGuiTestEngineHook_IdInfo(ImGuiContext* ctx, ImGuiDataType data_type, ImGuiID id, const void* data_id, const void* data_id_end); 2069 extern void ImGuiTestEngineHook_Log(ImGuiContext* ctx, const char* fmt, ...); 2070 #define IMGUI_TEST_ENGINE_ITEM_ADD(_BB,_ID) if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemAdd(&g, _BB, _ID) // Register item bounding box 2071 #define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemInfo(&g, _ID, _LABEL, _FLAGS) // Register item label and status flags (optional) 2072 #define IMGUI_TEST_ENGINE_LOG(_FMT,...) if (g.TestEngineHookItems) ImGuiTestEngineHook_Log(&g, _FMT, __VA_ARGS__) // Custom log entry from user land into test log 2073 #define IMGUI_TEST_ENGINE_ID_INFO(_ID,_TYPE,_DATA) if (g.TestEngineHookIdInfo == id) ImGuiTestEngineHook_IdInfo(&g, _TYPE, _ID, (const void*)(_DATA)); 2074 #define IMGUI_TEST_ENGINE_ID_INFO2(_ID,_TYPE,_DATA,_DATA2) if (g.TestEngineHookIdInfo == id) ImGuiTestEngineHook_IdInfo(&g, _TYPE, _ID, (const void*)(_DATA), (const void*)(_DATA2)); 2075 #else 2076 #define IMGUI_TEST_ENGINE_ITEM_ADD(_BB,_ID) do { } while (0) 2077 #define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) do { } while (0) 2078 #define IMGUI_TEST_ENGINE_LOG(_FMT,...) do { } while (0) 2079 #define IMGUI_TEST_ENGINE_ID_INFO(_ID,_TYPE,_DATA) do { } while (0) 2080 #define IMGUI_TEST_ENGINE_ID_INFO2(_ID,_TYPE,_DATA,_DATA2) do { } while (0) 2081 #endif 2082 2083 #if defined(__clang__) 1145 2084 #pragma clang diagnostic pop 2085 #elif defined(__GNUC__) 2086 #pragma GCC diagnostic pop 1146 2087 #endif 1147 2088 … … 1149 2090 #pragma warning (pop) 1150 2091 #endif 2092 2093 #endif // #ifndef IMGUI_DISABLE -
IMGUI/imstb_rectpack.h
r78c3045 re66fd66 1 // stb_rect_pack.h - v0.11 - public domain - rectangle packing 1 // [DEAR IMGUI] 2 // This is a slightly modified version of stb_rect_pack.h 1.00. 3 // Those changes would need to be pushed into nothings/stb: 4 // - Added STBRP__CDECL 5 // Grep for [DEAR IMGUI] to find the changes. 6 7 // stb_rect_pack.h - v1.00 - public domain - rectangle packing 2 8 // Sean Barrett 2014 3 9 // … … 32 38 // Bugfixes / warning fixes 33 39 // Jeremy Jaussaud 40 // Fabian Giesen 34 41 // 35 42 // Version history: 36 43 // 44 // 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles 45 // 0.99 (2019-02-07) warning fixes 37 46 // 0.11 (2017-03-03) return packing success/fail result 38 47 // 0.10 (2016-10-25) remove cast-away-const to avoid warnings … … 69 78 #endif 70 79 71 72 73 80 typedef struct stbrp_context stbrp_context; 81 typedef struct stbrp_node stbrp_node; 82 typedef struct stbrp_rect stbrp_rect; 74 83 75 84 #ifdef STBRP_LARGE_RECTS 76 85 typedef int stbrp_coord; 77 86 #else 78 79 #endif 80 81 STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects);82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem);143 144 145 146 147 148 STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic);149 150 151 152 153 154 155 STBRP_HEURISTIC_Skyline_default =0,156 157 158 159 160 161 162 163 164 165 166 167 168 stbrp_coord x,y;169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 87 typedef unsigned short stbrp_coord; 88 #endif 89 90 STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects); 91 // Assign packed locations to rectangles. The rectangles are of type 92 // 'stbrp_rect' defined below, stored in the array 'rects', and there 93 // are 'num_rects' many of them. 94 // 95 // Rectangles which are successfully packed have the 'was_packed' flag 96 // set to a non-zero value and 'x' and 'y' store the minimum location 97 // on each axis (i.e. bottom-left in cartesian coordinates, top-left 98 // if you imagine y increasing downwards). Rectangles which do not fit 99 // have the 'was_packed' flag set to 0. 100 // 101 // You should not try to access the 'rects' array from another thread 102 // while this function is running, as the function temporarily reorders 103 // the array while it executes. 104 // 105 // To pack into another rectangle, you need to call stbrp_init_target 106 // again. To continue packing into the same rectangle, you can call 107 // this function again. Calling this multiple times with multiple rect 108 // arrays will probably produce worse packing results than calling it 109 // a single time with the full rectangle array, but the option is 110 // available. 111 // 112 // The function returns 1 if all of the rectangles were successfully 113 // packed and 0 otherwise. 114 115 struct stbrp_rect 116 { 117 // reserved for your use: 118 int id; 119 120 // input: 121 stbrp_coord w, h; 122 123 // output: 124 stbrp_coord x, y; 125 int was_packed; // non-zero if valid packing 126 127 }; // 16 bytes, nominally 128 129 130 STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes); 131 // Initialize a rectangle packer to: 132 // pack a rectangle that is 'width' by 'height' in dimensions 133 // using temporary storage provided by the array 'nodes', which is 'num_nodes' long 134 // 135 // You must call this function every time you start packing into a new target. 136 // 137 // There is no "shutdown" function. The 'nodes' memory must stay valid for 138 // the following stbrp_pack_rects() call (or calls), but can be freed after 139 // the call (or calls) finish. 140 // 141 // Note: to guarantee best results, either: 142 // 1. make sure 'num_nodes' >= 'width' 143 // or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1' 144 // 145 // If you don't do either of the above things, widths will be quantized to multiples 146 // of small integers to guarantee the algorithm doesn't run out of temporary storage. 147 // 148 // If you do #2, then the non-quantized algorithm will be used, but the algorithm 149 // may run out of temporary storage and be unable to pack some rectangles. 150 151 STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem); 152 // Optionally call this function after init but before doing any packing to 153 // change the handling of the out-of-temp-memory scenario, described above. 154 // If you call init again, this will be reset to the default (false). 155 156 157 STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic); 158 // Optionally select which packing heuristic the library should use. Different 159 // heuristics will produce better/worse results for different data sets. 160 // If you call init again, this will be reset to the default. 161 162 enum 163 { 164 STBRP_HEURISTIC_Skyline_default=0, 165 STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default, 166 STBRP_HEURISTIC_Skyline_BF_sortHeight 167 }; 168 169 170 ////////////////////////////////////////////////////////////////////////////// 171 // 172 // the details of the following structures don't matter to you, but they must 173 // be visible so you can handle the memory allocations for them 174 175 struct stbrp_node 176 { 177 stbrp_coord x,y; 178 stbrp_node *next; 179 }; 180 181 struct stbrp_context 182 { 183 int width; 184 int height; 185 int align; 186 int init_mode; 187 int heuristic; 188 int num_nodes; 189 stbrp_node *active_head; 190 stbrp_node *free_head; 191 stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2' 192 }; 184 193 185 194 #ifdef __cplusplus … … 205 214 #endif 206 215 216 // [DEAR IMGUI] Added STBRP__CDECL 207 217 #ifdef _MSC_VER 208 218 #define STBRP__NOTUSED(v) (void)(v) … … 221 231 { 222 232 switch (context->init_mode) { 223 case STBRP__INIT_skyline:224 STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);225 context->heuristic = heuristic;226 break;227 default:228 STBRP_ASSERT(0);233 case STBRP__INIT_skyline: 234 STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight); 235 context->heuristic = heuristic; 236 break; 237 default: 238 STBRP_ASSERT(0); 229 239 } 230 240 } … … 246 256 // align = ceil(width/num_nodes) 247 257 248 context->align = (context->width + context->num_nodes -1) / context->num_nodes;258 context->align = (context->width + context->num_nodes-1) / context->num_nodes; 249 259 } 250 260 } … … 257 267 #endif 258 268 259 for (i = 0; i < num_nodes -1; ++i)260 nodes[i].next = &nodes[i +1];269 for (i=0; i < num_nodes-1; ++i) 270 nodes[i].next = &nodes[i+1]; 261 271 nodes[i].next = NULL; 262 272 context->init_mode = STBRP__INIT_skyline; … … 273 283 context->extra[0].y = 0; 274 284 context->extra[0].next = &context->extra[1]; 275 context->extra[1].x = (stbrp_coord) width;285 context->extra[1].x = (stbrp_coord) width; 276 286 #ifdef STBRP_LARGE_RECTS 277 context->extra[1].y = (1 <<30);287 context->extra[1].y = (1<<30); 278 288 #else 279 289 context->extra[1].y = 65535; … … 293 303 STBRP_ASSERT(first->x <= x0); 294 304 295 #if 0305 #if 0 296 306 // skip in case we're past the node 297 307 while (node->next->x <= x0) 298 308 ++node; 299 #else309 #else 300 310 STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency 301 #endif311 #endif 302 312 303 313 STBRP_ASSERT(node->x <= x0); … … 318 328 else 319 329 visited_width += node->next->x - node->x; 320 } 321 else { 330 } else { 322 331 // add waste area 323 332 int under_width = node->next->x - node->x; … … 336 345 typedef struct 337 346 { 338 int x, 347 int x,y; 339 348 stbrp_node **prev_link; 340 349 } stbrp__findresult; … … 342 351 static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height) 343 352 { 344 int best_waste = (1 <<30), best_x, best_y = (1 << 30);353 int best_waste = (1<<30), best_x, best_y = (1 << 30); 345 354 stbrp__findresult fr; 346 355 stbrp_node **prev, *node, *tail, **best = NULL; … … 351 360 STBRP_ASSERT(width % c->align == 0); 352 361 362 // if it can't possibly fit, bail immediately 363 if (width > c->width || height > c->height) { 364 fr.prev_link = NULL; 365 fr.x = fr.y = 0; 366 return fr; 367 } 368 353 369 node = c->active_head; 354 370 prev = &c->active_head; 355 371 while (node->x + width <= c->width) { 356 int y, 372 int y,waste; 357 373 y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste); 358 374 if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL 359 375 // bottom left 360 376 if (y < best_y) { 361 377 best_y = y; 362 378 best = prev; 363 379 } 364 } 365 else { 380 } else { 366 381 // best-fit 367 382 if (y + height <= c->height) { … … 406 421 while (tail) { 407 422 int xpos = tail->x - width; 408 int y, 423 int y,waste; 409 424 STBRP_ASSERT(xpos >= 0); 410 425 // find the left position that matches this … … 415 430 STBRP_ASSERT(node->next->x > xpos && node->x <= xpos); 416 431 y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste); 417 if (y + height < c->height) {432 if (y + height <= c->height) { 418 433 if (y <= best_y) { 419 if (y < best_y || waste < best_waste || (waste ==best_waste && xpos < best_x)) {434 if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) { 420 435 best_x = xpos; 421 436 STBRP_ASSERT(y <= best_y); … … 427 442 } 428 443 tail = tail->next; 429 } 444 } 430 445 } 431 446 … … 453 468 // on success, create new node 454 469 node = context->free_head; 455 node->x = (stbrp_coord) res.x;456 node->y = (stbrp_coord) (res.y + height);470 node->x = (stbrp_coord) res.x; 471 node->y = (stbrp_coord) (res.y + height); 457 472 458 473 context->free_head = node->next; … … 468 483 cur->next = node; 469 484 cur = next; 470 } 471 else { 485 } else { 472 486 *res.prev_link = node; 473 487 } … … 487 501 488 502 if (cur->x < res.x + width) 489 cur->x = (stbrp_coord) (res.x + width);503 cur->x = (stbrp_coord) (res.x + width); 490 504 491 505 #ifdef _DEBUG … … 498 512 499 513 { 500 int count =0;514 int count=0; 501 515 cur = context->active_head; 502 516 while (cur) { … … 509 523 ++count; 510 524 } 511 STBRP_ASSERT(count == context->num_nodes +2);525 STBRP_ASSERT(count == context->num_nodes+2); 512 526 } 513 527 #endif … … 516 530 } 517 531 532 // [DEAR IMGUI] Added STBRP__CDECL 518 533 static int STBRP__CDECL rect_height_compare(const void *a, const void *b) 519 534 { 520 const stbrp_rect *p = (const stbrp_rect *) a;521 const stbrp_rect *q = (const stbrp_rect *) b;535 const stbrp_rect *p = (const stbrp_rect *) a; 536 const stbrp_rect *q = (const stbrp_rect *) b; 522 537 if (p->h > q->h) 523 538 return -1; … … 527 542 } 528 543 544 // [DEAR IMGUI] Added STBRP__CDECL 529 545 static int STBRP__CDECL rect_original_order(const void *a, const void *b) 530 546 { 531 const stbrp_rect *p = (const stbrp_rect *) a;532 const stbrp_rect *q = (const stbrp_rect *) b;547 const stbrp_rect *p = (const stbrp_rect *) a; 548 const stbrp_rect *q = (const stbrp_rect *) b; 533 549 return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); 534 550 } … … 545 561 546 562 // we use the 'was_packed' field internally to allow sorting/unsorting 547 for (i =0; i < num_rects; ++i) {563 for (i=0; i < num_rects; ++i) { 548 564 rects[i].was_packed = i; 549 #ifndef STBRP_LARGE_RECTS550 STBRP_ASSERT(rects[i].w <= 0xffff && rects[i].h <= 0xffff);551 #endif552 565 } 553 566 … … 555 568 STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare); 556 569 557 for (i =0; i < num_rects; ++i) {570 for (i=0; i < num_rects; ++i) { 558 571 if (rects[i].w == 0 || rects[i].h == 0) { 559 572 rects[i].x = rects[i].y = 0; // empty rect needs no space 560 } 561 else { 573 } else { 562 574 stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h); 563 575 if (fr.prev_link) { 564 rects[i].x = (stbrp_coord)fr.x; 565 rects[i].y = (stbrp_coord)fr.y; 566 } 567 else { 576 rects[i].x = (stbrp_coord) fr.x; 577 rects[i].y = (stbrp_coord) fr.y; 578 } else { 568 579 rects[i].x = rects[i].y = STBRP__MAXVAL; 569 580 } … … 575 586 576 587 // set was_packed flags and all_rects_packed status 577 for (i =0; i < num_rects; ++i) {588 for (i=0; i < num_rects; ++i) { 578 589 rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL); 579 590 if (!rects[i].was_packed) … … 592 603 ALTERNATIVE A - MIT License 593 604 Copyright (c) 2017 Sean Barrett 594 Permission is hereby granted, free of charge, to any person obtaining a copy of 595 this software and associated documentation files (the "Software"), to deal in 596 the Software without restriction, including without limitation the rights to 597 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 598 of the Software, and to permit persons to whom the Software is furnished to do 605 Permission is hereby granted, free of charge, to any person obtaining a copy of 606 this software and associated documentation files (the "Software"), to deal in 607 the Software without restriction, including without limitation the rights to 608 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 609 of the Software, and to permit persons to whom the Software is furnished to do 599 610 so, subject to the following conditions: 600 The above copyright notice and this permission notice shall be included in all 611 The above copyright notice and this permission notice shall be included in all 601 612 copies or substantial portions of the Software. 602 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 603 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 604 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 605 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 606 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 607 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 613 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 614 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 615 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 616 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 617 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 618 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 608 619 SOFTWARE. 609 620 ------------------------------------------------------------------------------ 610 621 ALTERNATIVE B - Public Domain (www.unlicense.org) 611 622 This is free and unencumbered software released into the public domain. 612 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 613 software, either in source code form or as a compiled binary, for any purpose, 623 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 624 software, either in source code form or as a compiled binary, for any purpose, 614 625 commercial or non-commercial, and by any means. 615 In jurisdictions that recognize copyright laws, the author or authors of this 616 software dedicate any and all copyright interest in the software to the public 617 domain. We make this dedication for the benefit of the public at large and to 618 the detriment of our heirs and successors. We intend this dedication to be an 619 overt act of relinquishment in perpetuity of all present and future rights to 626 In jurisdictions that recognize copyright laws, the author or authors of this 627 software dedicate any and all copyright interest in the software to the public 628 domain. We make this dedication for the benefit of the public at large and to 629 the detriment of our heirs and successors. We intend this dedication to be an 630 overt act of relinquishment in perpetuity of all present and future rights to 620 631 this software under copyright law. 621 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 622 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 623 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 624 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 625 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 632 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 633 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 634 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 635 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 636 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 626 637 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 627 638 ------------------------------------------------------------------------------ -
IMGUI/imstb_textedit.h
r78c3045 re66fd66 1 // [ ImGui] this is a slightly modified version of stb_truetype.h 1.9. Those changes would need to be pushed into nothings/sb2 // [ImGui] - fixed linestart handler when over last character of multi-line buffer + simplified existing code (#588, #815)3 // [ImGui] - fixed a state corruption/crash bug in stb_text_redo and stb_textedit_discard_redo (#715)4 // [ImGui] - fixed a crash bug in stb_textedit_discard_redo (#681)5 // [ImGui] - fixed some minor warnings6 7 // stb_textedit.h - v1. 9- public domain - Sean Barrett1 // [DEAR IMGUI] 2 // This is a slightly modified version of stb_textedit.h 1.13. 3 // Those changes would need to be pushed into nothings/stb: 4 // - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321) 5 // Grep for [DEAR IMGUI] to find the changes. 6 7 // stb_textedit.h - v1.13 - public domain - Sean Barrett 8 8 // Development of this library was sponsored by RAD Game Tools 9 9 // … … 24 24 // LICENSE 25 25 // 26 // This software is dual-licensed to the public domain and under the following 27 // license: you are granted a perpetual, irrevocable license to copy, modify, 28 // publish, and distribute this file as you see fit. 26 // See end of file for license information. 29 27 // 30 28 // … … 38 36 // VERSION HISTORY 39 37 // 38 // 1.13 (2019-02-07) fix bug in undo size management 39 // 1.12 (2018-01-29) user can change STB_TEXTEDIT_KEYTYPE, fix redo to avoid crash 40 // 1.11 (2017-03-03) fix HOME on last line, dragging off single-line textfield 41 // 1.10 (2016-10-25) supress warnings about casting away const with -Wcast-qual 40 42 // 1.9 (2016-08-27) customizable move-by-word 41 43 // 1.8 (2016-04-02) better keyboard handling when mouse button is down … … 56 58 // Ulf Winklemann: move-by-word in 1.1 57 59 // Fabian Giesen: secondary key inputs in 1.5 58 // Martins Mozeiko: STB_TEXTEDIT_memmove 60 // Martins Mozeiko: STB_TEXTEDIT_memmove in 1.6 59 61 // 60 62 // Bugfixes: … … 62 64 // Daniel Keller 63 65 // Omar Cornut 66 // Dan Thompson 64 67 // 65 68 // USAGE … … 91 94 // it grows STB_TexteditState by the worst-case storage which is (in bytes): 92 95 // 93 // [4 + sizeof(STB_TEXTEDIT_POSITIONTYPE)] * STB_TEXTEDIT_UNDOSTATE_COUNT94 // + sizeof(STB_TEXTEDIT_CHARTYPE) * STB_TEXTEDIT_UNDOCHAR_COUNT96 // [4 + 3 * sizeof(STB_TEXTEDIT_POSITIONTYPE)] * STB_TEXTEDIT_UNDOSTATE_COUNT 97 // + sizeof(STB_TEXTEDIT_CHARTYPE) * STB_TEXTEDIT_UNDOCHAR_COUNT 95 98 // 96 99 // … … 115 118 // 116 119 // STB_TEXTEDIT_CHARTYPE the character type 117 // STB_TEXTEDIT_POSITIONTYPE small type that a valid cursor position120 // STB_TEXTEDIT_POSITIONTYPE small type that is a valid cursor position 118 121 // STB_TEXTEDIT_UNDOSTATECOUNT the number of undo states to allow 119 122 // STB_TEXTEDIT_UNDOCHARCOUNT the number of characters to store in the undo buffer … … 146 149 // STB_TEXTEDIT_K_UP keyboard input to move cursor up 147 150 // STB_TEXTEDIT_K_DOWN keyboard input to move cursor down 151 // STB_TEXTEDIT_K_PGUP keyboard input to move cursor up a page 152 // STB_TEXTEDIT_K_PGDOWN keyboard input to move cursor down a page 148 153 // STB_TEXTEDIT_K_LINESTART keyboard input to move cursor to start of line // e.g. HOME 149 154 // STB_TEXTEDIT_K_LINEEND keyboard input to move cursor to end of line // e.g. END … … 168 173 // STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text 169 174 // 170 // Todo:171 // STB_TEXTEDIT_K_PGUP keyboard input to move cursor up a page172 // STB_TEXTEDIT_K_PGDOWN keyboard input to move cursor down a page173 //174 175 // Keyboard input must be encoded as a single integer value; e.g. a character code 175 176 // and some bitflags that represent shift states. to simplify the interface, SHIFT must 176 177 // be a bitflag, so we can test the shifted state of cursor movements to allow selection, 177 // i.e. (STB_TEXTED _K_RIGHT|STB_TEXTEDIT_K_SHIFT) should be shifted right-arrow.178 // i.e. (STB_TEXTEDIT_K_RIGHT|STB_TEXTEDIT_K_SHIFT) should be shifted right-arrow. 178 179 // 179 180 // You can encode other things, such as CONTROL or ALT, in additional bits, and … … 204 205 // int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 205 206 // int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len) 206 // void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, intkey)207 // void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXEDIT_KEYTYPE key) 207 208 // 208 209 // Each of these functions potentially updates the string and updates the … … 238 239 // various definitions like STB_TEXTEDIT_K_LEFT have the is-key-event bit 239 240 // set, and make STB_TEXTEDIT_KEYTOCHAR check that the is-key-event bit is 240 // clear. 241 // clear. STB_TEXTEDIT_KEYTYPE defaults to int, but you can #define it to 242 // anything other type you wante before including. 243 // 241 244 // 242 245 // When rendering, you can read the cursor position and selection state from … … 298 301 // private data 299 302 STB_TEXTEDIT_POSITIONTYPE where; 300 shortinsert_length;301 shortdelete_length;302 shortchar_storage;303 STB_TEXTEDIT_POSITIONTYPE insert_length; 304 STB_TEXTEDIT_POSITIONTYPE delete_length; 305 int char_storage; 303 306 } StbUndoRecord; 304 307 … … 306 309 { 307 310 // private data 308 StbUndoRecord undo_rec [STB_TEXTEDIT_UNDOSTATECOUNT];311 StbUndoRecord undo_rec [STB_TEXTEDIT_UNDOSTATECOUNT]; 309 312 STB_TEXTEDIT_CHARTYPE undo_char[STB_TEXTEDIT_UNDOCHARCOUNT]; 310 313 short undo_point, redo_point; 311 short undo_char_point, redo_char_point;314 int undo_char_point, redo_char_point; 312 315 } StbUndoState; 313 316 … … 332 335 // each textfield keeps its own insert mode state. to keep an app-wide 333 336 // insert mode, copy this value in/out of the app state 337 338 int row_count_per_page; 339 // page size in number of row. 340 // this value MUST be set to >0 for pageup or pagedown in multilines documents. 334 341 335 342 ///////////////////// … … 357 364 typedef struct 358 365 { 359 float x0, 366 float x0,x1; // starting x location, end x location (allows for align=right, etc) 360 367 float baseline_y_delta; // position of baseline relative to previous row's baseline 361 float ymin, 368 float ymin,ymax; // height of row above and below baseline 362 369 int num_chars; 363 370 } StbTexteditRow; … … 394 401 int n = STB_TEXTEDIT_STRINGLEN(str); 395 402 float base_y = 0, prev_x; 396 int i =0, k;403 int i=0, k; 397 404 398 405 r.x0 = r.x1 = 0; … … 406 413 return n; 407 414 408 if (i ==0 && y < base_y + r.ymin)415 if (i==0 && y < base_y + r.ymin) 409 416 return 0; 410 417 … … 428 435 // search characters in row for one that straddles 'x' 429 436 prev_x = r.x0; 430 for (k =0; k < r.num_chars; ++k) {437 for (k=0; k < r.num_chars; ++k) { 431 438 float w = STB_TEXTEDIT_GETWIDTH(str, i, k); 432 if (x < prev_x +w) {433 if (x < prev_x + w /2)434 return k +i;439 if (x < prev_x+w) { 440 if (x < prev_x+w/2) 441 return k+i; 435 442 else 436 return k + i +1;443 return k+i+1; 437 444 } 438 445 prev_x += w; … … 442 449 443 450 // if the last character is a newline, return that. otherwise return 'after' the last character 444 if (STB_TEXTEDIT_GETCHAR(str, i + r.num_chars -1) == STB_TEXTEDIT_NEWLINE)445 return i + r.num_chars -1;451 if (STB_TEXTEDIT_GETCHAR(str, i+r.num_chars-1) == STB_TEXTEDIT_NEWLINE) 452 return i+r.num_chars-1; 446 453 else 447 return i +r.num_chars;454 return i+r.num_chars; 448 455 } 449 456 … … 451 458 static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) 452 459 { 460 // In single-line mode, just always make y = 0. This lets the drag keep working if the mouse 461 // goes off the top or bottom of the text 462 if( state->single_line ) 463 { 464 StbTexteditRow r; 465 STB_TEXTEDIT_LAYOUTROW(&r, str, 0); 466 y = r.ymin; 467 } 468 453 469 state->cursor = stb_text_locate_coord(str, x, y); 454 470 state->select_start = state->cursor; … … 460 476 static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) 461 477 { 462 int p = stb_text_locate_coord(str, x, y); 478 int p = 0; 479 480 // In single-line mode, just always make y = 0. This lets the drag keep working if the mouse 481 // goes off the top or bottom of the text 482 if( state->single_line ) 483 { 484 StbTexteditRow r; 485 STB_TEXTEDIT_LAYOUTROW(&r, str, 0); 486 y = r.ymin; 487 } 488 463 489 if (state->select_start == state->select_end) 464 490 state->select_start = state->cursor; 491 492 p = stb_text_locate_coord(str, x, y); 465 493 state->cursor = state->select_end = p; 466 494 } … … 480 508 typedef struct 481 509 { 482 float x, 510 float x,y; // position of n'th character 483 511 float height; // height of line 484 512 int first_char, length; // first char of row, and length … … 493 521 int prev_start = 0; 494 522 int z = STB_TEXTEDIT_STRINGLEN(str); 495 int i =0, first;523 int i=0, first; 496 524 497 525 if (n == z) { … … 505 533 find->height = r.ymax - r.ymin; 506 534 find->x = r.x1; 507 } 508 else { 535 } else { 509 536 find->y = 0; 510 537 find->x = 0; … … 525 552 find->y = 0; 526 553 527 for 554 for(;;) { 528 555 STB_TEXTEDIT_LAYOUTROW(&r, str, i); 529 556 if (n < i + r.num_chars) … … 541 568 // now scan to find xpos 542 569 find->x = r.x0; 543 i = 0; 544 for (i = 0; first + i < n; ++i) 570 for (i=0; first+i < n; ++i) 545 571 find->x += STB_TEXTEDIT_GETWIDTH(str, first, i); 546 572 } … … 578 604 stb_textedit_delete(str, state, state->select_start, state->select_end - state->select_start); 579 605 state->select_end = state->cursor = state->select_start; 580 } 581 else { 606 } else { 582 607 stb_textedit_delete(str, state, state->select_end, state->select_start - state->select_end); 583 608 state->select_start = state->cursor = state->select_end; … … 621 646 622 647 #ifdef STB_TEXTEDIT_IS_SPACE 623 static int is_word_boundary( STB_TEXTEDIT_STRING *str, int idx)624 { 625 return idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str, idx - 1)) && !STB_TEXTEDIT_IS_SPACE(STB_TEXTEDIT_GETCHAR(str, idx))) : 1;648 static int is_word_boundary( STB_TEXTEDIT_STRING *str, int idx ) 649 { 650 return idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str,idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str, idx) ) ) : 1; 626 651 } 627 652 628 653 #ifndef STB_TEXTEDIT_MOVEWORDLEFT 629 static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *str, int c)654 static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *str, int c ) 630 655 { 631 656 --c; // always move at least one character 632 while (c >= 0 && !is_word_boundary(str, c))657 while( c >= 0 && !is_word_boundary( str, c ) ) 633 658 --c; 634 659 635 if (c < 0)660 if( c < 0 ) 636 661 c = 0; 637 662 … … 642 667 643 668 #ifndef STB_TEXTEDIT_MOVEWORDRIGHT 644 static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *str, int c)669 static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *str, int c ) 645 670 { 646 671 const int len = STB_TEXTEDIT_STRINGLEN(str); 647 672 ++c; // always move at least one character 648 while (c < len && !is_word_boundary(str, c))673 while( c < len && !is_word_boundary( str, c ) ) 649 674 ++c; 650 675 651 if (c > len)676 if( c > len ) 652 677 c = len; 653 678 … … 672 697 { 673 698 if (STB_TEXT_HAS_SELECTION(state)) { 674 stb_textedit_delete_selection(str, state); // implicity clamps699 stb_textedit_delete_selection(str,state); // implicitly clamps 675 700 state->has_preferred_x = 0; 676 701 return 1; … … 680 705 681 706 // API paste: replace existing selection with passed-in text 682 static int stb_textedit_paste (STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE const*text, int len)707 static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len) 683 708 { 684 709 // if there's a selection, the paste should delete it 685 710 stb_textedit_clamp(str, state); 686 stb_textedit_delete_selection(str, 711 stb_textedit_delete_selection(str,state); 687 712 // try to insert the characters 688 713 if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, len)) { … … 698 723 } 699 724 725 #ifndef STB_TEXTEDIT_KEYTYPE 726 #define STB_TEXTEDIT_KEYTYPE int 727 #endif 728 700 729 // API key: process a keyboard input 701 static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, intkey)730 static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key) 702 731 { 703 732 retry: 704 733 switch (key) { 705 default: { 706 int c = STB_TEXTEDIT_KEYTOTEXT(key); 707 if (c > 0) { 708 STB_TEXTEDIT_CHARTYPE ch = (STB_TEXTEDIT_CHARTYPE)c; 709 710 // can't add newline in single-line mode 711 if (c == '\n' && state->single_line) 712 break; 713 714 if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) { 715 stb_text_makeundo_replace(str, state, state->cursor, 1, 1); 716 STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1); 717 if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { 718 ++state->cursor; 719 state->has_preferred_x = 0; 734 default: { 735 int c = STB_TEXTEDIT_KEYTOTEXT(key); 736 if (c > 0) { 737 STB_TEXTEDIT_CHARTYPE ch = (STB_TEXTEDIT_CHARTYPE) c; 738 739 // can't add newline in single-line mode 740 if (c == '\n' && state->single_line) 741 break; 742 743 if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) { 744 stb_text_makeundo_replace(str, state, state->cursor, 1, 1); 745 STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1); 746 if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { 747 ++state->cursor; 748 state->has_preferred_x = 0; 749 } 750 } else { 751 stb_textedit_delete_selection(str,state); // implicitly clamps 752 if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { 753 stb_text_makeundo_insert(state, state->cursor, 1); 754 ++state->cursor; 755 state->has_preferred_x = 0; 756 } 720 757 } 721 758 } 759 break; 760 } 761 762 #ifdef STB_TEXTEDIT_K_INSERT 763 case STB_TEXTEDIT_K_INSERT: 764 state->insert_mode = !state->insert_mode; 765 break; 766 #endif 767 768 case STB_TEXTEDIT_K_UNDO: 769 stb_text_undo(str, state); 770 state->has_preferred_x = 0; 771 break; 772 773 case STB_TEXTEDIT_K_REDO: 774 stb_text_redo(str, state); 775 state->has_preferred_x = 0; 776 break; 777 778 case STB_TEXTEDIT_K_LEFT: 779 // if currently there's a selection, move cursor to start of selection 780 if (STB_TEXT_HAS_SELECTION(state)) 781 stb_textedit_move_to_first(state); 782 else 783 if (state->cursor > 0) 784 --state->cursor; 785 state->has_preferred_x = 0; 786 break; 787 788 case STB_TEXTEDIT_K_RIGHT: 789 // if currently there's a selection, move cursor to end of selection 790 if (STB_TEXT_HAS_SELECTION(state)) 791 stb_textedit_move_to_last(str, state); 792 else 793 ++state->cursor; 794 stb_textedit_clamp(str, state); 795 state->has_preferred_x = 0; 796 break; 797 798 case STB_TEXTEDIT_K_LEFT | STB_TEXTEDIT_K_SHIFT: 799 stb_textedit_clamp(str, state); 800 stb_textedit_prep_selection_at_cursor(state); 801 // move selection left 802 if (state->select_end > 0) 803 --state->select_end; 804 state->cursor = state->select_end; 805 state->has_preferred_x = 0; 806 break; 807 808 #ifdef STB_TEXTEDIT_MOVEWORDLEFT 809 case STB_TEXTEDIT_K_WORDLEFT: 810 if (STB_TEXT_HAS_SELECTION(state)) 811 stb_textedit_move_to_first(state); 722 812 else { 723 stb_textedit_delete_selection(str, state); // implicity clamps 724 if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { 725 stb_text_makeundo_insert(state, state->cursor, 1); 813 state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor); 814 stb_textedit_clamp( str, state ); 815 } 816 break; 817 818 case STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT: 819 if( !STB_TEXT_HAS_SELECTION( state ) ) 820 stb_textedit_prep_selection_at_cursor(state); 821 822 state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor); 823 state->select_end = state->cursor; 824 825 stb_textedit_clamp( str, state ); 826 break; 827 #endif 828 829 #ifdef STB_TEXTEDIT_MOVEWORDRIGHT 830 case STB_TEXTEDIT_K_WORDRIGHT: 831 if (STB_TEXT_HAS_SELECTION(state)) 832 stb_textedit_move_to_last(str, state); 833 else { 834 state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor); 835 stb_textedit_clamp( str, state ); 836 } 837 break; 838 839 case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT: 840 if( !STB_TEXT_HAS_SELECTION( state ) ) 841 stb_textedit_prep_selection_at_cursor(state); 842 843 state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor); 844 state->select_end = state->cursor; 845 846 stb_textedit_clamp( str, state ); 847 break; 848 #endif 849 850 case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT: 851 stb_textedit_prep_selection_at_cursor(state); 852 // move selection right 853 ++state->select_end; 854 stb_textedit_clamp(str, state); 855 state->cursor = state->select_end; 856 state->has_preferred_x = 0; 857 break; 858 859 case STB_TEXTEDIT_K_DOWN: 860 case STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT: 861 case STB_TEXTEDIT_K_PGDOWN: 862 case STB_TEXTEDIT_K_PGDOWN | STB_TEXTEDIT_K_SHIFT: { 863 StbFindState find; 864 StbTexteditRow row; 865 int i, j, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0; 866 int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGDOWN; 867 int row_count = is_page ? state->row_count_per_page : 1; 868 869 if (!is_page && state->single_line) { 870 // on windows, up&down in single-line behave like left&right 871 key = STB_TEXTEDIT_K_RIGHT | (key & STB_TEXTEDIT_K_SHIFT); 872 goto retry; 873 } 874 875 if (sel) 876 stb_textedit_prep_selection_at_cursor(state); 877 else if (STB_TEXT_HAS_SELECTION(state)) 878 stb_textedit_move_to_last(str, state); 879 880 // compute current position of cursor point 881 stb_textedit_clamp(str, state); 882 stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); 883 884 for (j = 0; j < row_count; ++j) { 885 float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x; 886 int start = find.first_char + find.length; 887 888 if (find.length == 0) 889 break; 890 891 // [DEAR IMGUI] 892 // going down while being on the last line shouldn't bring us to that line end 893 if (STB_TEXTEDIT_GETCHAR(str, find.first_char + find.length - 1) != STB_TEXTEDIT_NEWLINE) 894 break; 895 896 // now find character position down a row 897 state->cursor = start; 898 STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); 899 x = row.x0; 900 for (i=0; i < row.num_chars; ++i) { 901 float dx = STB_TEXTEDIT_GETWIDTH(str, start, i); 902 #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE 903 if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE) 904 break; 905 #endif 906 x += dx; 907 if (x > goal_x) 908 break; 726 909 ++state->cursor; 727 state->has_preferred_x = 0; 910 } 911 stb_textedit_clamp(str, state); 912 913 state->has_preferred_x = 1; 914 state->preferred_x = goal_x; 915 916 if (sel) 917 state->select_end = state->cursor; 918 919 // go to next line 920 find.first_char = find.first_char + find.length; 921 find.length = row.num_chars; 922 } 923 break; 924 } 925 926 case STB_TEXTEDIT_K_UP: 927 case STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT: 928 case STB_TEXTEDIT_K_PGUP: 929 case STB_TEXTEDIT_K_PGUP | STB_TEXTEDIT_K_SHIFT: { 930 StbFindState find; 931 StbTexteditRow row; 932 int i, j, prev_scan, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0; 933 int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGUP; 934 int row_count = is_page ? state->row_count_per_page : 1; 935 936 if (!is_page && state->single_line) { 937 // on windows, up&down become left&right 938 key = STB_TEXTEDIT_K_LEFT | (key & STB_TEXTEDIT_K_SHIFT); 939 goto retry; 940 } 941 942 if (sel) 943 stb_textedit_prep_selection_at_cursor(state); 944 else if (STB_TEXT_HAS_SELECTION(state)) 945 stb_textedit_move_to_first(state); 946 947 // compute current position of cursor point 948 stb_textedit_clamp(str, state); 949 stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); 950 951 for (j = 0; j < row_count; ++j) { 952 float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x; 953 954 // can only go up if there's a previous row 955 if (find.prev_first == find.first_char) 956 break; 957 958 // now find character position up a row 959 state->cursor = find.prev_first; 960 STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); 961 x = row.x0; 962 for (i=0; i < row.num_chars; ++i) { 963 float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i); 964 #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE 965 if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE) 966 break; 967 #endif 968 x += dx; 969 if (x > goal_x) 970 break; 971 ++state->cursor; 972 } 973 stb_textedit_clamp(str, state); 974 975 state->has_preferred_x = 1; 976 state->preferred_x = goal_x; 977 978 if (sel) 979 state->select_end = state->cursor; 980 981 // go to previous line 982 // (we need to scan previous line the hard way. maybe we could expose this as a new API function?) 983 prev_scan = find.prev_first > 0 ? find.prev_first - 1 : 0; 984 while (prev_scan > 0 && STB_TEXTEDIT_GETCHAR(str, prev_scan - 1) != STB_TEXTEDIT_NEWLINE) 985 --prev_scan; 986 find.first_char = find.prev_first; 987 find.prev_first = prev_scan; 988 } 989 break; 990 } 991 992 case STB_TEXTEDIT_K_DELETE: 993 case STB_TEXTEDIT_K_DELETE | STB_TEXTEDIT_K_SHIFT: 994 if (STB_TEXT_HAS_SELECTION(state)) 995 stb_textedit_delete_selection(str, state); 996 else { 997 int n = STB_TEXTEDIT_STRINGLEN(str); 998 if (state->cursor < n) 999 stb_textedit_delete(str, state, state->cursor, 1); 1000 } 1001 state->has_preferred_x = 0; 1002 break; 1003 1004 case STB_TEXTEDIT_K_BACKSPACE: 1005 case STB_TEXTEDIT_K_BACKSPACE | STB_TEXTEDIT_K_SHIFT: 1006 if (STB_TEXT_HAS_SELECTION(state)) 1007 stb_textedit_delete_selection(str, state); 1008 else { 1009 stb_textedit_clamp(str, state); 1010 if (state->cursor > 0) { 1011 stb_textedit_delete(str, state, state->cursor-1, 1); 1012 --state->cursor; 728 1013 } 729 1014 } 1015 state->has_preferred_x = 0; 1016 break; 1017 1018 #ifdef STB_TEXTEDIT_K_TEXTSTART2 1019 case STB_TEXTEDIT_K_TEXTSTART2: 1020 #endif 1021 case STB_TEXTEDIT_K_TEXTSTART: 1022 state->cursor = state->select_start = state->select_end = 0; 1023 state->has_preferred_x = 0; 1024 break; 1025 1026 #ifdef STB_TEXTEDIT_K_TEXTEND2 1027 case STB_TEXTEDIT_K_TEXTEND2: 1028 #endif 1029 case STB_TEXTEDIT_K_TEXTEND: 1030 state->cursor = STB_TEXTEDIT_STRINGLEN(str); 1031 state->select_start = state->select_end = 0; 1032 state->has_preferred_x = 0; 1033 break; 1034 1035 #ifdef STB_TEXTEDIT_K_TEXTSTART2 1036 case STB_TEXTEDIT_K_TEXTSTART2 | STB_TEXTEDIT_K_SHIFT: 1037 #endif 1038 case STB_TEXTEDIT_K_TEXTSTART | STB_TEXTEDIT_K_SHIFT: 1039 stb_textedit_prep_selection_at_cursor(state); 1040 state->cursor = state->select_end = 0; 1041 state->has_preferred_x = 0; 1042 break; 1043 1044 #ifdef STB_TEXTEDIT_K_TEXTEND2 1045 case STB_TEXTEDIT_K_TEXTEND2 | STB_TEXTEDIT_K_SHIFT: 1046 #endif 1047 case STB_TEXTEDIT_K_TEXTEND | STB_TEXTEDIT_K_SHIFT: 1048 stb_textedit_prep_selection_at_cursor(state); 1049 state->cursor = state->select_end = STB_TEXTEDIT_STRINGLEN(str); 1050 state->has_preferred_x = 0; 1051 break; 1052 1053 1054 #ifdef STB_TEXTEDIT_K_LINESTART2 1055 case STB_TEXTEDIT_K_LINESTART2: 1056 #endif 1057 case STB_TEXTEDIT_K_LINESTART: 1058 stb_textedit_clamp(str, state); 1059 stb_textedit_move_to_first(state); 1060 if (state->single_line) 1061 state->cursor = 0; 1062 else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE) 1063 --state->cursor; 1064 state->has_preferred_x = 0; 1065 break; 1066 1067 #ifdef STB_TEXTEDIT_K_LINEEND2 1068 case STB_TEXTEDIT_K_LINEEND2: 1069 #endif 1070 case STB_TEXTEDIT_K_LINEEND: { 1071 int n = STB_TEXTEDIT_STRINGLEN(str); 1072 stb_textedit_clamp(str, state); 1073 stb_textedit_move_to_first(state); 1074 if (state->single_line) 1075 state->cursor = n; 1076 else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE) 1077 ++state->cursor; 1078 state->has_preferred_x = 0; 1079 break; 730 1080 } 731 break; 732 } 733 734 #ifdef STB_TEXTEDIT_K_INSERT 735 case STB_TEXTEDIT_K_INSERT: 736 state->insert_mode = !state->insert_mode; 737 break; 738 #endif 739 740 case STB_TEXTEDIT_K_UNDO: 741 stb_text_undo(str, state); 742 state->has_preferred_x = 0; 743 break; 744 745 case STB_TEXTEDIT_K_REDO: 746 stb_text_redo(str, state); 747 state->has_preferred_x = 0; 748 break; 749 750 case STB_TEXTEDIT_K_LEFT: 751 // if currently there's a selection, move cursor to start of selection 752 if (STB_TEXT_HAS_SELECTION(state)) 753 stb_textedit_move_to_first(state); 754 else 755 if (state->cursor > 0) 1081 1082 #ifdef STB_TEXTEDIT_K_LINESTART2 1083 case STB_TEXTEDIT_K_LINESTART2 | STB_TEXTEDIT_K_SHIFT: 1084 #endif 1085 case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT: 1086 stb_textedit_clamp(str, state); 1087 stb_textedit_prep_selection_at_cursor(state); 1088 if (state->single_line) 1089 state->cursor = 0; 1090 else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE) 756 1091 --state->cursor; 757 state->has_preferred_x = 0; 758 break; 759 760 case STB_TEXTEDIT_K_RIGHT: 761 // if currently there's a selection, move cursor to end of selection 762 if (STB_TEXT_HAS_SELECTION(state)) 763 stb_textedit_move_to_last(str, state); 764 else 765 ++state->cursor; 766 stb_textedit_clamp(str, state); 767 state->has_preferred_x = 0; 768 break; 769 770 case STB_TEXTEDIT_K_LEFT | STB_TEXTEDIT_K_SHIFT: 771 stb_textedit_clamp(str, state); 772 stb_textedit_prep_selection_at_cursor(state); 773 // move selection left 774 if (state->select_end > 0) 775 --state->select_end; 776 state->cursor = state->select_end; 777 state->has_preferred_x = 0; 778 break; 779 780 #ifdef STB_TEXTEDIT_MOVEWORDLEFT 781 case STB_TEXTEDIT_K_WORDLEFT: 782 if (STB_TEXT_HAS_SELECTION(state)) 783 stb_textedit_move_to_first(state); 784 else { 785 state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor); 1092 state->select_end = state->cursor; 1093 state->has_preferred_x = 0; 1094 break; 1095 1096 #ifdef STB_TEXTEDIT_K_LINEEND2 1097 case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT: 1098 #endif 1099 case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: { 1100 int n = STB_TEXTEDIT_STRINGLEN(str); 786 1101 stb_textedit_clamp(str, state); 1102 stb_textedit_prep_selection_at_cursor(state); 1103 if (state->single_line) 1104 state->cursor = n; 1105 else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE) 1106 ++state->cursor; 1107 state->select_end = state->cursor; 1108 state->has_preferred_x = 0; 1109 break; 787 1110 } 788 break;789 790 case STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT:791 if (!STB_TEXT_HAS_SELECTION(state))792 stb_textedit_prep_selection_at_cursor(state);793 794 state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor);795 state->select_end = state->cursor;796 797 stb_textedit_clamp(str, state);798 break;799 #endif800 801 #ifdef STB_TEXTEDIT_MOVEWORDRIGHT802 case STB_TEXTEDIT_K_WORDRIGHT:803 if (STB_TEXT_HAS_SELECTION(state))804 stb_textedit_move_to_last(str, state);805 else {806 state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor);807 stb_textedit_clamp(str, state);808 }809 break;810 811 case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT:812 if (!STB_TEXT_HAS_SELECTION(state))813 stb_textedit_prep_selection_at_cursor(state);814 815 state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor);816 state->select_end = state->cursor;817 818 stb_textedit_clamp(str, state);819 break;820 #endif821 822 case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT:823 stb_textedit_prep_selection_at_cursor(state);824 // move selection right825 ++state->select_end;826 stb_textedit_clamp(str, state);827 state->cursor = state->select_end;828 state->has_preferred_x = 0;829 break;830 831 case STB_TEXTEDIT_K_DOWN:832 case STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT: {833 StbFindState find;834 StbTexteditRow row;835 int i, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0;836 837 if (state->single_line) {838 // on windows, up&down in single-line behave like left&right839 key = STB_TEXTEDIT_K_RIGHT | (key & STB_TEXTEDIT_K_SHIFT);840 goto retry;841 }842 843 if (sel)844 stb_textedit_prep_selection_at_cursor(state);845 else if (STB_TEXT_HAS_SELECTION(state))846 stb_textedit_move_to_last(str, state);847 848 // compute current position of cursor point849 stb_textedit_clamp(str, state);850 stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);851 852 // now find character position down a row853 if (find.length) {854 float goal_x = state->has_preferred_x ? state->preferred_x : find.x;855 float x;856 int start = find.first_char + find.length;857 state->cursor = start;858 STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);859 x = row.x0;860 for (i = 0; i < row.num_chars; ++i) {861 float dx = STB_TEXTEDIT_GETWIDTH(str, start, i);862 #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE863 if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE)864 break;865 #endif866 x += dx;867 if (x > goal_x)868 break;869 ++state->cursor;870 }871 stb_textedit_clamp(str, state);872 873 state->has_preferred_x = 1;874 state->preferred_x = goal_x;875 876 if (sel)877 state->select_end = state->cursor;878 }879 break;880 }881 882 case STB_TEXTEDIT_K_UP:883 case STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT: {884 StbFindState find;885 StbTexteditRow row;886 int i, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0;887 888 if (state->single_line) {889 // on windows, up&down become left&right890 key = STB_TEXTEDIT_K_LEFT | (key & STB_TEXTEDIT_K_SHIFT);891 goto retry;892 }893 894 if (sel)895 stb_textedit_prep_selection_at_cursor(state);896 else if (STB_TEXT_HAS_SELECTION(state))897 stb_textedit_move_to_first(state);898 899 // compute current position of cursor point900 stb_textedit_clamp(str, state);901 stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);902 903 // can only go up if there's a previous row904 if (find.prev_first != find.first_char) {905 // now find character position up a row906 float goal_x = state->has_preferred_x ? state->preferred_x : find.x;907 float x;908 state->cursor = find.prev_first;909 STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);910 x = row.x0;911 for (i = 0; i < row.num_chars; ++i) {912 float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i);913 #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE914 if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE)915 break;916 #endif917 x += dx;918 if (x > goal_x)919 break;920 ++state->cursor;921 }922 stb_textedit_clamp(str, state);923 924 state->has_preferred_x = 1;925 state->preferred_x = goal_x;926 927 if (sel)928 state->select_end = state->cursor;929 }930 break;931 }932 933 case STB_TEXTEDIT_K_DELETE:934 case STB_TEXTEDIT_K_DELETE | STB_TEXTEDIT_K_SHIFT:935 if (STB_TEXT_HAS_SELECTION(state))936 stb_textedit_delete_selection(str, state);937 else {938 int n = STB_TEXTEDIT_STRINGLEN(str);939 if (state->cursor < n)940 stb_textedit_delete(str, state, state->cursor, 1);941 }942 state->has_preferred_x = 0;943 break;944 945 case STB_TEXTEDIT_K_BACKSPACE:946 case STB_TEXTEDIT_K_BACKSPACE | STB_TEXTEDIT_K_SHIFT:947 if (STB_TEXT_HAS_SELECTION(state))948 stb_textedit_delete_selection(str, state);949 else {950 stb_textedit_clamp(str, state);951 if (state->cursor > 0) {952 stb_textedit_delete(str, state, state->cursor - 1, 1);953 --state->cursor;954 }955 }956 state->has_preferred_x = 0;957 break;958 959 #ifdef STB_TEXTEDIT_K_TEXTSTART2960 case STB_TEXTEDIT_K_TEXTSTART2:961 #endif962 case STB_TEXTEDIT_K_TEXTSTART:963 state->cursor = state->select_start = state->select_end = 0;964 state->has_preferred_x = 0;965 break;966 967 #ifdef STB_TEXTEDIT_K_TEXTEND2968 case STB_TEXTEDIT_K_TEXTEND2:969 #endif970 case STB_TEXTEDIT_K_TEXTEND:971 state->cursor = STB_TEXTEDIT_STRINGLEN(str);972 state->select_start = state->select_end = 0;973 state->has_preferred_x = 0;974 break;975 976 #ifdef STB_TEXTEDIT_K_TEXTSTART2977 case STB_TEXTEDIT_K_TEXTSTART2 | STB_TEXTEDIT_K_SHIFT:978 #endif979 case STB_TEXTEDIT_K_TEXTSTART | STB_TEXTEDIT_K_SHIFT:980 stb_textedit_prep_selection_at_cursor(state);981 state->cursor = state->select_end = 0;982 state->has_preferred_x = 0;983 break;984 985 #ifdef STB_TEXTEDIT_K_TEXTEND2986 case STB_TEXTEDIT_K_TEXTEND2 | STB_TEXTEDIT_K_SHIFT:987 #endif988 case STB_TEXTEDIT_K_TEXTEND | STB_TEXTEDIT_K_SHIFT:989 stb_textedit_prep_selection_at_cursor(state);990 state->cursor = state->select_end = STB_TEXTEDIT_STRINGLEN(str);991 state->has_preferred_x = 0;992 break;993 994 995 #ifdef STB_TEXTEDIT_K_LINESTART2996 case STB_TEXTEDIT_K_LINESTART2:997 #endif998 case STB_TEXTEDIT_K_LINESTART:999 stb_textedit_clamp(str, state);1000 stb_textedit_move_to_first(state);1001 if (state->single_line)1002 state->cursor = 0;1003 else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor - 1) != STB_TEXTEDIT_NEWLINE)1004 --state->cursor;1005 state->has_preferred_x = 0;1006 break;1007 1008 #ifdef STB_TEXTEDIT_K_LINEEND21009 case STB_TEXTEDIT_K_LINEEND2:1010 #endif1011 case STB_TEXTEDIT_K_LINEEND: {1012 int n = STB_TEXTEDIT_STRINGLEN(str);1013 stb_textedit_clamp(str, state);1014 stb_textedit_move_to_first(state);1015 if (state->single_line)1016 state->cursor = n;1017 else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)1018 ++state->cursor;1019 state->has_preferred_x = 0;1020 break;1021 }1022 1023 #ifdef STB_TEXTEDIT_K_LINESTART21024 case STB_TEXTEDIT_K_LINESTART2 | STB_TEXTEDIT_K_SHIFT:1025 #endif1026 case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT:1027 stb_textedit_clamp(str, state);1028 stb_textedit_prep_selection_at_cursor(state);1029 if (state->single_line)1030 state->cursor = 0;1031 else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor - 1) != STB_TEXTEDIT_NEWLINE)1032 --state->cursor;1033 state->select_end = state->cursor;1034 state->has_preferred_x = 0;1035 break;1036 1037 #ifdef STB_TEXTEDIT_K_LINEEND21038 case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT:1039 #endif1040 case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: {1041 int n = STB_TEXTEDIT_STRINGLEN(str);1042 stb_textedit_clamp(str, state);1043 stb_textedit_prep_selection_at_cursor(state);1044 if (state->single_line)1045 state->cursor = n;1046 else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)1047 ++state->cursor;1048 state->select_end = state->cursor;1049 state->has_preferred_x = 0;1050 break;1051 }1052 1053 // @TODO:1054 // STB_TEXTEDIT_K_PGUP - move cursor up a page1055 // STB_TEXTEDIT_K_PGDOWN - move cursor down a page1056 1111 } 1057 1112 } … … 1077 1132 int n = state->undo_rec[0].insert_length, i; 1078 1133 // delete n characters from all other records 1079 state->undo_char_point = state->undo_char_point - (short)n; // vsnet051080 STB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (size_t) ((size_t)state->undo_char_point *sizeof(STB_TEXTEDIT_CHARTYPE)));1081 for (i =0; i < state->undo_point; ++i)1134 state->undo_char_point -= n; 1135 STB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (size_t) (state->undo_char_point*sizeof(STB_TEXTEDIT_CHARTYPE))); 1136 for (i=0; i < state->undo_point; ++i) 1082 1137 if (state->undo_rec[i].char_storage >= 0) 1083 state->undo_rec[i].char_storage = state->undo_rec[i].char_storage - (short)n; // vsnet05// @OPTIMIZE: get rid of char_storage and infer it1138 state->undo_rec[i].char_storage -= n; // @OPTIMIZE: get rid of char_storage and infer it 1084 1139 } 1085 1140 --state->undo_point; 1086 STB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec + 1, (size_t)((size_t)state->undo_point *sizeof(state->undo_rec[0])));1141 STB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec+1, (size_t) (state->undo_point*sizeof(state->undo_rec[0]))); 1087 1142 } 1088 1143 } … … 1094 1149 static void stb_textedit_discard_redo(StbUndoState *state) 1095 1150 { 1096 int k = STB_TEXTEDIT_UNDOSTATECOUNT -1;1151 int k = STB_TEXTEDIT_UNDOSTATECOUNT-1; 1097 1152 1098 1153 if (state->redo_point <= k) { … … 1100 1155 if (state->undo_rec[k].char_storage >= 0) { 1101 1156 int n = state->undo_rec[k].insert_length, i; 1102 // delete n characters from all other records 1103 state->redo_char_point = state->redo_char_point + (short)n; // vsnet05 1104 STB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point - n, (size_t)((size_t)(STB_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point) * sizeof(STB_TEXTEDIT_CHARTYPE))); 1105 for (i = state->redo_point; i < k; ++i) 1157 // move the remaining redo character data to the end of the buffer 1158 state->redo_char_point += n; 1159 STB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((STB_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point)*sizeof(STB_TEXTEDIT_CHARTYPE))); 1160 // adjust the position of all the other records to account for above memmove 1161 for (i=state->redo_point; i < k; ++i) 1106 1162 if (state->undo_rec[i].char_storage >= 0) 1107 state->undo_rec[i].char_storage = state->undo_rec[i].char_storage + (short)n; // vsnet051163 state->undo_rec[i].char_storage += n; 1108 1164 } 1109 STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point, state->undo_rec + state->redo_point - 1, (size_t)((size_t)(STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point) * sizeof(state->undo_rec[0]))); 1165 // now move all the redo records towards the end of the buffer; the first one is at 'redo_point' 1166 // [DEAR IMGUI] 1167 size_t move_size = (size_t)((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point - 1) * sizeof(state->undo_rec[0])); 1168 const char* buf_begin = (char*)state->undo_rec; (void)buf_begin; 1169 const char* buf_end = (char*)state->undo_rec + sizeof(state->undo_rec); (void)buf_end; 1170 IM_ASSERT(((char*)(state->undo_rec + state->redo_point)) >= buf_begin); 1171 IM_ASSERT(((char*)(state->undo_rec + state->redo_point + 1) + move_size) <= buf_end); 1172 STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point+1, state->undo_rec + state->redo_point, move_size); 1173 1174 // now move redo_point to point to the new one 1110 1175 ++state->redo_point; 1111 1176 } … … 1143 1208 1144 1209 r->where = pos; 1145 r->insert_length = ( short)insert_len;1146 r->delete_length = ( short)delete_len;1210 r->insert_length = (STB_TEXTEDIT_POSITIONTYPE) insert_len; 1211 r->delete_length = (STB_TEXTEDIT_POSITIONTYPE) delete_len; 1147 1212 1148 1213 if (insert_len == 0) { 1149 1214 r->char_storage = -1; 1150 1215 return NULL; 1151 } 1152 else { 1216 } else { 1153 1217 r->char_storage = state->undo_char_point; 1154 state->undo_char_point = state->undo_char_point + (short)insert_len;1218 state->undo_char_point += insert_len; 1155 1219 return &state->undo_char[r->char_storage]; 1156 1220 } … … 1165 1229 1166 1230 // we need to do two things: apply the undo record, and create a redo record 1167 u = s->undo_rec[s->undo_point -1];1168 r = &s->undo_rec[s->redo_point -1];1231 u = s->undo_rec[s->undo_point-1]; 1232 r = &s->undo_rec[s->redo_point-1]; 1169 1233 r->char_storage = -1; 1170 1234 … … 1187 1251 // the undo records take up too much character space; there's no space to store the redo characters 1188 1252 r->insert_length = 0; 1189 } 1190 else { 1253 } else { 1191 1254 int i; 1192 1255 1193 1256 // there's definitely room to store the characters eventually 1194 1257 while (s->undo_char_point + u.delete_length > s->redo_char_point) { 1195 // there's currently not enough room, so discard a redo record1196 stb_textedit_discard_redo(s);1197 1258 // should never happen: 1198 1259 if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT) 1199 1260 return; 1261 // there's currently not enough room, so discard a redo record 1262 stb_textedit_discard_redo(s); 1200 1263 } 1201 r = &s->undo_rec[s->redo_point -1];1264 r = &s->undo_rec[s->redo_point-1]; 1202 1265 1203 1266 r->char_storage = s->redo_char_point - u.delete_length; 1204 s->redo_char_point = s->redo_char_point - (short)u.delete_length;1267 s->redo_char_point = s->redo_char_point - u.delete_length; 1205 1268 1206 1269 // now save the characters 1207 for (i =0; i < u.delete_length; ++i)1270 for (i=0; i < u.delete_length; ++i) 1208 1271 s->undo_char[r->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u.where + i); 1209 1272 } … … 1252 1315 u->insert_length = 0; 1253 1316 u->delete_length = 0; 1254 } 1255 else { 1317 } else { 1256 1318 int i; 1257 1319 u->char_storage = s->undo_char_point; … … 1259 1321 1260 1322 // now save the characters 1261 for (i =0; i < u->insert_length; ++i)1323 for (i=0; i < u->insert_length; ++i) 1262 1324 s->undo_char[u->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u->where + i); 1263 1325 } … … 1288 1350 STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, length, 0); 1289 1351 if (p) { 1290 for (i =0; i < length; ++i)1291 p[i] = STB_TEXTEDIT_GETCHAR(str, where +i);1352 for (i=0; i < length; ++i) 1353 p[i] = STB_TEXTEDIT_GETCHAR(str, where+i); 1292 1354 } 1293 1355 } … … 1298 1360 STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, old_length, new_length); 1299 1361 if (p) { 1300 for (i =0; i < old_length; ++i)1301 p[i] = STB_TEXTEDIT_GETCHAR(str, where +i);1362 for (i=0; i < old_length; ++i) 1363 p[i] = STB_TEXTEDIT_GETCHAR(str, where+i); 1302 1364 } 1303 1365 } … … 1316 1378 state->cursor_at_end_of_line = 0; 1317 1379 state->initialized = 1; 1318 state->single_line = (unsigned char) is_single_line;1380 state->single_line = (unsigned char) is_single_line; 1319 1381 state->insert_mode = 0; 1382 state->row_count_per_page = 0; 1320 1383 } 1321 1384 … … 1325 1388 stb_textedit_clear_state(state, is_single_line); 1326 1389 } 1390 1391 #if defined(__GNUC__) || defined(__clang__) 1392 #pragma GCC diagnostic push 1393 #pragma GCC diagnostic ignored "-Wcast-qual" 1394 #endif 1395 1396 static int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE const *ctext, int len) 1397 { 1398 return stb_textedit_paste_internal(str, state, (STB_TEXTEDIT_CHARTYPE *) ctext, len); 1399 } 1400 1401 #if defined(__GNUC__) || defined(__clang__) 1402 #pragma GCC diagnostic pop 1403 #endif 1404 1327 1405 #endif//STB_TEXTEDIT_IMPLEMENTATION 1406 1407 /* 1408 ------------------------------------------------------------------------------ 1409 This software is available under 2 licenses -- choose whichever you prefer. 1410 ------------------------------------------------------------------------------ 1411 ALTERNATIVE A - MIT License 1412 Copyright (c) 2017 Sean Barrett 1413 Permission is hereby granted, free of charge, to any person obtaining a copy of 1414 this software and associated documentation files (the "Software"), to deal in 1415 the Software without restriction, including without limitation the rights to 1416 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 1417 of the Software, and to permit persons to whom the Software is furnished to do 1418 so, subject to the following conditions: 1419 The above copyright notice and this permission notice shall be included in all 1420 copies or substantial portions of the Software. 1421 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1422 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1423 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1424 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1425 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 1426 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 1427 SOFTWARE. 1428 ------------------------------------------------------------------------------ 1429 ALTERNATIVE B - Public Domain (www.unlicense.org) 1430 This is free and unencumbered software released into the public domain. 1431 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 1432 software, either in source code form or as a compiled binary, for any purpose, 1433 commercial or non-commercial, and by any means. 1434 In jurisdictions that recognize copyright laws, the author or authors of this 1435 software dedicate any and all copyright interest in the software to the public 1436 domain. We make this dedication for the benefit of the public at large and to 1437 the detriment of our heirs and successors. We intend this dedication to be an 1438 overt act of relinquishment in perpetuity of all present and future rights to 1439 this software under copyright law. 1440 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1441 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1442 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1443 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 1444 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 1445 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 1446 ------------------------------------------------------------------------------ 1447 */ -
IMGUI/imstb_truetype.h
r78c3045 re66fd66 1 // stb_truetype.h - v1.19 - public domain 1 // [DEAR IMGUI] 2 // This is a slightly modified version of stb_truetype.h 1.20. 3 // Mostly fixing for compiler and static analyzer warnings. 4 // Grep for [DEAR IMGUI] to find the changes. 5 6 // stb_truetype.h - v1.20 - public domain 2 7 // authored from 2009-2016 by Sean Barrett / RAD Game Tools 3 8 // … … 50 55 // VERSION HISTORY 51 56 // 57 // 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics() 52 58 // 1.19 (2018-02-11) GPOS kerning, STBTT_fmod 53 59 // 1.18 (2018-01-29) add missing function … … 76 82 // USAGE 77 83 // 78 // Include this file in whatever places nee ed to refer to it. In ONE C/C++84 // Include this file in whatever places need to refer to it. In ONE C/C++ 79 85 // file, write: 80 86 // #define STB_TRUETYPE_IMPLEMENTATION … … 248 254 // Sample code 140 LOC / 249 255 // Truetype parsing 620 LOC ---- 620 LOC TrueType 250 // Software rasterization 240 LOC \ 251 // Curve tessel ation120 LOC \__ 550 LOC Bitmap creation256 // Software rasterization 240 LOC \. 257 // Curve tessellation 120 LOC \__ 550 LOC Bitmap creation 252 258 // Bitmap management 100 LOC / 253 259 // Baked bitmap interface 70 LOC / … … 276 282 #include "stb_truetype.h" 277 283 278 unsigned char ttf_buffer[1 <<20];279 unsigned char temp_bitmap[512 *512];284 unsigned char ttf_buffer[1<<20]; 285 unsigned char temp_bitmap[512*512]; 280 286 281 287 stbtt_bakedchar cdata[96]; // ASCII 32..126 is 95 glyphs … … 284 290 void my_stbtt_initfont(void) 285 291 { 286 fread(ttf_buffer, 1, 1 <<20, fopen("c:/windows/fonts/times.ttf", "rb"));287 stbtt_BakeFontBitmap(ttf_buffer, 0, 32.0, temp_bitmap, 512, 512, 32,96, cdata); // no guarantee this fits!288 292 fread(ttf_buffer, 1, 1<<20, fopen("c:/windows/fonts/times.ttf", "rb")); 293 stbtt_BakeFontBitmap(ttf_buffer,0, 32.0, temp_bitmap,512,512, 32,96, cdata); // no guarantee this fits! 294 // can free ttf_buffer at this point 289 295 glGenTextures(1, &ftex); 290 296 glBindTexture(GL_TEXTURE_2D, ftex); 291 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 512, 297 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 512,512, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap); 292 298 // can free temp_bitmap at this point 293 299 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); … … 303 309 if (*text >= 32 && *text < 128) { 304 310 stbtt_aligned_quad q; 305 stbtt_GetBakedQuad(cdata, 512, 512, *text - 32, &x, &y, &q,1);//1=opengl & d3d10+,0=d3d9306 glTexCoord2f(q.s0, q.t1); glVertex2f(q.x0,q.y0);307 glTexCoord2f(q.s1, q.t1); glVertex2f(q.x1,q.y0);308 glTexCoord2f(q.s1, q.t0); glVertex2f(q.x1,q.y1);309 glTexCoord2f(q.s0, q.t0); glVertex2f(q.x0,q.y1);311 stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9 312 glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y0); 313 glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y0); 314 glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y1); 315 glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y1); 310 316 } 311 317 ++text; … … 325 331 #include "stb_truetype.h" 326 332 327 char ttf_buffer[1 <<25];333 char ttf_buffer[1<<25]; 328 334 329 335 int main(int argc, char **argv) … … 331 337 stbtt_fontinfo font; 332 338 unsigned char *bitmap; 333 int w, h, i, j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20);334 335 fread(ttf_buffer, 1, 1 <<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb"));336 337 stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer, 338 bitmap = stbtt_GetCodepointBitmap(&font, 0, stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0);339 340 for (j =0; j < h; ++j) {341 for (i =0; i < w; ++i)342 putchar(" .:ioVM@"[bitmap[j*w + i] >>5]);339 int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20); 340 341 fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb")); 342 343 stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0)); 344 bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0); 345 346 for (j=0; j < h; ++j) { 347 for (i=0; i < w; ++i) 348 putchar(" .:ioVM@"[bitmap[j*w+i]>>5]); 343 349 putchar('\n'); 344 350 } … … 365 371 // 366 372 #if 0 367 char buffer[24 <<20];373 char buffer[24<<20]; 368 374 unsigned char screen[20][79]; 369 375 … … 371 377 { 372 378 stbtt_fontinfo font; 373 int i, j, ascent, baseline, ch =0;374 float scale, xpos =2; // leave a little padding in case the character extends left379 int i,j,ascent,baseline,ch=0; 380 float scale, xpos=2; // leave a little padding in case the character extends left 375 381 char *text = "Heljo World!"; // intentionally misspelled to show 'lj' brokenness 376 382 … … 379 385 380 386 scale = stbtt_ScaleForPixelHeight(&font, 15); 381 stbtt_GetFontVMetrics(&font, &ascent, 0,0);382 baseline = (int) (ascent*scale);387 stbtt_GetFontVMetrics(&font, &ascent,0,0); 388 baseline = (int) (ascent*scale); 383 389 384 390 while (text[ch]) { 385 int advance, lsb, x0, y0, x1,y1;386 float x_shift = xpos - (float) floor(xpos);391 int advance,lsb,x0,y0,x1,y1; 392 float x_shift = xpos - (float) floor(xpos); 387 393 stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb); 388 stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale, scale, x_shift, 0, &x0, &y0, &x1,&y1);389 stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1 - x0, y1 - y0, 79, scale, scale, x_shift,0, text[ch]);394 stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1); 395 stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]); 390 396 // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong 391 397 // because this API is really for baking character bitmaps into textures. if you want to render … … 393 399 // "alpha blend" that into the working buffer 394 400 xpos += (advance * scale); 395 if (text[ch +1])396 xpos += scale * stbtt_GetCodepointKernAdvance(&font, text[ch], text[ch +1]);401 if (text[ch+1]) 402 xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]); 397 403 ++ch; 398 404 } 399 405 400 for (j =0; j < 20; ++j) {401 for (i =0; i < 78; ++i)402 putchar(" .:ioVM@"[screen[j][i] >>5]);406 for (j=0; j < 20; ++j) { 407 for (i=0; i < 78; ++i) 408 putchar(" .:ioVM@"[screen[j][i]>>5]); 403 409 putchar('\n'); 404 410 } … … 419 425 420 426 #ifdef STB_TRUETYPE_IMPLEMENTATION 421 // #define your own (u)stbtt_int8/16/32 before including to override this422 #ifndef stbtt_uint8423 typedef unsigned char stbtt_uint8;424 typedef signed char stbtt_int8;425 typedef unsigned short stbtt_uint16;426 typedef signed short stbtt_int16;427 typedef unsigned int stbtt_uint32;428 typedef signed int stbtt_int32;429 #endif430 431 typedef char stbtt__check_size32[sizeof(stbtt_int32) ==4 ? 1 : -1];432 typedef char stbtt__check_size16[sizeof(stbtt_int16) ==2 ? 1 : -1];433 434 // e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h435 #ifndef STBTT_ifloor436 #include <math.h>437 #define STBTT_ifloor(x) ((int) floor(x))438 #define STBTT_iceil(x) ((int) ceil(x))439 #endif440 441 #ifndef STBTT_sqrt442 #include <math.h>443 #define STBTT_sqrt(x) sqrt(x)444 #define STBTT_pow(x,y) pow(x,y)445 #endif446 447 #ifndef STBTT_fmod448 #include <math.h>449 #define STBTT_fmod(x,y) fmod(x,y)450 #endif451 452 #ifndef STBTT_cos453 #include <math.h>454 #define STBTT_cos(x) cos(x)455 #define STBTT_acos(x) acos(x)456 #endif457 458 #ifndef STBTT_fabs459 #include <math.h>460 #define STBTT_fabs(x) fabs(x)461 #endif462 463 // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h464 #ifndef STBTT_malloc465 #include <stdlib.h>466 #define STBTT_malloc(x,u) ((void)(u),malloc(x))467 #define STBTT_free(x,u) ((void)(u),free(x))468 #endif469 470 #ifndef STBTT_assert471 #include <assert.h>472 #define STBTT_assert(x) assert(x)473 #endif474 475 #ifndef STBTT_strlen476 #include <string.h>477 #define STBTT_strlen(x) strlen(x)478 #endif479 480 #ifndef STBTT_memcpy481 #include <string.h>482 #define STBTT_memcpy memcpy483 #define STBTT_memset memset484 #endif427 // #define your own (u)stbtt_int8/16/32 before including to override this 428 #ifndef stbtt_uint8 429 typedef unsigned char stbtt_uint8; 430 typedef signed char stbtt_int8; 431 typedef unsigned short stbtt_uint16; 432 typedef signed short stbtt_int16; 433 typedef unsigned int stbtt_uint32; 434 typedef signed int stbtt_int32; 435 #endif 436 437 typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1]; 438 typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1]; 439 440 // e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h 441 #ifndef STBTT_ifloor 442 #include <math.h> 443 #define STBTT_ifloor(x) ((int) floor(x)) 444 #define STBTT_iceil(x) ((int) ceil(x)) 445 #endif 446 447 #ifndef STBTT_sqrt 448 #include <math.h> 449 #define STBTT_sqrt(x) sqrt(x) 450 #define STBTT_pow(x,y) pow(x,y) 451 #endif 452 453 #ifndef STBTT_fmod 454 #include <math.h> 455 #define STBTT_fmod(x,y) fmod(x,y) 456 #endif 457 458 #ifndef STBTT_cos 459 #include <math.h> 460 #define STBTT_cos(x) cos(x) 461 #define STBTT_acos(x) acos(x) 462 #endif 463 464 #ifndef STBTT_fabs 465 #include <math.h> 466 #define STBTT_fabs(x) fabs(x) 467 #endif 468 469 // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h 470 #ifndef STBTT_malloc 471 #include <stdlib.h> 472 #define STBTT_malloc(x,u) ((void)(u),malloc(x)) 473 #define STBTT_free(x,u) ((void)(u),free(x)) 474 #endif 475 476 #ifndef STBTT_assert 477 #include <assert.h> 478 #define STBTT_assert(x) assert(x) 479 #endif 480 481 #ifndef STBTT_strlen 482 #include <string.h> 483 #define STBTT_strlen(x) strlen(x) 484 #endif 485 486 #ifndef STBTT_memcpy 487 #include <string.h> 488 #define STBTT_memcpy memcpy 489 #define STBTT_memset memset 490 #endif 485 491 #endif 486 492 … … 505 511 #endif 506 512 507 // private structure 508 typedef struct 509 { 510 unsigned char *data; 511 int cursor; 512 int size; 513 } stbtt__buf; 514 515 ////////////////////////////////////////////////////////////////////////////// 516 // 517 // TEXTURE BAKING API 518 // 519 // If you use this API, you only have to call two functions ever. 520 // 521 522 typedef struct 523 { 524 unsigned short x0, y0, x1, y1; // coordinates of bbox in bitmap 525 float xoff, yoff, xadvance; 526 } stbtt_bakedchar; 527 528 STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) 529 float pixel_height, // height of font in pixels 530 unsigned char *pixels, int pw, int ph, // bitmap to be filled in 531 int first_char, int num_chars, // characters to bake 532 stbtt_bakedchar *chardata); // you allocate this, it's num_chars long 533 // if return is positive, the first unused row of the bitmap 534 // if return is negative, returns the negative of the number of characters that fit 535 // if return is 0, no characters fit and no rows were used 536 // This uses a very crappy packing. 537 538 typedef struct 539 { 540 float x0, y0, s0, t0; // top-left 541 float x1, y1, s1, t1; // bottom-right 542 } stbtt_aligned_quad; 543 544 STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, // same data as above 545 int char_index, // character to display 546 float *xpos, float *ypos, // pointers to current position in screen pixel space 547 stbtt_aligned_quad *q, // output: quad to draw 548 int opengl_fillrule); // true if opengl fill rule; false if DX9 or earlier 549 // Call GetBakedQuad with char_index = 'character - first_char', and it 550 // creates the quad you need to draw and advances the current position. 551 // 552 // The coordinate system used assumes y increases downwards. 553 // 554 // Characters will extend both above and below the current position; 555 // see discussion of "BASELINE" above. 556 // 557 // It's inefficient; you might want to c&p it and optimize it. 558 559 560 561 ////////////////////////////////////////////////////////////////////////////// 562 // 563 // NEW TEXTURE BAKING API 564 // 565 // This provides options for packing multiple fonts into one atlas, not 566 // perfectly but better than nothing. 567 568 typedef struct 569 { 570 unsigned short x0, y0, x1, y1; // coordinates of bbox in bitmap 571 float xoff, yoff, xadvance; 572 float xoff2, yoff2; 573 } stbtt_packedchar; 574 575 typedef struct stbtt_pack_context stbtt_pack_context; 576 typedef struct stbtt_fontinfo stbtt_fontinfo; 513 // private structure 514 typedef struct 515 { 516 unsigned char *data; 517 int cursor; 518 int size; 519 } stbtt__buf; 520 521 ////////////////////////////////////////////////////////////////////////////// 522 // 523 // TEXTURE BAKING API 524 // 525 // If you use this API, you only have to call two functions ever. 526 // 527 528 typedef struct 529 { 530 unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap 531 float xoff,yoff,xadvance; 532 } stbtt_bakedchar; 533 534 STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) 535 float pixel_height, // height of font in pixels 536 unsigned char *pixels, int pw, int ph, // bitmap to be filled in 537 int first_char, int num_chars, // characters to bake 538 stbtt_bakedchar *chardata); // you allocate this, it's num_chars long 539 // if return is positive, the first unused row of the bitmap 540 // if return is negative, returns the negative of the number of characters that fit 541 // if return is 0, no characters fit and no rows were used 542 // This uses a very crappy packing. 543 544 typedef struct 545 { 546 float x0,y0,s0,t0; // top-left 547 float x1,y1,s1,t1; // bottom-right 548 } stbtt_aligned_quad; 549 550 STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, // same data as above 551 int char_index, // character to display 552 float *xpos, float *ypos, // pointers to current position in screen pixel space 553 stbtt_aligned_quad *q, // output: quad to draw 554 int opengl_fillrule); // true if opengl fill rule; false if DX9 or earlier 555 // Call GetBakedQuad with char_index = 'character - first_char', and it 556 // creates the quad you need to draw and advances the current position. 557 // 558 // The coordinate system used assumes y increases downwards. 559 // 560 // Characters will extend both above and below the current position; 561 // see discussion of "BASELINE" above. 562 // 563 // It's inefficient; you might want to c&p it and optimize it. 564 565 STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap); 566 // Query the font vertical metrics without having to create a font first. 567 568 569 ////////////////////////////////////////////////////////////////////////////// 570 // 571 // NEW TEXTURE BAKING API 572 // 573 // This provides options for packing multiple fonts into one atlas, not 574 // perfectly but better than nothing. 575 576 typedef struct 577 { 578 unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap 579 float xoff,yoff,xadvance; 580 float xoff2,yoff2; 581 } stbtt_packedchar; 582 583 typedef struct stbtt_pack_context stbtt_pack_context; 584 typedef struct stbtt_fontinfo stbtt_fontinfo; 577 585 #ifndef STB_RECT_PACK_VERSION 578 586 typedef struct stbrp_rect stbrp_rect; 579 587 #endif 580 588 581 582 583 584 585 586 587 588 589 590 591 592 STBTT_DEF void stbtt_PackEnd(stbtt_pack_context *spc);593 589 STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context); 590 // Initializes a packing context stored in the passed-in stbtt_pack_context. 591 // Future calls using this context will pack characters into the bitmap passed 592 // in here: a 1-channel bitmap that is width * height. stride_in_bytes is 593 // the distance from one row to the next (or 0 to mean they are packed tightly 594 // together). "padding" is the amount of padding to leave between each 595 // character (normally you want '1' for bitmaps you'll use as textures with 596 // bilinear filtering). 597 // 598 // Returns 0 on failure, 1 on success. 599 600 STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc); 601 // Cleans up the packing context and frees all memory. 594 602 595 603 #define STBTT_POINT_SIZE(x) (-(x)) 596 604 597 STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size, 598 int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range); 599 // Creates character bitmaps from the font_index'th font found in fontdata (use 600 // font_index=0 if you don't know what that is). It creates num_chars_in_range 601 // bitmaps for characters with unicode values starting at first_unicode_char_in_range 602 // and increasing. Data for how to render them is stored in chardata_for_range; 603 // pass these to stbtt_GetPackedQuad to get back renderable quads. 604 // 605 // font_size is the full height of the character from ascender to descender, 606 // as computed by stbtt_ScaleForPixelHeight. To use a point size as computed 607 // by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE() 608 // and pass that result as 'font_size': 609 // ..., 20 , ... // font max minus min y is 20 pixels tall 610 // ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall 611 612 typedef struct 613 { 614 float font_size; 615 int first_unicode_codepoint_in_range; // if non-zero, then the chars are continuous, and this is the first codepoint 616 int *array_of_unicode_codepoints; // if non-zero, then this is an array of unicode codepoints 617 int num_chars; 618 stbtt_packedchar *chardata_for_range; // output 619 unsigned char h_oversample, v_oversample; // don't set these, they're used internally 620 } stbtt_pack_range; 621 622 STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges); 623 // Creates character bitmaps from multiple ranges of characters stored in 624 // ranges. This will usually create a better-packed bitmap than multiple 625 // calls to stbtt_PackFontRange. Note that you can call this multiple 626 // times within a single PackBegin/PackEnd. 627 628 STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample); 629 // Oversampling a font increases the quality by allowing higher-quality subpixel 630 // positioning, and is especially valuable at smaller text sizes. 631 // 632 // This function sets the amount of oversampling for all following calls to 633 // stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given 634 // pack context. The default (no oversampling) is achieved by h_oversample=1 635 // and v_oversample=1. The total number of pixels required is 636 // h_oversample*v_oversample larger than the default; for example, 2x2 637 // oversampling requires 4x the storage of 1x1. For best results, render 638 // oversampled textures with bilinear filtering. Look at the readme in 639 // stb/tests/oversample for information about oversampled fonts 640 // 641 // To use with PackFontRangesGather etc., you must set it before calls 642 // call to PackFontRangesGatherRects. 643 644 STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, // same data as above 645 int char_index, // character to display 646 float *xpos, float *ypos, // pointers to current position in screen pixel space 647 stbtt_aligned_quad *q, // output: quad to draw 648 int align_to_integer); 649 650 STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); 651 STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects); 652 STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); 653 // Calling these functions in sequence is roughly equivalent to calling 654 // stbtt_PackFontRanges(). If you more control over the packing of multiple 655 // fonts, or if you want to pack custom data into a font texture, take a look 656 // at the source to of stbtt_PackFontRanges() and create a custom version 657 // using these functions, e.g. call GatherRects multiple times, 658 // building up a single array of rects, then call PackRects once, 659 // then call RenderIntoRects repeatedly. This may result in a 660 // better packing than calling PackFontRanges multiple times 661 // (or it may not). 662 663 // this is an opaque structure that you shouldn't mess with which holds 664 // all the context needed from PackBegin to PackEnd. 665 struct stbtt_pack_context { 666 void *user_allocator_context; 667 void *pack_info; 668 int width; 669 int height; 670 int stride_in_bytes; 671 int padding; 672 unsigned int h_oversample, v_oversample; 673 unsigned char *pixels; 674 void *nodes; 675 }; 676 677 ////////////////////////////////////////////////////////////////////////////// 678 // 679 // FONT LOADING 680 // 681 // 682 683 STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data); 684 // This function will determine the number of fonts in a font file. TrueType 685 // collection (.ttc) files may contain multiple fonts, while TrueType font 686 // (.ttf) files only contain one font. The number of fonts can be used for 687 // indexing with the previous function where the index is between zero and one 688 // less than the total fonts. If an error occurs, -1 is returned. 689 690 STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index); 691 // Each .ttf/.ttc file may have more than one font. Each font has a sequential 692 // index number starting from 0. Call this function to get the font offset for 693 // a given index; it returns -1 if the index is out of range. A regular .ttf 694 // file will only define one font and it always be at offset 0, so it will 695 // return '0' for index 0, and -1 for all other indices. 696 697 // The following structure is defined publically so you can declare one on 698 // the stack or as a global or etc, but you should treat it as opaque. 699 struct stbtt_fontinfo 700 { 701 void * userdata; 702 unsigned char * data; // pointer to .ttf file 703 int fontstart; // offset of start of font 704 705 int numGlyphs; // number of glyphs, needed for range checking 706 707 int loca, head, glyf, hhea, hmtx, kern, gpos; // table locations as offset from start of .ttf 708 int index_map; // a cmap mapping for our chosen character encoding 709 int indexToLocFormat; // format needed to map from glyph index to glyph 710 711 stbtt__buf cff; // cff font data 712 stbtt__buf charstrings; // the charstring index 713 stbtt__buf gsubrs; // global charstring subroutines index 714 stbtt__buf subrs; // private charstring subroutines index 715 stbtt__buf fontdicts; // array of font dicts 716 stbtt__buf fdselect; // map from glyph to fontdict 717 }; 718 719 STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset); 720 // Given an offset into the file that defines a font, this function builds 721 // the necessary cached info for the rest of the system. You must allocate 722 // the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't 723 // need to do anything special to free it, because the contents are pure 724 // value data with no additional data structures. Returns 0 on failure. 725 726 727 ////////////////////////////////////////////////////////////////////////////// 728 // 729 // CHARACTER TO GLYPH-INDEX CONVERSIOn 730 731 STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint); 732 // If you're going to perform multiple operations on the same character 733 // and you want a speed-up, call this function with the character you're 734 // going to process, then use glyph-based functions instead of the 735 // codepoint-based functions. 736 737 738 ////////////////////////////////////////////////////////////////////////////// 739 // 740 // CHARACTER PROPERTIES 741 // 742 743 STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels); 744 // computes a scale factor to produce a font whose "height" is 'pixels' tall. 745 // Height is measured as the distance from the highest ascender to the lowest 746 // descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics 747 // and computing: 748 // scale = pixels / (ascent - descent) 749 // so if you prefer to measure height by the ascent only, use a similar calculation. 750 751 STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels); 752 // computes a scale factor to produce a font whose EM size is mapped to 753 // 'pixels' tall. This is probably what traditional APIs compute, but 754 // I'm not positive. 755 756 STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap); 757 // ascent is the coordinate above the baseline the font extends; descent 758 // is the coordinate below the baseline the font extends (i.e. it is typically negative) 759 // lineGap is the spacing between one row's descent and the next row's ascent... 760 // so you should advance the vertical position by "*ascent - *descent + *lineGap" 761 // these are expressed in unscaled coordinates, so you must multiply by 762 // the scale factor for a given size 763 764 STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap); 765 // analogous to GetFontVMetrics, but returns the "typographic" values from the OS/2 766 // table (specific to MS/Windows TTF files). 767 // 768 // Returns 1 on success (table present), 0 on failure. 769 770 STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1); 771 // the bounding box around all possible characters 772 773 STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing); 774 // leftSideBearing is the offset from the current horizontal position to the left edge of the character 775 // advanceWidth is the offset from the current horizontal position to the next horizontal position 776 // these are expressed in unscaled coordinates 777 778 STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2); 779 // an additional amount to add to the 'advance' value between ch1 and ch2 780 781 STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1); 782 // Gets the bounding box of the visible part of the glyph, in unscaled coordinates 783 784 STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing); 785 STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2); 786 STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); 787 // as above, but takes one or more glyph indices for greater efficiency 788 789 790 ////////////////////////////////////////////////////////////////////////////// 791 // 792 // GLYPH SHAPES (you probably don't need these, but they have to go before 793 // the bitmaps for C declaration-order reasons) 794 // 605 STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size, 606 int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range); 607 // Creates character bitmaps from the font_index'th font found in fontdata (use 608 // font_index=0 if you don't know what that is). It creates num_chars_in_range 609 // bitmaps for characters with unicode values starting at first_unicode_char_in_range 610 // and increasing. Data for how to render them is stored in chardata_for_range; 611 // pass these to stbtt_GetPackedQuad to get back renderable quads. 612 // 613 // font_size is the full height of the character from ascender to descender, 614 // as computed by stbtt_ScaleForPixelHeight. To use a point size as computed 615 // by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE() 616 // and pass that result as 'font_size': 617 // ..., 20 , ... // font max minus min y is 20 pixels tall 618 // ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall 619 620 typedef struct 621 { 622 float font_size; 623 int first_unicode_codepoint_in_range; // if non-zero, then the chars are continuous, and this is the first codepoint 624 int *array_of_unicode_codepoints; // if non-zero, then this is an array of unicode codepoints 625 int num_chars; 626 stbtt_packedchar *chardata_for_range; // output 627 unsigned char h_oversample, v_oversample; // don't set these, they're used internally 628 } stbtt_pack_range; 629 630 STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges); 631 // Creates character bitmaps from multiple ranges of characters stored in 632 // ranges. This will usually create a better-packed bitmap than multiple 633 // calls to stbtt_PackFontRange. Note that you can call this multiple 634 // times within a single PackBegin/PackEnd. 635 636 STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample); 637 // Oversampling a font increases the quality by allowing higher-quality subpixel 638 // positioning, and is especially valuable at smaller text sizes. 639 // 640 // This function sets the amount of oversampling for all following calls to 641 // stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given 642 // pack context. The default (no oversampling) is achieved by h_oversample=1 643 // and v_oversample=1. The total number of pixels required is 644 // h_oversample*v_oversample larger than the default; for example, 2x2 645 // oversampling requires 4x the storage of 1x1. For best results, render 646 // oversampled textures with bilinear filtering. Look at the readme in 647 // stb/tests/oversample for information about oversampled fonts 648 // 649 // To use with PackFontRangesGather etc., you must set it before calls 650 // call to PackFontRangesGatherRects. 651 652 STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip); 653 // If skip != 0, this tells stb_truetype to skip any codepoints for which 654 // there is no corresponding glyph. If skip=0, which is the default, then 655 // codepoints without a glyph recived the font's "missing character" glyph, 656 // typically an empty box by convention. 657 658 STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, // same data as above 659 int char_index, // character to display 660 float *xpos, float *ypos, // pointers to current position in screen pixel space 661 stbtt_aligned_quad *q, // output: quad to draw 662 int align_to_integer); 663 664 STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); 665 STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects); 666 STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); 667 // Calling these functions in sequence is roughly equivalent to calling 668 // stbtt_PackFontRanges(). If you more control over the packing of multiple 669 // fonts, or if you want to pack custom data into a font texture, take a look 670 // at the source to of stbtt_PackFontRanges() and create a custom version 671 // using these functions, e.g. call GatherRects multiple times, 672 // building up a single array of rects, then call PackRects once, 673 // then call RenderIntoRects repeatedly. This may result in a 674 // better packing than calling PackFontRanges multiple times 675 // (or it may not). 676 677 // this is an opaque structure that you shouldn't mess with which holds 678 // all the context needed from PackBegin to PackEnd. 679 struct stbtt_pack_context { 680 void *user_allocator_context; 681 void *pack_info; 682 int width; 683 int height; 684 int stride_in_bytes; 685 int padding; 686 int skip_missing; 687 unsigned int h_oversample, v_oversample; 688 unsigned char *pixels; 689 void *nodes; 690 }; 691 692 ////////////////////////////////////////////////////////////////////////////// 693 // 694 // FONT LOADING 695 // 696 // 697 698 STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data); 699 // This function will determine the number of fonts in a font file. TrueType 700 // collection (.ttc) files may contain multiple fonts, while TrueType font 701 // (.ttf) files only contain one font. The number of fonts can be used for 702 // indexing with the previous function where the index is between zero and one 703 // less than the total fonts. If an error occurs, -1 is returned. 704 705 STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index); 706 // Each .ttf/.ttc file may have more than one font. Each font has a sequential 707 // index number starting from 0. Call this function to get the font offset for 708 // a given index; it returns -1 if the index is out of range. A regular .ttf 709 // file will only define one font and it always be at offset 0, so it will 710 // return '0' for index 0, and -1 for all other indices. 711 712 // The following structure is defined publicly so you can declare one on 713 // the stack or as a global or etc, but you should treat it as opaque. 714 struct stbtt_fontinfo 715 { 716 void * userdata; 717 unsigned char * data; // pointer to .ttf file 718 int fontstart; // offset of start of font 719 720 int numGlyphs; // number of glyphs, needed for range checking 721 722 int loca,head,glyf,hhea,hmtx,kern,gpos; // table locations as offset from start of .ttf 723 int index_map; // a cmap mapping for our chosen character encoding 724 int indexToLocFormat; // format needed to map from glyph index to glyph 725 726 stbtt__buf cff; // cff font data 727 stbtt__buf charstrings; // the charstring index 728 stbtt__buf gsubrs; // global charstring subroutines index 729 stbtt__buf subrs; // private charstring subroutines index 730 stbtt__buf fontdicts; // array of font dicts 731 stbtt__buf fdselect; // map from glyph to fontdict 732 }; 733 734 STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset); 735 // Given an offset into the file that defines a font, this function builds 736 // the necessary cached info for the rest of the system. You must allocate 737 // the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't 738 // need to do anything special to free it, because the contents are pure 739 // value data with no additional data structures. Returns 0 on failure. 740 741 742 ////////////////////////////////////////////////////////////////////////////// 743 // 744 // CHARACTER TO GLYPH-INDEX CONVERSIOn 745 746 STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint); 747 // If you're going to perform multiple operations on the same character 748 // and you want a speed-up, call this function with the character you're 749 // going to process, then use glyph-based functions instead of the 750 // codepoint-based functions. 751 // Returns 0 if the character codepoint is not defined in the font. 752 753 754 ////////////////////////////////////////////////////////////////////////////// 755 // 756 // CHARACTER PROPERTIES 757 // 758 759 STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels); 760 // computes a scale factor to produce a font whose "height" is 'pixels' tall. 761 // Height is measured as the distance from the highest ascender to the lowest 762 // descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics 763 // and computing: 764 // scale = pixels / (ascent - descent) 765 // so if you prefer to measure height by the ascent only, use a similar calculation. 766 767 STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels); 768 // computes a scale factor to produce a font whose EM size is mapped to 769 // 'pixels' tall. This is probably what traditional APIs compute, but 770 // I'm not positive. 771 772 STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap); 773 // ascent is the coordinate above the baseline the font extends; descent 774 // is the coordinate below the baseline the font extends (i.e. it is typically negative) 775 // lineGap is the spacing between one row's descent and the next row's ascent... 776 // so you should advance the vertical position by "*ascent - *descent + *lineGap" 777 // these are expressed in unscaled coordinates, so you must multiply by 778 // the scale factor for a given size 779 780 STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap); 781 // analogous to GetFontVMetrics, but returns the "typographic" values from the OS/2 782 // table (specific to MS/Windows TTF files). 783 // 784 // Returns 1 on success (table present), 0 on failure. 785 786 STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1); 787 // the bounding box around all possible characters 788 789 STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing); 790 // leftSideBearing is the offset from the current horizontal position to the left edge of the character 791 // advanceWidth is the offset from the current horizontal position to the next horizontal position 792 // these are expressed in unscaled coordinates 793 794 STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2); 795 // an additional amount to add to the 'advance' value between ch1 and ch2 796 797 STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1); 798 // Gets the bounding box of the visible part of the glyph, in unscaled coordinates 799 800 STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing); 801 STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2); 802 STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); 803 // as above, but takes one or more glyph indices for greater efficiency 804 805 806 ////////////////////////////////////////////////////////////////////////////// 807 // 808 // GLYPH SHAPES (you probably don't need these, but they have to go before 809 // the bitmaps for C declaration-order reasons) 810 // 795 811 796 812 #ifndef STBTT_vmove // you can predefine these to use different values (but why?) 797 813 enum { 798 STBTT_vmove =1,814 STBTT_vmove=1, 799 815 STBTT_vline, 800 816 STBTT_vcurve, … … 804 820 805 821 #ifndef stbtt_vertex // you can predefine this to use different values 806 // (we share this with other code at RAD)807 #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file822 // (we share this with other code at RAD) 823 #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file 808 824 typedef struct 809 825 { 810 stbtt_vertex_type x, y, cx, cy, cx1,cy1;811 unsigned char type, 826 stbtt_vertex_type x,y,cx,cy,cx1,cy1; 827 unsigned char type,padding; 812 828 } stbtt_vertex; 813 829 #endif 814 830 815 816 817 818 819 820 821 822 823 // The shape is a series of countours. Each one starts with824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);888 889 890 891 892 893 int w, h,stride;894 895 896 897 898 899 float flatness_in_pixels, // allowable error of curve in pixels900 stbtt_vertex *vertices, // array of vertices defining shape901 int num_verts, // number of vertices in above array902 float scale_x, float scale_y, // scale applied to input vertices903 float shift_x, float shift_y, // translation applied to input vertices904 int x_off, int y_off, // another translation applied to input905 int invert, // if non-zero, vertically flip shape906 void *userdata); // context for to STBTT_MALLOC907 908 909 910 911 912 913 914 915 916 917 918 919 // larger than some threshhold to produce scalable fonts.920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 831 STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index); 832 // returns non-zero if nothing is drawn for this glyph 833 834 STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices); 835 STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices); 836 // returns # of vertices and fills *vertices with the pointer to them 837 // these are expressed in "unscaled" coordinates 838 // 839 // The shape is a series of contours. Each one starts with 840 // a STBTT_moveto, then consists of a series of mixed 841 // STBTT_lineto and STBTT_curveto segments. A lineto 842 // draws a line from previous endpoint to its x,y; a curveto 843 // draws a quadratic bezier from previous endpoint to 844 // its x,y, using cx,cy as the bezier control point. 845 846 STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices); 847 // frees the data allocated above 848 849 ////////////////////////////////////////////////////////////////////////////// 850 // 851 // BITMAP RENDERING 852 // 853 854 STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata); 855 // frees the bitmap allocated below 856 857 STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff); 858 // allocates a large-enough single-channel 8bpp bitmap and renders the 859 // specified character/glyph at the specified scale into it, with 860 // antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque). 861 // *width & *height are filled out with the width & height of the bitmap, 862 // which is stored left-to-right, top-to-bottom. 863 // 864 // xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap 865 866 STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff); 867 // the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel 868 // shift for the character 869 870 STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint); 871 // the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap 872 // in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap 873 // is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the 874 // width and height and positioning info for it first. 875 876 STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint); 877 // same as stbtt_MakeCodepointBitmap, but you can specify a subpixel 878 // shift for the character 879 880 STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint); 881 // same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering 882 // is performed (see stbtt_PackSetOversampling) 883 884 STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); 885 // get the bbox of the bitmap centered around the glyph origin; so the 886 // bitmap width is ix1-ix0, height is iy1-iy0, and location to place 887 // the bitmap top left is (leftSideBearing*scale,iy0). 888 // (Note that the bitmap uses y-increases-down, but the shape uses 889 // y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.) 890 891 STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); 892 // same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel 893 // shift for the character 894 895 // the following functions are equivalent to the above functions, but operate 896 // on glyph indices instead of Unicode codepoints (for efficiency) 897 STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff); 898 STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff); 899 STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph); 900 STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph); 901 STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph); 902 STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); 903 STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); 904 905 906 // @TODO: don't expose this structure 907 typedef struct 908 { 909 int w,h,stride; 910 unsigned char *pixels; 911 } stbtt__bitmap; 912 913 // rasterize a shape with quadratic beziers into a bitmap 914 STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, // 1-channel bitmap to draw into 915 float flatness_in_pixels, // allowable error of curve in pixels 916 stbtt_vertex *vertices, // array of vertices defining shape 917 int num_verts, // number of vertices in above array 918 float scale_x, float scale_y, // scale applied to input vertices 919 float shift_x, float shift_y, // translation applied to input vertices 920 int x_off, int y_off, // another translation applied to input 921 int invert, // if non-zero, vertically flip shape 922 void *userdata); // context for to STBTT_MALLOC 923 924 ////////////////////////////////////////////////////////////////////////////// 925 // 926 // Signed Distance Function (or Field) rendering 927 928 STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata); 929 // frees the SDF bitmap allocated below 930 931 STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff); 932 STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff); 933 // These functions compute a discretized SDF field for a single character, suitable for storing 934 // in a single-channel texture, sampling with bilinear filtering, and testing against 935 // larger than some threshold to produce scalable fonts. 936 // info -- the font 937 // scale -- controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap 938 // glyph/codepoint -- the character to generate the SDF for 939 // padding -- extra "pixels" around the character which are filled with the distance to the character (not 0), 940 // which allows effects like bit outlines 941 // onedge_value -- value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character) 942 // pixel_dist_scale -- what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale) 943 // if positive, > onedge_value is inside; if negative, < onedge_value is inside 944 // width,height -- output height & width of the SDF bitmap (including padding) 945 // xoff,yoff -- output origin of the character 946 // return value -- a 2D array of bytes 0..255, width*height in size 947 // 948 // pixel_dist_scale & onedge_value are a scale & bias that allows you to make 949 // optimal use of the limited 0..255 for your application, trading off precision 950 // and special effects. SDF values outside the range 0..255 are clamped to 0..255. 951 // 952 // Example: 953 // scale = stbtt_ScaleForPixelHeight(22) 954 // padding = 5 955 // onedge_value = 180 956 // pixel_dist_scale = 180/5.0 = 36.0 957 // 958 // This will create an SDF bitmap in which the character is about 22 pixels 959 // high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled 960 // shape, sample the SDF at each pixel and fill the pixel if the SDF value 961 // is greater than or equal to 180/255. (You'll actually want to antialias, 962 // which is beyond the scope of this example.) Additionally, you can compute 963 // offset outlines (e.g. to stroke the character border inside & outside, 964 // or only outside). For example, to fill outside the character up to 3 SDF 965 // pixels, you would compare against (180-36.0*3)/255 = 72/255. The above 966 // choice of variables maps a range from 5 pixels outside the shape to 967 // 2 pixels inside the shape to 0..255; this is intended primarily for apply 968 // outside effects only (the interior range is needed to allow proper 969 // antialiasing of the font at *smaller* sizes) 970 // 971 // The function computes the SDF analytically at each SDF pixel, not by e.g. 972 // building a higher-res bitmap and approximating it. In theory the quality 973 // should be as high as possible for an SDF of this size & representation, but 974 // unclear if this is true in practice (perhaps building a higher-res bitmap 975 // and computing from that can allow drop-out prevention). 976 // 977 // The algorithm has not been optimized at all, so expect it to be slow 978 // if computing lots of characters or very large sizes. 979 980 981 982 ////////////////////////////////////////////////////////////////////////////// 983 // 984 // Finding the right font... 985 // 986 // You should really just solve this offline, keep your own tables 987 // of what font is what, and don't try to get it out of the .ttf file. 988 // That's because getting it out of the .ttf file is really hard, because 989 // the names in the file can appear in many possible encodings, in many 990 // possible languages, and e.g. if you need a case-insensitive comparison, 991 // the details of that depend on the encoding & language in a complex way 992 // (actually underspecified in truetype, but also gigantic). 993 // 994 // But you can use the provided functions in two possible ways: 995 // stbtt_FindMatchingFont() will use *case-sensitive* comparisons on 996 // unicode-encoded names to try to find the font you want; 997 // you can run this before calling stbtt_InitFont() 998 // 999 // stbtt_GetFontNameString() lets you get any of the various strings 1000 // from the file yourself and do your own comparisons on them. 1001 // You have to have called stbtt_InitFont() first. 1002 1003 1004 STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags); 1005 // returns the offset (not index) of the font that matches, or -1 if none 1006 // if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold". 1007 // if you use any other flag, use a font name like "Arial"; this checks 1008 // the 'macStyle' header field; i don't know if fonts set this consistently 993 1009 #define STBTT_MACSTYLE_DONTCARE 0 994 1010 #define STBTT_MACSTYLE_BOLD 1 … … 997 1013 #define STBTT_MACSTYLE_NONE 8 // <= not same as 0, this makes us check the bitfield is 0 998 1014 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 STBTT_PLATFORM_ID_UNICODE =0,1013 STBTT_PLATFORM_ID_MAC =1,1014 STBTT_PLATFORM_ID_ISO =2,1015 STBTT_PLATFORM_ID_MICROSOFT =31016 1017 1018 1019 STBTT_UNICODE_EID_UNICODE_1_0 =0,1020 STBTT_UNICODE_EID_UNICODE_1_1 =1,1021 STBTT_UNICODE_EID_ISO_10646 =2,1022 STBTT_UNICODE_EID_UNICODE_2_0_BMP =3,1023 STBTT_UNICODE_EID_UNICODE_2_0_FULL =41024 1025 1026 1027 STBTT_MS_EID_SYMBOL =0,1028 STBTT_MS_EID_UNICODE_BMP =1,1029 STBTT_MS_EID_SHIFTJIS =2,1030 STBTT_MS_EID_UNICODE_FULL =101031 1032 1033 1034 STBTT_MAC_EID_ROMAN = 0, STBTT_MAC_EID_ARABIC =4,1035 STBTT_MAC_EID_JAPANESE = 1, STBTT_MAC_EID_HEBREW =5,1036 STBTT_MAC_EID_CHINESE_TRAD = 2, STBTT_MAC_EID_GREEK =6,1037 STBTT_MAC_EID_KOREAN = 3, STBTT_MAC_EID_RUSSIAN =71038 1039 1040 1041 1042 STBTT_MS_LANG_ENGLISH = 0x0409, STBTT_MS_LANG_ITALIAN =0x0410,1043 STBTT_MS_LANG_CHINESE = 0x0804, STBTT_MS_LANG_JAPANESE =0x0411,1044 STBTT_MS_LANG_DUTCH = 0x0413, STBTT_MS_LANG_KOREAN =0x0412,1045 STBTT_MS_LANG_FRENCH = 0x040c, STBTT_MS_LANG_RUSSIAN =0x0419,1046 STBTT_MS_LANG_GERMAN = 0x0407, STBTT_MS_LANG_SPANISH =0x0409,1047 STBTT_MS_LANG_HEBREW = 0x040d, STBTT_MS_LANG_SWEDISH =0x041D1048 1049 1050 1051 STBTT_MAC_LANG_ENGLISH = 0, STBTT_MAC_LANG_JAPANESE =11,1052 STBTT_MAC_LANG_ARABIC = 12, STBTT_MAC_LANG_KOREAN =23,1053 STBTT_MAC_LANG_DUTCH = 4, STBTT_MAC_LANG_RUSSIAN =32,1054 STBTT_MAC_LANG_FRENCH = 1, STBTT_MAC_LANG_SPANISH = 6,1055 STBTT_MAC_LANG_GERMAN = 2, STBTT_MAC_LANG_SWEDISH = 5,1056 STBTT_MAC_LANG_HEBREW = 10, STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33,1057 STBTT_MAC_LANG_ITALIAN = 3, STBTT_MAC_LANG_CHINESE_TRAD =191058 1015 STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2); 1016 // returns 1/0 whether the first string interpreted as utf8 is identical to 1017 // the second string interpreted as big-endian utf16... useful for strings from next func 1018 1019 STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID); 1020 // returns the string (which may be big-endian double byte, e.g. for unicode) 1021 // and puts the length in bytes in *length. 1022 // 1023 // some of the values for the IDs are below; for more see the truetype spec: 1024 // http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html 1025 // http://www.microsoft.com/typography/otspec/name.htm 1026 1027 enum { // platformID 1028 STBTT_PLATFORM_ID_UNICODE =0, 1029 STBTT_PLATFORM_ID_MAC =1, 1030 STBTT_PLATFORM_ID_ISO =2, 1031 STBTT_PLATFORM_ID_MICROSOFT =3 1032 }; 1033 1034 enum { // encodingID for STBTT_PLATFORM_ID_UNICODE 1035 STBTT_UNICODE_EID_UNICODE_1_0 =0, 1036 STBTT_UNICODE_EID_UNICODE_1_1 =1, 1037 STBTT_UNICODE_EID_ISO_10646 =2, 1038 STBTT_UNICODE_EID_UNICODE_2_0_BMP=3, 1039 STBTT_UNICODE_EID_UNICODE_2_0_FULL=4 1040 }; 1041 1042 enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT 1043 STBTT_MS_EID_SYMBOL =0, 1044 STBTT_MS_EID_UNICODE_BMP =1, 1045 STBTT_MS_EID_SHIFTJIS =2, 1046 STBTT_MS_EID_UNICODE_FULL =10 1047 }; 1048 1049 enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes 1050 STBTT_MAC_EID_ROMAN =0, STBTT_MAC_EID_ARABIC =4, 1051 STBTT_MAC_EID_JAPANESE =1, STBTT_MAC_EID_HEBREW =5, 1052 STBTT_MAC_EID_CHINESE_TRAD =2, STBTT_MAC_EID_GREEK =6, 1053 STBTT_MAC_EID_KOREAN =3, STBTT_MAC_EID_RUSSIAN =7 1054 }; 1055 1056 enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID... 1057 // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs 1058 STBTT_MS_LANG_ENGLISH =0x0409, STBTT_MS_LANG_ITALIAN =0x0410, 1059 STBTT_MS_LANG_CHINESE =0x0804, STBTT_MS_LANG_JAPANESE =0x0411, 1060 STBTT_MS_LANG_DUTCH =0x0413, STBTT_MS_LANG_KOREAN =0x0412, 1061 STBTT_MS_LANG_FRENCH =0x040c, STBTT_MS_LANG_RUSSIAN =0x0419, 1062 STBTT_MS_LANG_GERMAN =0x0407, STBTT_MS_LANG_SPANISH =0x0409, 1063 STBTT_MS_LANG_HEBREW =0x040d, STBTT_MS_LANG_SWEDISH =0x041D 1064 }; 1065 1066 enum { // languageID for STBTT_PLATFORM_ID_MAC 1067 STBTT_MAC_LANG_ENGLISH =0 , STBTT_MAC_LANG_JAPANESE =11, 1068 STBTT_MAC_LANG_ARABIC =12, STBTT_MAC_LANG_KOREAN =23, 1069 STBTT_MAC_LANG_DUTCH =4 , STBTT_MAC_LANG_RUSSIAN =32, 1070 STBTT_MAC_LANG_FRENCH =1 , STBTT_MAC_LANG_SPANISH =6 , 1071 STBTT_MAC_LANG_GERMAN =2 , STBTT_MAC_LANG_SWEDISH =5 , 1072 STBTT_MAC_LANG_HEBREW =10, STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33, 1073 STBTT_MAC_LANG_ITALIAN =3 , STBTT_MAC_LANG_CHINESE_TRAD =19 1074 }; 1059 1075 1060 1076 #ifdef __cplusplus … … 1081 1097 #endif 1082 1098 1083 typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE -1)) == 0 ? 1 : -1];1099 typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1]; 1084 1100 1085 1101 #ifndef STBTT_RASTERIZER_VERSION … … 1137 1153 stbtt__buf r; 1138 1154 STBTT_assert(size < 0x40000000); 1139 r.data = (stbtt_uint8*) p;1140 r.size = (int) size;1155 r.data = (stbtt_uint8*) p; 1156 r.size = (int) size; 1141 1157 r.cursor = 0; 1142 1158 return r; … … 1173 1189 int b0 = stbtt__buf_get8(b); 1174 1190 if (b0 >= 32 && b0 <= 246) return b0 - 139; 1175 else if (b0 >= 247 && b0 <= 250) return (b0 - 247) *256 + stbtt__buf_get8(b) + 108;1176 else if (b0 >= 251 && b0 <= 254) return -(b0 - 251) *256 - stbtt__buf_get8(b) - 108;1191 else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108; 1192 else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108; 1177 1193 else if (b0 == 28) return stbtt__buf_get16(b); 1178 1194 else if (b0 == 29) return stbtt__buf_get32(b); … … 1191 1207 break; 1192 1208 } 1193 } 1194 else { 1209 } else { 1195 1210 stbtt__cff_int(b); 1196 1211 } … … 1207 1222 op = stbtt__buf_get8(b); 1208 1223 if (op == 12) op = stbtt__buf_get8(b) | 0x100; 1209 if (op == key) return stbtt__buf_range(b, start, end -start);1224 if (op == key) return stbtt__buf_range(b, start, end-start); 1210 1225 } 1211 1226 return stbtt__buf_range(b, 0, 0); … … 1237 1252 start = stbtt__buf_get(&b, offsize); 1238 1253 end = stbtt__buf_get(&b, offsize); 1239 return stbtt__buf_range(&b, 2 + (count + 1)*offsize +start, end - start);1254 return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start); 1240 1255 } 1241 1256 … … 1252 1267 #define ttFixed(p) ttLONG(p) 1253 1268 1254 static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0] *256 + p[1]; }1255 static stbtt_int16 ttSHORT(stbtt_uint8 *p) { return p[0] *256 + p[1]; }1256 static stbtt_uint32 ttULONG(stbtt_uint8 *p) { return (p[0] << 24) + (p[1] << 16) + (p[2] <<8) + p[3]; }1257 static stbtt_int32 ttLONG(stbtt_uint8 *p) { return (p[0] << 24) + (p[1] << 16) + (p[2] <<8) + p[3]; }1269 static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } 1270 static stbtt_int16 ttSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } 1271 static stbtt_uint32 ttULONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } 1272 static stbtt_int32 ttLONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } 1258 1273 1259 1274 #define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3)) … … 1263 1278 { 1264 1279 // check the version number 1265 if (stbtt_tag4(font, '1', 0, 0,0)) return 1; // TrueType 11280 if (stbtt_tag4(font, '1',0,0,0)) return 1; // TrueType 1 1266 1281 if (stbtt_tag(font, "typ1")) return 1; // TrueType with type 1 font -- we don't support this! 1267 1282 if (stbtt_tag(font, "OTTO")) return 1; // OpenType with CFF 1268 if (stbtt_tag4(font, 0, 1, 0,0)) return 1; // OpenType 1.01283 if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0 1269 1284 if (stbtt_tag(font, "true")) return 1; // Apple specification for TrueType fonts 1270 1285 return 0; … … 1274 1289 static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag) 1275 1290 { 1276 stbtt_int32 num_tables = ttUSHORT(data + fontstart +4);1291 stbtt_int32 num_tables = ttUSHORT(data+fontstart+4); 1277 1292 stbtt_uint32 tabledir = fontstart + 12; 1278 1293 stbtt_int32 i; 1279 for (i =0; i < num_tables; ++i) {1280 stbtt_uint32 loc = tabledir + 16 *i;1281 if (stbtt_tag(data + loc +0, tag))1282 return ttULONG(data + loc +8);1294 for (i=0; i < num_tables; ++i) { 1295 stbtt_uint32 loc = tabledir + 16*i; 1296 if (stbtt_tag(data+loc+0, tag)) 1297 return ttULONG(data+loc+8); 1283 1298 } 1284 1299 return 0; … … 1294 1309 if (stbtt_tag(font_collection, "ttcf")) { 1295 1310 // version 1? 1296 if (ttULONG(font_collection + 4) == 0x00010000 || ttULONG(font_collection +4) == 0x00020000) {1297 stbtt_int32 n = ttLONG(font_collection +8);1311 if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { 1312 stbtt_int32 n = ttLONG(font_collection+8); 1298 1313 if (index >= n) 1299 1314 return -1; 1300 return ttULONG(font_collection + 12 + index *4);1315 return ttULONG(font_collection+12+index*4); 1301 1316 } 1302 1317 } … … 1313 1328 if (stbtt_tag(font_collection, "ttcf")) { 1314 1329 // version 1? 1315 if (ttULONG(font_collection + 4) == 0x00010000 || ttULONG(font_collection +4) == 0x00020000) {1316 return ttLONG(font_collection +8);1330 if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { 1331 return ttLONG(font_collection+8); 1317 1332 } 1318 1333 } … … 1329 1344 stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff); 1330 1345 if (!subrsoff) return stbtt__new_buf(NULL, 0); 1331 stbtt__buf_seek(&cff, private_loc[1] +subrsoff);1346 stbtt__buf_seek(&cff, private_loc[1]+subrsoff); 1332 1347 return stbtt__cff_get_index(&cff); 1333 1348 } … … 1336 1351 { 1337 1352 stbtt_uint32 cmap, t; 1338 stbtt_int32 i, 1353 stbtt_int32 i,numTables; 1339 1354 1340 1355 info->data = data; … … 1356 1371 // required for truetype 1357 1372 if (!info->loca) return 0; 1358 } 1359 else { 1373 } else { 1360 1374 // initialization for CFF / Type2 fonts (OTF) 1361 1375 stbtt__buf b, topdict, topdictidx; … … 1370 1384 1371 1385 // @TODO this should use size from table (not 512MB) 1372 info->cff = stbtt__new_buf(data + cff, 512 * 1024 *1024);1386 info->cff = stbtt__new_buf(data+cff, 512*1024*1024); 1373 1387 b = info->cff; 1374 1388 … … 1377 1391 stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize 1378 1392 1379 1380 1393 // @TODO the name INDEX could list multiple fonts, 1394 // but we just use the first one. 1381 1395 stbtt__cff_get_index(&b); // name INDEX 1382 1396 topdictidx = stbtt__cff_get_index(&b); … … 1400 1414 stbtt__buf_seek(&b, fdarrayoff); 1401 1415 info->fontdicts = stbtt__cff_get_index(&b); 1402 info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size -fdselectoff);1416 info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff); 1403 1417 } 1404 1418 … … 1409 1423 t = stbtt__find_table(data, fontstart, "maxp"); 1410 1424 if (t) 1411 info->numGlyphs = ttUSHORT(data + t +4);1425 info->numGlyphs = ttUSHORT(data+t+4); 1412 1426 else 1413 1427 info->numGlyphs = 0xffff; … … 1418 1432 numTables = ttUSHORT(data + cmap + 2); 1419 1433 info->index_map = 0; 1420 for (i =0; i < numTables; ++i) {1434 for (i=0; i < numTables; ++i) { 1421 1435 stbtt_uint32 encoding_record = cmap + 4 + 8 * i; 1422 1436 // find an encoding we understand: 1423 switch (ttUSHORT(data + encoding_record)) { 1424 case STBTT_PLATFORM_ID_MICROSOFT: 1425 switch (ttUSHORT(data + encoding_record + 2)) { 1426 case STBTT_MS_EID_UNICODE_BMP: 1427 case STBTT_MS_EID_UNICODE_FULL: 1428 // MS/Unicode 1429 info->index_map = cmap + ttULONG(data + encoding_record + 4); 1437 switch(ttUSHORT(data+encoding_record)) { 1438 case STBTT_PLATFORM_ID_MICROSOFT: 1439 switch (ttUSHORT(data+encoding_record+2)) { 1440 case STBTT_MS_EID_UNICODE_BMP: 1441 case STBTT_MS_EID_UNICODE_FULL: 1442 // MS/Unicode 1443 info->index_map = cmap + ttULONG(data+encoding_record+4); 1444 break; 1445 } 1430 1446 break; 1431 } 1432 break; 1433 case STBTT_PLATFORM_ID_UNICODE: 1434 // Mac/iOS has these 1435 // all the encodingIDs are unicode, so we don't bother to check it 1436 info->index_map = cmap + ttULONG(data + encoding_record + 4); 1437 break; 1447 case STBTT_PLATFORM_ID_UNICODE: 1448 // Mac/iOS has these 1449 // all the encodingIDs are unicode, so we don't bother to check it 1450 info->index_map = cmap + ttULONG(data+encoding_record+4); 1451 break; 1438 1452 } 1439 1453 } … … 1441 1455 return 0; 1442 1456 1443 info->indexToLocFormat = ttUSHORT(data +info->head + 50);1457 info->indexToLocFormat = ttUSHORT(data+info->head + 50); 1444 1458 return 1; 1445 1459 } … … 1453 1467 if (format == 0) { // apple byte encoding 1454 1468 stbtt_int32 bytes = ttUSHORT(data + index_map + 2); 1455 if (unicode_codepoint < bytes -6)1469 if (unicode_codepoint < bytes-6) 1456 1470 return ttBYTE(data + index_map + 6 + unicode_codepoint); 1457 1471 return 0; 1458 } 1459 else if (format == 6) { 1472 } else if (format == 6) { 1460 1473 stbtt_uint32 first = ttUSHORT(data + index_map + 6); 1461 1474 stbtt_uint32 count = ttUSHORT(data + index_map + 8); 1462 if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32)unicode_codepoint < first +count)1463 return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first) *2);1475 if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count) 1476 return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2); 1464 1477 return 0; 1465 } 1466 else if (format == 2) { 1478 } else if (format == 2) { 1467 1479 STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean 1468 1480 return 0; 1469 } 1470 else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges 1471 stbtt_uint16 segcount = ttUSHORT(data + index_map + 6) >> 1; 1472 stbtt_uint16 searchRange = ttUSHORT(data + index_map + 8) >> 1; 1473 stbtt_uint16 entrySelector = ttUSHORT(data + index_map + 10); 1474 stbtt_uint16 rangeShift = ttUSHORT(data + index_map + 12) >> 1; 1481 } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges 1482 stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1; 1483 stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1; 1484 stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10); 1485 stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1; 1475 1486 1476 1487 // do a binary search of the segments … … 1483 1494 // they lie from endCount .. endCount + segCount 1484 1495 // but searchRange is the nearest power of two, so... 1485 if (unicode_codepoint >= ttUSHORT(data + search + rangeShift *2))1486 search += rangeShift *2;1496 if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2)) 1497 search += rangeShift*2; 1487 1498 1488 1499 // now decrement to bias correctly to find smallest … … 1491 1502 stbtt_uint16 end; 1492 1503 searchRange >>= 1; 1493 end = ttUSHORT(data + search + searchRange *2);1504 end = ttUSHORT(data + search + searchRange*2); 1494 1505 if (unicode_codepoint > end) 1495 search += searchRange *2;1506 search += searchRange*2; 1496 1507 --entrySelector; 1497 1508 } … … 1500 1511 { 1501 1512 stbtt_uint16 offset, start; 1502 stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1);1503 1504 STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2 *item));1505 start = ttUSHORT(data + index_map + 14 + segcount * 2 + 2 + 2 *item);1513 stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1); 1514 1515 STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item)); 1516 start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item); 1506 1517 if (unicode_codepoint < start) 1507 1518 return 0; 1508 1519 1509 offset = ttUSHORT(data + index_map + 14 + segcount * 6 + 2 + 2 *item);1520 offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item); 1510 1521 if (offset == 0) 1511 return (stbtt_uint16)(unicode_codepoint + ttSHORT(data + index_map + 14 + segcount * 4 + 2 + 2 * item)); 1512 1513 return ttUSHORT(data + offset + (unicode_codepoint - start) * 2 + index_map + 14 + segcount * 6 + 2 + 2 * item); 1514 } 1515 } 1516 else if (format == 12 || format == 13) { 1517 stbtt_uint32 ngroups = ttULONG(data + index_map + 12); 1518 stbtt_int32 low, high; 1522 return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item)); 1523 1524 return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item); 1525 } 1526 } else if (format == 12 || format == 13) { 1527 stbtt_uint32 ngroups = ttULONG(data+index_map+12); 1528 stbtt_int32 low,high; 1519 1529 low = 0; high = (stbtt_int32)ngroups; 1520 1530 // Binary search the right group. 1521 1531 while (low < high) { 1522 stbtt_int32 mid = low + ((high -low) >> 1); // rounds down, so low <= mid < high1523 stbtt_uint32 start_char = ttULONG(data + index_map + 16 + mid *12);1524 stbtt_uint32 end_char = ttULONG(data + index_map + 16 + mid * 12 +4);1525 if ((stbtt_uint32) unicode_codepoint < start_char)1532 stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high 1533 stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12); 1534 stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4); 1535 if ((stbtt_uint32) unicode_codepoint < start_char) 1526 1536 high = mid; 1527 else if ((stbtt_uint32) unicode_codepoint > end_char)1528 low = mid +1;1537 else if ((stbtt_uint32) unicode_codepoint > end_char) 1538 low = mid+1; 1529 1539 else { 1530 stbtt_uint32 start_glyph = ttULONG(data + index_map + 16 + mid * 12 +8);1540 stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8); 1531 1541 if (format == 12) 1532 return start_glyph + unicode_codepoint -start_char;1542 return start_glyph + unicode_codepoint-start_char; 1533 1543 else // format == 13 1534 1544 return start_glyph; … … 1550 1560 { 1551 1561 v->type = type; 1552 v->x = (stbtt_int16) x;1553 v->y = (stbtt_int16) y;1554 v->cx = (stbtt_int16) cx;1555 v->cy = (stbtt_int16) cy;1562 v->x = (stbtt_int16) x; 1563 v->y = (stbtt_int16) y; 1564 v->cx = (stbtt_int16) cx; 1565 v->cy = (stbtt_int16) cy; 1556 1566 } 1557 1567 1558 1568 static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index) 1559 1569 { 1560 int g1, 1570 int g1,g2; 1561 1571 1562 1572 STBTT_assert(!info->cff.size); … … 1568 1578 g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2; 1569 1579 g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2; 1570 } 1571 else { 1572 g1 = info->glyf + ttULONG(info->data + info->loca + glyph_index * 4); 1573 g2 = info->glyf + ttULONG(info->data + info->loca + glyph_index * 4 + 4); 1574 } 1575 1576 return g1 == g2 ? -1 : g1; // if length is 0, return -1 1580 } else { 1581 g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4); 1582 g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4); 1583 } 1584 1585 return g1==g2 ? -1 : g1; // if length is 0, return -1 1577 1586 } 1578 1587 … … 1583 1592 if (info->cff.size) { 1584 1593 stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1); 1585 } 1586 else { 1594 } else { 1587 1595 int g = stbtt__GetGlyfOffset(info, glyph_index); 1588 1596 if (g < 0) return 0; … … 1598 1606 STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1) 1599 1607 { 1600 return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info, codepoint), x0, y0, x1,y1);1608 return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1); 1601 1609 } 1602 1610 … … 1614 1622 1615 1623 static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off, 1616 stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy)1624 stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy) 1617 1625 { 1618 1626 if (start_off) { 1619 1627 if (was_off) 1620 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx + scx) >> 1, (cy + scy) >> 1, cx, cy); 1621 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx, sy, scx, scy); 1622 } 1623 else { 1628 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy); 1629 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy); 1630 } else { 1624 1631 if (was_off) 1625 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx, sy, cx,cy);1632 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy); 1626 1633 else 1627 stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, sx, sy, 0,0);1634 stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0); 1628 1635 } 1629 1636 return num_vertices; … … 1635 1642 stbtt_uint8 *endPtsOfContours; 1636 1643 stbtt_uint8 *data = info->data; 1637 stbtt_vertex *vertices =0;1638 int num_vertices =0;1644 stbtt_vertex *vertices=0; 1645 int num_vertices=0; 1639 1646 int g = stbtt__GetGlyfOffset(info, glyph_index); 1640 1647 … … 1646 1653 1647 1654 if (numberOfContours > 0) { 1648 stbtt_uint8 flags = 0,flagcount;1649 stbtt_int32 ins, i, j = 0, m, n, next_move, was_off = 0, off, start_off =0;1650 stbtt_int32 x, y, cx, cy, sx, sy, scx,scy;1655 stbtt_uint8 flags=0,flagcount; 1656 stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0; 1657 stbtt_int32 x,y,cx,cy,sx,sy, scx,scy; 1651 1658 stbtt_uint8 *points; 1652 1659 endPtsOfContours = (data + g + 10); … … 1654 1661 points = data + g + 10 + numberOfContours * 2 + 2 + ins; 1655 1662 1656 n = 1 + ttUSHORT(endPtsOfContours + numberOfContours * 2 -2);1657 1658 m = n + 2 *numberOfContours; // a loose bound on how many vertices we might need1659 vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata);1663 n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2); 1664 1665 m = n + 2*numberOfContours; // a loose bound on how many vertices we might need 1666 vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata); 1660 1667 if (vertices == 0) 1661 1668 return 0; 1662 1669 1663 1670 next_move = 0; 1664 flagcount =0;1671 flagcount=0; 1665 1672 1666 1673 // in first pass, we load uninterpreted data into the allocated array … … 1670 1677 off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated 1671 1678 1672 1673 1674 for (i =0; i < n; ++i) {1679 // first load flags 1680 1681 for (i=0; i < n; ++i) { 1675 1682 if (flagcount == 0) { 1676 1683 flags = *points++; 1677 1684 if (flags & 8) 1678 1685 flagcount = *points++; 1679 } 1680 else 1686 } else 1681 1687 --flagcount; 1682 vertices[off +i].type = flags;1688 vertices[off+i].type = flags; 1683 1689 } 1684 1690 1685 1691 // now load x coordinates 1686 x =0;1687 for (i =0; i < n; ++i) {1688 flags = vertices[off +i].type;1692 x=0; 1693 for (i=0; i < n; ++i) { 1694 flags = vertices[off+i].type; 1689 1695 if (flags & 2) { 1690 1696 stbtt_int16 dx = *points++; 1691 1697 x += (flags & 16) ? dx : -dx; // ??? 1692 } 1693 else { 1698 } else { 1694 1699 if (!(flags & 16)) { 1695 x = x + (stbtt_int16) (points[0] *256 + points[1]);1700 x = x + (stbtt_int16) (points[0]*256 + points[1]); 1696 1701 points += 2; 1697 1702 } 1698 1703 } 1699 vertices[off + i].x = (stbtt_int16)x;1704 vertices[off+i].x = (stbtt_int16) x; 1700 1705 } 1701 1706 1702 1707 // now load y coordinates 1703 y =0;1704 for (i =0; i < n; ++i) {1705 flags = vertices[off +i].type;1708 y=0; 1709 for (i=0; i < n; ++i) { 1710 flags = vertices[off+i].type; 1706 1711 if (flags & 4) { 1707 1712 stbtt_int16 dy = *points++; 1708 1713 y += (flags & 32) ? dy : -dy; // ??? 1709 } 1710 else { 1714 } else { 1711 1715 if (!(flags & 32)) { 1712 y = y + (stbtt_int16) (points[0] *256 + points[1]);1716 y = y + (stbtt_int16) (points[0]*256 + points[1]); 1713 1717 points += 2; 1714 1718 } 1715 1719 } 1716 vertices[off + i].y = (stbtt_int16)y;1720 vertices[off+i].y = (stbtt_int16) y; 1717 1721 } 1718 1722 1719 1723 // now convert them to our format 1720 num_vertices =0;1724 num_vertices=0; 1721 1725 sx = sy = cx = cy = scx = scy = 0; 1722 for (i =0; i < n; ++i) {1723 flags = vertices[off +i].type;1724 x = (stbtt_int16)vertices[off +i].x;1725 y = (stbtt_int16)vertices[off +i].y;1726 for (i=0; i < n; ++i) { 1727 flags = vertices[off+i].type; 1728 x = (stbtt_int16) vertices[off+i].x; 1729 y = (stbtt_int16) vertices[off+i].y; 1726 1730 1727 1731 if (next_move == i) { 1728 1732 if (i != 0) 1729 num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx, sy, scx, scy, cx,cy);1733 num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); 1730 1734 1731 1735 // now start the new one … … 1736 1740 scx = x; 1737 1741 scy = y; 1738 if (!(vertices[off + i +1].type & 1)) {1742 if (!(vertices[off+i+1].type & 1)) { 1739 1743 // next point is also a curve point, so interpolate an on-point curve 1740 sx = (x + (stbtt_int32)vertices[off + i + 1].x) >> 1; 1741 sy = (y + (stbtt_int32)vertices[off + i + 1].y) >> 1; 1742 } 1743 else { 1744 sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1; 1745 sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1; 1746 } else { 1744 1747 // otherwise just use the next point as our start point 1745 sx = (stbtt_int32) vertices[off + i +1].x;1746 sy = (stbtt_int32) vertices[off + i +1].y;1748 sx = (stbtt_int32) vertices[off+i+1].x; 1749 sy = (stbtt_int32) vertices[off+i+1].y; 1747 1750 ++i; // we're using point i+1 as the starting point, so skip it 1748 1751 } 1749 } 1750 else { 1752 } else { 1751 1753 sx = x; 1752 1754 sy = y; 1753 1755 } 1754 stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove, sx, sy, 0,0);1756 stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0); 1755 1757 was_off = 0; 1756 next_move = 1 + ttUSHORT(endPtsOfContours + j *2);1758 next_move = 1 + ttUSHORT(endPtsOfContours+j*2); 1757 1759 ++j; 1758 } 1759 else { 1760 } else { 1760 1761 if (!(flags & 1)) { // if it's a curve 1761 1762 if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint 1762 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx + x) >> 1, (cy + y) >>1, cx, cy);1763 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy); 1763 1764 cx = x; 1764 1765 cy = y; 1765 1766 was_off = 1; 1766 } 1767 else { 1767 } else { 1768 1768 if (was_off) 1769 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x, 1769 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy); 1770 1770 else 1771 stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x, y, 0,0);1771 stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0); 1772 1772 was_off = 0; 1773 1773 } 1774 1774 } 1775 1775 } 1776 num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx, sy, scx, scy, cx, cy); 1777 } 1778 else if (numberOfContours == -1) { 1776 num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); 1777 } else if (numberOfContours == -1) { 1779 1778 // Compound shapes. 1780 1779 int more = 1; … … 1786 1785 int comp_num_verts = 0, i; 1787 1786 stbtt_vertex *comp_verts = 0, *tmp = 0; 1788 float mtx[6] = { 1,0,0,1,0,0}, m, n;1789 1790 flags = ttSHORT(comp); comp +=2;1791 gidx = ttSHORT(comp); comp +=2;1787 float mtx[6] = {1,0,0,1,0,0}, m, n; 1788 1789 flags = ttSHORT(comp); comp+=2; 1790 gidx = ttSHORT(comp); comp+=2; 1792 1791 1793 1792 if (flags & 2) { // XY values 1794 1793 if (flags & 1) { // shorts 1795 mtx[4] = ttSHORT(comp); comp += 2; 1796 mtx[5] = ttSHORT(comp); comp += 2; 1797 } 1798 else { 1799 mtx[4] = ttCHAR(comp); comp += 1; 1800 mtx[5] = ttCHAR(comp); comp += 1; 1794 mtx[4] = ttSHORT(comp); comp+=2; 1795 mtx[5] = ttSHORT(comp); comp+=2; 1796 } else { 1797 mtx[4] = ttCHAR(comp); comp+=1; 1798 mtx[5] = ttCHAR(comp); comp+=1; 1801 1799 } 1802 1800 } … … 1805 1803 STBTT_assert(0); 1806 1804 } 1807 if (flags & (1 <<3)) { // WE_HAVE_A_SCALE1808 mtx[0] = mtx[3] = ttSHORT(comp) / 16384.0f; comp +=2;1805 if (flags & (1<<3)) { // WE_HAVE_A_SCALE 1806 mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; 1809 1807 mtx[1] = mtx[2] = 0; 1808 } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE 1809 mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; 1810 mtx[1] = mtx[2] = 0; 1811 mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; 1812 } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO 1813 mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; 1814 mtx[1] = ttSHORT(comp)/16384.0f; comp+=2; 1815 mtx[2] = ttSHORT(comp)/16384.0f; comp+=2; 1816 mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; 1810 1817 } 1811 else if (flags & (1 << 6)) { // WE_HAVE_AN_X_AND_YSCALE 1812 mtx[0] = ttSHORT(comp) / 16384.0f; comp += 2; 1813 mtx[1] = mtx[2] = 0; 1814 mtx[3] = ttSHORT(comp) / 16384.0f; comp += 2; 1815 } 1816 else if (flags & (1 << 7)) { // WE_HAVE_A_TWO_BY_TWO 1817 mtx[0] = ttSHORT(comp) / 16384.0f; comp += 2; 1818 mtx[1] = ttSHORT(comp) / 16384.0f; comp += 2; 1819 mtx[2] = ttSHORT(comp) / 16384.0f; comp += 2; 1820 mtx[3] = ttSHORT(comp) / 16384.0f; comp += 2; 1821 } 1822 1818 1823 1819 // Find transformation scales. 1824 m = (float) STBTT_sqrt(mtx[0] * mtx[0] + mtx[1] *mtx[1]);1825 n = (float) STBTT_sqrt(mtx[2] * mtx[2] + mtx[3] *mtx[3]);1820 m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]); 1821 n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]); 1826 1822 1827 1823 // Get indexed glyph. … … 1831 1827 for (i = 0; i < comp_num_verts; ++i) { 1832 1828 stbtt_vertex* v = &comp_verts[i]; 1833 stbtt_vertex_type x, 1834 x = v->x; y =v->y;1835 v->x = (stbtt_vertex_type)(m * (mtx[0] * x + mtx[2] *y + mtx[4]));1836 v->y = (stbtt_vertex_type)(n * (mtx[1] * x + mtx[3] *y + mtx[5]));1837 x = v->cx; y =v->cy;1838 v->cx = (stbtt_vertex_type)(m * (mtx[0] * x + mtx[2] *y + mtx[4]));1839 v->cy = (stbtt_vertex_type)(n * (mtx[1] * x + mtx[3] *y + mtx[5]));1829 stbtt_vertex_type x,y; 1830 x=v->x; y=v->y; 1831 v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); 1832 v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); 1833 x=v->cx; y=v->cy; 1834 v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); 1835 v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); 1840 1836 } 1841 1837 // Append vertices. 1842 tmp = (stbtt_vertex*)STBTT_malloc((num_vertices + comp_num_verts) *sizeof(stbtt_vertex), info->userdata);1838 tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata); 1843 1839 if (!tmp) { 1844 1840 if (vertices) STBTT_free(vertices, info->userdata); … … 1846 1842 return 0; 1847 1843 } 1848 if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices * sizeof(stbtt_vertex));1849 STBTT_memcpy(tmp + num_vertices, comp_verts, comp_num_verts *sizeof(stbtt_vertex));1844 if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); //-V595 1845 STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex)); 1850 1846 if (vertices) STBTT_free(vertices, info->userdata); 1851 1847 vertices = tmp; … … 1854 1850 } 1855 1851 // More components ? 1856 more = flags & (1 << 5); 1857 } 1858 } 1859 else if (numberOfContours < 0) { 1852 more = flags & (1<<5); 1853 } 1854 } else if (numberOfContours < 0) { 1860 1855 // @TODO other compound variations? 1861 1856 STBTT_assert(0); 1862 } 1863 else { 1857 } else { 1864 1858 // numberOfCounters == 0, do nothing 1865 1859 } … … 1900 1894 stbtt__track_vertex(c, cx1, cy1); 1901 1895 } 1902 } 1903 else { 1896 } else { 1904 1897 stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy); 1905 c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1;1906 c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1;1898 c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1; 1899 c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1; 1907 1900 } 1908 1901 c->num_vertices++; … … 1966 1959 stbtt__buf_skip(&fdselect, glyph_index); 1967 1960 fdselector = stbtt__buf_get8(&fdselect); 1968 } 1969 else if (fmt == 3) { 1961 } else if (fmt == 3) { 1970 1962 nranges = stbtt__buf_get16(&fdselect); 1971 1963 start = stbtt__buf_get16(&fdselect); … … 2001 1993 b0 = stbtt__buf_get8(&b); 2002 1994 switch (b0) { 2003 1995 // @TODO implement hinting 2004 1996 case 0x13: // hintmask 2005 1997 case 0x14: // cntrmask … … 2020 2012 in_header = 0; 2021 2013 if (sp < 2) return STBTT__CSERR("rmoveto stack"); 2022 stbtt__csctx_rmove_to(c, s[sp - 2], s[sp -1]);2014 stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]); 2023 2015 break; 2024 2016 case 0x04: // vmoveto 2025 2017 in_header = 0; 2026 2018 if (sp < 1) return STBTT__CSERR("vmoveto stack"); 2027 stbtt__csctx_rmove_to(c, 0, s[sp -1]);2019 stbtt__csctx_rmove_to(c, 0, s[sp-1]); 2028 2020 break; 2029 2021 case 0x16: // hmoveto 2030 2022 in_header = 0; 2031 2023 if (sp < 1) return STBTT__CSERR("hmoveto stack"); 2032 stbtt__csctx_rmove_to(c, s[sp -1], 0);2024 stbtt__csctx_rmove_to(c, s[sp-1], 0); 2033 2025 break; 2034 2026 … … 2036 2028 if (sp < 2) return STBTT__CSERR("rlineto stack"); 2037 2029 for (; i + 1 < sp; i += 2) 2038 stbtt__csctx_rline_to(c, s[i], s[i +1]);2030 stbtt__csctx_rline_to(c, s[i], s[i+1]); 2039 2031 break; 2040 2032 2041 2042 2033 // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical 2034 // starting from a different place. 2043 2035 2044 2036 case 0x07: // vlineto … … 2051 2043 stbtt__csctx_rline_to(c, s[i], 0); 2052 2044 i++; 2053 2045 vlineto: 2054 2046 if (i >= sp) break; 2055 2047 stbtt__csctx_rline_to(c, 0, s[i]); … … 2065 2057 for (;;) { 2066 2058 if (i + 3 >= sp) break; 2067 stbtt__csctx_rccurve_to(c, 0, s[i], s[i + 1], s[i + 2], s[i +3], (sp - i == 5) ? s[i + 4] : 0.0f);2059 stbtt__csctx_rccurve_to(c, 0, s[i], s[i+1], s[i+2], s[i+3], (sp - i == 5) ? s[i + 4] : 0.0f); 2068 2060 i += 4; 2069 2061 hvcurveto: 2070 2062 if (i + 3 >= sp) break; 2071 stbtt__csctx_rccurve_to(c, s[i], 0, s[i + 1], s[i + 2], (sp - i == 5) ? s[i + 4] : 0.0f, s[i +3]);2063 stbtt__csctx_rccurve_to(c, s[i], 0, s[i+1], s[i+2], (sp - i == 5) ? s[i+4] : 0.0f, s[i+3]); 2072 2064 i += 4; 2073 2065 } … … 2077 2069 if (sp < 6) return STBTT__CSERR("rcurveline stack"); 2078 2070 for (; i + 5 < sp; i += 6) 2079 stbtt__csctx_rccurve_to(c, s[i], s[i + 1], s[i + 2], s[i + 3], s[i + 4], s[i +5]);2071 stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); 2080 2072 break; 2081 2073 … … 2083 2075 if (sp < 8) return STBTT__CSERR("rcurveline stack"); 2084 2076 for (; i + 5 < sp - 2; i += 6) 2085 stbtt__csctx_rccurve_to(c, s[i], s[i + 1], s[i + 2], s[i + 3], s[i + 4], s[i +5]);2077 stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); 2086 2078 if (i + 1 >= sp) return STBTT__CSERR("rcurveline stack"); 2087 stbtt__csctx_rline_to(c, s[i], s[i +1]);2079 stbtt__csctx_rline_to(c, s[i], s[i+1]); 2088 2080 break; 2089 2081 … … 2091 2083 if (sp < 8) return STBTT__CSERR("rlinecurve stack"); 2092 2084 for (; i + 1 < sp - 6; i += 2) 2093 stbtt__csctx_rline_to(c, s[i], s[i +1]);2085 stbtt__csctx_rline_to(c, s[i], s[i+1]); 2094 2086 if (i + 5 >= sp) return STBTT__CSERR("rlinecurve stack"); 2095 stbtt__csctx_rccurve_to(c, s[i], s[i + 1], s[i + 2], s[i + 3], s[i + 4], s[i +5]);2087 stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); 2096 2088 break; 2097 2089 … … 2103 2095 for (; i + 3 < sp; i += 4) { 2104 2096 if (b0 == 0x1B) 2105 stbtt__csctx_rccurve_to(c, s[i], f, s[i + 1], s[i + 2], s[i +3], 0.0);2097 stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0); 2106 2098 else 2107 stbtt__csctx_rccurve_to(c, f, s[i], s[i + 1], s[i + 2], 0.0, s[i +3]);2099 stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]); 2108 2100 f = 0.0; 2109 2101 } … … 2119 2111 case 0x1D: // callgsubr 2120 2112 if (sp < 1) return STBTT__CSERR("call(g|)subr stack"); 2121 v = (int) s[--sp];2113 v = (int) s[--sp]; 2122 2114 if (subr_stack_height >= 10) return STBTT__CSERR("recursion limit"); 2123 2115 subr_stack[subr_stack_height++] = b; … … 2143 2135 int b1 = stbtt__buf_get8(&b); 2144 2136 switch (b1) { 2145 2146 2137 // @TODO These "flex" implementations ignore the flex-depth and resolution, 2138 // and always draw beziers. 2147 2139 case 0x22: // hflex 2148 2140 if (sp < 7) return STBTT__CSERR("hflex stack"); … … 2189 2181 dx6 = s[8]; 2190 2182 stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0); 2191 stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1 + dy2 +dy5));2183 stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5)); 2192 2184 break; 2193 2185 … … 2205 2197 dy5 = s[9]; 2206 2198 dx6 = dy6 = s[10]; 2207 dx = dx1 + dx2 + dx3 + dx4 +dx5;2208 dy = dy1 + dy2 + dy3 + dy4 +dy5;2199 dx = dx1+dx2+dx3+dx4+dx5; 2200 dy = dy1+dy2+dy3+dy4+dy5; 2209 2201 if (STBTT_fabs(dx) > STBTT_fabs(dy)) 2210 2202 dy6 = -dy; … … 2221 2213 2222 2214 default: 2223 if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254)) 2215 if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254)) //-V560 2224 2216 return STBTT__CSERR("reserved operator"); 2225 2217 … … 2227 2219 if (b0 == 255) { 2228 2220 f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000; 2229 } 2230 else { 2221 } else { 2231 2222 stbtt__buf_skip(&b, -1); 2232 2223 f = (float)(stbtt_int16)stbtt__cff_int(&b); … … 2250 2241 stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0); 2251 2242 if (stbtt__run_charstring(info, glyph_index, &count_ctx)) { 2252 *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices *sizeof(stbtt_vertex), info->userdata);2243 *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*sizeof(stbtt_vertex), info->userdata); 2253 2244 output_ctx.pvertices = *pvertices; 2254 2245 if (stbtt__run_charstring(info, glyph_index, &output_ctx)) { … … 2282 2273 STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing) 2283 2274 { 2284 stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data +info->hhea + 34);2275 stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34); 2285 2276 if (glyph_index < numOfLongHorMetrics) { 2286 if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4 * glyph_index); 2287 if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4 * glyph_index + 2); 2288 } 2289 else { 2290 if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4 * (numOfLongHorMetrics - 1)); 2291 if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4 * numOfLongHorMetrics + 2 * (glyph_index - numOfLongHorMetrics)); 2277 if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*glyph_index); 2278 if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2); 2279 } else { 2280 if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1)); 2281 if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics)); 2292 2282 } 2293 2283 } … … 2302 2292 if (!info->kern) 2303 2293 return 0; 2304 if (ttUSHORT(data +2) < 1) // number of tables, need at least 12294 if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 2305 2295 return 0; 2306 if (ttUSHORT(data +8) != 1) // horizontal flag must be set in format2296 if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format 2307 2297 return 0; 2308 2298 2309 2299 l = 0; 2310 r = ttUSHORT(data +10) - 1;2300 r = ttUSHORT(data+10) - 1; 2311 2301 needle = glyph1 << 16 | glyph2; 2312 2302 while (l <= r) { 2313 2303 m = (l + r) >> 1; 2314 straw = ttULONG(data + 18 + (m *6)); // note: unaligned read2304 straw = ttULONG(data+18+(m*6)); // note: unaligned read 2315 2305 if (needle < straw) 2316 2306 r = m - 1; … … 2318 2308 l = m + 1; 2319 2309 else 2320 return ttSHORT(data + 22 + (m *6));2310 return ttSHORT(data+22+(m*6)); 2321 2311 } 2322 2312 return 0; … … 2325 2315 static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph) 2326 2316 { 2327 stbtt_uint16 coverageFormat = ttUSHORT(coverageTable);2328 switch(coverageFormat) {2329 case 1: {2330 stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2);2331 2332 // Binary search.2333 stbtt_int32 l = 0, r = glyphCount -1, m;2334 int straw, needle =glyph;2335 while (l <= r) {2336 stbtt_uint8 *glyphArray = coverageTable + 4;2337 stbtt_uint16 glyphID;2338 m = (l + r) >> 1;2339 glyphID = ttUSHORT(glyphArray + 2 * m);2340 straw = glyphID;2341 if (needle < straw)2342 r = m - 1;2343 else if (needle > straw)2344 l = m + 1;2345 else {2346 return m;2347 }2348 }2349 } break;2350 2351 case 2: {2352 stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2);2353 stbtt_uint8 *rangeArray = coverageTable + 4;2354 2355 // Binary search.2356 stbtt_int32 l = 0, r = rangeCount -1, m;2357 int strawStart, strawEnd, needle =glyph;2358 while (l <= r) {2359 stbtt_uint8 *rangeRecord;2360 m = (l + r) >> 1;2361 rangeRecord = rangeArray + 6 * m;2362 strawStart = ttUSHORT(rangeRecord);2363 strawEnd = ttUSHORT(rangeRecord + 2);2364 if (needle < strawStart)2365 r = m - 1;2366 else if (needle > strawEnd)2367 l = m + 1;2368 else {2369 stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4);2370 return startCoverageIndex + glyph - strawStart;2371 }2372 }2373 } break;2374 2375 default: {2376 // There are no other cases.2377 STBTT_assert(0);2378 } break;2379 }2380 2381 return -1;2317 stbtt_uint16 coverageFormat = ttUSHORT(coverageTable); 2318 switch(coverageFormat) { 2319 case 1: { 2320 stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2); 2321 2322 // Binary search. 2323 stbtt_int32 l=0, r=glyphCount-1, m; 2324 int straw, needle=glyph; 2325 while (l <= r) { 2326 stbtt_uint8 *glyphArray = coverageTable + 4; 2327 stbtt_uint16 glyphID; 2328 m = (l + r) >> 1; 2329 glyphID = ttUSHORT(glyphArray + 2 * m); 2330 straw = glyphID; 2331 if (needle < straw) 2332 r = m - 1; 2333 else if (needle > straw) 2334 l = m + 1; 2335 else { 2336 return m; 2337 } 2338 } 2339 } break; 2340 2341 case 2: { 2342 stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2); 2343 stbtt_uint8 *rangeArray = coverageTable + 4; 2344 2345 // Binary search. 2346 stbtt_int32 l=0, r=rangeCount-1, m; 2347 int strawStart, strawEnd, needle=glyph; 2348 while (l <= r) { 2349 stbtt_uint8 *rangeRecord; 2350 m = (l + r) >> 1; 2351 rangeRecord = rangeArray + 6 * m; 2352 strawStart = ttUSHORT(rangeRecord); 2353 strawEnd = ttUSHORT(rangeRecord + 2); 2354 if (needle < strawStart) 2355 r = m - 1; 2356 else if (needle > strawEnd) 2357 l = m + 1; 2358 else { 2359 stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4); 2360 return startCoverageIndex + glyph - strawStart; 2361 } 2362 } 2363 } break; 2364 2365 default: { 2366 // There are no other cases. 2367 STBTT_assert(0); 2368 } break; 2369 } 2370 2371 return -1; 2382 2372 } 2383 2373 2384 2374 static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph) 2385 2375 { 2386 stbtt_uint16 classDefFormat = ttUSHORT(classDefTable); 2387 switch (classDefFormat) 2388 { 2389 case 1: { 2390 stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2); 2391 stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4); 2392 stbtt_uint8 *classDef1ValueArray = classDefTable + 6; 2393 2394 if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount) 2395 return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID)); 2396 2397 classDefTable = classDef1ValueArray + 2 * glyphCount; 2398 } break; 2399 2400 case 2: { 2401 stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2); 2402 stbtt_uint8 *classRangeRecords = classDefTable + 4; 2403 2404 // Binary search. 2405 stbtt_int32 l = 0, r = classRangeCount - 1, m; 2406 int strawStart, strawEnd, needle = glyph; 2407 while (l <= r) { 2408 stbtt_uint8 *classRangeRecord; 2409 m = (l + r) >> 1; 2410 classRangeRecord = classRangeRecords + 6 * m; 2411 strawStart = ttUSHORT(classRangeRecord); 2412 strawEnd = ttUSHORT(classRangeRecord + 2); 2413 if (needle < strawStart) 2414 r = m - 1; 2415 else if (needle > strawEnd) 2416 l = m + 1; 2417 else 2418 return (stbtt_int32)ttUSHORT(classRangeRecord + 4); 2419 } 2420 2421 classDefTable = classRangeRecords + 6 * classRangeCount; 2422 } break; 2423 2424 default: { 2425 // There are no other cases. 2426 STBTT_assert(0); 2427 } break; 2428 } 2429 2430 return -1; 2376 stbtt_uint16 classDefFormat = ttUSHORT(classDefTable); 2377 switch(classDefFormat) 2378 { 2379 case 1: { 2380 stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2); 2381 stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4); 2382 stbtt_uint8 *classDef1ValueArray = classDefTable + 6; 2383 2384 if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount) 2385 return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID)); 2386 2387 // [DEAR IMGUI] Commented to fix static analyzer warning 2388 //classDefTable = classDef1ValueArray + 2 * glyphCount; 2389 } break; 2390 2391 case 2: { 2392 stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2); 2393 stbtt_uint8 *classRangeRecords = classDefTable + 4; 2394 2395 // Binary search. 2396 stbtt_int32 l=0, r=classRangeCount-1, m; 2397 int strawStart, strawEnd, needle=glyph; 2398 while (l <= r) { 2399 stbtt_uint8 *classRangeRecord; 2400 m = (l + r) >> 1; 2401 classRangeRecord = classRangeRecords + 6 * m; 2402 strawStart = ttUSHORT(classRangeRecord); 2403 strawEnd = ttUSHORT(classRangeRecord + 2); 2404 if (needle < strawStart) 2405 r = m - 1; 2406 else if (needle > strawEnd) 2407 l = m + 1; 2408 else 2409 return (stbtt_int32)ttUSHORT(classRangeRecord + 4); 2410 } 2411 2412 // [DEAR IMGUI] Commented to fix static analyzer warning 2413 //classDefTable = classRangeRecords + 6 * classRangeCount; 2414 } break; 2415 2416 default: { 2417 // There are no other cases. 2418 STBTT_assert(0); 2419 } break; 2420 } 2421 2422 return -1; 2431 2423 } 2432 2424 … … 2436 2428 static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) 2437 2429 { 2438 stbtt_uint16 lookupListOffset;2439 stbtt_uint8 *lookupList;2440 stbtt_uint16 lookupCount;2441 stbtt_uint8 *data;2442 stbtt_int32 i;2443 2444 if (!info->gpos) return 0;2445 2446 data = info->data + info->gpos;2447 2448 if (ttUSHORT(data +0) != 1) return 0; // Major version 12449 if (ttUSHORT(data +2) != 0) return 0; // Minor version 02450 2451 lookupListOffset = ttUSHORT(data +8);2452 lookupList = data + lookupListOffset;2453 lookupCount = ttUSHORT(lookupList);2454 2455 for (i =0; i<lookupCount; ++i) {2456 stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i);2457 stbtt_uint8 *lookupTable = lookupList + lookupOffset;2458 2459 stbtt_uint16 lookupType = ttUSHORT(lookupTable);2460 stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4);2461 stbtt_uint8 *subTableOffsets = lookupTable + 6;2462 switch(lookupType) {2463 case 2: { // Pair Adjustment Positioning Subtable2464 stbtt_int32 sti;2465 for (sti =0; sti<subTableCount; sti++) {2466 stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti);2467 stbtt_uint8 *table = lookupTable + subtableOffset;2468 stbtt_uint16 posFormat = ttUSHORT(table);2469 stbtt_uint16 coverageOffset = ttUSHORT(table + 2);2470 stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1);2471 if (coverageIndex == -1) continue;2472 2473 switch (posFormat) {2474 case 1: {2475 stbtt_int32 l, r, m;2476 int straw, needle;2477 stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);2478 stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);2479 stbtt_int32 valueRecordPairSizeInBytes = 2;2480 stbtt_uint16 pairSetCount = ttUSHORT(table + 8);2481 stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex);2482 stbtt_uint8 *pairValueTable = table + pairPosOffset;2483 stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable);2484 stbtt_uint8 *pairValueArray = pairValueTable + 2;2485 // TODO: Support more formats.2486 STBTT_GPOS_TODO_assert(valueFormat1 == 4);2487 if (valueFormat1 != 4) return 0;2488 STBTT_GPOS_TODO_assert(valueFormat2 == 0);2489 if (valueFormat2 != 0) return 0;2490 2491 STBTT_assert(coverageIndex < pairSetCount);2492 STBTT__NOTUSED(pairSetCount);2493 2494 needle =glyph2;2495 r = pairValueCount -1;2496 l =0;2497 2498 // Binary search.2499 while (l <= r) {2500 stbtt_uint16 secondGlyph;2501 stbtt_uint8 *pairValue;2502 m = (l + r) >> 1;2503 pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m;2504 secondGlyph = ttUSHORT(pairValue);2505 straw = secondGlyph;2506 if (needle < straw)2507 r = m - 1;2508 else if (needle > straw)2509 l = m + 1;2510 else {2511 stbtt_int16 xAdvance = ttSHORT(pairValue + 2);2512 return xAdvance;2513 }2514 }2515 } break;2516 2517 case 2: {2518 stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);2519 stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);2520 2521 stbtt_uint16 classDef1Offset = ttUSHORT(table + 8);2522 stbtt_uint16 classDef2Offset = ttUSHORT(table + 10);2523 int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1);2524 int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2);2525 2526 stbtt_uint16 class1Count = ttUSHORT(table + 12);2527 stbtt_uint16 class2Count = ttUSHORT(table + 14);2528 STBTT_assert(glyph1class < class1Count);2529 STBTT_assert(glyph2class < class2Count);2530 2531 // TODO: Support more formats.2532 STBTT_GPOS_TODO_assert(valueFormat1 == 4);2533 if (valueFormat1 != 4) return 0;2534 STBTT_GPOS_TODO_assert(valueFormat2 == 0);2535 if (valueFormat2 != 0) return 0;2536 2537 if (glyph1class >= 0 && glyph1class < class1Count && glyph2class >= 0 && glyph2class < class2Count) {2538 stbtt_uint8 *class1Records = table + 16;2539 stbtt_uint8 *class2Records = class1Records + 2 * (glyph1class * class2Count);2540 stbtt_int16 xAdvance = ttSHORT(class2Records + 2 * glyph2class);2541 return xAdvance;2542 }2543 } break;2544 2545 default: {2546 // There are no other cases.2547 STBTT_assert(0);2548 break;2549 };2550 }2551 }2552 break;2553 };2554 2555 default:2556 // TODO: Implement other stuff.2557 break;2558 }2559 }2560 2561 return 0;2430 stbtt_uint16 lookupListOffset; 2431 stbtt_uint8 *lookupList; 2432 stbtt_uint16 lookupCount; 2433 stbtt_uint8 *data; 2434 stbtt_int32 i; 2435 2436 if (!info->gpos) return 0; 2437 2438 data = info->data + info->gpos; 2439 2440 if (ttUSHORT(data+0) != 1) return 0; // Major version 1 2441 if (ttUSHORT(data+2) != 0) return 0; // Minor version 0 2442 2443 lookupListOffset = ttUSHORT(data+8); 2444 lookupList = data + lookupListOffset; 2445 lookupCount = ttUSHORT(lookupList); 2446 2447 for (i=0; i<lookupCount; ++i) { 2448 stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i); 2449 stbtt_uint8 *lookupTable = lookupList + lookupOffset; 2450 2451 stbtt_uint16 lookupType = ttUSHORT(lookupTable); 2452 stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4); 2453 stbtt_uint8 *subTableOffsets = lookupTable + 6; 2454 switch(lookupType) { 2455 case 2: { // Pair Adjustment Positioning Subtable 2456 stbtt_int32 sti; 2457 for (sti=0; sti<subTableCount; sti++) { 2458 stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti); 2459 stbtt_uint8 *table = lookupTable + subtableOffset; 2460 stbtt_uint16 posFormat = ttUSHORT(table); 2461 stbtt_uint16 coverageOffset = ttUSHORT(table + 2); 2462 stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1); 2463 if (coverageIndex == -1) continue; 2464 2465 switch (posFormat) { 2466 case 1: { 2467 stbtt_int32 l, r, m; 2468 int straw, needle; 2469 stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); 2470 stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); 2471 stbtt_int32 valueRecordPairSizeInBytes = 2; 2472 stbtt_uint16 pairSetCount = ttUSHORT(table + 8); 2473 stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex); 2474 stbtt_uint8 *pairValueTable = table + pairPosOffset; 2475 stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable); 2476 stbtt_uint8 *pairValueArray = pairValueTable + 2; 2477 // TODO: Support more formats. 2478 STBTT_GPOS_TODO_assert(valueFormat1 == 4); 2479 if (valueFormat1 != 4) return 0; 2480 STBTT_GPOS_TODO_assert(valueFormat2 == 0); 2481 if (valueFormat2 != 0) return 0; 2482 2483 STBTT_assert(coverageIndex < pairSetCount); 2484 STBTT__NOTUSED(pairSetCount); 2485 2486 needle=glyph2; 2487 r=pairValueCount-1; 2488 l=0; 2489 2490 // Binary search. 2491 while (l <= r) { 2492 stbtt_uint16 secondGlyph; 2493 stbtt_uint8 *pairValue; 2494 m = (l + r) >> 1; 2495 pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m; 2496 secondGlyph = ttUSHORT(pairValue); 2497 straw = secondGlyph; 2498 if (needle < straw) 2499 r = m - 1; 2500 else if (needle > straw) 2501 l = m + 1; 2502 else { 2503 stbtt_int16 xAdvance = ttSHORT(pairValue + 2); 2504 return xAdvance; 2505 } 2506 } 2507 } break; 2508 2509 case 2: { 2510 stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); 2511 stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); 2512 2513 stbtt_uint16 classDef1Offset = ttUSHORT(table + 8); 2514 stbtt_uint16 classDef2Offset = ttUSHORT(table + 10); 2515 int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1); 2516 int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2); 2517 2518 stbtt_uint16 class1Count = ttUSHORT(table + 12); 2519 stbtt_uint16 class2Count = ttUSHORT(table + 14); 2520 STBTT_assert(glyph1class < class1Count); 2521 STBTT_assert(glyph2class < class2Count); 2522 2523 // TODO: Support more formats. 2524 STBTT_GPOS_TODO_assert(valueFormat1 == 4); 2525 if (valueFormat1 != 4) return 0; 2526 STBTT_GPOS_TODO_assert(valueFormat2 == 0); 2527 if (valueFormat2 != 0) return 0; 2528 2529 if (glyph1class >= 0 && glyph1class < class1Count && glyph2class >= 0 && glyph2class < class2Count) { 2530 stbtt_uint8 *class1Records = table + 16; 2531 stbtt_uint8 *class2Records = class1Records + 2 * (glyph1class * class2Count); 2532 stbtt_int16 xAdvance = ttSHORT(class2Records + 2 * glyph2class); 2533 return xAdvance; 2534 } 2535 } break; 2536 2537 default: { 2538 // There are no other cases. 2539 STBTT_assert(0); 2540 break; 2541 } // [DEAR IMGUI] removed ; 2542 } 2543 } 2544 break; 2545 } // [DEAR IMGUI] removed ; 2546 2547 default: 2548 // TODO: Implement other stuff. 2549 break; 2550 } 2551 } 2552 2553 return 0; 2562 2554 } 2563 2555 … … 2579 2571 if (!info->kern && !info->gpos) // if no kerning table, don't waste time looking up both codepoint->glyphs 2580 2572 return 0; 2581 return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info, ch1), stbtt_FindGlyphIndex(info,ch2));2573 return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2)); 2582 2574 } 2583 2575 2584 2576 STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing) 2585 2577 { 2586 stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info, 2578 stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing); 2587 2579 } 2588 2580 2589 2581 STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap) 2590 2582 { 2591 if (ascent ) *ascent = ttSHORT(info->data +info->hhea + 4);2592 if (descent) *descent = ttSHORT(info->data +info->hhea + 6);2593 if (lineGap) *lineGap = ttSHORT(info->data +info->hhea + 8);2583 if (ascent ) *ascent = ttSHORT(info->data+info->hhea + 4); 2584 if (descent) *descent = ttSHORT(info->data+info->hhea + 6); 2585 if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8); 2594 2586 } 2595 2587 … … 2599 2591 if (!tab) 2600 2592 return 0; 2601 if (typoAscent ) *typoAscent = ttSHORT(info->data +tab + 68);2602 if (typoDescent) *typoDescent = ttSHORT(info->data +tab + 70);2603 if (typoLineGap) *typoLineGap = ttSHORT(info->data +tab + 72);2593 if (typoAscent ) *typoAscent = ttSHORT(info->data+tab + 68); 2594 if (typoDescent) *typoDescent = ttSHORT(info->data+tab + 70); 2595 if (typoLineGap) *typoLineGap = ttSHORT(info->data+tab + 72); 2604 2596 return 1; 2605 2597 } … … 2616 2608 { 2617 2609 int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6); 2618 return (float) height / fheight;2610 return (float) height / fheight; 2619 2611 } 2620 2612 … … 2635 2627 // 2636 2628 2637 STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, 2638 { 2639 int x0 = 0, y0 = 0, x1,y1; // =0 suppresses compiler warning2640 if (!stbtt_GetGlyphBox(font, glyph, &x0, &y0, &x1,&y1)) {2629 STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) 2630 { 2631 int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning 2632 if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) { 2641 2633 // e.g. space character 2642 2634 if (ix0) *ix0 = 0; … … 2644 2636 if (ix1) *ix1 = 0; 2645 2637 if (iy1) *iy1 = 0; 2646 } 2647 else { 2638 } else { 2648 2639 // move to integral bboxes (treating pixels as little squares, what pixels get touched)? 2649 if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x);2640 if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x); 2650 2641 if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y); 2651 if (ix1) *ix1 = STBTT_iceil (x1 * scale_x + shift_x);2652 if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y);2642 if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x); 2643 if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y); 2653 2644 } 2654 2645 } … … 2656 2647 STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) 2657 2648 { 2658 stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y, 0.0f,0.0f, ix0, iy0, ix1, iy1);2649 stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1); 2659 2650 } 2660 2651 2661 2652 STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) 2662 2653 { 2663 stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font, codepoint), scale_x, scale_y, shift_x, shift_y, ix0, iy0, ix1,iy1);2654 stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1); 2664 2655 } 2665 2656 2666 2657 STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) 2667 2658 { 2668 stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y, 0.0f, 0.0f, ix0, iy0, ix1,iy1);2659 stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1); 2669 2660 } 2670 2661 … … 2689 2680 if (hh->first_free) { 2690 2681 void *p = hh->first_free; 2691 hh->first_free = * (void **)p;2682 hh->first_free = * (void **) p; 2692 2683 return p; 2693 } 2694 else { 2684 } else { 2695 2685 if (hh->num_remaining_in_head_chunk == 0) { 2696 2686 int count = (size < 32 ? 2000 : size < 128 ? 800 : 100); 2697 stbtt__hheap_chunk *c = (stbtt__hheap_chunk *) STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata);2687 stbtt__hheap_chunk *c = (stbtt__hheap_chunk *) STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata); 2698 2688 if (c == NULL) 2699 2689 return NULL; … … 2703 2693 } 2704 2694 --hh->num_remaining_in_head_chunk; 2705 return (char *) (hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk;2695 return (char *) (hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk; 2706 2696 } 2707 2697 } … … 2709 2699 static void stbtt__hheap_free(stbtt__hheap *hh, void *p) 2710 2700 { 2711 *(void **) p = hh->first_free;2701 *(void **) p = hh->first_free; 2712 2702 hh->first_free = p; 2713 2703 } … … 2724 2714 2725 2715 typedef struct stbtt__edge { 2726 float x0, y0, x1,y1;2716 float x0,y0, x1,y1; 2727 2717 int invert; 2728 2718 } stbtt__edge; … … 2732 2722 { 2733 2723 struct stbtt__active_edge *next; 2734 #if STBTT_RASTERIZER_VERSION==12735 int x, 2724 #if STBTT_RASTERIZER_VERSION==1 2725 int x,dx; 2736 2726 float ey; 2737 2727 int direction; 2738 #elif STBTT_RASTERIZER_VERSION==22739 float fx, fdx,fdy;2728 #elif STBTT_RASTERIZER_VERSION==2 2729 float fx,fdx,fdy; 2740 2730 float direction; 2741 2731 float sy; 2742 2732 float ey; 2743 #else2744 #error "Unrecognized value of STBTT_RASTERIZER_VERSION"2745 #endif2733 #else 2734 #error "Unrecognized value of STBTT_RASTERIZER_VERSION" 2735 #endif 2746 2736 } stbtt__active_edge; 2747 2737 … … 2753 2743 static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) 2754 2744 { 2755 stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);2745 stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); 2756 2746 float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); 2757 2747 STBTT_assert(z != NULL); 2758 2748 if (!z) return z; 2759 2749 2760 2750 // round dx down to avoid overshooting 2761 2751 if (dxdy < 0) … … 2775 2765 static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) 2776 2766 { 2777 stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);2767 stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); 2778 2768 float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); 2779 2769 STBTT_assert(z != NULL); … … 2781 2771 if (!z) return z; 2782 2772 z->fdx = dxdy; 2783 z->fdy = dxdy != 0.0f ? (1.0f /dxdy) : 0.0f;2773 z->fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f; 2784 2774 z->fx = e->x0 + dxdy * (start_point - e->y0); 2785 2775 z->fx -= off_x; … … 2801 2791 { 2802 2792 // non-zero winding fill 2803 int x0 = 0, w =0;2793 int x0=0, w=0; 2804 2794 2805 2795 while (e) { … … 2807 2797 // if we're currently at zero, we need to record the edge start point 2808 2798 x0 = e->x; w += e->direction; 2809 } 2810 else { 2799 } else { 2811 2800 int x1 = e->x; w += e->direction; 2812 2801 // if we went to zero, we need to draw … … 2818 2807 if (i == j) { 2819 2808 // x0,x1 are the same pixel, so compute combined coverage 2820 scanline[i] = scanline[i] + (stbtt_uint8)((x1 - x0) * max_weight >> STBTT_FIXSHIFT); 2821 } 2822 else { 2809 scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT); 2810 } else { 2823 2811 if (i >= 0) // add antialiasing for x0 2824 scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT);2812 scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT); 2825 2813 else 2826 2814 i = -1; // clip 2827 2815 2828 2816 if (j < len) // add antialiasing for x1 2829 scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT);2817 scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT); 2830 2818 else 2831 2819 j = len; // clip 2832 2820 2833 2821 for (++i; i < j; ++i) // fill pixels between x0 and x1 2834 scanline[i] = scanline[i] + (stbtt_uint8) max_weight;2822 scanline[i] = scanline[i] + (stbtt_uint8) max_weight; 2835 2823 } 2836 2824 } 2837 2825 } 2838 2826 } 2839 2827 2840 2828 e = e->next; 2841 2829 } … … 2846 2834 stbtt__hheap hh = { 0, 0, 0 }; 2847 2835 stbtt__active_edge *active = NULL; 2848 int y, j =0;2836 int y,j=0; 2849 2837 int max_weight = (255 / vsubsample); // weight per vertical scanline 2850 2838 int s; // vertical subsample index … … 2852 2840 2853 2841 if (result->w > 512) 2854 scanline = (unsigned char *) STBTT_malloc(result->w, userdata);2842 scanline = (unsigned char *) STBTT_malloc(result->w, userdata); 2855 2843 else 2856 2844 scanline = scanline_data; 2857 2845 2858 2846 y = off_y * vsubsample; 2859 e[n].y0 = (off_y + result->h) * (float) vsubsample + 1;2847 e[n].y0 = (off_y + result->h) * (float) vsubsample + 1; 2860 2848 2861 2849 while (j < result->h) { 2862 2850 STBTT_memset(scanline, 0, result->w); 2863 for (s =0; s < vsubsample; ++s) {2851 for (s=0; s < vsubsample; ++s) { 2864 2852 // find center of pixel for this scanline 2865 2853 float scan_y = y + 0.5f; … … 2875 2863 z->direction = 0; 2876 2864 stbtt__hheap_free(&hh, z); 2877 } 2878 else { 2865 } else { 2879 2866 z->x += z->dx; // advance to position for current scanline 2880 2867 step = &((*step)->next); // advance through list … … 2883 2870 2884 2871 // resort the list if needed 2885 for 2886 int changed =0;2872 for(;;) { 2873 int changed=0; 2887 2874 step = &active; 2888 2875 while (*step && (*step)->next) { … … 2913 2900 z->next = active; 2914 2901 active = z; 2915 } 2916 else { 2902 } else { 2917 2903 // find thing to insert AFTER 2918 2904 stbtt__active_edge *p = active; … … 2956 2942 if (y1 < e->sy) return; 2957 2943 if (y0 < e->sy) { 2958 x0 += (x1 - x0) * (e->sy - y0) / (y1 -y0);2944 x0 += (x1-x0) * (e->sy - y0) / (y1-y0); 2959 2945 y0 = e->sy; 2960 2946 } 2961 2947 if (y1 > e->ey) { 2962 x1 += (x1 - x0) * (e->ey - y1) / (y1 -y0);2948 x1 += (x1-x0) * (e->ey - y1) / (y1-y0); 2963 2949 y1 = e->ey; 2964 2950 } 2965 2951 2966 2952 if (x0 == x) 2967 STBTT_assert(x1 <= x +1);2968 else if (x0 == x +1)2953 STBTT_assert(x1 <= x+1); 2954 else if (x0 == x+1) 2969 2955 STBTT_assert(x1 >= x); 2970 2956 else if (x0 <= x) 2971 2957 STBTT_assert(x1 <= x); 2972 else if (x0 >= x +1)2973 STBTT_assert(x1 >= x +1);2958 else if (x0 >= x+1) 2959 STBTT_assert(x1 >= x+1); 2974 2960 else 2975 STBTT_assert(x1 >= x && x1 <= x +1);2961 STBTT_assert(x1 >= x && x1 <= x+1); 2976 2962 2977 2963 if (x0 <= x && x1 <= x) 2978 scanline[x] += e->direction * (y1 -y0);2979 else if (x0 >= x + 1 && x1 >= x +1)2964 scanline[x] += e->direction * (y1-y0); 2965 else if (x0 >= x+1 && x1 >= x+1) 2980 2966 ; 2981 2967 else { 2982 STBTT_assert(x0 >= x && x0 <= x + 1 && x1 >= x && x1 <= x +1);2983 scanline[x] += e->direction * (y1 - y0) * (1 - ((x0 - x) + (x1 - x)) /2); // coverage = 1 - average x position2968 STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1); 2969 scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); // coverage = 1 - average x position 2984 2970 } 2985 2971 } … … 2987 2973 static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top) 2988 2974 { 2989 float y_bottom = y_top +1;2975 float y_bottom = y_top+1; 2990 2976 2991 2977 while (e) { … … 2999 2985 if (x0 < len) { 3000 2986 if (x0 >= 0) { 3001 stbtt__handle_clipped_edge(scanline, (int)x0, e, x0, y_top, x0, y_bottom); 3002 stbtt__handle_clipped_edge(scanline_fill - 1, (int)x0 + 1, e, x0, y_top, x0, y_bottom); 3003 } 3004 else { 3005 stbtt__handle_clipped_edge(scanline_fill - 1, 0, e, x0, y_top, x0, y_bottom); 2987 stbtt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom); 2988 stbtt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom); 2989 } else { 2990 stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom); 3006 2991 } 3007 2992 } 3008 } 3009 else { 2993 } else { 3010 2994 float x0 = e->fx; 3011 2995 float dx = e->fdx; 3012 2996 float xb = x0 + dx; 3013 2997 float x_top, x_bottom; 3014 float sy0, 2998 float sy0,sy1; 3015 2999 float dy = e->fdy; 3016 3000 STBTT_assert(e->sy <= y_bottom && e->ey >= y_top); … … 3022 3006 x_top = x0 + dx * (e->sy - y_top); 3023 3007 sy0 = e->sy; 3024 } 3025 else { 3008 } else { 3026 3009 x_top = x0; 3027 3010 sy0 = y_top; … … 3030 3013 x_bottom = x0 + dx * (e->ey - y_top); 3031 3014 sy1 = e->ey; 3032 } 3033 else { 3015 } else { 3034 3016 x_bottom = xb; 3035 3017 sy1 = y_bottom; … … 3039 3021 // from here on, we don't have to range check x values 3040 3022 3041 if ((int) x_top == (int)x_bottom) {3023 if ((int) x_top == (int) x_bottom) { 3042 3024 float height; 3043 3025 // simple case, only spans one pixel 3044 int x = (int) x_top;3026 int x = (int) x_top; 3045 3027 height = sy1 - sy0; 3046 3028 STBTT_assert(x >= 0 && x < len); 3047 scanline[x] += e->direction * (1 - ((x_top - x) + (x_bottom - x)) /2) * height;3029 scanline[x] += e->direction * (1-((x_top - x) + (x_bottom-x))/2) * height; 3048 3030 scanline_fill[x] += e->direction * height; // everything right of this pixel is filled 3049 } 3050 else { 3051 int x, x1, x2; 3031 } else { 3032 int x,x1,x2; 3052 3033 float y_crossing, step, sign, area; 3053 3034 // covers 2+ pixels … … 3062 3043 dy = -dy; 3063 3044 t = x0, x0 = xb, xb = t; 3045 // [DEAR IMGUI] Fix static analyzer warning 3046 (void)dx; // [ImGui: fix static analyzer warning] 3064 3047 } 3065 3048 3066 x1 = (int) x_top;3067 x2 = (int) x_bottom;3049 x1 = (int) x_top; 3050 x2 = (int) x_bottom; 3068 3051 // compute intersection with y axis at x1+1 3069 y_crossing = (x1 +1 - x0) * dy + y_top;3052 y_crossing = (x1+1 - x0) * dy + y_top; 3070 3053 3071 3054 sign = e->direction; 3072 3055 // area of the rectangle covered from y0..y_crossing 3073 area = sign * (y_crossing -sy0);3056 area = sign * (y_crossing-sy0); 3074 3057 // area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing) 3075 scanline[x1] += area * (1 - ((x_top - x1) + (x1 + 1 - x1)) /2);3058 scanline[x1] += area * (1-((x_top - x1)+(x1+1-x1))/2); 3076 3059 3077 3060 step = sign * dy; 3078 for (x = x1 +1; x < x2; ++x) {3079 scanline[x] += area + step /2;3061 for (x = x1+1; x < x2; ++x) { 3062 scanline[x] += area + step/2; 3080 3063 area += step; 3081 3064 } 3082 y_crossing += dy * (x2 - (x1 +1));3065 y_crossing += dy * (x2 - (x1+1)); 3083 3066 3084 3067 STBTT_assert(STBTT_fabs(area) <= 1.01f); 3085 3068 3086 scanline[x2] += area + sign * (1 - ((x2 - x2) + (x_bottom - x2)) / 2) * (sy1 -y_crossing);3087 3088 scanline_fill[x2] += sign * (sy1 -sy0);3069 scanline[x2] += area + sign * (1-((x2-x2)+(x_bottom-x2))/2) * (sy1-y_crossing); 3070 3071 scanline_fill[x2] += sign * (sy1-sy0); 3089 3072 } 3090 } 3091 else { 3073 } else { 3092 3074 // if edge goes outside of box we're drawing, we require 3093 3075 // clipping logic. since this does not match the intended use … … 3095 3077 // force implementation 3096 3078 int x; 3097 for (x =0; x < len; ++x) {3079 for (x=0; x < len; ++x) { 3098 3080 // cases: 3099 3081 // … … 3111 3093 // rename variables to clearly-defined pairs 3112 3094 float y0 = y_top; 3113 float x1 = (float) (x);3114 float x2 = (float) (x +1);3095 float x1 = (float) (x); 3096 float x2 = (float) (x+1); 3115 3097 float x3 = xb; 3116 3098 float y3 = y_bottom; … … 3120 3102 // y = (x - e->x) / e->dx + y_top 3121 3103 float y1 = (x - x0) / dx + y_top; 3122 float y2 = (x +1 - x0) / dx + y_top;3104 float y2 = (x+1 - x0) / dx + y_top; 3123 3105 3124 3106 if (x0 < x1 && x3 > x2) { // three segments descending down-right 3125 stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x1, y1); 3126 stbtt__handle_clipped_edge(scanline, x, e, x1, y1, x2, y2); 3127 stbtt__handle_clipped_edge(scanline, x, e, x2, y2, x3, y3); 3128 } 3129 else if (x3 < x1 && x0 > x2) { // three segments descending down-left 3130 stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x2, y2); 3131 stbtt__handle_clipped_edge(scanline, x, e, x2, y2, x1, y1); 3132 stbtt__handle_clipped_edge(scanline, x, e, x1, y1, x3, y3); 3133 } 3134 else if (x0 < x1 && x3 > x1) { // two segments across x, down-right 3135 stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x1, y1); 3136 stbtt__handle_clipped_edge(scanline, x, e, x1, y1, x3, y3); 3137 } 3138 else if (x3 < x1 && x0 > x1) { // two segments across x, down-left 3139 stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x1, y1); 3140 stbtt__handle_clipped_edge(scanline, x, e, x1, y1, x3, y3); 3141 } 3142 else if (x0 < x2 && x3 > x2) { // two segments across x+1, down-right 3143 stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x2, y2); 3144 stbtt__handle_clipped_edge(scanline, x, e, x2, y2, x3, y3); 3145 } 3146 else if (x3 < x2 && x0 > x2) { // two segments across x+1, down-left 3147 stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x2, y2); 3148 stbtt__handle_clipped_edge(scanline, x, e, x2, y2, x3, y3); 3149 } 3150 else { // one segment 3151 stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x3, y3); 3107 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); 3108 stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2); 3109 stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); 3110 } else if (x3 < x1 && x0 > x2) { // three segments descending down-left 3111 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); 3112 stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1); 3113 stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); 3114 } else if (x0 < x1 && x3 > x1) { // two segments across x, down-right 3115 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); 3116 stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); 3117 } else if (x3 < x1 && x0 > x1) { // two segments across x, down-left 3118 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); 3119 stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); 3120 } else if (x0 < x2 && x3 > x2) { // two segments across x+1, down-right 3121 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); 3122 stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); 3123 } else if (x3 < x2 && x0 > x2) { // two segments across x+1, down-left 3124 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); 3125 stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); 3126 } else { // one segment 3127 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3); 3152 3128 } 3153 3129 } … … 3163 3139 stbtt__hheap hh = { 0, 0, 0 }; 3164 3140 stbtt__active_edge *active = NULL; 3165 int y, j =0, i;3141 int y,j=0, i; 3166 3142 float scanline_data[129], *scanline, *scanline2; 3167 3143 … … 3169 3145 3170 3146 if (result->w > 64) 3171 scanline = (float *) STBTT_malloc((result->w * 2 +1) * sizeof(float), userdata);3147 scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata); 3172 3148 else 3173 3149 scanline = scanline_data; … … 3176 3152 3177 3153 y = off_y; 3178 e[n].y0 = (float) (off_y + result->h) + 1;3154 e[n].y0 = (float) (off_y + result->h) + 1; 3179 3155 3180 3156 while (j < result->h) { 3181 3157 // find center of pixel for this scanline 3182 float scan_y_top = y + 0.0f;3158 float scan_y_top = y + 0.0f; 3183 3159 float scan_y_bottom = y + 1.0f; 3184 3160 stbtt__active_edge **step = &active; 3185 3161 3186 STBTT_memset(scanline , 0, result->w *sizeof(scanline[0]));3187 STBTT_memset(scanline2, 0, (result->w + 1) *sizeof(scanline[0]));3162 STBTT_memset(scanline , 0, result->w*sizeof(scanline[0])); 3163 STBTT_memset(scanline2, 0, (result->w+1)*sizeof(scanline[0])); 3188 3164 3189 3165 // update all active edges; … … 3196 3172 z->direction = 0; 3197 3173 stbtt__hheap_free(&hh, z); 3198 } 3199 else { 3174 } else { 3200 3175 step = &((*step)->next); // advance through list 3201 3176 } … … 3207 3182 stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata); 3208 3183 if (z != NULL) { 3209 STBTT_assert(z->ey >= scan_y_top); 3184 if (j == 0 && off_y != 0) { 3185 if (z->ey < scan_y_top) { 3186 // this can happen due to subpixel positioning and some kind of fp rounding error i think 3187 z->ey = scan_y_top; 3188 } 3189 } 3190 STBTT_assert(z->ey >= scan_y_top); // if we get really unlucky a tiny bit of an edge can be out of bounds 3210 3191 // insert at front 3211 3192 z->next = active; … … 3218 3199 // now process all active edges 3219 3200 if (active) 3220 stbtt__fill_active_edges_new(scanline, scanline2 +1, result->w, active, scan_y_top);3201 stbtt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top); 3221 3202 3222 3203 { 3223 3204 float sum = 0; 3224 for (i =0; i < result->w; ++i) {3205 for (i=0; i < result->w; ++i) { 3225 3206 float k; 3226 3207 int m; 3227 3208 sum += scanline2[i]; 3228 3209 k = scanline[i] + sum; 3229 k = (float) STBTT_fabs(k) *255 + 0.5f;3230 m = (int) k;3210 k = (float) STBTT_fabs(k)*255 + 0.5f; 3211 m = (int) k; 3231 3212 if (m > 255) m = 255; 3232 result->pixels[j*result->stride + i] = (unsigned char) m;3213 result->pixels[j*result->stride + i] = (unsigned char) m; 3233 3214 } 3234 3215 } … … 3258 3239 static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n) 3259 3240 { 3260 int i, 3261 for (i =1; i < n; ++i) {3241 int i,j; 3242 for (i=1; i < n; ++i) { 3262 3243 stbtt__edge t = p[i], *a = &t; 3263 3244 j = i; 3264 3245 while (j > 0) { 3265 stbtt__edge *b = &p[j -1];3266 int c = STBTT__COMPARE(a, 3246 stbtt__edge *b = &p[j-1]; 3247 int c = STBTT__COMPARE(a,b); 3267 3248 if (!c) break; 3268 p[j] = p[j -1];3249 p[j] = p[j-1]; 3269 3250 --j; 3270 3251 } … … 3276 3257 static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n) 3277 3258 { 3278 /* thresh hold for transitioning to insertion sort */3259 /* threshold for transitioning to insertion sort */ 3279 3260 while (n > 12) { 3280 3261 stbtt__edge t; 3281 int c01, c12, c, m, i,j;3262 int c01,c12,c,m,i,j; 3282 3263 3283 3264 /* compute median of three */ 3284 3265 m = n >> 1; 3285 c01 = STBTT__COMPARE(&p[0], 3286 c12 = STBTT__COMPARE(&p[m], &p[n -1]);3266 c01 = STBTT__COMPARE(&p[0],&p[m]); 3267 c12 = STBTT__COMPARE(&p[m],&p[n-1]); 3287 3268 /* if 0 >= mid >= end, or 0 < mid < end, then use mid */ 3288 3269 if (c01 != c12) { 3289 3270 /* otherwise, we'll need to swap something else to middle */ 3290 3271 int z; 3291 c = STBTT__COMPARE(&p[0], &p[n -1]);3272 c = STBTT__COMPARE(&p[0],&p[n-1]); 3292 3273 /* 0>mid && mid<n: 0>n => n; 0<n => 0 */ 3293 3274 /* 0<mid && mid>n: 0>n => 0; 0<n => n */ 3294 z = (c == c12) ? 0 : n -1;3275 z = (c == c12) ? 0 : n-1; 3295 3276 t = p[z]; 3296 3277 p[z] = p[m]; … … 3304 3285 3305 3286 /* partition loop */ 3306 i =1;3307 j = n -1;3308 for 3287 i=1; 3288 j=n-1; 3289 for(;;) { 3309 3290 /* handling of equality is crucial here */ 3310 3291 /* for sentinels & efficiency with duplicates */ 3311 for (;; 3292 for (;;++i) { 3312 3293 if (!STBTT__COMPARE(&p[i], &p[0])) break; 3313 3294 } 3314 for (;; 3295 for (;;--j) { 3315 3296 if (!STBTT__COMPARE(&p[0], &p[j])) break; 3316 3297 } … … 3325 3306 } 3326 3307 /* recurse on smaller side, iterate on larger */ 3327 if (j < (n - i)) { 3328 stbtt__sort_edges_quicksort(p, j); 3329 p = p + i; 3330 n = n - i; 3331 } 3332 else { 3333 stbtt__sort_edges_quicksort(p + i, n - i); 3308 if (j < (n-i)) { 3309 stbtt__sort_edges_quicksort(p,j); 3310 p = p+i; 3311 n = n-i; 3312 } else { 3313 stbtt__sort_edges_quicksort(p+i, n-i); 3334 3314 n = j; 3335 3315 } … … 3345 3325 typedef struct 3346 3326 { 3347 float x, 3327 float x,y; 3348 3328 } stbtt__point; 3349 3329 … … 3352 3332 float y_scale_inv = invert ? -scale_y : scale_y; 3353 3333 stbtt__edge *e; 3354 int n, i, j, k,m;3334 int n,i,j,k,m; 3355 3335 #if STBTT_RASTERIZER_VERSION == 1 3356 3336 int vsubsample = result->h < 8 ? 15 : 5; … … 3358 3338 int vsubsample = 1; 3359 3339 #else 3360 #error "Unrecognized value of STBTT_RASTERIZER_VERSION"3340 #error "Unrecognized value of STBTT_RASTERIZER_VERSION" 3361 3341 #endif 3362 3342 // vsubsample should divide 255 evenly; otherwise we won't reach full opacity … … 3364 3344 // now we have to blow out the windings into explicit edge lists 3365 3345 n = 0; 3366 for (i =0; i < windings; ++i)3346 for (i=0; i < windings; ++i) 3367 3347 n += wcount[i]; 3368 3348 3369 e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n +1), userdata); // add an extra one as a sentinel3349 e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); // add an extra one as a sentinel 3370 3350 if (e == 0) return; 3371 3351 n = 0; 3372 3352 3373 m =0;3374 for (i =0; i < windings; ++i) {3353 m=0; 3354 for (i=0; i < windings; ++i) { 3375 3355 stbtt__point *p = pts + m; 3376 3356 m += wcount[i]; 3377 j = wcount[i] -1;3378 for (k = 0; k < wcount[i]; j =k++) {3379 int a = k, b =j;3357 j = wcount[i]-1; 3358 for (k=0; k < wcount[i]; j=k++) { 3359 int a=k,b=j; 3380 3360 // skip the edge if horizontal 3381 3361 if (p[j].y == p[k].y) … … 3385 3365 if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) { 3386 3366 e[n].invert = 1; 3387 a = j, b =k;3367 a=j,b=k; 3388 3368 } 3389 3369 e[n].x0 = p[a].x * scale_x + shift_x; … … 3412 3392 } 3413 3393 3414 // tessel ate until threshhold p is happy... @TODO warped to compensate for non-linear stretching3394 // tessellate until threshold p is happy... @TODO warped to compensate for non-linear stretching 3415 3395 static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n) 3416 3396 { 3417 3397 // midpoint 3418 float mx = (x0 + 2 * x1 + x2) /4;3419 float my = (y0 + 2 * y1 + y2) /4;3398 float mx = (x0 + 2*x1 + x2)/4; 3399 float my = (y0 + 2*y1 + y2)/4; 3420 3400 // versus directly drawn line 3421 float dx = (x0 + x2) /2 - mx;3422 float dy = (y0 + y2) /2 - my;3401 float dx = (x0+x2)/2 - mx; 3402 float dy = (y0+y2)/2 - my; 3423 3403 if (n > 16) // 65536 segments on one curve better be enough! 3424 3404 return 1; 3425 if (dx*dx + dy * dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA 3426 stbtt__tesselate_curve(points, num_points, x0, y0, (x0 + x1) / 2.0f, (y0 + y1) / 2.0f, mx, my, objspace_flatness_squared, n + 1); 3427 stbtt__tesselate_curve(points, num_points, mx, my, (x1 + x2) / 2.0f, (y1 + y2) / 2.0f, x2, y2, objspace_flatness_squared, n + 1); 3428 } 3429 else { 3430 stbtt__add_point(points, *num_points, x2, y2); 3431 *num_points = *num_points + 1; 3405 if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA 3406 stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1); 3407 stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1); 3408 } else { 3409 stbtt__add_point(points, *num_points,x2,y2); 3410 *num_points = *num_points+1; 3432 3411 } 3433 3412 return 1; … … 3437 3416 { 3438 3417 // @TODO this "flatness" calculation is just made-up nonsense that seems to work well enough 3439 float dx0 = x1 -x0;3440 float dy0 = y1 -y0;3441 float dx1 = x2 -x1;3442 float dy1 = y2 -y1;3443 float dx2 = x3 -x2;3444 float dy2 = y3 -y2;3445 float dx = x3 -x0;3446 float dy = y3 -y0;3447 float longlen = (float) (STBTT_sqrt(dx0*dx0 + dy0 * dy0) + STBTT_sqrt(dx1*dx1 + dy1 * dy1) + STBTT_sqrt(dx2*dx2 + dy2 *dy2));3448 float shortlen = (float) STBTT_sqrt(dx*dx + dy *dy);3449 float flatness_squared = longlen * longlen - shortlen *shortlen;3418 float dx0 = x1-x0; 3419 float dy0 = y1-y0; 3420 float dx1 = x2-x1; 3421 float dy1 = y2-y1; 3422 float dx2 = x3-x2; 3423 float dy2 = y3-y2; 3424 float dx = x3-x0; 3425 float dy = y3-y0; 3426 float longlen = (float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2)); 3427 float shortlen = (float) STBTT_sqrt(dx*dx+dy*dy); 3428 float flatness_squared = longlen*longlen-shortlen*shortlen; 3450 3429 3451 3430 if (n > 16) // 65536 segments on one curve better be enough! … … 3453 3432 3454 3433 if (flatness_squared > objspace_flatness_squared) { 3455 float x01 = (x0 + x1) / 2; 3456 float y01 = (y0 + y1) / 2; 3457 float x12 = (x1 + x2) / 2; 3458 float y12 = (y1 + y2) / 2; 3459 float x23 = (x2 + x3) / 2; 3460 float y23 = (y2 + y3) / 2; 3461 3462 float xa = (x01 + x12) / 2; 3463 float ya = (y01 + y12) / 2; 3464 float xb = (x12 + x23) / 2; 3465 float yb = (y12 + y23) / 2; 3466 3467 float mx = (xa + xb) / 2; 3468 float my = (ya + yb) / 2; 3469 3470 stbtt__tesselate_cubic(points, num_points, x0, y0, x01, y01, xa, ya, mx, my, objspace_flatness_squared, n + 1); 3471 stbtt__tesselate_cubic(points, num_points, mx, my, xb, yb, x23, y23, x3, y3, objspace_flatness_squared, n + 1); 3472 } 3473 else { 3474 stbtt__add_point(points, *num_points, x3, y3); 3475 *num_points = *num_points + 1; 3434 float x01 = (x0+x1)/2; 3435 float y01 = (y0+y1)/2; 3436 float x12 = (x1+x2)/2; 3437 float y12 = (y1+y2)/2; 3438 float x23 = (x2+x3)/2; 3439 float y23 = (y2+y3)/2; 3440 3441 float xa = (x01+x12)/2; 3442 float ya = (y01+y12)/2; 3443 float xb = (x12+x23)/2; 3444 float yb = (y12+y23)/2; 3445 3446 float mx = (xa+xb)/2; 3447 float my = (ya+yb)/2; 3448 3449 stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1); 3450 stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1); 3451 } else { 3452 stbtt__add_point(points, *num_points,x3,y3); 3453 *num_points = *num_points+1; 3476 3454 } 3477 3455 } … … 3480 3458 static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata) 3481 3459 { 3482 stbtt__point *points =0;3483 int num_points =0;3460 stbtt__point *points=0; 3461 int num_points=0; 3484 3462 3485 3463 float objspace_flatness_squared = objspace_flatness * objspace_flatness; 3486 int i, n = 0, start =0, pass;3464 int i,n=0,start=0, pass; 3487 3465 3488 3466 // count how many "moves" there are to get the contour count 3489 for (i =0; i < num_verts; ++i)3467 for (i=0; i < num_verts; ++i) 3490 3468 if (vertices[i].type == STBTT_vmove) 3491 3469 ++n; … … 3494 3472 if (n == 0) return 0; 3495 3473 3496 *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata);3474 *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata); 3497 3475 3498 3476 if (*contour_lengths == 0) { … … 3502 3480 3503 3481 // make two passes through the points so we don't need to realloc 3504 for (pass =0; pass < 2; ++pass) {3505 float x = 0, y =0;3482 for (pass=0; pass < 2; ++pass) { 3483 float x=0,y=0; 3506 3484 if (pass == 1) { 3507 points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata);3485 points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata); 3508 3486 if (points == NULL) goto error; 3509 3487 } 3510 3488 num_points = 0; 3511 n 3512 for (i =0; i < num_verts; ++i) {3489 n= -1; 3490 for (i=0; i < num_verts; ++i) { 3513 3491 switch (vertices[i].type) { 3514 case STBTT_vmove:3515 // start the next contour3516 if (n >= 0)3517 (*contour_lengths)[n] = num_points - start;3518 ++n;3519 start = num_points;3520 3521 x = vertices[i].x, y = vertices[i].y;3522 stbtt__add_point(points, num_points++, x,y);3523 break;3524 case STBTT_vline:3525 x = vertices[i].x, y = vertices[i].y;3526 stbtt__add_point(points, num_points++, x, y);3527 break;3528 case STBTT_vcurve:3529 stbtt__tesselate_curve(points, &num_points, x,y,3530 vertices[i].cx, vertices[i].cy,3531 vertices[i].x,vertices[i].y,3532 objspace_flatness_squared, 0);3533 x = vertices[i].x, y = vertices[i].y;3534 break;3535 case STBTT_vcubic:3536 stbtt__tesselate_cubic(points, &num_points, x,y,3537 vertices[i].cx, vertices[i].cy,3538 vertices[i].cx1, vertices[i].cy1,3539 vertices[i].x,vertices[i].y,3540 objspace_flatness_squared, 0);3541 x = vertices[i].x, y = vertices[i].y;3542 break;3492 case STBTT_vmove: 3493 // start the next contour 3494 if (n >= 0) 3495 (*contour_lengths)[n] = num_points - start; 3496 ++n; 3497 start = num_points; 3498 3499 x = vertices[i].x, y = vertices[i].y; 3500 stbtt__add_point(points, num_points++, x,y); 3501 break; 3502 case STBTT_vline: 3503 x = vertices[i].x, y = vertices[i].y; 3504 stbtt__add_point(points, num_points++, x, y); 3505 break; 3506 case STBTT_vcurve: 3507 stbtt__tesselate_curve(points, &num_points, x,y, 3508 vertices[i].cx, vertices[i].cy, 3509 vertices[i].x, vertices[i].y, 3510 objspace_flatness_squared, 0); 3511 x = vertices[i].x, y = vertices[i].y; 3512 break; 3513 case STBTT_vcubic: 3514 stbtt__tesselate_cubic(points, &num_points, x,y, 3515 vertices[i].cx, vertices[i].cy, 3516 vertices[i].cx1, vertices[i].cy1, 3517 vertices[i].x, vertices[i].y, 3518 objspace_flatness_squared, 0); 3519 x = vertices[i].x, y = vertices[i].y; 3520 break; 3543 3521 } 3544 3522 } … … 3557 3535 STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata) 3558 3536 { 3559 float scale = scale_x > scale_y ? scale_y : scale_x;3560 int winding_count = 0;3561 int *winding_lengths = NULL;3537 float scale = scale_x > scale_y ? scale_y : scale_x; 3538 int winding_count = 0; 3539 int *winding_lengths = NULL; 3562 3540 stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata); 3563 3541 if (windings) { … … 3575 3553 STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff) 3576 3554 { 3577 int ix0, iy0, ix1,iy1;3555 int ix0,iy0,ix1,iy1; 3578 3556 stbtt__bitmap gbm; 3579 stbtt_vertex *vertices; 3557 stbtt_vertex *vertices; 3580 3558 int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); 3581 3559 … … 3589 3567 } 3590 3568 3591 stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0, &iy0, &ix1,&iy1);3569 stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1); 3592 3570 3593 3571 // now we get the size … … 3596 3574 gbm.pixels = NULL; // in case we error 3597 3575 3598 if (width ) *width= gbm.w;3576 if (width ) *width = gbm.w; 3599 3577 if (height) *height = gbm.h; 3600 if (xoff ) *xoff= ix0;3601 if (yoff ) *yoff= iy0;3602 3578 if (xoff ) *xoff = ix0; 3579 if (yoff ) *yoff = iy0; 3580 3603 3581 if (gbm.w && gbm.h) { 3604 gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata);3582 gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata); 3605 3583 if (gbm.pixels) { 3606 3584 gbm.stride = gbm.w; … … 3611 3589 STBTT_free(vertices, info->userdata); 3612 3590 return gbm.pixels; 3613 } 3591 } 3614 3592 3615 3593 STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff) … … 3620 3598 STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph) 3621 3599 { 3622 int ix0, 3600 int ix0,iy0; 3623 3601 stbtt_vertex *vertices; 3624 3602 int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); 3625 stbtt__bitmap gbm; 3626 3627 stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0, &iy0, 0,0);3603 stbtt__bitmap gbm; 3604 3605 stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0); 3628 3606 gbm.pixels = output; 3629 3607 gbm.w = out_w; … … 3632 3610 3633 3611 if (gbm.w && gbm.h) 3634 stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, 3612 stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata); 3635 3613 3636 3614 STBTT_free(vertices, info->userdata); … … 3639 3617 STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph) 3640 3618 { 3641 stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f, 3619 stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph); 3642 3620 } 3643 3621 3644 3622 STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff) 3645 3623 { 3646 return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info, codepoint), width, height, xoff,yoff);3647 } 3624 return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff); 3625 } 3648 3626 3649 3627 STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint) 3650 3628 { 3651 stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, oversample_x, oversample_y, sub_x, sub_y, stbtt_FindGlyphIndex(info, 3629 stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, oversample_x, oversample_y, sub_x, sub_y, stbtt_FindGlyphIndex(info,codepoint)); 3652 3630 } 3653 3631 3654 3632 STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint) 3655 3633 { 3656 stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info, 3634 stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint)); 3657 3635 } 3658 3636 3659 3637 STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff) 3660 3638 { 3661 return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, codepoint, width, height, xoff,yoff);3662 } 3639 return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff); 3640 } 3663 3641 3664 3642 STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint) 3665 3643 { 3666 stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f, 3644 stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint); 3667 3645 } 3668 3646 … … 3674 3652 3675 3653 static int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) 3676 float pixel_height, // height of font in pixels3677 unsigned char *pixels, int pw, int ph, // bitmap to be filled in3678 int first_char, int num_chars, // characters to bake3679 stbtt_bakedchar *chardata)3654 float pixel_height, // height of font in pixels 3655 unsigned char *pixels, int pw, int ph, // bitmap to be filled in 3656 int first_char, int num_chars, // characters to bake 3657 stbtt_bakedchar *chardata) 3680 3658 { 3681 3659 float scale; 3682 int x, y,bottom_y, i;3660 int x,y,bottom_y, i; 3683 3661 stbtt_fontinfo f; 3684 3662 f.userdata = NULL; … … 3686 3664 return -1; 3687 3665 STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels 3688 x = y =1;3666 x=y=1; 3689 3667 bottom_y = 1; 3690 3668 3691 3669 scale = stbtt_ScaleForPixelHeight(&f, pixel_height); 3692 3670 3693 for (i =0; i < num_chars; ++i) {3694 int advance, lsb, x0, y0, x1, y1, gw,gh;3671 for (i=0; i < num_chars; ++i) { 3672 int advance, lsb, x0,y0,x1,y1,gw,gh; 3695 3673 int g = stbtt_FindGlyphIndex(&f, first_char + i); 3696 3674 stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb); 3697 stbtt_GetGlyphBitmapBox(&f, g, scale, scale, &x0, &y0, &x1,&y1);3698 gw = x1 -x0;3699 gh = y1 -y0;3675 stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1); 3676 gw = x1-x0; 3677 gh = y1-y0; 3700 3678 if (x + gw + 1 >= pw) 3701 3679 y = bottom_y, x = 1; // advance to next row 3702 3680 if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row 3703 3681 return -i; 3704 STBTT_assert(x +gw < pw);3705 STBTT_assert(y +gh < ph);3706 stbtt_MakeGlyphBitmap(&f, pixels + x + y * pw, gw, gh, pw, scale,scale, g);3707 chardata[i].x0 = (stbtt_int16) x;3708 chardata[i].y0 = (stbtt_int16) y;3709 chardata[i].x1 = (stbtt_int16) (x + gw);3710 chardata[i].y1 = (stbtt_int16) (y + gh);3682 STBTT_assert(x+gw < pw); 3683 STBTT_assert(y+gh < ph); 3684 stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g); 3685 chardata[i].x0 = (stbtt_int16) x; 3686 chardata[i].y0 = (stbtt_int16) y; 3687 chardata[i].x1 = (stbtt_int16) (x + gw); 3688 chardata[i].y1 = (stbtt_int16) (y + gh); 3711 3689 chardata[i].xadvance = scale * advance; 3712 chardata[i].xoff = (float)x0;3713 chardata[i].yoff = (float)y0;3690 chardata[i].xoff = (float) x0; 3691 chardata[i].yoff = (float) y0; 3714 3692 x = x + gw + 1; 3715 if (y + gh +1 > bottom_y)3716 bottom_y = y + gh +1;3693 if (y+gh+1 > bottom_y) 3694 bottom_y = y+gh+1; 3717 3695 } 3718 3696 return bottom_y; … … 3762 3740 typedef struct 3763 3741 { 3764 int width, 3765 int x, y,bottom_y;3742 int width,height; 3743 int x,y,bottom_y; 3766 3744 } stbrp_context; 3767 3745 … … 3773 3751 struct stbrp_rect 3774 3752 { 3775 stbrp_coord x, 3776 int id, w, h,was_packed;3753 stbrp_coord x,y; 3754 int id,w,h,was_packed; 3777 3755 }; 3778 3756 3779 3757 static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes) 3780 3758 { 3781 con->width = pw;3759 con->width = pw; 3782 3760 con->height = ph; 3783 3761 con->x = 0; … … 3785 3763 con->bottom_y = 0; 3786 3764 STBTT__NOTUSED(nodes); 3787 STBTT__NOTUSED(num_nodes); 3765 STBTT__NOTUSED(num_nodes); 3788 3766 } 3789 3767 … … 3791 3769 { 3792 3770 int i; 3793 for (i =0; i < num_rects; ++i) {3771 for (i=0; i < num_rects; ++i) { 3794 3772 if (con->x + rects[i].w > con->width) { 3795 3773 con->x = 0; … … 3805 3783 con->bottom_y = con->y + rects[i].h; 3806 3784 } 3807 for ( ; i < num_rects; ++i)3785 for ( ; i < num_rects; ++i) 3808 3786 rects[i].was_packed = 0; 3809 3787 } … … 3819 3797 STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context) 3820 3798 { 3821 stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context),alloc_context);3799 stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context) ,alloc_context); 3822 3800 int num_nodes = pw - padding; 3823 stbrp_node *nodes = (stbrp_node *)STBTT_malloc(sizeof(*nodes) * num_nodes,alloc_context);3801 stbrp_node *nodes = (stbrp_node *) STBTT_malloc(sizeof(*nodes ) * num_nodes,alloc_context); 3824 3802 3825 3803 if (context == NULL || nodes == NULL) { 3826 3804 if (context != NULL) STBTT_free(context, alloc_context); 3827 if (nodes != NULL) STBTT_free(nodes, alloc_context);3805 if (nodes != NULL) STBTT_free(nodes , alloc_context); 3828 3806 return 0; 3829 3807 } … … 3839 3817 spc->h_oversample = 1; 3840 3818 spc->v_oversample = 1; 3841 3842 stbrp_init_target(context, pw - padding, ph - padding, nodes, num_nodes); 3819 spc->skip_missing = 0; 3820 3821 stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes); 3843 3822 3844 3823 if (pixels) … … 3848 3827 } 3849 3828 3850 STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc)3851 { 3852 STBTT_free(spc->nodes , spc->user_allocator_context);3829 STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc) 3830 { 3831 STBTT_free(spc->nodes , spc->user_allocator_context); 3853 3832 STBTT_free(spc->pack_info, spc->user_allocator_context); 3854 3833 } … … 3864 3843 } 3865 3844 3845 STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip) 3846 { 3847 spc->skip_missing = skip; 3848 } 3849 3866 3850 #define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE-1) 3867 3851 … … 3872 3856 int j; 3873 3857 STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze 3874 for (j =0; j < h; ++j) {3858 for (j=0; j < h; ++j) { 3875 3859 int i; 3876 3860 unsigned int total; … … 3881 3865 // make kernel_width a constant in common cases so compiler can optimize out the divide 3882 3866 switch (kernel_width) { 3883 case 2:3884 for (i =0; i <= safe_w; ++i) {3885 total += pixels[i] - buffer[i & STBTT__OVER_MASK];3886 buffer[(i +kernel_width) & STBTT__OVER_MASK] = pixels[i];3887 pixels[i] = (unsigned char)(total / 2);3888 }3889 break;3890 case 3:3891 for (i =0; i <= safe_w; ++i) {3892 total += pixels[i] - buffer[i & STBTT__OVER_MASK];3893 buffer[(i +kernel_width) & STBTT__OVER_MASK] = pixels[i];3894 pixels[i] = (unsigned char)(total / 3);3895 }3896 break;3897 case 4:3898 for (i =0; i <= safe_w; ++i) {3899 total += pixels[i] - buffer[i & STBTT__OVER_MASK];3900 buffer[(i +kernel_width) & STBTT__OVER_MASK] = pixels[i];3901 pixels[i] = (unsigned char)(total / 4);3902 }3903 break;3904 case 5:3905 for (i =0; i <= safe_w; ++i) {3906 total += pixels[i] - buffer[i & STBTT__OVER_MASK];3907 buffer[(i +kernel_width) & STBTT__OVER_MASK] = pixels[i];3908 pixels[i] = (unsigned char)(total / 5);3909 }3910 break;3911 default:3912 for (i =0; i <= safe_w; ++i) {3913 total += pixels[i] - buffer[i & STBTT__OVER_MASK];3914 buffer[(i +kernel_width) & STBTT__OVER_MASK] = pixels[i];3915 pixels[i] = (unsigned char)(total / kernel_width);3916 }3917 break;3867 case 2: 3868 for (i=0; i <= safe_w; ++i) { 3869 total += pixels[i] - buffer[i & STBTT__OVER_MASK]; 3870 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; 3871 pixels[i] = (unsigned char) (total / 2); 3872 } 3873 break; 3874 case 3: 3875 for (i=0; i <= safe_w; ++i) { 3876 total += pixels[i] - buffer[i & STBTT__OVER_MASK]; 3877 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; 3878 pixels[i] = (unsigned char) (total / 3); 3879 } 3880 break; 3881 case 4: 3882 for (i=0; i <= safe_w; ++i) { 3883 total += pixels[i] - buffer[i & STBTT__OVER_MASK]; 3884 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; 3885 pixels[i] = (unsigned char) (total / 4); 3886 } 3887 break; 3888 case 5: 3889 for (i=0; i <= safe_w; ++i) { 3890 total += pixels[i] - buffer[i & STBTT__OVER_MASK]; 3891 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; 3892 pixels[i] = (unsigned char) (total / 5); 3893 } 3894 break; 3895 default: 3896 for (i=0; i <= safe_w; ++i) { 3897 total += pixels[i] - buffer[i & STBTT__OVER_MASK]; 3898 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; 3899 pixels[i] = (unsigned char) (total / kernel_width); 3900 } 3901 break; 3918 3902 } 3919 3903 … … 3921 3905 STBTT_assert(pixels[i] == 0); 3922 3906 total -= buffer[i & STBTT__OVER_MASK]; 3923 pixels[i] = (unsigned char) (total / kernel_width);3907 pixels[i] = (unsigned char) (total / kernel_width); 3924 3908 } 3925 3909 … … 3934 3918 int j; 3935 3919 STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze 3936 for (j =0; j < w; ++j) {3920 for (j=0; j < w; ++j) { 3937 3921 int i; 3938 3922 unsigned int total; … … 3943 3927 // make kernel_width a constant in common cases so compiler can optimize out the divide 3944 3928 switch (kernel_width) { 3945 case 2:3946 for (i =0; i <= safe_h; ++i) {3947 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];3948 buffer[(i +kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];3949 pixels[i*stride_in_bytes] = (unsigned char)(total / 2);3950 }3951 break;3952 case 3:3953 for (i =0; i <= safe_h; ++i) {3954 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];3955 buffer[(i +kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];3956 pixels[i*stride_in_bytes] = (unsigned char)(total / 3);3957 }3958 break;3959 case 4:3960 for (i =0; i <= safe_h; ++i) {3961 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];3962 buffer[(i +kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];3963 pixels[i*stride_in_bytes] = (unsigned char)(total / 4);3964 }3965 break;3966 case 5:3967 for (i =0; i <= safe_h; ++i) {3968 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];3969 buffer[(i +kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];3970 pixels[i*stride_in_bytes] = (unsigned char)(total / 5);3971 }3972 break;3973 default:3974 for (i =0; i <= safe_h; ++i) {3975 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];3976 buffer[(i +kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];3977 pixels[i*stride_in_bytes] = (unsigned char)(total / kernel_width);3978 }3979 break;3929 case 2: 3930 for (i=0; i <= safe_h; ++i) { 3931 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; 3932 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; 3933 pixels[i*stride_in_bytes] = (unsigned char) (total / 2); 3934 } 3935 break; 3936 case 3: 3937 for (i=0; i <= safe_h; ++i) { 3938 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; 3939 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; 3940 pixels[i*stride_in_bytes] = (unsigned char) (total / 3); 3941 } 3942 break; 3943 case 4: 3944 for (i=0; i <= safe_h; ++i) { 3945 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; 3946 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; 3947 pixels[i*stride_in_bytes] = (unsigned char) (total / 4); 3948 } 3949 break; 3950 case 5: 3951 for (i=0; i <= safe_h; ++i) { 3952 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; 3953 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; 3954 pixels[i*stride_in_bytes] = (unsigned char) (total / 5); 3955 } 3956 break; 3957 default: 3958 for (i=0; i <= safe_h; ++i) { 3959 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; 3960 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; 3961 pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); 3962 } 3963 break; 3980 3964 } 3981 3965 … … 3983 3967 STBTT_assert(pixels[i*stride_in_bytes] == 0); 3984 3968 total -= buffer[i & STBTT__OVER_MASK]; 3985 pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width);3969 pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); 3986 3970 } 3987 3971 … … 4005 3989 STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) 4006 3990 { 4007 int i, j,k;4008 4009 k =0;4010 for (i =0; i < num_ranges; ++i) {3991 int i,j,k; 3992 3993 k=0; 3994 for (i=0; i < num_ranges; ++i) { 4011 3995 float fh = ranges[i].font_size; 4012 3996 float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); 4013 ranges[i].h_oversample = (unsigned char) spc->h_oversample;4014 ranges[i].v_oversample = (unsigned char) spc->v_oversample;4015 for (j =0; j < ranges[i].num_chars; ++j) {4016 int x0, y0, x1,y1;3997 ranges[i].h_oversample = (unsigned char) spc->h_oversample; 3998 ranges[i].v_oversample = (unsigned char) spc->v_oversample; 3999 for (j=0; j < ranges[i].num_chars; ++j) { 4000 int x0,y0,x1,y1; 4017 4001 int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; 4018 4002 int glyph = stbtt_FindGlyphIndex(info, codepoint); 4019 stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, 4020 scale * spc->h_oversample, 4021 scale * spc->v_oversample, 4022 0, 0, 4023 &x0, &y0, &x1, &y1); 4024 rects[k].w = (stbrp_coord)(x1 - x0 + spc->padding + spc->h_oversample - 1); 4025 rects[k].h = (stbrp_coord)(y1 - y0 + spc->padding + spc->v_oversample - 1); 4003 if (glyph == 0 && spc->skip_missing) { 4004 rects[k].w = rects[k].h = 0; 4005 } else { 4006 stbtt_GetGlyphBitmapBoxSubpixel(info,glyph, 4007 scale * spc->h_oversample, 4008 scale * spc->v_oversample, 4009 0,0, 4010 &x0,&y0,&x1,&y1); 4011 rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1); 4012 rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1); 4013 } 4026 4014 ++k; 4027 4015 } … … 4034 4022 { 4035 4023 stbtt_MakeGlyphBitmapSubpixel(info, 4036 output,4037 out_w - (prefilter_x - 1),4038 out_h - (prefilter_y - 1),4039 out_stride,4040 scale_x,4041 scale_y,4042 shift_x,4043 shift_y,4044 glyph);4024 output, 4025 out_w - (prefilter_x - 1), 4026 out_h - (prefilter_y - 1), 4027 out_stride, 4028 scale_x, 4029 scale_y, 4030 shift_x, 4031 shift_y, 4032 glyph); 4045 4033 4046 4034 if (prefilter_x > 1) … … 4057 4045 STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) 4058 4046 { 4059 int i, j,k, return_value = 1;4047 int i,j,k, return_value = 1; 4060 4048 4061 4049 // save current values … … 4064 4052 4065 4053 k = 0; 4066 for (i =0; i < num_ranges; ++i) {4054 for (i=0; i < num_ranges; ++i) { 4067 4055 float fh = ranges[i].font_size; 4068 4056 float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); 4069 float recip_h, recip_v, sub_x,sub_y;4057 float recip_h,recip_v,sub_x,sub_y; 4070 4058 spc->h_oversample = ranges[i].h_oversample; 4071 4059 spc->v_oversample = ranges[i].v_oversample; … … 4074 4062 sub_x = stbtt__oversample_shift(spc->h_oversample); 4075 4063 sub_y = stbtt__oversample_shift(spc->v_oversample); 4076 for (j =0; j < ranges[i].num_chars; ++j) {4064 for (j=0; j < ranges[i].num_chars; ++j) { 4077 4065 stbrp_rect *r = &rects[k]; 4078 if (r->was_packed ) {4066 if (r->was_packed && r->w != 0 && r->h != 0) { 4079 4067 stbtt_packedchar *bc = &ranges[i].chardata_for_range[j]; 4080 int advance, lsb, x0, y0, x1,y1;4068 int advance, lsb, x0,y0,x1,y1; 4081 4069 int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; 4082 4070 int glyph = stbtt_FindGlyphIndex(info, codepoint); 4083 stbrp_coord pad = (stbrp_coord) spc->padding;4071 stbrp_coord pad = (stbrp_coord) spc->padding; 4084 4072 4085 4073 // pad on left and top … … 4090 4078 stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb); 4091 4079 stbtt_GetGlyphBitmapBox(info, glyph, 4092 scale * spc->h_oversample,4093 scale * spc->v_oversample,4094 &x0, &y0, &x1,&y1);4080 scale * spc->h_oversample, 4081 scale * spc->v_oversample, 4082 &x0,&y0,&x1,&y1); 4095 4083 stbtt_MakeGlyphBitmapSubpixel(info, 4096 spc->pixels + r->x + r->y*spc->stride_in_bytes,4097 r->w - spc->h_oversample +1,4098 r->h - spc->v_oversample +1,4099 spc->stride_in_bytes,4100 scale * spc->h_oversample,4101 scale * spc->v_oversample,4102 0,0,4103 glyph);4084 spc->pixels + r->x + r->y*spc->stride_in_bytes, 4085 r->w - spc->h_oversample+1, 4086 r->h - spc->v_oversample+1, 4087 spc->stride_in_bytes, 4088 scale * spc->h_oversample, 4089 scale * spc->v_oversample, 4090 0,0, 4091 glyph); 4104 4092 4105 4093 if (spc->h_oversample > 1) 4106 4094 stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, 4107 r->w, r->h, spc->stride_in_bytes,4108 spc->h_oversample);4095 r->w, r->h, spc->stride_in_bytes, 4096 spc->h_oversample); 4109 4097 4110 4098 if (spc->v_oversample > 1) 4111 4099 stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, 4112 r->w, r->h, spc->stride_in_bytes, 4113 spc->v_oversample); 4114 4115 bc->x0 = (stbtt_int16)r->x; 4116 bc->y0 = (stbtt_int16)r->y; 4117 bc->x1 = (stbtt_int16)(r->x + r->w); 4118 bc->y1 = (stbtt_int16)(r->y + r->h); 4119 bc->xadvance = scale * advance; 4120 bc->xoff = (float)x0 * recip_h + sub_x; 4121 bc->yoff = (float)y0 * recip_v + sub_y; 4122 bc->xoff2 = (x0 + r->w) * recip_h + sub_x; 4123 bc->yoff2 = (y0 + r->h) * recip_v + sub_y; 4124 } 4125 else { 4100 r->w, r->h, spc->stride_in_bytes, 4101 spc->v_oversample); 4102 4103 bc->x0 = (stbtt_int16) r->x; 4104 bc->y0 = (stbtt_int16) r->y; 4105 bc->x1 = (stbtt_int16) (r->x + r->w); 4106 bc->y1 = (stbtt_int16) (r->y + r->h); 4107 bc->xadvance = scale * advance; 4108 bc->xoff = (float) x0 * recip_h + sub_x; 4109 bc->yoff = (float) y0 * recip_v + sub_y; 4110 bc->xoff2 = (x0 + r->w) * recip_h + sub_x; 4111 bc->yoff2 = (y0 + r->h) * recip_v + sub_y; 4112 } else { 4126 4113 return_value = 0; // if any fail, report failure 4127 4114 } … … 4140 4127 STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects) 4141 4128 { 4142 stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects);4129 stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects); 4143 4130 } 4144 4131 … … 4146 4133 { 4147 4134 stbtt_fontinfo info; 4148 int i, j, n, return_value = 1;4135 int i,j,n, return_value; // [DEAR IMGUI] removed = 1 4149 4136 //stbrp_context *context = (stbrp_context *) spc->pack_info; 4150 4137 stbrp_rect *rects; 4151 4138 4152 4139 // flag all characters as NOT packed 4153 for (i =0; i < num_ranges; ++i)4154 for (j =0; j < ranges[i].num_chars; ++j)4140 for (i=0; i < num_ranges; ++i) 4141 for (j=0; j < ranges[i].num_chars; ++j) 4155 4142 ranges[i].chardata_for_range[j].x0 = 4156 4143 ranges[i].chardata_for_range[j].y0 = … … 4159 4146 4160 4147 n = 0; 4161 for (i =0; i < num_ranges; ++i)4148 for (i=0; i < num_ranges; ++i) 4162 4149 n += ranges[i].num_chars; 4163 4164 rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context);4150 4151 rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context); 4165 4152 if (rects == NULL) 4166 4153 return 0; 4167 4154 4168 4155 info.userdata = spc->user_allocator_context; 4169 stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, 4156 stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index)); 4170 4157 4171 4158 n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects); 4172 4159 4173 4160 stbtt_PackFontRangesPackRects(spc, rects, n); 4174 4161 4175 4162 return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects); 4176 4163 … … 4180 4167 4181 4168 STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size, 4182 int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range)4169 int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range) 4183 4170 { 4184 4171 stbtt_pack_range range; 4185 4172 range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range; 4186 4173 range.array_of_unicode_codepoints = NULL; 4187 range.num_chars = num_chars_in_range;4188 range.chardata_for_range = chardata_for_range;4189 range.font_size = font_size;4174 range.num_chars = num_chars_in_range; 4175 range.chardata_for_range = chardata_for_range; 4176 range.font_size = font_size; 4190 4177 return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1); 4178 } 4179 4180 STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap) 4181 { 4182 int i_ascent, i_descent, i_lineGap; 4183 float scale; 4184 stbtt_fontinfo info; 4185 stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index)); 4186 scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) : stbtt_ScaleForMappingEmToPixels(&info, -size); 4187 stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap); 4188 *ascent = (float) i_ascent * scale; 4189 *descent = (float) i_descent * scale; 4190 *lineGap = (float) i_lineGap * scale; 4191 4191 } 4192 4192 … … 4197 4197 4198 4198 if (align_to_integer) { 4199 float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f);4200 float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f);4199 float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f); 4200 float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f); 4201 4201 q->x0 = x; 4202 4202 q->y0 = y; 4203 4203 q->x1 = x + b->xoff2 - b->xoff; 4204 4204 q->y1 = y + b->yoff2 - b->yoff; 4205 } 4206 else { 4205 } else { 4207 4206 q->x0 = *xpos + b->xoff; 4208 4207 q->y0 = *ypos + b->yoff; … … 4229 4228 static int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], float q1[2], float q2[2], float hits[2][2]) 4230 4229 { 4231 float q0perp = q0[1] * ray[0] - q0[0] *ray[1];4232 float q1perp = q1[1] * ray[0] - q1[0] *ray[1];4233 float q2perp = q2[1] * ray[0] - q2[0] *ray[1];4234 float roperp = orig[1] * ray[0] - orig[0] *ray[1];4235 4236 float a = q0perp - 2 *q1perp + q2perp;4230 float q0perp = q0[1]*ray[0] - q0[0]*ray[1]; 4231 float q1perp = q1[1]*ray[0] - q1[0]*ray[1]; 4232 float q2perp = q2[1]*ray[0] - q2[0]*ray[1]; 4233 float roperp = orig[1]*ray[0] - orig[0]*ray[1]; 4234 4235 float a = q0perp - 2*q1perp + q2perp; 4237 4236 float b = q1perp - q0perp; 4238 4237 float c = q0perp - roperp; … … 4242 4241 4243 4242 if (a != 0.0) { 4244 float discr = b * b - a *c;4243 float discr = b*b - a*c; 4245 4244 if (discr > 0.0) { 4246 4245 float rcpna = -1 / a; 4247 float d = (float) STBTT_sqrt(discr);4248 s0 = (b +d) * rcpna;4249 s1 = (b -d) * rcpna;4246 float d = (float) STBTT_sqrt(discr); 4247 s0 = (b+d) * rcpna; 4248 s1 = (b-d) * rcpna; 4250 4249 if (s0 >= 0.0 && s0 <= 1.0) 4251 4250 num_s = 1; … … 4255 4254 } 4256 4255 } 4257 } 4258 else { 4256 } else { 4259 4257 // 2*b*s + c = 0 4260 4258 // s = -c / (2*b) … … 4267 4265 return 0; 4268 4266 else { 4269 float rcp_len2 = 1 / (ray[0] * ray[0] + ray[1] *ray[1]);4267 float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]); 4270 4268 float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2; 4271 4269 4272 float q0d = q0[0] * rayn_x + q0[1] *rayn_y;4273 float q1d = q1[0] * rayn_x + q1[1] *rayn_y;4274 float q2d = q2[0] * rayn_x + q2[1] *rayn_y;4275 float rod = orig[0] * rayn_x + orig[1] *rayn_y;4270 float q0d = q0[0]*rayn_x + q0[1]*rayn_y; 4271 float q1d = q1[0]*rayn_x + q1[1]*rayn_y; 4272 float q2d = q2[0]*rayn_x + q2[1]*rayn_y; 4273 float rod = orig[0]*rayn_x + orig[1]*rayn_y; 4276 4274 4277 4275 float q10d = q1d - q0d; … … 4279 4277 float q0rd = q0d - rod; 4280 4278 4281 hits[0][0] = q0rd + s0 * (2.0f - 2.0f*s0)*q10d + s0 *s0*q20d;4282 hits[0][1] = a * s0 +b;4279 hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d; 4280 hits[0][1] = a*s0+b; 4283 4281 4284 4282 if (num_s > 1) { 4285 hits[1][0] = q0rd + s1 * (2.0f - 2.0f*s1)*q10d + s1 *s1*q20d;4286 hits[1][1] = a * s1 +b;4283 hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d; 4284 hits[1][1] = a*s1+b; 4287 4285 return 2; 4288 } 4289 else { 4286 } else { 4290 4287 return 1; 4291 4288 } … … 4306 4303 4307 4304 orig[0] = x; 4308 orig[1] = y;4305 //orig[1] = y; // [DEAR IMGUI] commmented double assignment 4309 4306 4310 4307 // make sure y never passes through a vertex of the shape 4311 y_frac = (float) STBTT_fmod(y, 1.0f);4308 y_frac = (float) STBTT_fmod(y, 1.0f); 4312 4309 if (y_frac < 0.01f) 4313 4310 y += 0.01f; … … 4317 4314 4318 4315 // test a ray from (-infinity,y) to (x,y) 4319 for (i =0; i < nverts; ++i) {4316 for (i=0; i < nverts; ++i) { 4320 4317 if (verts[i].type == STBTT_vline) { 4321 int x0 = (int) verts[i - 1].x, y0 = (int)verts[i -1].y;4322 int x1 = (int) verts[i].x, y1 = (int)verts[i].y;4323 if (y > STBTT_min(y0, y1) && y < STBTT_max(y0, y1) && x > STBTT_min(x0,x1)) {4324 float x_inter = (y - y0) / (y1 - y0) * (x1 -x0) + x0;4325 if (x_inter < x) 4318 int x0 = (int) verts[i-1].x, y0 = (int) verts[i-1].y; 4319 int x1 = (int) verts[i ].x, y1 = (int) verts[i ].y; 4320 if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { 4321 float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; 4322 if (x_inter < x) 4326 4323 winding += (y0 < y1) ? 1 : -1; 4327 4324 } 4328 4325 } 4329 4326 if (verts[i].type == STBTT_vcurve) { 4330 int x0 = (int) verts[i - 1].x, y0 = (int)verts[i - 1].y;4331 int x1 = (int) verts[i].cx, y1 = (int)verts[i].cy;4332 int x2 = (int) verts[i].x, y2 = (int)verts[i].y;4333 int ax = STBTT_min(x0, STBTT_min(x1, x2)), ay = STBTT_min(y0, STBTT_min(y1,y2));4334 int by = STBTT_max(y0, STBTT_max(y1,y2));4327 int x0 = (int) verts[i-1].x , y0 = (int) verts[i-1].y ; 4328 int x1 = (int) verts[i ].cx, y1 = (int) verts[i ].cy; 4329 int x2 = (int) verts[i ].x , y2 = (int) verts[i ].y ; 4330 int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2)); 4331 int by = STBTT_max(y0,STBTT_max(y1,y2)); 4335 4332 if (y > ay && y < by && x > ax) { 4336 float q0[2], q1[2],q2[2];4333 float q0[2],q1[2],q2[2]; 4337 4334 float hits[2][2]; 4338 4335 q0[0] = (float)x0; … … 4342 4339 q2[0] = (float)x2; 4343 4340 q2[1] = (float)y2; 4344 if (equal(q0, q1) || equal(q1,q2)) {4345 x0 = (int)verts[i -1].x;4346 y0 = (int)verts[i -1].y;4347 x1 = (int)verts[i ].x;4348 y1 = (int)verts[i ].y;4349 if (y > STBTT_min(y0, y1) && y < STBTT_max(y0, y1) && x > STBTT_min(x0,x1)) {4350 float x_inter = (y - y0) / (y1 - y0) * (x1 -x0) + x0;4351 if (x_inter < x) 4341 if (equal(q0,q1) || equal(q1,q2)) { 4342 x0 = (int)verts[i-1].x; 4343 y0 = (int)verts[i-1].y; 4344 x1 = (int)verts[i ].x; 4345 y1 = (int)verts[i ].y; 4346 if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { 4347 float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; 4348 if (x_inter < x) 4352 4349 winding += (y0 < y1) ? 1 : -1; 4353 4350 } 4354 } 4355 else { 4351 } else { 4356 4352 int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits); 4357 4353 if (num_hits >= 1) … … 4362 4358 winding += (hits[1][1] < 0 ? -1 : 1); 4363 4359 } 4364 } 4360 } 4365 4361 } 4366 4362 } … … 4368 4364 } 4369 4365 4370 static float stbtt__cuberoot( float x)4366 static float stbtt__cuberoot( float x ) 4371 4367 { 4372 4368 if (x<0) 4373 return -(float) STBTT_pow(-x, 1.0f /3.0f);4369 return -(float) STBTT_pow(-x,1.0f/3.0f); 4374 4370 else 4375 return (float) STBTT_pow(x, 1.0f /3.0f);4371 return (float) STBTT_pow( x,1.0f/3.0f); 4376 4372 } 4377 4373 … … 4379 4375 static int stbtt__solve_cubic(float a, float b, float c, float* r) 4380 4376 { 4381 float s = -a / 3; 4382 float p = b - a * a / 3; 4383 float q = a * (2 * a*a - 9 * b) / 27 + c; 4384 float p3 = p * p*p; 4385 float d = q * q + 4 * p3 / 27; 4386 if (d >= 0) { 4387 float z = (float)STBTT_sqrt(d); 4388 float u = (-q + z) / 2; 4389 float v = (-q - z) / 2; 4390 u = stbtt__cuberoot(u); 4391 v = stbtt__cuberoot(v); 4392 r[0] = s + u + v; 4393 return 1; 4394 } 4395 else { 4396 float u = (float)STBTT_sqrt(-p / 3); 4397 float v = (float)STBTT_acos(-STBTT_sqrt(-27 / p3) * q / 2) / 3; // p3 must be negative, since d is negative 4398 float m = (float)STBTT_cos(v); 4399 float n = (float)STBTT_cos(v - 3.141592 / 2)*1.732050808f; 4400 r[0] = s + u * 2 * m; 4401 r[1] = s - u * (m + n); 4402 r[2] = s - u * (m - n); 4377 float s = -a / 3; 4378 float p = b - a*a / 3; 4379 float q = a * (2*a*a - 9*b) / 27 + c; 4380 float p3 = p*p*p; 4381 float d = q*q + 4*p3 / 27; 4382 if (d >= 0) { 4383 float z = (float) STBTT_sqrt(d); 4384 float u = (-q + z) / 2; 4385 float v = (-q - z) / 2; 4386 u = stbtt__cuberoot(u); 4387 v = stbtt__cuberoot(v); 4388 r[0] = s + u + v; 4389 return 1; 4390 } else { 4391 float u = (float) STBTT_sqrt(-p/3); 4392 float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative 4393 float m = (float) STBTT_cos(v); 4394 float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f; 4395 r[0] = s + u * 2 * m; 4396 r[1] = s - u * (m + n); 4397 r[2] = s - u * (m - n); 4403 4398 4404 4399 //STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f); // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe? 4405 4400 //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f); 4406 4401 //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f); 4407 4402 return 3; 4408 4403 } 4409 4404 } … … 4412 4407 { 4413 4408 float scale_x = scale, scale_y = scale; 4414 int ix0, iy0, ix1,iy1;4415 int w, 4409 int ix0,iy0,ix1,iy1; 4410 int w,h; 4416 4411 unsigned char *data; 4417 4412 … … 4423 4418 } 4424 4419 4425 stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f, 0.0f, &ix0, &iy0, &ix1,&iy1);4420 stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1); 4426 4421 4427 4422 // if empty, return NULL … … 4437 4432 h = (iy1 - iy0); 4438 4433 4439 if (width ) *width= w;4434 if (width ) *width = w; 4440 4435 if (height) *height = h; 4441 if (xoff ) *xoff= ix0;4442 if (yoff ) *yoff= iy0;4436 if (xoff ) *xoff = ix0; 4437 if (yoff ) *yoff = iy0; 4443 4438 4444 4439 // invert for y-downwards bitmaps 4445 4440 scale_y = -scale_y; 4446 4441 4447 4442 { 4448 int x, y, i,j;4443 int x,y,i,j; 4449 4444 float *precompute; 4450 4445 stbtt_vertex *verts; 4451 4446 int num_verts = stbtt_GetGlyphShape(info, glyph, &verts); 4452 data = (unsigned char *) STBTT_malloc(w * h, info->userdata);4453 precompute = (float *) STBTT_malloc(num_verts * sizeof(float), info->userdata);4454 4455 for (i = 0, j = num_verts - 1; i < num_verts; j =i++) {4447 data = (unsigned char *) STBTT_malloc(w * h, info->userdata); 4448 precompute = (float *) STBTT_malloc(num_verts * sizeof(float), info->userdata); 4449 4450 for (i=0,j=num_verts-1; i < num_verts; j=i++) { 4456 4451 if (verts[i].type == STBTT_vline) { 4457 4452 float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; 4458 4453 float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y; 4459 float dist = (float) STBTT_sqrt((x1 - x0)*(x1 - x0) + (y1 - y0)*(y1 -y0));4454 float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0)); 4460 4455 precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist; 4461 } 4462 else if (verts[i].type == STBTT_vcurve) { 4456 } else if (verts[i].type == STBTT_vcurve) { 4463 4457 float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y; 4464 4458 float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y; 4465 4459 float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y; 4466 float bx = x0 - 2 * x1 + x2, by = y0 - 2 *y1 + y2;4467 float len2 = bx * bx + by *by;4460 float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; 4461 float len2 = bx*bx + by*by; 4468 4462 if (len2 != 0.0f) 4469 precompute[i] = 1.0f / (bx*bx + by *by);4463 precompute[i] = 1.0f / (bx*bx + by*by); 4470 4464 else 4471 4465 precompute[i] = 0.0f; 4472 } 4473 else 4466 } else 4474 4467 precompute[i] = 0.0f; 4475 4468 } 4476 4469 4477 for (y =iy0; y < iy1; ++y) {4478 for (x =ix0; x < ix1; ++x) {4470 for (y=iy0; y < iy1; ++y) { 4471 for (x=ix0; x < ix1; ++x) { 4479 4472 float val; 4480 4473 float min_dist = 999999.0f; 4481 float sx = (float) x + 0.5f;4482 float sy = (float) y + 0.5f;4474 float sx = (float) x + 0.5f; 4475 float sy = (float) y + 0.5f; 4483 4476 float x_gspace = (sx / scale_x); 4484 4477 float y_gspace = (sy / scale_y); … … 4486 4479 int winding = stbtt__compute_crossings_x(x_gspace, y_gspace, num_verts, verts); // @OPTIMIZE: this could just be a rasterization, but needs to be line vs. non-tesselated curves so a new path 4487 4480 4488 for (i =0; i < num_verts; ++i) {4481 for (i=0; i < num_verts; ++i) { 4489 4482 float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; 4490 4483 4491 4484 // check against every point here rather than inside line/curve primitives -- @TODO: wrong if multiple 'moves' in a row produce a garbage point, and given culling, probably more efficient to do within line/curve 4492 float dist2 = (x0 - sx)*(x0 - sx) + (y0 - sy)*(y0 -sy);4485 float dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); 4493 4486 if (dist2 < min_dist*min_dist) 4494 min_dist = (float) STBTT_sqrt(dist2);4487 min_dist = (float) STBTT_sqrt(dist2); 4495 4488 4496 4489 if (verts[i].type == STBTT_vline) { 4497 float x1 = verts[i - 1].x*scale_x, y1 = verts[i -1].y*scale_y;4490 float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y; 4498 4491 4499 4492 // coarse culling against bbox 4500 4493 //if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist && 4501 4494 // sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist) 4502 float dist = (float) STBTT_fabs((x1 - x0)*(y0 - sy) - (y1 - y0)*(x0 -sx)) * precompute[i];4495 float dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i]; 4503 4496 STBTT_assert(i != 0); 4504 4497 if (dist < min_dist) { … … 4506 4499 // x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0) 4507 4500 // minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy) 4508 float dx = x1 - x0, dy = y1 -y0;4509 float px = x0 - sx, py = y0 -sy;4501 float dx = x1-x0, dy = y1-y0; 4502 float px = x0-sx, py = y0-sy; 4510 4503 // minimize (px+t*dx)^2 + (py+t*dy)^2 = px*px + 2*px*dx*t + t^2*dx*dx + py*py + 2*py*dy*t + t^2*dy*dy 4511 4504 // derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve 4512 float t = -(px*dx + py * dy) / (dx*dx + dy *dy);4505 float t = -(px*dx + py*dy) / (dx*dx + dy*dy); 4513 4506 if (t >= 0.0f && t <= 1.0f) 4514 4507 min_dist = dist; 4515 4508 } 4516 } 4517 else if (verts[i].type == STBTT_vcurve) { 4518 float x2 = verts[i - 1].x *scale_x, y2 = verts[i - 1].y *scale_y; 4519 float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y; 4520 float box_x0 = STBTT_min(STBTT_min(x0, x1), x2); 4521 float box_y0 = STBTT_min(STBTT_min(y0, y1), y2); 4522 float box_x1 = STBTT_max(STBTT_max(x0, x1), x2); 4523 float box_y1 = STBTT_max(STBTT_max(y0, y1), y2); 4509 } else if (verts[i].type == STBTT_vcurve) { 4510 float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y; 4511 float x1 = verts[i ].cx*scale_x, y1 = verts[i ].cy*scale_y; 4512 float box_x0 = STBTT_min(STBTT_min(x0,x1),x2); 4513 float box_y0 = STBTT_min(STBTT_min(y0,y1),y2); 4514 float box_x1 = STBTT_max(STBTT_max(x0,x1),x2); 4515 float box_y1 = STBTT_max(STBTT_max(y0,y1),y2); 4524 4516 // coarse culling against bbox to avoid computing cubic unnecessarily 4525 if (sx > box_x0 - min_dist && sx < box_x1 + min_dist && sy > box_y0 - min_dist && sy < box_y1 +min_dist) {4526 int num =0;4527 float ax = x1 - x0, ay = y1 -y0;4528 float bx = x0 - 2 * x1 + x2, by = y0 - 2 *y1 + y2;4517 if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) { 4518 int num=0; 4519 float ax = x1-x0, ay = y1-y0; 4520 float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; 4529 4521 float mx = x0 - sx, my = y0 - sy; 4530 float res[3], px, py, t,it;4522 float res[3],px,py,t,it; 4531 4523 float a_inv = precompute[i]; 4532 4524 if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula 4533 float a = 3 * (ax*bx + ay *by);4534 float b = 2 * (ax*ax + ay * ay) + (mx*bx + my *by);4535 float c = mx * ax + my *ay;4525 float a = 3*(ax*bx + ay*by); 4526 float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by); 4527 float c = mx*ax+my*ay; 4536 4528 if (a == 0.0) { // if a is 0, it's linear 4537 4529 if (b != 0.0) { 4538 res[num++] = -c /b;4530 res[num++] = -c/b; 4539 4531 } 4540 } 4541 else { 4542 float discriminant = b * b - 4 * a*c; 4532 } else { 4533 float discriminant = b*b - 4*a*c; 4543 4534 if (discriminant < 0) 4544 4535 num = 0; 4545 4536 else { 4546 float root = (float) STBTT_sqrt(discriminant);4547 res[0] = (-b - root) / (2 *a);4548 res[1] = (-b + root) / (2 *a);4537 float root = (float) STBTT_sqrt(discriminant); 4538 res[0] = (-b - root)/(2*a); 4539 res[1] = (-b + root)/(2*a); 4549 4540 num = 2; // don't bother distinguishing 1-solution case, as code below will still work 4550 4541 } 4551 4542 } 4552 } 4553 else { 4554 float b = 3 * (ax*bx + ay * by) * a_inv; // could precompute this as it doesn't depend on sample point 4555 float c = (2 * (ax*ax + ay * ay) + (mx*bx + my * by)) * a_inv; 4556 float d = (mx*ax + my * ay) * a_inv; 4543 } else { 4544 float b = 3*(ax*bx + ay*by) * a_inv; // could precompute this as it doesn't depend on sample point 4545 float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv; 4546 float d = (mx*ax+my*ay) * a_inv; 4557 4547 num = stbtt__solve_cubic(b, c, d, res); 4558 4548 } 4559 4549 if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) { 4560 4550 t = res[0], it = 1.0f - t; 4561 px = it * it*x0 + 2 * t*it*x1 + t *t*x2;4562 py = it * it*y0 + 2 * t*it*y1 + t *t*y2;4563 dist2 = (px - sx)*(px - sx) + (py - sy)*(py -sy);4551 px = it*it*x0 + 2*t*it*x1 + t*t*x2; 4552 py = it*it*y0 + 2*t*it*y1 + t*t*y2; 4553 dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); 4564 4554 if (dist2 < min_dist * min_dist) 4565 min_dist = (float) STBTT_sqrt(dist2);4555 min_dist = (float) STBTT_sqrt(dist2); 4566 4556 } 4567 4557 if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) { 4568 4558 t = res[1], it = 1.0f - t; 4569 px = it * it*x0 + 2 * t*it*x1 + t *t*x2;4570 py = it * it*y0 + 2 * t*it*y1 + t *t*y2;4571 dist2 = (px - sx)*(px - sx) + (py - sy)*(py -sy);4559 px = it*it*x0 + 2*t*it*x1 + t*t*x2; 4560 py = it*it*y0 + 2*t*it*y1 + t*t*y2; 4561 dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); 4572 4562 if (dist2 < min_dist * min_dist) 4573 min_dist = (float) STBTT_sqrt(dist2);4563 min_dist = (float) STBTT_sqrt(dist2); 4574 4564 } 4575 4565 if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) { 4576 4566 t = res[2], it = 1.0f - t; 4577 px = it * it*x0 + 2 * t*it*x1 + t *t*x2;4578 py = it * it*y0 + 2 * t*it*y1 + t *t*y2;4579 dist2 = (px - sx)*(px - sx) + (py - sy)*(py -sy);4567 px = it*it*x0 + 2*t*it*x1 + t*t*x2; 4568 py = it*it*y0 + 2*t*it*y1 + t*t*y2; 4569 dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); 4580 4570 if (dist2 < min_dist * min_dist) 4581 min_dist = (float) STBTT_sqrt(dist2);4571 min_dist = (float) STBTT_sqrt(dist2); 4582 4572 } 4583 4573 } … … 4591 4581 else if (val > 255) 4592 4582 val = 255; 4593 data[(y - iy0)*w + (x - ix0)] = (unsigned char)val;4583 data[(y-iy0)*w+(x-ix0)] = (unsigned char) val; 4594 4584 } 4595 4585 } … … 4598 4588 } 4599 4589 return data; 4600 } 4590 } 4601 4591 4602 4592 STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff) … … 4616 4606 4617 4607 // check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string 4618 static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2) 4619 { 4620 stbtt_int32 i =0;4608 static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2) 4609 { 4610 stbtt_int32 i=0; 4621 4611 4622 4612 // convert utf16 to utf8 and compare the results while converting 4623 4613 while (len2) { 4624 stbtt_uint16 ch = s2[0] *256 + s2[1];4614 stbtt_uint16 ch = s2[0]*256 + s2[1]; 4625 4615 if (ch < 0x80) { 4626 4616 if (i >= len1) return -1; 4627 4617 if (s1[i++] != ch) return -1; 4628 } 4629 else if (ch < 0x800) { 4630 if (i + 1 >= len1) return -1; 4618 } else if (ch < 0x800) { 4619 if (i+1 >= len1) return -1; 4631 4620 if (s1[i++] != 0xc0 + (ch >> 6)) return -1; 4632 4621 if (s1[i++] != 0x80 + (ch & 0x3f)) return -1; 4633 } 4634 else if (ch >= 0xd800 && ch < 0xdc00) { 4622 } else if (ch >= 0xd800 && ch < 0xdc00) { 4635 4623 stbtt_uint32 c; 4636 stbtt_uint16 ch2 = s2[2] *256 + s2[3];4637 if (i +3 >= len1) return -1;4624 stbtt_uint16 ch2 = s2[2]*256 + s2[3]; 4625 if (i+3 >= len1) return -1; 4638 4626 c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000; 4639 4627 if (s1[i++] != 0xf0 + (c >> 18)) return -1; 4640 4628 if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1; 4641 if (s1[i++] != 0x80 + ((c >> 6) & 0x3f)) return -1;4642 if (s1[i++] != 0x80 + ((c ) & 0x3f)) return -1;4629 if (s1[i++] != 0x80 + ((c >> 6) & 0x3f)) return -1; 4630 if (s1[i++] != 0x80 + ((c ) & 0x3f)) return -1; 4643 4631 s2 += 2; // plus another 2 below 4644 4632 len2 -= 2; 4645 } 4646 else if (ch >= 0xdc00 && ch < 0xe000) { 4633 } else if (ch >= 0xdc00 && ch < 0xe000) { 4647 4634 return -1; 4648 } 4649 else { 4650 if (i + 2 >= len1) return -1; 4635 } else { 4636 if (i+2 >= len1) return -1; 4651 4637 if (s1[i++] != 0xe0 + (ch >> 12)) return -1; 4652 4638 if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1; 4653 if (s1[i++] != 0x80 + ((ch ) & 0x3f)) return -1;4639 if (s1[i++] != 0x80 + ((ch ) & 0x3f)) return -1; 4654 4640 } 4655 4641 s2 += 2; … … 4659 4645 } 4660 4646 4661 static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2) 4662 { 4663 return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*)s2, len2);4647 static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2) 4648 { 4649 return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2); 4664 4650 } 4665 4651 … … 4668 4654 STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID) 4669 4655 { 4670 stbtt_int32 i, count,stringOffset;4656 stbtt_int32 i,count,stringOffset; 4671 4657 stbtt_uint8 *fc = font->data; 4672 4658 stbtt_uint32 offset = font->fontstart; … … 4674 4660 if (!nm) return NULL; 4675 4661 4676 count = ttUSHORT(fc + nm +2);4677 stringOffset = nm + ttUSHORT(fc + nm +4);4678 for (i =0; i < count; ++i) {4662 count = ttUSHORT(fc+nm+2); 4663 stringOffset = nm + ttUSHORT(fc+nm+4); 4664 for (i=0; i < count; ++i) { 4679 4665 stbtt_uint32 loc = nm + 6 + 12 * i; 4680 if (platformID == ttUSHORT(fc + loc + 0) && encodingID == ttUSHORT(fc + loc +2)4681 && languageID == ttUSHORT(fc + loc + 4) && nameID == ttUSHORT(fc + loc +6)) {4682 *length = ttUSHORT(fc + loc +8);4683 return (const char *) (fc + stringOffset + ttUSHORT(fc + loc +10));4666 if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2) 4667 && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) { 4668 *length = ttUSHORT(fc+loc+8); 4669 return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10)); 4684 4670 } 4685 4671 } … … 4690 4676 { 4691 4677 stbtt_int32 i; 4692 stbtt_int32 count = ttUSHORT(fc + nm +2);4693 stbtt_int32 stringOffset = nm + ttUSHORT(fc + nm +4);4694 4695 for (i =0; i < count; ++i) {4678 stbtt_int32 count = ttUSHORT(fc+nm+2); 4679 stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4); 4680 4681 for (i=0; i < count; ++i) { 4696 4682 stbtt_uint32 loc = nm + 6 + 12 * i; 4697 stbtt_int32 id = ttUSHORT(fc + loc +6);4683 stbtt_int32 id = ttUSHORT(fc+loc+6); 4698 4684 if (id == target_id) { 4699 4685 // find the encoding 4700 stbtt_int32 platform = ttUSHORT(fc + loc + 0), encoding = ttUSHORT(fc + loc + 2), language = ttUSHORT(fc + loc +4);4686 stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4); 4701 4687 4702 4688 // is this a Unicode encoding? 4703 4689 if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) { 4704 stbtt_int32 slen = ttUSHORT(fc + loc +8);4705 stbtt_int32 off = ttUSHORT(fc + loc +10);4690 stbtt_int32 slen = ttUSHORT(fc+loc+8); 4691 stbtt_int32 off = ttUSHORT(fc+loc+10); 4706 4692 4707 4693 // check if there's a prefix match 4708 stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc + stringOffset + off,slen);4694 stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen); 4709 4695 if (matchlen >= 0) { 4710 4696 // check for target_id+1 immediately following, with same encoding & language 4711 if (i + 1 < count && ttUSHORT(fc + loc + 12 + 6) == next_id && ttUSHORT(fc + loc + 12) == platform && ttUSHORT(fc + loc + 12 + 2) == encoding && ttUSHORT(fc + loc + 12 +4) == language) {4712 slen = ttUSHORT(fc + loc + 12 +8);4713 off = ttUSHORT(fc + loc + 12 +10);4697 if (i+1 < count && ttUSHORT(fc+loc+12+6) == next_id && ttUSHORT(fc+loc+12) == platform && ttUSHORT(fc+loc+12+2) == encoding && ttUSHORT(fc+loc+12+4) == language) { 4698 slen = ttUSHORT(fc+loc+12+8); 4699 off = ttUSHORT(fc+loc+12+10); 4714 4700 if (slen == 0) { 4715 4701 if (matchlen == nlen) 4716 4702 return 1; 4717 } 4718 else if (matchlen < nlen && name[matchlen] == ' ') { 4703 } else if (matchlen < nlen && name[matchlen] == ' ') { 4719 4704 ++matchlen; 4720 if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name + matchlen), nlen - matchlen, (char*)(fc + stringOffset + off),slen))4705 if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen)) 4721 4706 return 1; 4722 4707 } 4723 } 4724 else { 4708 } else { 4725 4709 // if nothing immediately following 4726 4710 if (matchlen == nlen) … … 4738 4722 static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags) 4739 4723 { 4740 stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *)name);4741 stbtt_uint32 nm, 4742 if (!stbtt__isfont(fc +offset)) return 0;4724 stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name); 4725 stbtt_uint32 nm,hd; 4726 if (!stbtt__isfont(fc+offset)) return 0; 4743 4727 4744 4728 // check italics/bold/underline flags in macStyle... 4745 4729 if (flags) { 4746 4730 hd = stbtt__find_table(fc, offset, "head"); 4747 if ((ttUSHORT(fc + hd +44) & 7) != (flags & 7)) return 0;4731 if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0; 4748 4732 } 4749 4733 … … 4754 4738 // if we checked the macStyle flags, then just check the family and ignore the subfamily 4755 4739 if (stbtt__matchpair(fc, nm, name, nlen, 16, -1)) return 1; 4756 if (stbtt__matchpair(fc, nm, name, nlen, 1, -1)) return 1; 4757 if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; 4758 } 4759 else { 4740 if (stbtt__matchpair(fc, nm, name, nlen, 1, -1)) return 1; 4741 if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; 4742 } else { 4760 4743 if (stbtt__matchpair(fc, nm, name, nlen, 16, 17)) return 1; 4761 if (stbtt__matchpair(fc, nm, name, nlen, 1,2)) return 1;4762 if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1;4744 if (stbtt__matchpair(fc, nm, name, nlen, 1, 2)) return 1; 4745 if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; 4763 4746 } 4764 4747 … … 4769 4752 { 4770 4753 stbtt_int32 i; 4771 for (i = 0;;++i) {4754 for (i=0;;++i) { 4772 4755 stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i); 4773 4756 if (off < 0) return off; 4774 if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*)name_utf8, flags))4757 if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags)) 4775 4758 return off; 4776 4759 } … … 4783 4766 4784 4767 STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, 4785 float pixel_height, unsigned char *pixels, int pw, int ph,4786 int first_char, int num_chars, stbtt_bakedchar *chardata)4787 { 4788 return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata);4768 float pixel_height, unsigned char *pixels, int pw, int ph, 4769 int first_char, int num_chars, stbtt_bakedchar *chardata) 4770 { 4771 return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata); 4789 4772 } 4790 4773 4791 4774 STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index) 4792 4775 { 4793 return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index);4776 return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index); 4794 4777 } 4795 4778 4796 4779 STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data) 4797 4780 { 4798 return stbtt_GetNumberOfFonts_internal((unsigned char *) data);4781 return stbtt_GetNumberOfFonts_internal((unsigned char *) data); 4799 4782 } 4800 4783 4801 4784 STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset) 4802 4785 { 4803 return stbtt_InitFont_internal(info, (unsigned char *) data, offset);4786 return stbtt_InitFont_internal(info, (unsigned char *) data, offset); 4804 4787 } 4805 4788 4806 4789 STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags) 4807 4790 { 4808 return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *)name, flags);4791 return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *) name, flags); 4809 4792 } 4810 4793 4811 4794 STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2) 4812 4795 { 4813 return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *)s2, len2);4796 return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *) s2, len2); 4814 4797 } 4815 4798 … … 4884 4867 ALTERNATIVE A - MIT License 4885 4868 Copyright (c) 2017 Sean Barrett 4886 Permission is hereby granted, free of charge, to any person obtaining a copy of 4887 this software and associated documentation files (the "Software"), to deal in 4888 the Software without restriction, including without limitation the rights to 4889 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 4890 of the Software, and to permit persons to whom the Software is furnished to do 4869 Permission is hereby granted, free of charge, to any person obtaining a copy of 4870 this software and associated documentation files (the "Software"), to deal in 4871 the Software without restriction, including without limitation the rights to 4872 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 4873 of the Software, and to permit persons to whom the Software is furnished to do 4891 4874 so, subject to the following conditions: 4892 The above copyright notice and this permission notice shall be included in all 4875 The above copyright notice and this permission notice shall be included in all 4893 4876 copies or substantial portions of the Software. 4894 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 4895 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 4896 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 4897 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 4898 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 4899 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 4877 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 4878 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 4879 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 4880 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 4881 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 4882 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 4900 4883 SOFTWARE. 4901 4884 ------------------------------------------------------------------------------ 4902 4885 ALTERNATIVE B - Public Domain (www.unlicense.org) 4903 4886 This is free and unencumbered software released into the public domain. 4904 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 4905 software, either in source code form or as a compiled binary, for any purpose, 4887 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 4888 software, either in source code form or as a compiled binary, for any purpose, 4906 4889 commercial or non-commercial, and by any means. 4907 In jurisdictions that recognize copyright laws, the author or authors of this 4908 software dedicate any and all copyright interest in the software to the public 4909 domain. We make this dedication for the benefit of the public at large and to 4910 the detriment of our heirs and successors. We intend this dedication to be an 4911 overt act of relinquishment in perpetuity of all present and future rights to 4890 In jurisdictions that recognize copyright laws, the author or authors of this 4891 software dedicate any and all copyright interest in the software to the public 4892 domain. We make this dedication for the benefit of the public at large and to 4893 the detriment of our heirs and successors. We intend this dedication to be an 4894 overt act of relinquishment in perpetuity of all present and future rights to 4912 4895 this software under copyright law. 4913 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 4914 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 4915 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 4916 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 4917 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 4896 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 4897 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 4898 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 4899 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 4900 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 4918 4901 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 4919 4902 ------------------------------------------------------------------------------ -
OpenGLReference.vcxproj
r78c3045 re66fd66 145 145 <ClCompile Include="IMGUI\imgui_demo.cpp" /> 146 146 <ClCompile Include="IMGUI\imgui_draw.cpp" /> 147 <ClCompile Include="imgui_impl_glfw_gl3.cpp" /> 147 <ClCompile Include="IMGUI\imgui_impl_glfw.cpp" /> 148 <ClCompile Include="IMGUI\imgui_impl_opengl3.cpp" /> 149 <ClCompile Include="IMGUI\imgui_widgets.cpp" /> 148 150 <ClCompile Include="logger.cpp" /> 149 151 <ClCompile Include="new-game.cpp" /> … … 154 156 <ClInclude Include="crash-logger.hpp" /> 155 157 <ClInclude Include="FileStackWalker.h" /> 158 <ClInclude Include="IMGUI\imconfig.h" /> 156 159 <ClInclude Include="IMGUI\imgui.h" /> 160 <ClInclude Include="IMGUI\imgui_impl_glfw.h" /> 161 <ClInclude Include="IMGUI\imgui_impl_opengl3.h" /> 157 162 <ClInclude Include="IMGUI\imgui_internal.h" /> 158 <ClInclude Include="IMGUI\stb_rect_pack.h" /> 159 <ClInclude Include="IMGUI\stb_textedit.h" /> 160 <ClInclude Include="IMGUI\stb_truetype.h" /> 161 <ClInclude Include="imgui_impl_glfw_gl3.h" /> 162 <ClInclude Include="logger.h" /> 163 <ClInclude Include="IMGUI\imstb_rectpack.h" /> 164 <ClInclude Include="IMGUI\imstb_textedit.h" /> 165 <ClInclude Include="IMGUI\imstb_truetype.h" /> 166 <ClInclude Include="logger.hpp" /> 163 167 <ClInclude Include="StackWalker.h" /> 164 168 <ClInclude Include="stb_image.h" /> … … 180 184 <None Include="gl-shaders\ship.frag" /> 181 185 <None Include="gl-shaders\ship.vert" /> 182 <None Include="texture.frag" />183 <None Include="texture.vert" />184 186 </ItemGroup> 185 187 <ItemGroup> -
new-game.cpp
r78c3045 re66fd66 9 9 10 10 #include "IMGUI/imgui.h" 11 #include "imgui_impl_glfw_gl3.h" 11 #include "IMGUI/imgui_impl_glfw.h" 12 #include "IMGUI/imgui_impl_opengl3.h" 12 13 13 14 #include <GL/glew.h> … … 36 37 using namespace glm; 37 38 38 enum State {39 STATE_MAIN_MENU,40 STATE_GAME,39 enum class State { 40 MAIN_MENU, 41 GAME, 41 42 }; 42 43 43 enum Event {44 EVENT_GO_TO_MAIN_MENU,45 EVENT_GO_TO_GAME,46 EVENT_QUIT,44 enum class Event { 45 GO_TO_MAIN_MENU, 46 GO_TO_GAME, 47 QUIT, 47 48 }; 48 49 49 50 /*** START OF REFACTORED CODE ***/ 50 enum ObjectType {51 TYPE_SHIP,52 TYPE_ASTEROID,53 TYPE_LASER,54 TYPE_EXPLOSION,51 enum class ObjectType { 52 SHIP, 53 ASTEROID, 54 LASER, 55 EXPLOSION, 55 56 }; 56 57 57 enum AttribType {58 ATTRIB_UNIFORM,59 ATTRIB_OBJECT_VARYING,60 ATTRIB_POINT_VARYING,58 enum class AttribType { 59 UNIFORM, 60 OBJECT_VARYING, 61 POINT_VARYING, 61 62 }; 62 63 … … 248 249 249 250 #define NUM_KEYS (512) 250 #define ONE_DEG_IN_RAD ((2.0f * M_PI) / 360.0f) // 0.017444444 (maybe make this a const instead)251 251 #define TARGET_FPS 60.0f 252 252 … … 332 332 return 1; 333 333 } 334 335 string glsl_version = "#version 410"; 334 336 335 337 #ifdef MAC … … 411 413 IMGUI_CHECKVERSION(); 412 414 ImGui::CreateContext(); 415 413 416 ImGuiIO& io = ImGui::GetIO(); (void)io; 414 //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls 415 //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls 416 ImGui_ImplGlfwGL3_Init(window, true); 417 418 // Setup style 417 //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls 418 //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls 419 420 // Setup Dear ImGui style 419 421 ImGui::StyleColorsDark(); 420 422 //ImGui::StyleColorsClassic(); 423 424 // Setup Platform/Renderer backends 425 ImGui_ImplGlfw_InitForOpenGL(window, true); 426 ImGui_ImplOpenGL3_Init(glsl_version.c_str()); 421 427 422 428 glfwSetMouseButtonCallback(window, mouse_button_callback); … … 497 503 map<ObjectType, ShaderModelGroup> modelGroups; 498 504 499 modelGroups[ TYPE_SHIP] = createModelGroup(505 modelGroups[ObjectType::SHIP] = createModelGroup( 500 506 loadShaderProgram("gl-shaders/ship.vert", "gl-shaders/ship.frag")); 501 shaderBufferInfo[modelGroups[ TYPE_SHIP].shaderProgram] = BufferInfo(); // temporary502 503 defineModelGroupAttrib(modelGroups[ TYPE_SHIP], "vertex_position", ATTRIB_POINT_VARYING,507 shaderBufferInfo[modelGroups[ObjectType::SHIP].shaderProgram] = BufferInfo(); // temporary 508 509 defineModelGroupAttrib(modelGroups[ObjectType::SHIP], "vertex_position", AttribType::POINT_VARYING, 504 510 3, GL_FLOAT, offset_of(&SceneObject::points)); 505 defineModelGroupAttrib(modelGroups[ TYPE_SHIP], "vertex_color", ATTRIB_POINT_VARYING,511 defineModelGroupAttrib(modelGroups[ObjectType::SHIP], "vertex_color", AttribType::POINT_VARYING, 506 512 3, GL_FLOAT, offset_of(&SceneObject::colors)); 507 defineModelGroupAttrib(modelGroups[ TYPE_SHIP], "vertex_normal", ATTRIB_POINT_VARYING,513 defineModelGroupAttrib(modelGroups[ObjectType::SHIP], "vertex_normal", AttribType::POINT_VARYING, 508 514 3, GL_FLOAT, offset_of(&SceneObject::normals)); 509 defineModelGroupAttrib(modelGroups[ TYPE_SHIP], "ubo_index", ATTRIB_OBJECT_VARYING,515 defineModelGroupAttrib(modelGroups[ObjectType::SHIP], "ubo_index", AttribType::OBJECT_VARYING, 510 516 1, GL_UNSIGNED_INT, offset_of(&SceneObject::ubo_offset)); 511 517 512 defineModelGroupUniform(modelGroups[ TYPE_SHIP], "view", ATTRIB_UNIFORM,518 defineModelGroupUniform(modelGroups[ObjectType::SHIP], "view", AttribType::UNIFORM, 513 519 1, UNIFORM_MATRIX_4F, value_ptr(view_mat)); 514 defineModelGroupUniform(modelGroups[ TYPE_SHIP], "proj", ATTRIB_UNIFORM,520 defineModelGroupUniform(modelGroups[ObjectType::SHIP], "proj", AttribType::UNIFORM, 515 521 1, UNIFORM_MATRIX_4F, value_ptr(proj_mat)); 516 522 517 initModelGroupAttribs(modelGroups[ TYPE_SHIP]);518 519 modelGroups[ TYPE_ASTEROID] = createModelGroup(523 initModelGroupAttribs(modelGroups[ObjectType::SHIP]); 524 525 modelGroups[ObjectType::ASTEROID] = createModelGroup( 520 526 loadShaderProgram("gl-shaders/asteroid.vert", "gl-shaders/asteroid.frag")); 521 shaderBufferInfo[modelGroups[ TYPE_ASTEROID].shaderProgram] = BufferInfo(); // temporary522 523 defineModelGroupAttrib(modelGroups[ TYPE_ASTEROID], "vertex_position", ATTRIB_POINT_VARYING,527 shaderBufferInfo[modelGroups[ObjectType::ASTEROID].shaderProgram] = BufferInfo(); // temporary 528 529 defineModelGroupAttrib(modelGroups[ObjectType::ASTEROID], "vertex_position", AttribType::POINT_VARYING, 524 530 3, GL_FLOAT, offset_of(&SceneObject::points)); 525 defineModelGroupAttrib(modelGroups[ TYPE_ASTEROID], "vertex_color", ATTRIB_POINT_VARYING,531 defineModelGroupAttrib(modelGroups[ObjectType::ASTEROID], "vertex_color", AttribType::POINT_VARYING, 526 532 3, GL_FLOAT, offset_of(&SceneObject::colors)); 527 defineModelGroupAttrib(modelGroups[ TYPE_ASTEROID], "vertex_normal", ATTRIB_POINT_VARYING,533 defineModelGroupAttrib(modelGroups[ObjectType::ASTEROID], "vertex_normal", AttribType::POINT_VARYING, 528 534 3, GL_FLOAT, offset_of(&SceneObject::normals)); 529 defineModelGroupAttrib(modelGroups[ TYPE_ASTEROID], "ubo_index", ATTRIB_OBJECT_VARYING,535 defineModelGroupAttrib(modelGroups[ObjectType::ASTEROID], "ubo_index", AttribType::OBJECT_VARYING, 530 536 1, GL_UNSIGNED_INT, offset_of(&SceneObject::ubo_offset)); 531 537 532 defineModelGroupUniform(modelGroups[ TYPE_ASTEROID], "view", ATTRIB_UNIFORM,538 defineModelGroupUniform(modelGroups[ObjectType::ASTEROID], "view", AttribType::UNIFORM, 533 539 1, UNIFORM_MATRIX_4F, value_ptr(view_mat)); 534 defineModelGroupUniform(modelGroups[ TYPE_ASTEROID], "proj", ATTRIB_UNIFORM,540 defineModelGroupUniform(modelGroups[ObjectType::ASTEROID], "proj", AttribType::UNIFORM, 535 541 1, UNIFORM_MATRIX_4F, value_ptr(proj_mat)); 536 542 537 initModelGroupAttribs(modelGroups[ TYPE_ASTEROID]);538 539 modelGroups[ TYPE_LASER] = createModelGroup(543 initModelGroupAttribs(modelGroups[ObjectType::ASTEROID]); 544 545 modelGroups[ObjectType::LASER] = createModelGroup( 540 546 loadShaderProgram("gl-shaders/laser.vert", "gl-shaders/laser.frag")); 541 shaderBufferInfo[modelGroups[ TYPE_LASER].shaderProgram] = BufferInfo(); // temporary542 543 defineModelGroupAttrib(modelGroups[ TYPE_LASER], "vertex_position", ATTRIB_POINT_VARYING,547 shaderBufferInfo[modelGroups[ObjectType::LASER].shaderProgram] = BufferInfo(); // temporary 548 549 defineModelGroupAttrib(modelGroups[ObjectType::LASER], "vertex_position", AttribType::POINT_VARYING, 544 550 3, GL_FLOAT, offset_of(&SceneObject::points)); 545 defineModelGroupAttrib(modelGroups[ TYPE_LASER], "vt", ATTRIB_POINT_VARYING,551 defineModelGroupAttrib(modelGroups[ObjectType::LASER], "vt", AttribType::POINT_VARYING, 546 552 2, GL_FLOAT, offset_of(&SceneObject::texcoords)); 547 defineModelGroupAttrib(modelGroups[ TYPE_LASER], "ubo_index", ATTRIB_OBJECT_VARYING,553 defineModelGroupAttrib(modelGroups[ObjectType::LASER], "ubo_index", AttribType::OBJECT_VARYING, 548 554 1, GL_UNSIGNED_INT, offset_of(&SceneObject::ubo_offset)); 549 555 550 defineModelGroupUniform(modelGroups[ TYPE_LASER], "view", ATTRIB_UNIFORM,556 defineModelGroupUniform(modelGroups[ObjectType::LASER], "view", AttribType::UNIFORM, 551 557 1, UNIFORM_MATRIX_4F, value_ptr(view_mat)); 552 defineModelGroupUniform(modelGroups[ TYPE_LASER], "proj", ATTRIB_UNIFORM,558 defineModelGroupUniform(modelGroups[ObjectType::LASER], "proj", AttribType::UNIFORM, 553 559 1, UNIFORM_MATRIX_4F, value_ptr(proj_mat)); 554 defineModelGroupUniform(modelGroups[ TYPE_LASER], "laser_color", ATTRIB_UNIFORM,560 defineModelGroupUniform(modelGroups[ObjectType::LASER], "laser_color", AttribType::UNIFORM, 555 561 1, UNIFORM_3F, laserColor); 556 562 557 initModelGroupAttribs(modelGroups[ TYPE_LASER]);558 559 modelGroups[ TYPE_EXPLOSION] = createModelGroup(563 initModelGroupAttribs(modelGroups[ObjectType::LASER]); 564 565 modelGroups[ObjectType::EXPLOSION] = createModelGroup( 560 566 loadShaderProgram("gl-shaders/explosion.vert", "gl-shaders/explosion.frag")); 561 shaderBufferInfo[modelGroups[ TYPE_EXPLOSION].shaderProgram] = BufferInfo(); // temporary562 563 defineModelGroupAttrib(modelGroups[ TYPE_EXPLOSION], "v_i", ATTRIB_POINT_VARYING,567 shaderBufferInfo[modelGroups[ObjectType::EXPLOSION].shaderProgram] = BufferInfo(); // temporary 568 569 defineModelGroupAttrib(modelGroups[ObjectType::EXPLOSION], "v_i", AttribType::POINT_VARYING, 564 570 3, GL_FLOAT, offset_of(&ParticleEffect::particleVelocities)); 565 defineModelGroupAttrib(modelGroups[ TYPE_EXPLOSION], "start_time", ATTRIB_POINT_VARYING,571 defineModelGroupAttrib(modelGroups[ObjectType::EXPLOSION], "start_time", AttribType::POINT_VARYING, 566 572 1, GL_FLOAT, offset_of(&ParticleEffect::particleTimes)); 567 defineModelGroupAttrib(modelGroups[ TYPE_EXPLOSION], "ubo_index", ATTRIB_OBJECT_VARYING,573 defineModelGroupAttrib(modelGroups[ObjectType::EXPLOSION], "ubo_index", AttribType::OBJECT_VARYING, 568 574 1, GL_UNSIGNED_INT, offset_of(&SceneObject::ubo_offset)); 569 575 570 defineModelGroupUniform(modelGroups[ TYPE_EXPLOSION], "cur_time", ATTRIB_UNIFORM,576 defineModelGroupUniform(modelGroups[ObjectType::EXPLOSION], "cur_time", AttribType::UNIFORM, 571 577 1, UNIFORM_1F, &curTime); 572 defineModelGroupUniform(modelGroups[ TYPE_EXPLOSION], "view", ATTRIB_UNIFORM,578 defineModelGroupUniform(modelGroups[ObjectType::EXPLOSION], "view", AttribType::UNIFORM, 573 579 1, UNIFORM_MATRIX_4F, value_ptr(view_mat)); 574 defineModelGroupUniform(modelGroups[ TYPE_EXPLOSION], "proj", ATTRIB_UNIFORM,580 defineModelGroupUniform(modelGroups[ObjectType::EXPLOSION], "proj", AttribType::UNIFORM, 575 581 1, UNIFORM_MATRIX_4F, value_ptr(proj_mat)); 576 582 577 initModelGroupAttribs(modelGroups[ TYPE_EXPLOSION]);583 initModelGroupAttribs(modelGroups[ObjectType::EXPLOSION]); 578 584 579 585 cam_pos = vec3(0.0f, 0.0f, 2.0f); … … 587 593 588 594 float cam_speed = 1.0f; 589 float cam_yaw_speed = 60.0f*ONE_DEG_IN_RAD;590 float cam_pitch_speed = 60.0f*ONE_DEG_IN_RAD;595 float cam_yaw_speed = radians(60.0f); 596 float cam_pitch_speed = radians(60.0f); 591 597 592 598 // glm::lookAt can create the view matrix … … 601 607 // TODO: Create a function to construct the projection matrix 602 608 // (Maybe I should just use glm::perspective, after making sure it matches what I have now) 603 float fov = 67.0f * ONE_DEG_IN_RAD;609 float fov = radians(67.0f); 604 610 float aspect = (float)windowWidth / (float)windowHeight; 605 611 … … 657 663 GLuint ub_binding_point = 0; 658 664 659 GLuint ship_sp_models_ub_index = glGetUniformBlockIndex(modelGroups[ TYPE_SHIP].shaderProgram, "models");660 661 GLuint asteroid_sp_models_ub_index = glGetUniformBlockIndex(modelGroups[ TYPE_ASTEROID].shaderProgram, "models");662 663 GLuint laser_sp_models_ub_index = glGetUniformBlockIndex(modelGroups[ TYPE_LASER].shaderProgram, "models");664 665 GLuint explosion_sp_models_ub_index = glGetUniformBlockIndex(modelGroups[ TYPE_EXPLOSION].shaderProgram, "models");666 667 668 glUseProgram(modelGroups[ TYPE_SHIP].shaderProgram);669 bindUniformData(modelGroups[ TYPE_SHIP].attribs["view"]);670 bindUniformData(modelGroups[ TYPE_SHIP].attribs["proj"]);671 672 glUniformBlockBinding(modelGroups[ TYPE_SHIP].shaderProgram, ship_sp_models_ub_index, ub_binding_point);665 GLuint ship_sp_models_ub_index = glGetUniformBlockIndex(modelGroups[ObjectType::SHIP].shaderProgram, "models"); 666 667 GLuint asteroid_sp_models_ub_index = glGetUniformBlockIndex(modelGroups[ObjectType::ASTEROID].shaderProgram, "models"); 668 669 GLuint laser_sp_models_ub_index = glGetUniformBlockIndex(modelGroups[ObjectType::LASER].shaderProgram, "models"); 670 671 GLuint explosion_sp_models_ub_index = glGetUniformBlockIndex(modelGroups[ObjectType::EXPLOSION].shaderProgram, "models"); 672 673 674 glUseProgram(modelGroups[ObjectType::SHIP].shaderProgram); 675 bindUniformData(modelGroups[ObjectType::SHIP].attribs["view"]); 676 bindUniformData(modelGroups[ObjectType::SHIP].attribs["proj"]); 677 678 glUniformBlockBinding(modelGroups[ObjectType::SHIP].shaderProgram, ship_sp_models_ub_index, ub_binding_point); 673 679 glBindBufferRange(GL_UNIFORM_BUFFER, ub_binding_point, ubo, 0, GL_MAX_UNIFORM_BLOCK_SIZE); 674 680 675 681 676 glUseProgram(modelGroups[ TYPE_ASTEROID].shaderProgram);677 bindUniformData(modelGroups[ TYPE_ASTEROID].attribs["view"]);678 bindUniformData(modelGroups[ TYPE_ASTEROID].attribs["proj"]);679 680 glUniformBlockBinding(modelGroups[ TYPE_ASTEROID].shaderProgram, asteroid_sp_models_ub_index, ub_binding_point);682 glUseProgram(modelGroups[ObjectType::ASTEROID].shaderProgram); 683 bindUniformData(modelGroups[ObjectType::ASTEROID].attribs["view"]); 684 bindUniformData(modelGroups[ObjectType::ASTEROID].attribs["proj"]); 685 686 glUniformBlockBinding(modelGroups[ObjectType::ASTEROID].shaderProgram, asteroid_sp_models_ub_index, ub_binding_point); 681 687 glBindBufferRange(GL_UNIFORM_BUFFER, ub_binding_point, ubo, 0, GL_MAX_UNIFORM_BLOCK_SIZE); 682 688 … … 685 691 // Right now, I think I'm getting away without getting that uniform location because I'm only 686 692 // using one texture, so setting it to GL_TEXTURE0 once works 687 glUseProgram(modelGroups[ TYPE_LASER].shaderProgram);688 bindUniformData(modelGroups[ TYPE_LASER].attribs["view"]);689 bindUniformData(modelGroups[ TYPE_LASER].attribs["proj"]);690 bindUniformData(modelGroups[ TYPE_LASER].attribs["laser_color"]);691 692 glUniformBlockBinding(modelGroups[ TYPE_LASER].shaderProgram, laser_sp_models_ub_index, ub_binding_point);693 glUseProgram(modelGroups[ObjectType::LASER].shaderProgram); 694 bindUniformData(modelGroups[ObjectType::LASER].attribs["view"]); 695 bindUniformData(modelGroups[ObjectType::LASER].attribs["proj"]); 696 bindUniformData(modelGroups[ObjectType::LASER].attribs["laser_color"]); 697 698 glUniformBlockBinding(modelGroups[ObjectType::LASER].shaderProgram, laser_sp_models_ub_index, ub_binding_point); 693 699 glBindBufferRange(GL_UNIFORM_BUFFER, ub_binding_point, ubo, 0, GL_MAX_UNIFORM_BLOCK_SIZE); 694 700 695 701 696 glUseProgram(modelGroups[ TYPE_EXPLOSION].shaderProgram);697 bindUniformData(modelGroups[ TYPE_EXPLOSION].attribs["view"]);698 bindUniformData(modelGroups[ TYPE_EXPLOSION].attribs["proj"]);699 700 glUniformBlockBinding(modelGroups[ TYPE_EXPLOSION].shaderProgram, explosion_sp_models_ub_index, ub_binding_point);702 glUseProgram(modelGroups[ObjectType::EXPLOSION].shaderProgram); 703 bindUniformData(modelGroups[ObjectType::EXPLOSION].attribs["view"]); 704 bindUniformData(modelGroups[ObjectType::EXPLOSION].attribs["proj"]); 705 706 glUniformBlockBinding(modelGroups[ObjectType::EXPLOSION].shaderProgram, explosion_sp_models_ub_index, ub_binding_point); 701 707 glBindBufferRange(GL_UNIFORM_BUFFER, ub_binding_point, ubo, 0, GL_MAX_UNIFORM_BLOCK_SIZE); 702 708 /*** END OF REFACTORED CODE ***/ … … 720 726 //glfwSwapInterval(0); 721 727 722 State curState = S TATE_MAIN_MENU;728 State curState = State::MAIN_MENU; 723 729 724 730 initGuiValueLists(valueLists); … … 762 768 while (!events.empty()) { 763 769 switch (events.front()) { 764 case EVENT_GO_TO_MAIN_MENU:765 curState = S TATE_MAIN_MENU;770 case Event::GO_TO_MAIN_MENU: 771 curState = State::MAIN_MENU; 766 772 break; 767 case E VENT_GO_TO_GAME:768 curState = S TATE_GAME;773 case Event::GO_TO_GAME: 774 curState = State::GAME; 769 775 break; 770 case E VENT_QUIT:776 case Event::QUIT: 771 777 isRunning = false; 772 778 break; … … 775 781 } 776 782 777 if (curState == S TATE_GAME) {783 if (curState == State::GAME) { 778 784 779 785 /*** START OF REFACTORED CODE ***/ … … 857 863 for (unsigned int i = 0; i < objects.size(); i++) { 858 864 if (!objects[i]->deleted) { 859 if (objects[i]->type == TYPE_ASTEROID) {865 if (objects[i]->type == ObjectType::ASTEROID) { 860 866 transformObject(*objects[i], translate(mat4(1.0f), vec3(0.0f, 0.0f, 0.04f)), ubo); 861 867 … … 878 884 addObjectToScene(createExplosion(model_mat), shaderBufferInfo, modelGroups, ubo); 879 885 } 880 } else if (objects[i]->type == TYPE_EXPLOSION) {886 } else if (objects[i]->type == ObjectType::EXPLOSION) { 881 887 ParticleEffect* explosion = (ParticleEffect*)objects[i]; 882 888 if (glfwGetTime() >= explosion->startTime + explosion->duration) { … … 888 894 889 895 if (leftLaser != NULL && !leftLaser->deleted) { 890 updateLaserTarget(leftLaser, objects, modelGroups[ TYPE_LASER], modelGroups[TYPE_ASTEROID].shaderProgram);896 updateLaserTarget(leftLaser, objects, modelGroups[ObjectType::LASER], modelGroups[ObjectType::ASTEROID].shaderProgram); 891 897 } 892 898 if (rightLaser != NULL && !rightLaser->deleted) { 893 updateLaserTarget(rightLaser, objects, modelGroups[ TYPE_LASER], modelGroups[TYPE_ASTEROID].shaderProgram);899 updateLaserTarget(rightLaser, objects, modelGroups[ObjectType::LASER], modelGroups[ObjectType::ASTEROID].shaderProgram); 894 900 } 895 901 } … … 963 969 view_mat = R * T; 964 970 965 glUseProgram(modelGroups[ TYPE_SHIP].shaderProgram);966 bindUniformData(modelGroups[ TYPE_SHIP].attribs["view"]);967 968 glUseProgram(modelGroups[ TYPE_LASER].shaderProgram);969 bindUniformData(modelGroups[ TYPE_LASER].attribs["view"]);971 glUseProgram(modelGroups[ObjectType::SHIP].shaderProgram); 972 bindUniformData(modelGroups[ObjectType::SHIP].attribs["view"]); 973 974 glUseProgram(modelGroups[ObjectType::LASER].shaderProgram); 975 bindUniformData(modelGroups[ObjectType::LASER].attribs["view"]); 970 976 971 977 cam_moved = false; 972 978 } 973 979 974 glUseProgram(modelGroups[ TYPE_EXPLOSION].shaderProgram);975 bindUniformData(modelGroups[ TYPE_EXPLOSION].attribs["cur_time"]);980 glUseProgram(modelGroups[ObjectType::EXPLOSION].shaderProgram); 981 bindUniformData(modelGroups[ObjectType::EXPLOSION].attribs["cur_time"]); 976 982 977 983 // Render scene … … 981 987 982 988 switch (curState) { 983 case S TATE_MAIN_MENU:989 case State::MAIN_MENU: 984 990 renderMainMenu(); 985 991 renderMainMenuGui(); 986 992 break; 987 case S TATE_GAME:993 case State::GAME: 988 994 renderScene(modelGroups, ubo); 989 995 renderSceneGui(valueLists); … … 994 1000 } 995 1001 996 ImGui_ImplGlfwGL3_Shutdown(); 1002 ImGui_ImplOpenGL3_Shutdown(); 1003 ImGui_ImplGlfw_Shutdown(); 997 1004 ImGui::DestroyContext(); 998 1005 … … 1040 1047 1041 1048 for (vector<SceneObject*>::iterator it = objects.begin(); it != objects.end(); it++) { 1042 if ((*it)->type == TYPE_LASER) continue;1049 if ((*it)->type == ObjectType::LASER) continue; 1043 1050 for (unsigned int p_idx = 0; p_idx < (*it)->points.size(); p_idx += 9) { 1044 1051 if (faceClicked( … … 1342 1349 } 1343 1350 1344 if (obj->type == TYPE_SHIP || obj->type == TYPE_ASTEROID) {1351 if (obj->type == ObjectType::SHIP || obj->type == ObjectType::ASTEROID) { 1345 1352 calculateObjectBoundingBox(obj); 1346 1353 … … 1444 1451 SceneObject* ship = new SceneObject(); 1445 1452 1446 ship->type = TYPE_SHIP;1453 ship->type = ObjectType::SHIP; 1447 1454 1448 1455 ship->points = { … … 1839 1846 Laser* createLaser(vec3 start, vec3 end, vec3 color, GLfloat width) { 1840 1847 Laser* obj = new Laser(); 1841 obj->type = TYPE_LASER;1848 obj->type = ObjectType::LASER; 1842 1849 obj->targetAsteroid = NULL; 1843 1850 … … 1970 1977 map<string, AttribInfo>::iterator it; 1971 1978 for (it = modelGroup.attribs.begin(); it != modelGroup.attribs.end(); it++) { 1972 if (it->second.attribType == A TTRIB_UNIFORM) {1979 if (it->second.attribType == AttribType::UNIFORM) { 1973 1980 it->second.buffer = glGetUniformLocation(modelGroup.shaderProgram, it->first.c_str()); 1974 1981 } else { … … 2133 2140 map<string, AttribInfo>::iterator attrIt; 2134 2141 for (attrIt = smg->attribs.begin(); attrIt != smg->attribs.end(); attrIt++) { 2135 if (attrIt->second.attribType != A TTRIB_UNIFORM) {2142 if (attrIt->second.attribType != AttribType::UNIFORM) { 2136 2143 glBindBuffer(GL_ARRAY_BUFFER, attrIt->second.buffer); 2137 2144 glBufferData(GL_ARRAY_BUFFER, smg->vboCapacity * GLsizeof(attrIt->second.type) * attrIt->second.size, NULL, GL_DYNAMIC_DRAW); … … 2165 2172 2166 2173 switch (it->second.attribType) { 2167 case A TTRIB_POINT_VARYING:2174 case AttribType::POINT_VARYING: 2168 2175 glBufferSubData(GL_ARRAY_BUFFER, obj.vertex_vbo_offset * GLsizeof(it->second.type) * it->second.size, 2169 2176 obj.num_points * GLsizeof(it->second.type) * it->second.size, getVectorAttribPtr(obj, it->second.fieldOffset)); 2170 2177 break; 2171 case A TTRIB_OBJECT_VARYING:2178 case AttribType::OBJECT_VARYING: 2172 2179 for (unsigned int i = 0; i < obj.num_points; i++) { 2173 2180 glBufferSubData(GL_ARRAY_BUFFER, (obj.vertex_vbo_offset + i) * GLsizeof(it->second.type) * it->second.size, … … 2175 2182 } 2176 2183 break; 2177 case A TTRIB_UNIFORM:2184 case AttribType::UNIFORM: 2178 2185 break; 2179 2186 } … … 2185 2192 glBufferSubData(GL_UNIFORM_BUFFER, obj.ubo_offset * sizeof(mat4), sizeof(mat4), value_ptr(obj.model_mat)); 2186 2193 2187 if (obj.type == TYPE_ASTEROID) {2188 glUseProgram(modelGroups[ TYPE_ASTEROID].shaderProgram);2194 if (obj.type == ObjectType::ASTEROID) { 2195 glUseProgram(modelGroups[ObjectType::ASTEROID].shaderProgram); 2189 2196 2190 2197 ostringstream oss; 2191 2198 oss << "hp[" << obj.ubo_offset << "]"; 2192 glUniform1f(glGetUniformLocation(modelGroups[ TYPE_ASTEROID].shaderProgram, oss.str().c_str()), ((Asteroid&)obj).hp);2193 } else if (obj.type == TYPE_EXPLOSION) {2194 glUseProgram(modelGroups[ TYPE_EXPLOSION].shaderProgram);2199 glUniform1f(glGetUniformLocation(modelGroups[ObjectType::ASTEROID].shaderProgram, oss.str().c_str()), ((Asteroid&)obj).hp); 2200 } else if (obj.type == ObjectType::EXPLOSION) { 2201 glUseProgram(modelGroups[ObjectType::EXPLOSION].shaderProgram); 2195 2202 2196 2203 ostringstream oss; 2197 2204 oss << "explosion_start_time[" << obj.ubo_offset << "]"; 2198 glUniform1f(glGetUniformLocation(modelGroups[ TYPE_EXPLOSION].shaderProgram, oss.str().c_str()), ((ParticleEffect&)obj).startTime);2205 glUniform1f(glGetUniformLocation(modelGroups[ObjectType::EXPLOSION].shaderProgram, oss.str().c_str()), ((ParticleEffect&)obj).startTime); 2199 2206 } 2200 2207 … … 2255 2262 2256 2263 for (vector<SceneObject*>::iterator it = objects.begin(); it != objects.end(); it++) { 2257 if ((*it)->type == TYPE_ASTEROID && !(*it)->deleted && getLaserAndAsteroidIntersection(start, end, **it, intersection)) {2264 if ((*it)->type == ObjectType::ASTEROID && !(*it)->deleted && getLaserAndAsteroidIntersection(start, end, **it, intersection)) { 2258 2265 // TODO: Implement a more generic algorithm for testing the closest object by getting the distance between the points 2259 2266 if (closestAsteroid == NULL || intersection.z > closestIntersection.z) { … … 2367 2374 void renderScene(map<ObjectType, ShaderModelGroup>& modelGroups, GLuint ubo) { 2368 2375 2369 glUseProgram(modelGroups[ TYPE_SHIP].shaderProgram);2370 glBindVertexArray(modelGroups[ TYPE_SHIP].vao);2371 2372 glDrawArrays(GL_TRIANGLES, 0, modelGroups[ TYPE_SHIP].numPoints);2373 2374 glUseProgram(modelGroups[ TYPE_ASTEROID].shaderProgram);2375 glBindVertexArray(modelGroups[ TYPE_ASTEROID].vao);2376 2377 glDrawArrays(GL_TRIANGLES, 0, modelGroups[ TYPE_ASTEROID].numPoints);2376 glUseProgram(modelGroups[ObjectType::SHIP].shaderProgram); 2377 glBindVertexArray(modelGroups[ObjectType::SHIP].vao); 2378 2379 glDrawArrays(GL_TRIANGLES, 0, modelGroups[ObjectType::SHIP].numPoints); 2380 2381 glUseProgram(modelGroups[ObjectType::ASTEROID].shaderProgram); 2382 glBindVertexArray(modelGroups[ObjectType::ASTEROID].vao); 2383 2384 glDrawArrays(GL_TRIANGLES, 0, modelGroups[ObjectType::ASTEROID].numPoints); 2378 2385 2379 2386 glEnable(GL_BLEND); 2380 2387 2381 glUseProgram(modelGroups[ TYPE_LASER].shaderProgram);2382 glBindVertexArray(modelGroups[ TYPE_LASER].vao);2383 2384 glDrawArrays(GL_TRIANGLES, 0, modelGroups[ TYPE_LASER].numPoints);2385 2386 glUseProgram(modelGroups[ TYPE_EXPLOSION].shaderProgram);2387 glBindVertexArray(modelGroups[ TYPE_EXPLOSION].vao);2388 glUseProgram(modelGroups[ObjectType::LASER].shaderProgram); 2389 glBindVertexArray(modelGroups[ObjectType::LASER].vao); 2390 2391 glDrawArrays(GL_TRIANGLES, 0, modelGroups[ObjectType::LASER].numPoints); 2392 2393 glUseProgram(modelGroups[ObjectType::EXPLOSION].shaderProgram); 2394 glBindVertexArray(modelGroups[ObjectType::EXPLOSION].vao); 2388 2395 2389 2396 glEnable(GL_PROGRAM_POINT_SIZE); 2390 2397 2391 glDrawArrays(GL_POINTS, 0, modelGroups[ TYPE_EXPLOSION].numPoints);2398 glDrawArrays(GL_POINTS, 0, modelGroups[ObjectType::EXPLOSION].numPoints); 2392 2399 2393 2400 glDisable(GL_PROGRAM_POINT_SIZE); … … 2397 2404 2398 2405 void renderSceneGui(map<string, vector<UIValue>> valueLists) { 2399 ImGui_ImplGlfwGL3_NewFrame(); 2406 ImGui_ImplOpenGL3_NewFrame(); 2407 ImGui_ImplGlfw_NewFrame(); 2408 ImGui::NewFrame(); 2400 2409 2401 2410 // 1. Show a simple window. … … 2443 2452 ImGui::SameLine(); 2444 2453 if (ImGui::Button("Main Menu")) { 2445 events.push(E VENT_GO_TO_MAIN_MENU);2454 events.push(Event::GO_TO_MAIN_MENU); 2446 2455 } 2447 2456 ImGui::End(); … … 2462 2471 2463 2472 ImGui::Render(); 2464 ImGui_Impl GlfwGL3_RenderDrawData(ImGui::GetDrawData());2473 ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); 2465 2474 } 2466 2475 … … 2470 2479 /*** START OF REFACTORED CODE ***/ 2471 2480 void renderMainMenuGui() { 2472 ImGui_ImplGlfwGL3_NewFrame(); 2481 ImGui_ImplOpenGL3_NewFrame(); 2482 ImGui_ImplGlfw_NewFrame(); 2483 ImGui::NewFrame(); 2473 2484 2474 2485 { … … 2485 2496 ImGui::SameLine(); 2486 2497 if (ImGui::Button("New Game")) { 2487 events.push(E VENT_GO_TO_GAME);2498 events.push(Event::GO_TO_GAME); 2488 2499 } 2489 2500 … … 2492 2503 ImGui::SameLine(); 2493 2504 if (ImGui::Button("Quit")) { 2494 events.push(E VENT_QUIT);2505 events.push(Event::QUIT); 2495 2506 } 2496 2507 … … 2499 2510 2500 2511 ImGui::Render(); 2501 ImGui_Impl GlfwGL3_RenderDrawData(ImGui::GetDrawData());2512 ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); 2502 2513 } 2503 2514 /*** END OF REFACTORED CODE ***/ … … 2544 2555 Asteroid* createAsteroid(vec3 pos) { 2545 2556 Asteroid* obj = new Asteroid(); 2546 obj->type = TYPE_ASTEROID;2557 obj->type = ObjectType::ASTEROID; 2547 2558 obj->hp = 10.0f; 2548 2559 … … 2648 2659 2649 2660 mat4 T = translate(mat4(1.0f), pos); 2650 mat4 R = rotate(mat4(1.0f), 60.0f * (float)ONE_DEG_IN_RAD, vec3(1.0f, 1.0f, -1.0f));2661 mat4 R = rotate(mat4(1.0f), radians(60.0f), vec3(1.0f, 1.0f, -1.0f)); 2651 2662 obj->model_base = T * R * scale(mat4(1.0f), vec3(0.1f, 0.1f, 0.1f)); 2652 2663 … … 2668 2679 ParticleEffect* obj = new ParticleEffect(); 2669 2680 2670 obj->type = TYPE_EXPLOSION;2681 obj->type = ObjectType::EXPLOSION; 2671 2682 2672 2683 initObject(obj);
Note:
See TracChangeset
for help on using the changeset viewer.