imgui_demo.cpp (390934B)
1 // dear imgui, v1.83 2 // (demo code) 3 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 the 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 codebase: 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. 16 // Everything in this file will be stripped out by the linker if you don't call ImGui::ShowDemoWindow(). 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 another situation, whenever you have Dear ImGui available you probably want this to be available for reference. 20 // Thank you, 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 use 'static' variables inside functions. A static variable persists 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 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 // Navigating this file: 42 // - In Visual Studio IDE: CTRL+comma ("Edit.NavigateTo") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot. 43 // - With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments. 44 45 /* 46 47 Index of this file: 48 49 // [SECTION] Forward Declarations, Helpers 50 // [SECTION] Demo Window / ShowDemoWindow() 51 // - sub section: ShowDemoWindowWidgets() 52 // - sub section: ShowDemoWindowLayout() 53 // - sub section: ShowDemoWindowPopups() 54 // - sub section: ShowDemoWindowTables() 55 // - sub section: ShowDemoWindowMisc() 56 // [SECTION] About Window / ShowAboutWindow() 57 // [SECTION] Font Viewer / ShowFontAtlas() 58 // [SECTION] Style Editor / ShowStyleEditor() 59 // [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar() 60 // [SECTION] Example App: Debug Console / ShowExampleAppConsole() 61 // [SECTION] Example App: Debug Log / ShowExampleAppLog() 62 // [SECTION] Example App: Simple Layout / ShowExampleAppLayout() 63 // [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor() 64 // [SECTION] Example App: Long Text / ShowExampleAppLongText() 65 // [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize() 66 // [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize() 67 // [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay() 68 // [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen() 69 // [SECTION] Example App: Manipulating window titles / ShowExampleAppWindowTitles() 70 // [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering() 71 // [SECTION] Example App: Documents Handling / ShowExampleAppDocuments() 72 73 */ 74 75 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) 76 #define _CRT_SECURE_NO_WARNINGS 77 #endif 78 79 #include "imgui.h" 80 #ifndef IMGUI_DISABLE 81 82 // System includes 83 #include <ctype.h> // toupper 84 #include <limits.h> // INT_MIN, INT_MAX 85 #include <math.h> // sqrtf, powf, cosf, sinf, floorf, ceilf 86 #include <stdio.h> // vsnprintf, sscanf, printf 87 #include <stdlib.h> // NULL, malloc, free, atoi 88 #if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier 89 #include <stddef.h> // intptr_t 90 #else 91 #include <stdint.h> // intptr_t 92 #endif 93 94 // Visual Studio warnings 95 #ifdef _MSC_VER 96 #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen 97 #pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2). 98 #endif 99 100 // Clang/GCC warnings with -Weverything 101 #if defined(__clang__) 102 #if __has_warning("-Wunknown-warning-option") 103 #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! 104 #endif 105 #pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' 106 #pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. 107 #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) 108 #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning: cast to 'void *' from smaller integer type 109 #pragma clang diagnostic ignored "-Wformat-security" // warning: format string is not a string literal 110 #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. 111 #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. 112 #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0 113 #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. 114 #pragma clang diagnostic ignored "-Wreserved-id-macro" // warning: macro name is a reserved identifier 115 #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision 116 #elif defined(__GNUC__) 117 #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind 118 #pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size 119 #pragma GCC diagnostic ignored "-Wformat-security" // warning: format string is not a string literal (potentially insecure) 120 #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function 121 #pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value 122 #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. 123 #endif 124 125 // Play it nice with Windows users (Update: May 2018, Notepad now supports Unix-style carriage returns!) 126 #ifdef _WIN32 127 #define IM_NEWLINE "\r\n" 128 #else 129 #define IM_NEWLINE "\n" 130 #endif 131 132 // Helpers 133 #if defined(_MSC_VER) && !defined(snprintf) 134 #define snprintf _snprintf 135 #endif 136 #if defined(_MSC_VER) && !defined(vsnprintf) 137 #define vsnprintf _vsnprintf 138 #endif 139 140 // Format specifiers, printing 64-bit hasn't been decently standardized... 141 // In a real application you should be using PRId64 and PRIu64 from <inttypes.h> (non-windows) and on Windows define them yourself. 142 #ifdef _MSC_VER 143 #define IM_PRId64 "I64d" 144 #define IM_PRIu64 "I64u" 145 #else 146 #define IM_PRId64 "lld" 147 #define IM_PRIu64 "llu" 148 #endif 149 150 // Helpers macros 151 // We normally try to not use many helpers in imgui_demo.cpp in order to make code easier to copy and paste, 152 // but making an exception here as those are largely simplifying code... 153 // In other imgui sources we can use nicer internal functions from imgui_internal.h (ImMin/ImMax) but not in the demo. 154 #define IM_MIN(A, B) (((A) < (B)) ? (A) : (B)) 155 #define IM_MAX(A, B) (((A) >= (B)) ? (A) : (B)) 156 #define IM_CLAMP(V, MN, MX) ((V) < (MN) ? (MN) : (V) > (MX) ? (MX) : (V)) 157 158 // Enforce cdecl calling convention for functions called by the standard library, in case compilation settings changed the default to e.g. __vectorcall 159 #ifndef IMGUI_CDECL 160 #ifdef _MSC_VER 161 #define IMGUI_CDECL __cdecl 162 #else 163 #define IMGUI_CDECL 164 #endif 165 #endif 166 167 //----------------------------------------------------------------------------- 168 // [SECTION] Forward Declarations, Helpers 169 //----------------------------------------------------------------------------- 170 171 #if !defined(IMGUI_DISABLE_DEMO_WINDOWS) 172 173 // Forward Declarations 174 static void ShowExampleAppDocuments(bool* p_open); 175 static void ShowExampleAppMainMenuBar(); 176 static void ShowExampleAppConsole(bool* p_open); 177 static void ShowExampleAppLog(bool* p_open); 178 static void ShowExampleAppLayout(bool* p_open); 179 static void ShowExampleAppPropertyEditor(bool* p_open); 180 static void ShowExampleAppLongText(bool* p_open); 181 static void ShowExampleAppAutoResize(bool* p_open); 182 static void ShowExampleAppConstrainedResize(bool* p_open); 183 static void ShowExampleAppSimpleOverlay(bool* p_open); 184 static void ShowExampleAppFullscreen(bool* p_open); 185 static void ShowExampleAppWindowTitles(bool* p_open); 186 static void ShowExampleAppCustomRendering(bool* p_open); 187 static void ShowExampleMenuFile(); 188 189 // Helper to display a little (?) mark which shows a tooltip when hovered. 190 // In your own code you may want to display an actual icon if you are using a merged icon fonts (see docs/FONTS.md) 191 static void HelpMarker(const char* desc) 192 { 193 ImGui::TextDisabled("(?)"); 194 if (ImGui::IsItemHovered()) 195 { 196 ImGui::BeginTooltip(); 197 ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); 198 ImGui::TextUnformatted(desc); 199 ImGui::PopTextWrapPos(); 200 ImGui::EndTooltip(); 201 } 202 } 203 204 // Helper to display basic user controls. 205 void ImGui::ShowUserGuide() 206 { 207 ImGuiIO& io = ImGui::GetIO(); 208 ImGui::BulletText("Double-click on title bar to collapse window."); 209 ImGui::BulletText( 210 "Click and drag on lower corner to resize window\n" 211 "(double-click to auto fit window to its contents)."); 212 ImGui::BulletText("CTRL+Click on a slider or drag box to input value as text."); 213 ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields."); 214 if (io.FontAllowUserScaling) 215 ImGui::BulletText("CTRL+Mouse Wheel to zoom window contents."); 216 ImGui::BulletText("While inputing text:\n"); 217 ImGui::Indent(); 218 ImGui::BulletText("CTRL+Left/Right to word jump."); 219 ImGui::BulletText("CTRL+A or double-click to select all."); 220 ImGui::BulletText("CTRL+X/C/V to use clipboard cut/copy/paste."); 221 ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo."); 222 ImGui::BulletText("ESCAPE to revert."); 223 ImGui::BulletText("You can apply arithmetic operators +,*,/ on numerical values.\nUse +- to subtract."); 224 ImGui::Unindent(); 225 ImGui::BulletText("With keyboard navigation enabled:"); 226 ImGui::Indent(); 227 ImGui::BulletText("Arrow keys to navigate."); 228 ImGui::BulletText("Space to activate a widget."); 229 ImGui::BulletText("Return to input text into a widget."); 230 ImGui::BulletText("Escape to deactivate a widget, close popup, exit child window."); 231 ImGui::BulletText("Alt to jump to the menu layer of a window."); 232 ImGui::BulletText("CTRL+Tab to select a window."); 233 ImGui::Unindent(); 234 } 235 236 //----------------------------------------------------------------------------- 237 // [SECTION] Demo Window / ShowDemoWindow() 238 //----------------------------------------------------------------------------- 239 // - ShowDemoWindowWidgets() 240 // - ShowDemoWindowLayout() 241 // - ShowDemoWindowPopups() 242 // - ShowDemoWindowTables() 243 // - ShowDemoWindowColumns() 244 // - ShowDemoWindowMisc() 245 //----------------------------------------------------------------------------- 246 247 // We split the contents of the big ShowDemoWindow() function into smaller functions 248 // (because the link time of very large functions grow non-linearly) 249 static void ShowDemoWindowWidgets(); 250 static void ShowDemoWindowLayout(); 251 static void ShowDemoWindowPopups(); 252 static void ShowDemoWindowTables(); 253 static void ShowDemoWindowColumns(); 254 static void ShowDemoWindowMisc(); 255 256 // Demonstrate most Dear ImGui features (this is big function!) 257 // You may execute this function to experiment with the UI and understand what it does. 258 // You may then search for keywords in the code when you are interested by a specific feature. 259 void ImGui::ShowDemoWindow(bool* p_open) 260 { 261 // Exceptionally add an extra assert here for people confused about initial Dear ImGui setup 262 // Most ImGui functions would normally just crash if the context is missing. 263 IM_ASSERT(ImGui::GetCurrentContext() != NULL && "Missing dear imgui context. Refer to examples app!"); 264 265 // Examples Apps (accessible from the "Examples" menu) 266 static bool show_app_main_menu_bar = false; 267 static bool show_app_documents = false; 268 269 static bool show_app_console = false; 270 static bool show_app_log = false; 271 static bool show_app_layout = false; 272 static bool show_app_property_editor = false; 273 static bool show_app_long_text = false; 274 static bool show_app_auto_resize = false; 275 static bool show_app_constrained_resize = false; 276 static bool show_app_simple_overlay = false; 277 static bool show_app_fullscreen = false; 278 static bool show_app_window_titles = false; 279 static bool show_app_custom_rendering = false; 280 281 if (show_app_main_menu_bar) ShowExampleAppMainMenuBar(); 282 if (show_app_documents) ShowExampleAppDocuments(&show_app_documents); 283 284 if (show_app_console) ShowExampleAppConsole(&show_app_console); 285 if (show_app_log) ShowExampleAppLog(&show_app_log); 286 if (show_app_layout) ShowExampleAppLayout(&show_app_layout); 287 if (show_app_property_editor) ShowExampleAppPropertyEditor(&show_app_property_editor); 288 if (show_app_long_text) ShowExampleAppLongText(&show_app_long_text); 289 if (show_app_auto_resize) ShowExampleAppAutoResize(&show_app_auto_resize); 290 if (show_app_constrained_resize) ShowExampleAppConstrainedResize(&show_app_constrained_resize); 291 if (show_app_simple_overlay) ShowExampleAppSimpleOverlay(&show_app_simple_overlay); 292 if (show_app_fullscreen) ShowExampleAppFullscreen(&show_app_fullscreen); 293 if (show_app_window_titles) ShowExampleAppWindowTitles(&show_app_window_titles); 294 if (show_app_custom_rendering) ShowExampleAppCustomRendering(&show_app_custom_rendering); 295 296 // Dear ImGui Apps (accessible from the "Tools" menu) 297 static bool show_app_metrics = false; 298 static bool show_app_style_editor = false; 299 static bool show_app_about = false; 300 301 if (show_app_metrics) { ImGui::ShowMetricsWindow(&show_app_metrics); } 302 if (show_app_about) { ImGui::ShowAboutWindow(&show_app_about); } 303 if (show_app_style_editor) 304 { 305 ImGui::Begin("Dear ImGui Style Editor", &show_app_style_editor); 306 ImGui::ShowStyleEditor(); 307 ImGui::End(); 308 } 309 310 // Demonstrate the various window flags. Typically you would just use the default! 311 static bool no_titlebar = false; 312 static bool no_scrollbar = false; 313 static bool no_menu = false; 314 static bool no_move = false; 315 static bool no_resize = false; 316 static bool no_collapse = false; 317 static bool no_close = false; 318 static bool no_nav = false; 319 static bool no_background = false; 320 static bool no_bring_to_front = false; 321 322 ImGuiWindowFlags window_flags = 0; 323 if (no_titlebar) window_flags |= ImGuiWindowFlags_NoTitleBar; 324 if (no_scrollbar) window_flags |= ImGuiWindowFlags_NoScrollbar; 325 if (!no_menu) window_flags |= ImGuiWindowFlags_MenuBar; 326 if (no_move) window_flags |= ImGuiWindowFlags_NoMove; 327 if (no_resize) window_flags |= ImGuiWindowFlags_NoResize; 328 if (no_collapse) window_flags |= ImGuiWindowFlags_NoCollapse; 329 if (no_nav) window_flags |= ImGuiWindowFlags_NoNav; 330 if (no_background) window_flags |= ImGuiWindowFlags_NoBackground; 331 if (no_bring_to_front) window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus; 332 if (no_close) p_open = NULL; // Don't pass our bool* to Begin 333 334 // We specify a default position/size in case there's no data in the .ini file. 335 // We only do it to make the demo applications a little more welcoming, but typically this isn't required. 336 const ImGuiViewport* main_viewport = ImGui::GetMainViewport(); 337 ImGui::SetNextWindowPos(ImVec2(main_viewport->WorkPos.x + 650, main_viewport->WorkPos.y + 20), ImGuiCond_FirstUseEver); 338 ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver); 339 340 // Main body of the Demo window starts here. 341 if (!ImGui::Begin("Dear ImGui Demo", p_open, window_flags)) 342 { 343 // Early out if the window is collapsed, as an optimization. 344 ImGui::End(); 345 return; 346 } 347 348 // Most "big" widgets share a common width settings by default. See 'Demo->Layout->Widgets Width' for details. 349 350 // e.g. Use 2/3 of the space for widgets and 1/3 for labels (right align) 351 //ImGui::PushItemWidth(-ImGui::GetWindowWidth() * 0.35f); 352 353 // e.g. Leave a fixed amount of width for labels (by passing a negative value), the rest goes to widgets. 354 ImGui::PushItemWidth(ImGui::GetFontSize() * -12); 355 356 // Menu Bar 357 if (ImGui::BeginMenuBar()) 358 { 359 if (ImGui::BeginMenu("Menu")) 360 { 361 ShowExampleMenuFile(); 362 ImGui::EndMenu(); 363 } 364 if (ImGui::BeginMenu("Examples")) 365 { 366 ImGui::MenuItem("Main menu bar", NULL, &show_app_main_menu_bar); 367 ImGui::MenuItem("Console", NULL, &show_app_console); 368 ImGui::MenuItem("Log", NULL, &show_app_log); 369 ImGui::MenuItem("Simple layout", NULL, &show_app_layout); 370 ImGui::MenuItem("Property editor", NULL, &show_app_property_editor); 371 ImGui::MenuItem("Long text display", NULL, &show_app_long_text); 372 ImGui::MenuItem("Auto-resizing window", NULL, &show_app_auto_resize); 373 ImGui::MenuItem("Constrained-resizing window", NULL, &show_app_constrained_resize); 374 ImGui::MenuItem("Simple overlay", NULL, &show_app_simple_overlay); 375 ImGui::MenuItem("Fullscreen window", NULL, &show_app_fullscreen); 376 ImGui::MenuItem("Manipulating window titles", NULL, &show_app_window_titles); 377 ImGui::MenuItem("Custom rendering", NULL, &show_app_custom_rendering); 378 ImGui::MenuItem("Documents", NULL, &show_app_documents); 379 ImGui::EndMenu(); 380 } 381 if (ImGui::BeginMenu("Tools")) 382 { 383 ImGui::MenuItem("Metrics/Debugger", NULL, &show_app_metrics); 384 ImGui::MenuItem("Style Editor", NULL, &show_app_style_editor); 385 ImGui::MenuItem("About Dear ImGui", NULL, &show_app_about); 386 ImGui::EndMenu(); 387 } 388 ImGui::EndMenuBar(); 389 } 390 391 ImGui::Text("dear imgui says hello. (%s)", IMGUI_VERSION); 392 ImGui::Spacing(); 393 394 if (ImGui::CollapsingHeader("Help")) 395 { 396 ImGui::Text("ABOUT THIS DEMO:"); 397 ImGui::BulletText("Sections below are demonstrating many aspects of the library."); 398 ImGui::BulletText("The \"Examples\" menu above leads to more demo contents."); 399 ImGui::BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n" 400 "and Metrics/Debugger (general purpose Dear ImGui debugging tool)."); 401 ImGui::Separator(); 402 403 ImGui::Text("PROGRAMMER GUIDE:"); 404 ImGui::BulletText("See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!"); 405 ImGui::BulletText("See comments in imgui.cpp."); 406 ImGui::BulletText("See example applications in the examples/ folder."); 407 ImGui::BulletText("Read the FAQ at http://www.dearimgui.org/faq/"); 408 ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls."); 409 ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls."); 410 ImGui::Separator(); 411 412 ImGui::Text("USER GUIDE:"); 413 ImGui::ShowUserGuide(); 414 } 415 416 if (ImGui::CollapsingHeader("Configuration")) 417 { 418 ImGuiIO& io = ImGui::GetIO(); 419 420 if (ImGui::TreeNode("Configuration##2")) 421 { 422 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard); 423 ImGui::SameLine(); HelpMarker("Enable keyboard controls."); 424 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", &io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad); 425 ImGui::SameLine(); HelpMarker("Enable gamepad controls. Require backend to set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details."); 426 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableSetMousePos", &io.ConfigFlags, ImGuiConfigFlags_NavEnableSetMousePos); 427 ImGui::SameLine(); HelpMarker("Instruct navigation to move the mouse cursor. See comment for ImGuiConfigFlags_NavEnableSetMousePos."); 428 ImGui::CheckboxFlags("io.ConfigFlags: NoMouse", &io.ConfigFlags, ImGuiConfigFlags_NoMouse); 429 if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) 430 { 431 // The "NoMouse" option can get us stuck with a disabled mouse! Let's provide an alternative way to fix it: 432 if (fmodf((float)ImGui::GetTime(), 0.40f) < 0.20f) 433 { 434 ImGui::SameLine(); 435 ImGui::Text("<<PRESS SPACE TO DISABLE>>"); 436 } 437 if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Space))) 438 io.ConfigFlags &= ~ImGuiConfigFlags_NoMouse; 439 } 440 ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", &io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange); 441 ImGui::SameLine(); HelpMarker("Instruct backend to not alter mouse cursor shape and visibility."); 442 ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink); 443 ImGui::SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting)"); 444 ImGui::Checkbox("io.ConfigDragClickToInputText", &io.ConfigDragClickToInputText); 445 ImGui::SameLine(); HelpMarker("Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving)."); 446 ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges); 447 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."); 448 ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly); 449 ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor); 450 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)."); 451 ImGui::Text("Also see Style->Rendering for rendering options."); 452 ImGui::TreePop(); 453 ImGui::Separator(); 454 } 455 456 if (ImGui::TreeNode("Backend Flags")) 457 { 458 HelpMarker( 459 "Those flags are set by the backends (imgui_impl_xxx files) to specify their capabilities.\n" 460 "Here we expose then as read-only fields to avoid breaking interactions with your backend."); 461 462 // Make a local copy to avoid modifying actual backend flags. 463 ImGuiBackendFlags backend_flags = io.BackendFlags; 464 ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", &backend_flags, ImGuiBackendFlags_HasGamepad); 465 ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &backend_flags, ImGuiBackendFlags_HasMouseCursors); 466 ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos", &backend_flags, ImGuiBackendFlags_HasSetMousePos); 467 ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", &backend_flags, ImGuiBackendFlags_RendererHasVtxOffset); 468 ImGui::TreePop(); 469 ImGui::Separator(); 470 } 471 472 if (ImGui::TreeNode("Style")) 473 { 474 HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function."); 475 ImGui::ShowStyleEditor(); 476 ImGui::TreePop(); 477 ImGui::Separator(); 478 } 479 480 if (ImGui::TreeNode("Capture/Logging")) 481 { 482 HelpMarker( 483 "The logging API redirects all text output so you can easily capture the content of " 484 "a window or a block. Tree nodes can be automatically expanded.\n" 485 "Try opening any of the contents below in this window and then click one of the \"Log To\" button."); 486 ImGui::LogButtons(); 487 488 HelpMarker("You can also call ImGui::LogText() to output directly to the log without a visual output."); 489 if (ImGui::Button("Copy \"Hello, world!\" to clipboard")) 490 { 491 ImGui::LogToClipboard(); 492 ImGui::LogText("Hello, world!"); 493 ImGui::LogFinish(); 494 } 495 ImGui::TreePop(); 496 } 497 } 498 499 if (ImGui::CollapsingHeader("Window options")) 500 { 501 if (ImGui::BeginTable("split", 3)) 502 { 503 ImGui::TableNextColumn(); ImGui::Checkbox("No titlebar", &no_titlebar); 504 ImGui::TableNextColumn(); ImGui::Checkbox("No scrollbar", &no_scrollbar); 505 ImGui::TableNextColumn(); ImGui::Checkbox("No menu", &no_menu); 506 ImGui::TableNextColumn(); ImGui::Checkbox("No move", &no_move); 507 ImGui::TableNextColumn(); ImGui::Checkbox("No resize", &no_resize); 508 ImGui::TableNextColumn(); ImGui::Checkbox("No collapse", &no_collapse); 509 ImGui::TableNextColumn(); ImGui::Checkbox("No close", &no_close); 510 ImGui::TableNextColumn(); ImGui::Checkbox("No nav", &no_nav); 511 ImGui::TableNextColumn(); ImGui::Checkbox("No background", &no_background); 512 ImGui::TableNextColumn(); ImGui::Checkbox("No bring to front", &no_bring_to_front); 513 ImGui::EndTable(); 514 } 515 } 516 517 // All demo contents 518 ShowDemoWindowWidgets(); 519 ShowDemoWindowLayout(); 520 ShowDemoWindowPopups(); 521 ShowDemoWindowTables(); 522 ShowDemoWindowMisc(); 523 524 // End of ShowDemoWindow() 525 ImGui::PopItemWidth(); 526 ImGui::End(); 527 } 528 529 static void ShowDemoWindowWidgets() 530 { 531 if (!ImGui::CollapsingHeader("Widgets")) 532 return; 533 534 if (ImGui::TreeNode("Basic")) 535 { 536 static int clicked = 0; 537 if (ImGui::Button("Button")) 538 clicked++; 539 if (clicked & 1) 540 { 541 ImGui::SameLine(); 542 ImGui::Text("Thanks for clicking me!"); 543 } 544 545 static bool check = true; 546 ImGui::Checkbox("checkbox", &check); 547 548 static int e = 0; 549 ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine(); 550 ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine(); 551 ImGui::RadioButton("radio c", &e, 2); 552 553 // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style. 554 for (int i = 0; i < 7; i++) 555 { 556 if (i > 0) 557 ImGui::SameLine(); 558 ImGui::PushID(i); 559 ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.6f)); 560 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.7f)); 561 ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.8f, 0.8f)); 562 ImGui::Button("Click"); 563 ImGui::PopStyleColor(3); 564 ImGui::PopID(); 565 } 566 567 // Use AlignTextToFramePadding() to align text baseline to the baseline of framed widgets elements 568 // (otherwise a Text+SameLine+Button sequence will have the text a little too high by default!) 569 // See 'Demo->Layout->Text Baseline Alignment' for details. 570 ImGui::AlignTextToFramePadding(); 571 ImGui::Text("Hold to repeat:"); 572 ImGui::SameLine(); 573 574 // Arrow buttons with Repeater 575 static int counter = 0; 576 float spacing = ImGui::GetStyle().ItemInnerSpacing.x; 577 ImGui::PushButtonRepeat(true); 578 if (ImGui::ArrowButton("##left", ImGuiDir_Left)) { counter--; } 579 ImGui::SameLine(0.0f, spacing); 580 if (ImGui::ArrowButton("##right", ImGuiDir_Right)) { counter++; } 581 ImGui::PopButtonRepeat(); 582 ImGui::SameLine(); 583 ImGui::Text("%d", counter); 584 585 ImGui::Text("Hover over me"); 586 if (ImGui::IsItemHovered()) 587 ImGui::SetTooltip("I am a tooltip"); 588 589 ImGui::SameLine(); 590 ImGui::Text("- or me"); 591 if (ImGui::IsItemHovered()) 592 { 593 ImGui::BeginTooltip(); 594 ImGui::Text("I am a fancy tooltip"); 595 static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; 596 ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr)); 597 ImGui::EndTooltip(); 598 } 599 600 ImGui::Separator(); 601 602 ImGui::LabelText("label", "Value"); 603 604 { 605 // Using the _simplified_ one-liner Combo() api here 606 // See "Combo" section for examples of how to use the more flexible BeginCombo()/EndCombo() api. 607 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" }; 608 static int item_current = 0; 609 ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items)); 610 ImGui::SameLine(); HelpMarker( 611 "Using the simplified one-liner Combo API here.\nRefer to the \"Combo\" section below for an explanation of how to use the more flexible and general BeginCombo/EndCombo API."); 612 } 613 614 { 615 // To wire InputText() with std::string or any other custom string type, 616 // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file. 617 static char str0[128] = "Hello, world!"; 618 ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0)); 619 ImGui::SameLine(); HelpMarker( 620 "USER:\n" 621 "Hold SHIFT or use mouse to select text.\n" 622 "CTRL+Left/Right to word jump.\n" 623 "CTRL+A or double-click to select all.\n" 624 "CTRL+X,CTRL+C,CTRL+V clipboard.\n" 625 "CTRL+Z,CTRL+Y undo/redo.\n" 626 "ESCAPE to revert.\n\n" 627 "PROGRAMMER:\n" 628 "You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() " 629 "to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example (this is not demonstrated " 630 "in imgui_demo.cpp)."); 631 632 static char str1[128] = ""; 633 ImGui::InputTextWithHint("input text (w/ hint)", "enter text here", str1, IM_ARRAYSIZE(str1)); 634 635 static int i0 = 123; 636 ImGui::InputInt("input int", &i0); 637 ImGui::SameLine(); HelpMarker( 638 "You can apply arithmetic operators +,*,/ on numerical values.\n" 639 " e.g. [ 100 ], input \'*2\', result becomes [ 200 ]\n" 640 "Use +- to subtract."); 641 642 static float f0 = 0.001f; 643 ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f"); 644 645 static double d0 = 999999.00000001; 646 ImGui::InputDouble("input double", &d0, 0.01f, 1.0f, "%.8f"); 647 648 static float f1 = 1.e10f; 649 ImGui::InputFloat("input scientific", &f1, 0.0f, 0.0f, "%e"); 650 ImGui::SameLine(); HelpMarker( 651 "You can input value using the scientific notation,\n" 652 " e.g. \"1e+8\" becomes \"100000000\"."); 653 654 static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; 655 ImGui::InputFloat3("input float3", vec4a); 656 } 657 658 { 659 static int i1 = 50, i2 = 42; 660 ImGui::DragInt("drag int", &i1, 1); 661 ImGui::SameLine(); HelpMarker( 662 "Click and drag to edit value.\n" 663 "Hold SHIFT/ALT for faster/slower edit.\n" 664 "Double-click or CTRL+click to input value."); 665 666 ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp); 667 668 static float f1 = 1.00f, f2 = 0.0067f; 669 ImGui::DragFloat("drag float", &f1, 0.005f); 670 ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns"); 671 } 672 673 { 674 static int i1 = 0; 675 ImGui::SliderInt("slider int", &i1, -1, 3); 676 ImGui::SameLine(); HelpMarker("CTRL+click to input value."); 677 678 static float f1 = 0.123f, f2 = 0.0f; 679 ImGui::SliderFloat("slider float", &f1, 0.0f, 1.0f, "ratio = %.3f"); 680 ImGui::SliderFloat("slider float (log)", &f2, -10.0f, 10.0f, "%.4f", ImGuiSliderFlags_Logarithmic); 681 682 static float angle = 0.0f; 683 ImGui::SliderAngle("slider angle", &angle); 684 685 // Using the format string to display a name instead of an integer. 686 // Here we completely omit '%d' from the format string, so it'll only display a name. 687 // This technique can also be used with DragInt(). 688 enum Element { Element_Fire, Element_Earth, Element_Air, Element_Water, Element_COUNT }; 689 static int elem = Element_Fire; 690 const char* elems_names[Element_COUNT] = { "Fire", "Earth", "Air", "Water" }; 691 const char* elem_name = (elem >= 0 && elem < Element_COUNT) ? elems_names[elem] : "Unknown"; 692 ImGui::SliderInt("slider enum", &elem, 0, Element_COUNT - 1, elem_name); 693 ImGui::SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer."); 694 } 695 696 { 697 static float col1[3] = { 1.0f, 0.0f, 0.2f }; 698 static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f }; 699 ImGui::ColorEdit3("color 1", col1); 700 ImGui::SameLine(); HelpMarker( 701 "Click on the color square to open a color picker.\n" 702 "Click and hold to use drag and drop.\n" 703 "Right-click on the color square to show options.\n" 704 "CTRL+click on individual component to input value.\n"); 705 706 ImGui::ColorEdit4("color 2", col2); 707 } 708 709 { 710 // Using the _simplified_ one-liner ListBox() api here 711 // See "List boxes" section for examples of how to use the more flexible BeginListBox()/EndListBox() api. 712 const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" }; 713 static int item_current = 1; 714 ImGui::ListBox("listbox", &item_current, items, IM_ARRAYSIZE(items), 4); 715 ImGui::SameLine(); HelpMarker( 716 "Using the simplified one-liner ListBox API here.\nRefer to the \"List boxes\" section below for an explanation of how to use the more flexible and general BeginListBox/EndListBox API."); 717 } 718 719 ImGui::TreePop(); 720 } 721 722 // Testing ImGuiOnceUponAFrame helper. 723 //static ImGuiOnceUponAFrame once; 724 //for (int i = 0; i < 5; i++) 725 // if (once) 726 // ImGui::Text("This will be displayed only once."); 727 728 if (ImGui::TreeNode("Trees")) 729 { 730 if (ImGui::TreeNode("Basic trees")) 731 { 732 for (int i = 0; i < 5; i++) 733 { 734 // Use SetNextItemOpen() so set the default state of a node to be open. We could 735 // also use TreeNodeEx() with the ImGuiTreeNodeFlags_DefaultOpen flag to achieve the same thing! 736 if (i == 0) 737 ImGui::SetNextItemOpen(true, ImGuiCond_Once); 738 739 if (ImGui::TreeNode((void*)(intptr_t)i, "Child %d", i)) 740 { 741 ImGui::Text("blah blah"); 742 ImGui::SameLine(); 743 if (ImGui::SmallButton("button")) {} 744 ImGui::TreePop(); 745 } 746 } 747 ImGui::TreePop(); 748 } 749 750 if (ImGui::TreeNode("Advanced, with Selectable nodes")) 751 { 752 HelpMarker( 753 "This is a more typical looking tree with selectable nodes.\n" 754 "Click to select, CTRL+Click to toggle, click on arrows or double-click to open."); 755 static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth; 756 static bool align_label_with_current_x_position = false; 757 static bool test_drag_and_drop = false; 758 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnArrow", &base_flags, ImGuiTreeNodeFlags_OpenOnArrow); 759 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", &base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick); 760 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAvailWidth", &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."); 761 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &base_flags, ImGuiTreeNodeFlags_SpanFullWidth); 762 ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position); 763 ImGui::Checkbox("Test tree node as drag source", &test_drag_and_drop); 764 ImGui::Text("Hello!"); 765 if (align_label_with_current_x_position) 766 ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing()); 767 768 // 'selection_mask' is dumb representation of what may be user-side selection state. 769 // You may retain selection state inside or outside your objects in whatever format you see fit. 770 // 'node_clicked' is temporary storage of what node we have clicked to process selection at the end 771 /// of the loop. May be a pointer to your own node type, etc. 772 static int selection_mask = (1 << 2); 773 int node_clicked = -1; 774 for (int i = 0; i < 6; i++) 775 { 776 // Disable the default "open on single-click behavior" + set Selected flag according to our selection. 777 ImGuiTreeNodeFlags node_flags = base_flags; 778 const bool is_selected = (selection_mask & (1 << i)) != 0; 779 if (is_selected) 780 node_flags |= ImGuiTreeNodeFlags_Selected; 781 if (i < 3) 782 { 783 // Items 0..2 are Tree Node 784 bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Node %d", i); 785 if (ImGui::IsItemClicked()) 786 node_clicked = i; 787 if (test_drag_and_drop && ImGui::BeginDragDropSource()) 788 { 789 ImGui::SetDragDropPayload("_TREENODE", NULL, 0); 790 ImGui::Text("This is a drag and drop source"); 791 ImGui::EndDragDropSource(); 792 } 793 if (node_open) 794 { 795 ImGui::BulletText("Blah blah\nBlah Blah"); 796 ImGui::TreePop(); 797 } 798 } 799 else 800 { 801 // Items 3..5 are Tree Leaves 802 // The only reason we use TreeNode at all is to allow selection of the leaf. Otherwise we can 803 // use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text(). 804 node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet 805 ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i); 806 if (ImGui::IsItemClicked()) 807 node_clicked = i; 808 if (test_drag_and_drop && ImGui::BeginDragDropSource()) 809 { 810 ImGui::SetDragDropPayload("_TREENODE", NULL, 0); 811 ImGui::Text("This is a drag and drop source"); 812 ImGui::EndDragDropSource(); 813 } 814 } 815 } 816 if (node_clicked != -1) 817 { 818 // Update selection state 819 // (process outside of tree loop to avoid visual inconsistencies during the clicking frame) 820 if (ImGui::GetIO().KeyCtrl) 821 selection_mask ^= (1 << node_clicked); // CTRL+click to toggle 822 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 823 selection_mask = (1 << node_clicked); // Click to single-select 824 } 825 if (align_label_with_current_x_position) 826 ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing()); 827 ImGui::TreePop(); 828 } 829 ImGui::TreePop(); 830 } 831 832 if (ImGui::TreeNode("Collapsing Headers")) 833 { 834 static bool closable_group = true; 835 ImGui::Checkbox("Show 2nd header", &closable_group); 836 if (ImGui::CollapsingHeader("Header", ImGuiTreeNodeFlags_None)) 837 { 838 ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered()); 839 for (int i = 0; i < 5; i++) 840 ImGui::Text("Some content %d", i); 841 } 842 if (ImGui::CollapsingHeader("Header with a close button", &closable_group)) 843 { 844 ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered()); 845 for (int i = 0; i < 5; i++) 846 ImGui::Text("More content %d", i); 847 } 848 /* 849 if (ImGui::CollapsingHeader("Header with a bullet", ImGuiTreeNodeFlags_Bullet)) 850 ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered()); 851 */ 852 ImGui::TreePop(); 853 } 854 855 if (ImGui::TreeNode("Bullets")) 856 { 857 ImGui::BulletText("Bullet point 1"); 858 ImGui::BulletText("Bullet point 2\nOn multiple lines"); 859 if (ImGui::TreeNode("Tree node")) 860 { 861 ImGui::BulletText("Another bullet point"); 862 ImGui::TreePop(); 863 } 864 ImGui::Bullet(); ImGui::Text("Bullet point 3 (two calls)"); 865 ImGui::Bullet(); ImGui::SmallButton("Button"); 866 ImGui::TreePop(); 867 } 868 869 if (ImGui::TreeNode("Text")) 870 { 871 if (ImGui::TreeNode("Colorful Text")) 872 { 873 // Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility. 874 ImGui::TextColored(ImVec4(1.0f, 0.0f, 1.0f, 1.0f), "Pink"); 875 ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Yellow"); 876 ImGui::TextDisabled("Disabled"); 877 ImGui::SameLine(); HelpMarker("The TextDisabled color is stored in ImGuiStyle."); 878 ImGui::TreePop(); 879 } 880 881 if (ImGui::TreeNode("Word Wrapping")) 882 { 883 // Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility. 884 ImGui::TextWrapped( 885 "This text should automatically wrap on the edge of the window. The current implementation " 886 "for text wrapping follows simple rules suitable for English and possibly other languages."); 887 ImGui::Spacing(); 888 889 static float wrap_width = 200.0f; 890 ImGui::SliderFloat("Wrap width", &wrap_width, -20, 600, "%.0f"); 891 892 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 893 for (int n = 0; n < 2; n++) 894 { 895 ImGui::Text("Test paragraph %d:", n); 896 ImVec2 pos = ImGui::GetCursorScreenPos(); 897 ImVec2 marker_min = ImVec2(pos.x + wrap_width, pos.y); 898 ImVec2 marker_max = ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight()); 899 ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width); 900 if (n == 0) 901 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); 902 else 903 ImGui::Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh"); 904 905 // Draw actual text bounding box, following by marker of our expected limit (should not overlap!) 906 draw_list->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 255, 0, 255)); 907 draw_list->AddRectFilled(marker_min, marker_max, IM_COL32(255, 0, 255, 255)); 908 ImGui::PopTextWrapPos(); 909 } 910 911 ImGui::TreePop(); 912 } 913 914 if (ImGui::TreeNode("UTF-8 Text")) 915 { 916 // UTF-8 test with Japanese characters 917 // (Needs a suitable font? Try "Google Noto" or "Arial Unicode". See docs/FONTS.md for details.) 918 // - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8 919 // - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. in Visual Studio, you 920 // can save your source files as 'UTF-8 without signature'). 921 // - FOR THIS DEMO FILE ONLY, BECAUSE WE WANT TO SUPPORT OLD COMPILERS, WE ARE *NOT* INCLUDING RAW UTF-8 922 // CHARACTERS IN THIS SOURCE FILE. Instead we are encoding a few strings with hexadecimal constants. 923 // Don't do this in your application! Please use u8"text in any language" in your application! 924 // Note that characters values are preserved even by InputText() if the font cannot be displayed, 925 // so you can safely copy & paste garbled characters into another application. 926 ImGui::TextWrapped( 927 "CJK text will only appears if the font was loaded with the appropriate CJK character ranges. " 928 "Call io.Fonts->AddFontFromFileTTF() manually to load extra character ranges. " 929 "Read docs/FONTS.md for details."); 930 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. 931 ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)"); 932 static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"; 933 //static char buf[32] = u8"NIHONGO"; // <- this is how you would write it with C++11, using real kanjis 934 ImGui::InputText("UTF-8 input", buf, IM_ARRAYSIZE(buf)); 935 ImGui::TreePop(); 936 } 937 ImGui::TreePop(); 938 } 939 940 if (ImGui::TreeNode("Images")) 941 { 942 ImGuiIO& io = ImGui::GetIO(); 943 ImGui::TextWrapped( 944 "Below we are displaying the font texture (which is the only texture we have access to in this demo). " 945 "Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. " 946 "Hover the texture for a zoomed view!"); 947 948 // Below we are displaying the font texture because it is the only texture we have access to inside the demo! 949 // Remember that ImTextureID is just storage for whatever you want it to be. It is essentially a value that 950 // will be passed to the rendering backend via the ImDrawCmd structure. 951 // If you use one of the default imgui_impl_XXXX.cpp rendering backend, they all have comments at the top 952 // of their respective source file to specify what they expect to be stored in ImTextureID, for example: 953 // - The imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer 954 // - The imgui_impl_opengl3.cpp renderer expect a GLuint OpenGL texture identifier, etc. 955 // More: 956 // - If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers 957 // to ImGui::Image(), and gather width/height through your own functions, etc. 958 // - You can use ShowMetricsWindow() to inspect the draw data that are being passed to your renderer, 959 // it will help you debug issues if you are confused about it. 960 // - Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage(). 961 // - Read https://github.com/ocornut/imgui/blob/master/docs/FAQ.md 962 // - Read https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples 963 ImTextureID my_tex_id = io.Fonts->TexID; 964 float my_tex_w = (float)io.Fonts->TexWidth; 965 float my_tex_h = (float)io.Fonts->TexHeight; 966 { 967 ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h); 968 ImVec2 pos = ImGui::GetCursorScreenPos(); 969 ImVec2 uv_min = ImVec2(0.0f, 0.0f); // Top-left 970 ImVec2 uv_max = ImVec2(1.0f, 1.0f); // Lower-right 971 ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint 972 ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f); // 50% opaque white 973 ImGui::Image(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, tint_col, border_col); 974 if (ImGui::IsItemHovered()) 975 { 976 ImGui::BeginTooltip(); 977 float region_sz = 32.0f; 978 float region_x = io.MousePos.x - pos.x - region_sz * 0.5f; 979 float region_y = io.MousePos.y - pos.y - region_sz * 0.5f; 980 float zoom = 4.0f; 981 if (region_x < 0.0f) { region_x = 0.0f; } 982 else if (region_x > my_tex_w - region_sz) { region_x = my_tex_w - region_sz; } 983 if (region_y < 0.0f) { region_y = 0.0f; } 984 else if (region_y > my_tex_h - region_sz) { region_y = my_tex_h - region_sz; } 985 ImGui::Text("Min: (%.2f, %.2f)", region_x, region_y); 986 ImGui::Text("Max: (%.2f, %.2f)", region_x + region_sz, region_y + region_sz); 987 ImVec2 uv0 = ImVec2((region_x) / my_tex_w, (region_y) / my_tex_h); 988 ImVec2 uv1 = ImVec2((region_x + region_sz) / my_tex_w, (region_y + region_sz) / my_tex_h); 989 ImGui::Image(my_tex_id, ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, tint_col, border_col); 990 ImGui::EndTooltip(); 991 } 992 } 993 ImGui::TextWrapped("And now some textured buttons.."); 994 static int pressed_count = 0; 995 for (int i = 0; i < 8; i++) 996 { 997 ImGui::PushID(i); 998 int frame_padding = -1 + i; // -1 == uses default padding (style.FramePadding) 999 ImVec2 size = ImVec2(32.0f, 32.0f); // Size of the image we want to make visible 1000 ImVec2 uv0 = ImVec2(0.0f, 0.0f); // UV coordinates for lower-left 1001 ImVec2 uv1 = ImVec2(32.0f / my_tex_w, 32.0f / my_tex_h);// UV coordinates for (32,32) in our texture 1002 ImVec4 bg_col = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); // Black background 1003 ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint 1004 if (ImGui::ImageButton(my_tex_id, size, uv0, uv1, frame_padding, bg_col, tint_col)) 1005 pressed_count += 1; 1006 ImGui::PopID(); 1007 ImGui::SameLine(); 1008 } 1009 ImGui::NewLine(); 1010 ImGui::Text("Pressed %d times.", pressed_count); 1011 ImGui::TreePop(); 1012 } 1013 1014 if (ImGui::TreeNode("Combo")) 1015 { 1016 // Expose flags as checkbox for the demo 1017 static ImGuiComboFlags flags = 0; 1018 ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", &flags, ImGuiComboFlags_PopupAlignLeft); 1019 ImGui::SameLine(); HelpMarker("Only makes a difference if the popup is larger than the combo"); 1020 if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", &flags, ImGuiComboFlags_NoArrowButton)) 1021 flags &= ~ImGuiComboFlags_NoPreview; // Clear the other flag, as we cannot combine both 1022 if (ImGui::CheckboxFlags("ImGuiComboFlags_NoPreview", &flags, ImGuiComboFlags_NoPreview)) 1023 flags &= ~ImGuiComboFlags_NoArrowButton; // Clear the other flag, as we cannot combine both 1024 1025 // Using the generic BeginCombo() API, you have full control over how to display the combo contents. 1026 // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively 1027 // stored in the object itself, etc.) 1028 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; 1029 static int item_current_idx = 0; // Here we store our selection data as an index. 1030 const char* combo_label = items[item_current_idx]; // Label to preview before opening the combo (technically it could be anything) 1031 if (ImGui::BeginCombo("combo 1", combo_label, flags)) 1032 { 1033 for (int n = 0; n < IM_ARRAYSIZE(items); n++) 1034 { 1035 const bool is_selected = (item_current_idx == n); 1036 if (ImGui::Selectable(items[n], is_selected)) 1037 item_current_idx = n; 1038 1039 // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) 1040 if (is_selected) 1041 ImGui::SetItemDefaultFocus(); 1042 } 1043 ImGui::EndCombo(); 1044 } 1045 1046 // Simplified one-liner Combo() API, using values packed in a single constant string 1047 static int item_current_2 = 0; 1048 ImGui::Combo("combo 2 (one-liner)", &item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); 1049 1050 // Simplified one-liner Combo() using an array of const char* 1051 static int item_current_3 = -1; // If the selection isn't within 0..count, Combo won't display a preview 1052 ImGui::Combo("combo 3 (array)", &item_current_3, items, IM_ARRAYSIZE(items)); 1053 1054 // Simplified one-liner Combo() using an accessor function 1055 struct Funcs { static bool ItemGetter(void* data, int n, const char** out_str) { *out_str = ((const char**)data)[n]; return true; } }; 1056 static int item_current_4 = 0; 1057 ImGui::Combo("combo 4 (function)", &item_current_4, &Funcs::ItemGetter, items, IM_ARRAYSIZE(items)); 1058 1059 ImGui::TreePop(); 1060 } 1061 1062 if (ImGui::TreeNode("List boxes")) 1063 { 1064 // Using the generic BeginListBox() API, you have full control over how to display the combo contents. 1065 // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively 1066 // stored in the object itself, etc.) 1067 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; 1068 static int item_current_idx = 0; // Here we store our selection data as an index. 1069 if (ImGui::BeginListBox("listbox 1")) 1070 { 1071 for (int n = 0; n < IM_ARRAYSIZE(items); n++) 1072 { 1073 const bool is_selected = (item_current_idx == n); 1074 if (ImGui::Selectable(items[n], is_selected)) 1075 item_current_idx = n; 1076 1077 // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) 1078 if (is_selected) 1079 ImGui::SetItemDefaultFocus(); 1080 } 1081 ImGui::EndListBox(); 1082 } 1083 1084 // Custom size: use all width, 5 items tall 1085 ImGui::Text("Full-width:"); 1086 if (ImGui::BeginListBox("##listbox 2", ImVec2(-FLT_MIN, 5 * ImGui::GetTextLineHeightWithSpacing()))) 1087 { 1088 for (int n = 0; n < IM_ARRAYSIZE(items); n++) 1089 { 1090 const bool is_selected = (item_current_idx == n); 1091 if (ImGui::Selectable(items[n], is_selected)) 1092 item_current_idx = n; 1093 1094 // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) 1095 if (is_selected) 1096 ImGui::SetItemDefaultFocus(); 1097 } 1098 ImGui::EndListBox(); 1099 } 1100 1101 ImGui::TreePop(); 1102 } 1103 1104 if (ImGui::TreeNode("Selectables")) 1105 { 1106 // Selectable() has 2 overloads: 1107 // - The one taking "bool selected" as a read-only selection information. 1108 // When Selectable() has been clicked it returns true and you can alter selection state accordingly. 1109 // - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases) 1110 // The earlier is more flexible, as in real application your selection may be stored in many different ways 1111 // and not necessarily inside a bool value (e.g. in flags within objects, as an external list, etc). 1112 if (ImGui::TreeNode("Basic")) 1113 { 1114 static bool selection[5] = { false, true, false, false, false }; 1115 ImGui::Selectable("1. I am selectable", &selection[0]); 1116 ImGui::Selectable("2. I am selectable", &selection[1]); 1117 ImGui::Text("3. I am not selectable"); 1118 ImGui::Selectable("4. I am selectable", &selection[3]); 1119 if (ImGui::Selectable("5. I am double clickable", selection[4], ImGuiSelectableFlags_AllowDoubleClick)) 1120 if (ImGui::IsMouseDoubleClicked(0)) 1121 selection[4] = !selection[4]; 1122 ImGui::TreePop(); 1123 } 1124 if (ImGui::TreeNode("Selection State: Single Selection")) 1125 { 1126 static int selected = -1; 1127 for (int n = 0; n < 5; n++) 1128 { 1129 char buf[32]; 1130 sprintf(buf, "Object %d", n); 1131 if (ImGui::Selectable(buf, selected == n)) 1132 selected = n; 1133 } 1134 ImGui::TreePop(); 1135 } 1136 if (ImGui::TreeNode("Selection State: Multiple Selection")) 1137 { 1138 HelpMarker("Hold CTRL and click to select multiple items."); 1139 static bool selection[5] = { false, false, false, false, false }; 1140 for (int n = 0; n < 5; n++) 1141 { 1142 char buf[32]; 1143 sprintf(buf, "Object %d", n); 1144 if (ImGui::Selectable(buf, selection[n])) 1145 { 1146 if (!ImGui::GetIO().KeyCtrl) // Clear selection when CTRL is not held 1147 memset(selection, 0, sizeof(selection)); 1148 selection[n] ^= 1; 1149 } 1150 } 1151 ImGui::TreePop(); 1152 } 1153 if (ImGui::TreeNode("Rendering more text into the same line")) 1154 { 1155 // Using the Selectable() override that takes "bool* p_selected" parameter, 1156 // this function toggle your bool value automatically. 1157 static bool selected[3] = { false, false, false }; 1158 ImGui::Selectable("main.c", &selected[0]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes"); 1159 ImGui::Selectable("Hello.cpp", &selected[1]); ImGui::SameLine(300); ImGui::Text("12,345 bytes"); 1160 ImGui::Selectable("Hello.h", &selected[2]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes"); 1161 ImGui::TreePop(); 1162 } 1163 if (ImGui::TreeNode("In columns")) 1164 { 1165 static bool selected[10] = {}; 1166 1167 if (ImGui::BeginTable("split1", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings)) 1168 { 1169 for (int i = 0; i < 10; i++) 1170 { 1171 char label[32]; 1172 sprintf(label, "Item %d", i); 1173 ImGui::TableNextColumn(); 1174 ImGui::Selectable(label, &selected[i]); // FIXME-TABLE: Selection overlap 1175 } 1176 ImGui::EndTable(); 1177 } 1178 ImGui::Separator(); 1179 if (ImGui::BeginTable("split2", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings)) 1180 { 1181 for (int i = 0; i < 10; i++) 1182 { 1183 char label[32]; 1184 sprintf(label, "Item %d", i); 1185 ImGui::TableNextRow(); 1186 ImGui::TableNextColumn(); 1187 ImGui::Selectable(label, &selected[i], ImGuiSelectableFlags_SpanAllColumns); 1188 ImGui::TableNextColumn(); 1189 ImGui::Text("Some other contents"); 1190 ImGui::TableNextColumn(); 1191 ImGui::Text("123456"); 1192 } 1193 ImGui::EndTable(); 1194 } 1195 ImGui::TreePop(); 1196 } 1197 if (ImGui::TreeNode("Grid")) 1198 { 1199 static char selected[4][4] = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } }; 1200 1201 // Add in a bit of silly fun... 1202 const float time = (float)ImGui::GetTime(); 1203 const bool winning_state = memchr(selected, 0, sizeof(selected)) == NULL; // If all cells are selected... 1204 if (winning_state) 1205 ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f + 0.5f * cosf(time * 2.0f), 0.5f + 0.5f * sinf(time * 3.0f))); 1206 1207 for (int y = 0; y < 4; y++) 1208 for (int x = 0; x < 4; x++) 1209 { 1210 if (x > 0) 1211 ImGui::SameLine(); 1212 ImGui::PushID(y * 4 + x); 1213 if (ImGui::Selectable("Sailor", selected[y][x] != 0, 0, ImVec2(50, 50))) 1214 { 1215 // Toggle clicked cell + toggle neighbors 1216 selected[y][x] ^= 1; 1217 if (x > 0) { selected[y][x - 1] ^= 1; } 1218 if (x < 3) { selected[y][x + 1] ^= 1; } 1219 if (y > 0) { selected[y - 1][x] ^= 1; } 1220 if (y < 3) { selected[y + 1][x] ^= 1; } 1221 } 1222 ImGui::PopID(); 1223 } 1224 1225 if (winning_state) 1226 ImGui::PopStyleVar(); 1227 ImGui::TreePop(); 1228 } 1229 if (ImGui::TreeNode("Alignment")) 1230 { 1231 HelpMarker( 1232 "By default, Selectables uses style.SelectableTextAlign but it can be overridden on a per-item " 1233 "basis using PushStyleVar(). You'll probably want to always keep your default situation to " 1234 "left-align otherwise it becomes difficult to layout multiple items on a same line"); 1235 static bool selected[3 * 3] = { true, false, true, false, true, false, true, false, true }; 1236 for (int y = 0; y < 3; y++) 1237 { 1238 for (int x = 0; x < 3; x++) 1239 { 1240 ImVec2 alignment = ImVec2((float)x / 2.0f, (float)y / 2.0f); 1241 char name[32]; 1242 sprintf(name, "(%.1f,%.1f)", alignment.x, alignment.y); 1243 if (x > 0) ImGui::SameLine(); 1244 ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, alignment); 1245 ImGui::Selectable(name, &selected[3 * y + x], ImGuiSelectableFlags_None, ImVec2(80, 80)); 1246 ImGui::PopStyleVar(); 1247 } 1248 } 1249 ImGui::TreePop(); 1250 } 1251 ImGui::TreePop(); 1252 } 1253 1254 // To wire InputText() with std::string or any other custom string type, 1255 // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file. 1256 if (ImGui::TreeNode("Text Input")) 1257 { 1258 if (ImGui::TreeNode("Multi-line Text Input")) 1259 { 1260 // Note: we are using a fixed-sized buffer for simplicity here. See ImGuiInputTextFlags_CallbackResize 1261 // and the code in misc/cpp/imgui_stdlib.h for how to setup InputText() for dynamically resizing strings. 1262 static char text[1024 * 16] = 1263 "/*\n" 1264 " The Pentium F00F bug, shorthand for F0 0F C7 C8,\n" 1265 " the hexadecimal encoding of one offending instruction,\n" 1266 " more formally, the invalid operand with locked CMPXCHG8B\n" 1267 " instruction bug, is a design flaw in the majority of\n" 1268 " Intel Pentium, Pentium MMX, and Pentium OverDrive\n" 1269 " processors (all in the P5 microarchitecture).\n" 1270 "*/\n\n" 1271 "label:\n" 1272 "\tlock cmpxchg8b eax\n"; 1273 1274 static ImGuiInputTextFlags flags = ImGuiInputTextFlags_AllowTabInput; 1275 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)"); 1276 ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly); 1277 ImGui::CheckboxFlags("ImGuiInputTextFlags_AllowTabInput", &flags, ImGuiInputTextFlags_AllowTabInput); 1278 ImGui::CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", &flags, ImGuiInputTextFlags_CtrlEnterForNewLine); 1279 ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16), flags); 1280 ImGui::TreePop(); 1281 } 1282 1283 if (ImGui::TreeNode("Filtered Text Input")) 1284 { 1285 struct TextFilters 1286 { 1287 // Return 0 (pass) if the character is 'i' or 'm' or 'g' or 'u' or 'i' 1288 static int FilterImGuiLetters(ImGuiInputTextCallbackData* data) 1289 { 1290 if (data->EventChar < 256 && strchr("imgui", (char)data->EventChar)) 1291 return 0; 1292 return 1; 1293 } 1294 }; 1295 1296 static char buf1[64] = ""; ImGui::InputText("default", buf1, 64); 1297 static char buf2[64] = ""; ImGui::InputText("decimal", buf2, 64, ImGuiInputTextFlags_CharsDecimal); 1298 static char buf3[64] = ""; ImGui::InputText("hexadecimal", buf3, 64, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase); 1299 static char buf4[64] = ""; ImGui::InputText("uppercase", buf4, 64, ImGuiInputTextFlags_CharsUppercase); 1300 static char buf5[64] = ""; ImGui::InputText("no blank", buf5, 64, ImGuiInputTextFlags_CharsNoBlank); 1301 static char buf6[64] = ""; ImGui::InputText("\"imgui\" letters", buf6, 64, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters); 1302 ImGui::TreePop(); 1303 } 1304 1305 if (ImGui::TreeNode("Password Input")) 1306 { 1307 static char password[64] = "password123"; 1308 ImGui::InputText("password", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password); 1309 ImGui::SameLine(); HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n"); 1310 ImGui::InputTextWithHint("password (w/ hint)", "<password>", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password); 1311 ImGui::InputText("password (clear)", password, IM_ARRAYSIZE(password)); 1312 ImGui::TreePop(); 1313 } 1314 1315 if (ImGui::TreeNode("Completion, History, Edit Callbacks")) 1316 { 1317 struct Funcs 1318 { 1319 static int MyCallback(ImGuiInputTextCallbackData* data) 1320 { 1321 if (data->EventFlag == ImGuiInputTextFlags_CallbackCompletion) 1322 { 1323 data->InsertChars(data->CursorPos, ".."); 1324 } 1325 else if (data->EventFlag == ImGuiInputTextFlags_CallbackHistory) 1326 { 1327 if (data->EventKey == ImGuiKey_UpArrow) 1328 { 1329 data->DeleteChars(0, data->BufTextLen); 1330 data->InsertChars(0, "Pressed Up!"); 1331 data->SelectAll(); 1332 } 1333 else if (data->EventKey == ImGuiKey_DownArrow) 1334 { 1335 data->DeleteChars(0, data->BufTextLen); 1336 data->InsertChars(0, "Pressed Down!"); 1337 data->SelectAll(); 1338 } 1339 } 1340 else if (data->EventFlag == ImGuiInputTextFlags_CallbackEdit) 1341 { 1342 // Toggle casing of first character 1343 char c = data->Buf[0]; 1344 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) data->Buf[0] ^= 32; 1345 data->BufDirty = true; 1346 1347 // Increment a counter 1348 int* p_int = (int*)data->UserData; 1349 *p_int = *p_int + 1; 1350 } 1351 return 0; 1352 } 1353 }; 1354 static char buf1[64]; 1355 ImGui::InputText("Completion", buf1, 64, ImGuiInputTextFlags_CallbackCompletion, Funcs::MyCallback); 1356 ImGui::SameLine(); HelpMarker("Here we append \"..\" each time Tab is pressed. See 'Examples>Console' for a more meaningful demonstration of using this callback."); 1357 1358 static char buf2[64]; 1359 ImGui::InputText("History", buf2, 64, ImGuiInputTextFlags_CallbackHistory, Funcs::MyCallback); 1360 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."); 1361 1362 static char buf3[64]; 1363 static int edit_count = 0; 1364 ImGui::InputText("Edit", buf3, 64, ImGuiInputTextFlags_CallbackEdit, Funcs::MyCallback, (void*)&edit_count); 1365 ImGui::SameLine(); HelpMarker("Here we toggle the casing of the first character on every edits + count edits."); 1366 ImGui::SameLine(); ImGui::Text("(%d)", edit_count); 1367 1368 ImGui::TreePop(); 1369 } 1370 1371 if (ImGui::TreeNode("Resize Callback")) 1372 { 1373 // To wire InputText() with std::string or any other custom string type, 1374 // you can use the ImGuiInputTextFlags_CallbackResize flag + create a custom ImGui::InputText() wrapper 1375 // using your preferred type. See misc/cpp/imgui_stdlib.h for an implementation of this using std::string. 1376 HelpMarker( 1377 "Using ImGuiInputTextFlags_CallbackResize to wire your custom string type to InputText().\n\n" 1378 "See misc/cpp/imgui_stdlib.h for an implementation of this for std::string."); 1379 struct Funcs 1380 { 1381 static int MyResizeCallback(ImGuiInputTextCallbackData* data) 1382 { 1383 if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) 1384 { 1385 ImVector<char>* my_str = (ImVector<char>*)data->UserData; 1386 IM_ASSERT(my_str->begin() == data->Buf); 1387 my_str->resize(data->BufSize); // NB: On resizing calls, generally data->BufSize == data->BufTextLen + 1 1388 data->Buf = my_str->begin(); 1389 } 1390 return 0; 1391 } 1392 1393 // Note: Because ImGui:: is a namespace you would typically add your own function into the namespace. 1394 // For example, you code may declare a function 'ImGui::InputText(const char* label, MyString* my_str)' 1395 static bool MyInputTextMultiline(const char* label, ImVector<char>* my_str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0) 1396 { 1397 IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); 1398 return ImGui::InputTextMultiline(label, my_str->begin(), (size_t)my_str->size(), size, flags | ImGuiInputTextFlags_CallbackResize, Funcs::MyResizeCallback, (void*)my_str); 1399 } 1400 }; 1401 1402 // For this demo we are using ImVector as a string container. 1403 // Note that because we need to store a terminating zero character, our size/capacity are 1 more 1404 // than usually reported by a typical string class. 1405 static ImVector<char> my_str; 1406 if (my_str.empty()) 1407 my_str.push_back(0); 1408 Funcs::MyInputTextMultiline("##MyStr", &my_str, ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16)); 1409 ImGui::Text("Data: %p\nSize: %d\nCapacity: %d", (void*)my_str.begin(), my_str.size(), my_str.capacity()); 1410 ImGui::TreePop(); 1411 } 1412 1413 ImGui::TreePop(); 1414 } 1415 1416 // Tabs 1417 if (ImGui::TreeNode("Tabs")) 1418 { 1419 if (ImGui::TreeNode("Basic")) 1420 { 1421 ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None; 1422 if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) 1423 { 1424 if (ImGui::BeginTabItem("Avocado")) 1425 { 1426 ImGui::Text("This is the Avocado tab!\nblah blah blah blah blah"); 1427 ImGui::EndTabItem(); 1428 } 1429 if (ImGui::BeginTabItem("Broccoli")) 1430 { 1431 ImGui::Text("This is the Broccoli tab!\nblah blah blah blah blah"); 1432 ImGui::EndTabItem(); 1433 } 1434 if (ImGui::BeginTabItem("Cucumber")) 1435 { 1436 ImGui::Text("This is the Cucumber tab!\nblah blah blah blah blah"); 1437 ImGui::EndTabItem(); 1438 } 1439 ImGui::EndTabBar(); 1440 } 1441 ImGui::Separator(); 1442 ImGui::TreePop(); 1443 } 1444 1445 if (ImGui::TreeNode("Advanced & Close Button")) 1446 { 1447 // Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0). 1448 static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable; 1449 ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", &tab_bar_flags, ImGuiTabBarFlags_Reorderable); 1450 ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", &tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs); 1451 ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton); 1452 ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", &tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton); 1453 if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0) 1454 tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_; 1455 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown)) 1456 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown); 1457 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll)) 1458 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll); 1459 1460 // Tab Bar 1461 const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" }; 1462 static bool opened[4] = { true, true, true, true }; // Persistent user state 1463 for (int n = 0; n < IM_ARRAYSIZE(opened); n++) 1464 { 1465 if (n > 0) { ImGui::SameLine(); } 1466 ImGui::Checkbox(names[n], &opened[n]); 1467 } 1468 1469 // Passing a bool* to BeginTabItem() is similar to passing one to Begin(): 1470 // the underlying bool will be set to false when the tab is closed. 1471 if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) 1472 { 1473 for (int n = 0; n < IM_ARRAYSIZE(opened); n++) 1474 if (opened[n] && ImGui::BeginTabItem(names[n], &opened[n], ImGuiTabItemFlags_None)) 1475 { 1476 ImGui::Text("This is the %s tab!", names[n]); 1477 if (n & 1) 1478 ImGui::Text("I am an odd tab."); 1479 ImGui::EndTabItem(); 1480 } 1481 ImGui::EndTabBar(); 1482 } 1483 ImGui::Separator(); 1484 ImGui::TreePop(); 1485 } 1486 1487 if (ImGui::TreeNode("TabItemButton & Leading/Trailing flags")) 1488 { 1489 static ImVector<int> active_tabs; 1490 static int next_tab_id = 0; 1491 if (next_tab_id == 0) // Initialize with some default tabs 1492 for (int i = 0; i < 3; i++) 1493 active_tabs.push_back(next_tab_id++); 1494 1495 // TabItemButton() and Leading/Trailing flags are distinct features which we will demo together. 1496 // (It is possible to submit regular tabs with Leading/Trailing flags, or TabItemButton tabs without Leading/Trailing flags... 1497 // but they tend to make more sense together) 1498 static bool show_leading_button = true; 1499 static bool show_trailing_button = true; 1500 ImGui::Checkbox("Show Leading TabItemButton()", &show_leading_button); 1501 ImGui::Checkbox("Show Trailing TabItemButton()", &show_trailing_button); 1502 1503 // Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs 1504 static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_FittingPolicyResizeDown; 1505 ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton); 1506 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown)) 1507 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown); 1508 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll)) 1509 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll); 1510 1511 if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) 1512 { 1513 // Demo a Leading TabItemButton(): click the "?" button to open a menu 1514 if (show_leading_button) 1515 if (ImGui::TabItemButton("?", ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_NoTooltip)) 1516 ImGui::OpenPopup("MyHelpMenu"); 1517 if (ImGui::BeginPopup("MyHelpMenu")) 1518 { 1519 ImGui::Selectable("Hello!"); 1520 ImGui::EndPopup(); 1521 } 1522 1523 // 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 "+") 1524 // Note that we submit it before the regular tabs, but because of the ImGuiTabItemFlags_Trailing flag it will always appear at the end. 1525 if (show_trailing_button) 1526 if (ImGui::TabItemButton("+", ImGuiTabItemFlags_Trailing | ImGuiTabItemFlags_NoTooltip)) 1527 active_tabs.push_back(next_tab_id++); // Add new tab 1528 1529 // Submit our regular tabs 1530 for (int n = 0; n < active_tabs.Size; ) 1531 { 1532 bool open = true; 1533 char name[16]; 1534 snprintf(name, IM_ARRAYSIZE(name), "%04d", active_tabs[n]); 1535 if (ImGui::BeginTabItem(name, &open, ImGuiTabItemFlags_None)) 1536 { 1537 ImGui::Text("This is the %s tab!", name); 1538 ImGui::EndTabItem(); 1539 } 1540 1541 if (!open) 1542 active_tabs.erase(active_tabs.Data + n); 1543 else 1544 n++; 1545 } 1546 1547 ImGui::EndTabBar(); 1548 } 1549 ImGui::Separator(); 1550 ImGui::TreePop(); 1551 } 1552 ImGui::TreePop(); 1553 } 1554 1555 // Plot/Graph widgets are not very good. 1556 // Consider writing your own, or using a third-party one, see: 1557 // - ImPlot https://github.com/epezent/implot 1558 // - others https://github.com/ocornut/imgui/wiki/Useful-Extensions 1559 if (ImGui::TreeNode("Plots Widgets")) 1560 { 1561 static bool animate = true; 1562 ImGui::Checkbox("Animate", &animate); 1563 1564 static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; 1565 ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr)); 1566 1567 // Fill an array of contiguous float values to plot 1568 // Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float 1569 // and the sizeof() of your structure in the "stride" parameter. 1570 static float values[90] = {}; 1571 static int values_offset = 0; 1572 static double refresh_time = 0.0; 1573 if (!animate || refresh_time == 0.0) 1574 refresh_time = ImGui::GetTime(); 1575 while (refresh_time < ImGui::GetTime()) // Create data at fixed 60 Hz rate for the demo 1576 { 1577 static float phase = 0.0f; 1578 values[values_offset] = cosf(phase); 1579 values_offset = (values_offset + 1) % IM_ARRAYSIZE(values); 1580 phase += 0.10f * values_offset; 1581 refresh_time += 1.0f / 60.0f; 1582 } 1583 1584 // Plots can display overlay texts 1585 // (in this example, we will display an average value) 1586 { 1587 float average = 0.0f; 1588 for (int n = 0; n < IM_ARRAYSIZE(values); n++) 1589 average += values[n]; 1590 average /= (float)IM_ARRAYSIZE(values); 1591 char overlay[32]; 1592 sprintf(overlay, "avg %f", average); 1593 ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, overlay, -1.0f, 1.0f, ImVec2(0, 80.0f)); 1594 } 1595 ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0, 80.0f)); 1596 1597 // Use functions to generate output 1598 // FIXME: This is rather awkward because current plot API only pass in indices. 1599 // We probably want an API passing floats and user provide sample rate/count. 1600 struct Funcs 1601 { 1602 static float Sin(void*, int i) { return sinf(i * 0.1f); } 1603 static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; } 1604 }; 1605 static int func_type = 0, display_count = 70; 1606 ImGui::Separator(); 1607 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); 1608 ImGui::Combo("func", &func_type, "Sin\0Saw\0"); 1609 ImGui::SameLine(); 1610 ImGui::SliderInt("Sample count", &display_count, 1, 400); 1611 float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw; 1612 ImGui::PlotLines("Lines", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); 1613 ImGui::PlotHistogram("Histogram", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); 1614 ImGui::Separator(); 1615 1616 // Animate a simple progress bar 1617 static float progress = 0.0f, progress_dir = 1.0f; 1618 if (animate) 1619 { 1620 progress += progress_dir * 0.4f * ImGui::GetIO().DeltaTime; 1621 if (progress >= +1.1f) { progress = +1.1f; progress_dir *= -1.0f; } 1622 if (progress <= -0.1f) { progress = -0.1f; progress_dir *= -1.0f; } 1623 } 1624 1625 // Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width, 1626 // or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth. 1627 ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f)); 1628 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); 1629 ImGui::Text("Progress Bar"); 1630 1631 float progress_saturated = IM_CLAMP(progress, 0.0f, 1.0f); 1632 char buf[32]; 1633 sprintf(buf, "%d/%d", (int)(progress_saturated * 1753), 1753); 1634 ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), buf); 1635 ImGui::TreePop(); 1636 } 1637 1638 if (ImGui::TreeNode("Color/Picker Widgets")) 1639 { 1640 static ImVec4 color = ImVec4(114.0f / 255.0f, 144.0f / 255.0f, 154.0f / 255.0f, 200.0f / 255.0f); 1641 1642 static bool alpha_preview = true; 1643 static bool alpha_half_preview = false; 1644 static bool drag_and_drop = true; 1645 static bool options_menu = true; 1646 static bool hdr = false; 1647 ImGui::Checkbox("With Alpha Preview", &alpha_preview); 1648 ImGui::Checkbox("With Half Alpha Preview", &alpha_half_preview); 1649 ImGui::Checkbox("With Drag and Drop", &drag_and_drop); 1650 ImGui::Checkbox("With Options Menu", &options_menu); ImGui::SameLine(); HelpMarker("Right-click on the individual color widget to show options."); 1651 ImGui::Checkbox("With HDR", &hdr); ImGui::SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets."); 1652 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); 1653 1654 ImGui::Text("Color widget:"); 1655 ImGui::SameLine(); HelpMarker( 1656 "Click on the color square to open a color picker.\n" 1657 "CTRL+click on individual component to input value.\n"); 1658 ImGui::ColorEdit3("MyColor##1", (float*)&color, misc_flags); 1659 1660 ImGui::Text("Color widget HSV with Alpha:"); 1661 ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_DisplayHSV | misc_flags); 1662 1663 ImGui::Text("Color widget with Float Display:"); 1664 ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | misc_flags); 1665 1666 ImGui::Text("Color button with Picker:"); 1667 ImGui::SameLine(); HelpMarker( 1668 "With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\n" 1669 "With the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only " 1670 "be used for the tooltip and picker popup."); 1671 ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | misc_flags); 1672 1673 ImGui::Text("Color button with Custom Picker Popup:"); 1674 1675 // Generate a default palette. The palette will persist and can be edited. 1676 static bool saved_palette_init = true; 1677 static ImVec4 saved_palette[32] = {}; 1678 if (saved_palette_init) 1679 { 1680 for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++) 1681 { 1682 ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f, 1683 saved_palette[n].x, saved_palette[n].y, saved_palette[n].z); 1684 saved_palette[n].w = 1.0f; // Alpha 1685 } 1686 saved_palette_init = false; 1687 } 1688 1689 static ImVec4 backup_color; 1690 bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags); 1691 ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x); 1692 open_popup |= ImGui::Button("Palette"); 1693 if (open_popup) 1694 { 1695 ImGui::OpenPopup("mypicker"); 1696 backup_color = color; 1697 } 1698 if (ImGui::BeginPopup("mypicker")) 1699 { 1700 ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!"); 1701 ImGui::Separator(); 1702 ImGui::ColorPicker4("##picker", (float*)&color, misc_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview); 1703 ImGui::SameLine(); 1704 1705 ImGui::BeginGroup(); // Lock X position 1706 ImGui::Text("Current"); 1707 ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40)); 1708 ImGui::Text("Previous"); 1709 if (ImGui::ColorButton("##previous", backup_color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40))) 1710 color = backup_color; 1711 ImGui::Separator(); 1712 ImGui::Text("Palette"); 1713 for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++) 1714 { 1715 ImGui::PushID(n); 1716 if ((n % 8) != 0) 1717 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y); 1718 1719 ImGuiColorEditFlags palette_button_flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip; 1720 if (ImGui::ColorButton("##palette", saved_palette[n], palette_button_flags, ImVec2(20, 20))) 1721 color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha! 1722 1723 // Allow user to drop colors into each palette entry. Note that ColorButton() is already a 1724 // drag source by default, unless specifying the ImGuiColorEditFlags_NoDragDrop flag. 1725 if (ImGui::BeginDragDropTarget()) 1726 { 1727 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) 1728 memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3); 1729 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) 1730 memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4); 1731 ImGui::EndDragDropTarget(); 1732 } 1733 1734 ImGui::PopID(); 1735 } 1736 ImGui::EndGroup(); 1737 ImGui::EndPopup(); 1738 } 1739 1740 ImGui::Text("Color button only:"); 1741 static bool no_border = false; 1742 ImGui::Checkbox("ImGuiColorEditFlags_NoBorder", &no_border); 1743 ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, misc_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80)); 1744 1745 ImGui::Text("Color picker:"); 1746 static bool alpha = true; 1747 static bool alpha_bar = true; 1748 static bool side_preview = true; 1749 static bool ref_color = false; 1750 static ImVec4 ref_color_v(1.0f, 0.0f, 1.0f, 0.5f); 1751 static int display_mode = 0; 1752 static int picker_mode = 0; 1753 ImGui::Checkbox("With Alpha", &alpha); 1754 ImGui::Checkbox("With Alpha Bar", &alpha_bar); 1755 ImGui::Checkbox("With Side Preview", &side_preview); 1756 if (side_preview) 1757 { 1758 ImGui::SameLine(); 1759 ImGui::Checkbox("With Ref Color", &ref_color); 1760 if (ref_color) 1761 { 1762 ImGui::SameLine(); 1763 ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | misc_flags); 1764 } 1765 } 1766 ImGui::Combo("Display Mode", &display_mode, "Auto/Current\0None\0RGB Only\0HSV Only\0Hex Only\0"); 1767 ImGui::SameLine(); HelpMarker( 1768 "ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, " 1769 "but the user can change it with a right-click.\n\nColorPicker defaults to displaying RGB+HSV+Hex " 1770 "if you don't specify a display mode.\n\nYou can change the defaults using SetColorEditOptions()."); 1771 ImGui::Combo("Picker Mode", &picker_mode, "Auto/Current\0Hue bar + SV rect\0Hue wheel + SV triangle\0"); 1772 ImGui::SameLine(); HelpMarker("User can right-click the picker to change mode."); 1773 ImGuiColorEditFlags flags = misc_flags; 1774 if (!alpha) flags |= ImGuiColorEditFlags_NoAlpha; // This is by default if you call ColorPicker3() instead of ColorPicker4() 1775 if (alpha_bar) flags |= ImGuiColorEditFlags_AlphaBar; 1776 if (!side_preview) flags |= ImGuiColorEditFlags_NoSidePreview; 1777 if (picker_mode == 1) flags |= ImGuiColorEditFlags_PickerHueBar; 1778 if (picker_mode == 2) flags |= ImGuiColorEditFlags_PickerHueWheel; 1779 if (display_mode == 1) flags |= ImGuiColorEditFlags_NoInputs; // Disable all RGB/HSV/Hex displays 1780 if (display_mode == 2) flags |= ImGuiColorEditFlags_DisplayRGB; // Override display mode 1781 if (display_mode == 3) flags |= ImGuiColorEditFlags_DisplayHSV; 1782 if (display_mode == 4) flags |= ImGuiColorEditFlags_DisplayHex; 1783 ImGui::ColorPicker4("MyColor##4", (float*)&color, flags, ref_color ? &ref_color_v.x : NULL); 1784 1785 ImGui::Text("Set defaults in code:"); 1786 ImGui::SameLine(); HelpMarker( 1787 "SetColorEditOptions() is designed to allow you to set boot-time default.\n" 1788 "We don't have Push/Pop functions because you can force options on a per-widget basis if needed," 1789 "and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid" 1790 "encouraging you to persistently save values that aren't forward-compatible."); 1791 if (ImGui::Button("Default: Uint8 + HSV + Hue Bar")) 1792 ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_PickerHueBar); 1793 if (ImGui::Button("Default: Float + HDR + Hue Wheel")) 1794 ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel); 1795 1796 // HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0) 1797 static ImVec4 color_hsv(0.23f, 1.0f, 1.0f, 1.0f); // Stored as HSV! 1798 ImGui::Spacing(); 1799 ImGui::Text("HSV encoded colors"); 1800 ImGui::SameLine(); HelpMarker( 1801 "By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV" 1802 "allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV. This comes with the" 1803 "added benefit that you can manipulate hue values with the picker even when saturation or value are zero."); 1804 ImGui::Text("Color widget with InputHSV:"); 1805 ImGui::ColorEdit4("HSV shown as RGB##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float); 1806 ImGui::ColorEdit4("HSV shown as HSV##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float); 1807 ImGui::DragFloat4("Raw HSV values", (float*)&color_hsv, 0.01f, 0.0f, 1.0f); 1808 1809 ImGui::TreePop(); 1810 } 1811 1812 if (ImGui::TreeNode("Drag/Slider Flags")) 1813 { 1814 // Demonstrate using advanced flags for DragXXX and SliderXXX functions. Note that the flags are the same! 1815 static ImGuiSliderFlags flags = ImGuiSliderFlags_None; 1816 ImGui::CheckboxFlags("ImGuiSliderFlags_AlwaysClamp", &flags, ImGuiSliderFlags_AlwaysClamp); 1817 ImGui::SameLine(); HelpMarker("Always clamp value to min/max bounds (if any) when input manually with CTRL+Click."); 1818 ImGui::CheckboxFlags("ImGuiSliderFlags_Logarithmic", &flags, ImGuiSliderFlags_Logarithmic); 1819 ImGui::SameLine(); HelpMarker("Enable logarithmic editing (more precision for small values)."); 1820 ImGui::CheckboxFlags("ImGuiSliderFlags_NoRoundToFormat", &flags, ImGuiSliderFlags_NoRoundToFormat); 1821 ImGui::SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits)."); 1822 ImGui::CheckboxFlags("ImGuiSliderFlags_NoInput", &flags, ImGuiSliderFlags_NoInput); 1823 ImGui::SameLine(); HelpMarker("Disable CTRL+Click or Enter key allowing to input text directly into the widget."); 1824 1825 // Drags 1826 static float drag_f = 0.5f; 1827 static int drag_i = 50; 1828 ImGui::Text("Underlying float value: %f", drag_f); 1829 ImGui::DragFloat("DragFloat (0 -> 1)", &drag_f, 0.005f, 0.0f, 1.0f, "%.3f", flags); 1830 ImGui::DragFloat("DragFloat (0 -> +inf)", &drag_f, 0.005f, 0.0f, FLT_MAX, "%.3f", flags); 1831 ImGui::DragFloat("DragFloat (-inf -> 1)", &drag_f, 0.005f, -FLT_MAX, 1.0f, "%.3f", flags); 1832 ImGui::DragFloat("DragFloat (-inf -> +inf)", &drag_f, 0.005f, -FLT_MAX, +FLT_MAX, "%.3f", flags); 1833 ImGui::DragInt("DragInt (0 -> 100)", &drag_i, 0.5f, 0, 100, "%d", flags); 1834 1835 // Sliders 1836 static float slider_f = 0.5f; 1837 static int slider_i = 50; 1838 ImGui::Text("Underlying float value: %f", slider_f); 1839 ImGui::SliderFloat("SliderFloat (0 -> 1)", &slider_f, 0.0f, 1.0f, "%.3f", flags); 1840 ImGui::SliderInt("SliderInt (0 -> 100)", &slider_i, 0, 100, "%d", flags); 1841 1842 ImGui::TreePop(); 1843 } 1844 1845 if (ImGui::TreeNode("Range Widgets")) 1846 { 1847 static float begin = 10, end = 90; 1848 static int begin_i = 100, end_i = 1000; 1849 ImGui::DragFloatRange2("range float", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%", ImGuiSliderFlags_AlwaysClamp); 1850 ImGui::DragIntRange2("range int", &begin_i, &end_i, 5, 0, 1000, "Min: %d units", "Max: %d units"); 1851 ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %d units", "Max: %d units"); 1852 ImGui::TreePop(); 1853 } 1854 1855 if (ImGui::TreeNode("Data Types")) 1856 { 1857 // DragScalar/InputScalar/SliderScalar functions allow various data types 1858 // - signed/unsigned 1859 // - 8/16/32/64-bits 1860 // - integer/float/double 1861 // To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum 1862 // to pass the type, and passing all arguments by pointer. 1863 // This is the reason the test code below creates local variables to hold "zero" "one" etc. for each types. 1864 // In practice, if you frequently use a given type that is not covered by the normal API entry points, 1865 // you can wrap it yourself inside a 1 line function which can take typed argument as value instead of void*, 1866 // and then pass their address to the generic function. For example: 1867 // bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld") 1868 // { 1869 // return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format); 1870 // } 1871 1872 // Setup limits (as helper variables so we can take their address, as explained above) 1873 // Note: SliderScalar() functions have a maximum usable range of half the natural type maximum, hence the /2. 1874 #ifndef LLONG_MIN 1875 ImS64 LLONG_MIN = -9223372036854775807LL - 1; 1876 ImS64 LLONG_MAX = 9223372036854775807LL; 1877 ImU64 ULLONG_MAX = (2ULL * 9223372036854775807LL + 1); 1878 #endif 1879 const char s8_zero = 0, s8_one = 1, s8_fifty = 50, s8_min = -128, s8_max = 127; 1880 const ImU8 u8_zero = 0, u8_one = 1, u8_fifty = 50, u8_min = 0, u8_max = 255; 1881 const short s16_zero = 0, s16_one = 1, s16_fifty = 50, s16_min = -32768, s16_max = 32767; 1882 const ImU16 u16_zero = 0, u16_one = 1, u16_fifty = 50, u16_min = 0, u16_max = 65535; 1883 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; 1884 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; 1885 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; 1886 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; 1887 const float f32_zero = 0.f, f32_one = 1.f, f32_lo_a = -10000000000.0f, f32_hi_a = +10000000000.0f; 1888 const double f64_zero = 0., f64_one = 1., f64_lo_a = -1000000000000000.0, f64_hi_a = +1000000000000000.0; 1889 1890 // State 1891 static char s8_v = 127; 1892 static ImU8 u8_v = 255; 1893 static short s16_v = 32767; 1894 static ImU16 u16_v = 65535; 1895 static ImS32 s32_v = -1; 1896 static ImU32 u32_v = (ImU32)-1; 1897 static ImS64 s64_v = -1; 1898 static ImU64 u64_v = (ImU64)-1; 1899 static float f32_v = 0.123f; 1900 static double f64_v = 90000.01234567890123456789; 1901 1902 const float drag_speed = 0.2f; 1903 static bool drag_clamp = false; 1904 ImGui::Text("Drags:"); 1905 ImGui::Checkbox("Clamp integers to 0..50", &drag_clamp); 1906 ImGui::SameLine(); HelpMarker( 1907 "As with every widgets in dear imgui, we never modify values unless there is a user interaction.\n" 1908 "You can override the clamping limits by using CTRL+Click to input a value."); 1909 ImGui::DragScalar("drag s8", ImGuiDataType_S8, &s8_v, drag_speed, drag_clamp ? &s8_zero : NULL, drag_clamp ? &s8_fifty : NULL); 1910 ImGui::DragScalar("drag u8", ImGuiDataType_U8, &u8_v, drag_speed, drag_clamp ? &u8_zero : NULL, drag_clamp ? &u8_fifty : NULL, "%u ms"); 1911 ImGui::DragScalar("drag s16", ImGuiDataType_S16, &s16_v, drag_speed, drag_clamp ? &s16_zero : NULL, drag_clamp ? &s16_fifty : NULL); 1912 ImGui::DragScalar("drag u16", ImGuiDataType_U16, &u16_v, drag_speed, drag_clamp ? &u16_zero : NULL, drag_clamp ? &u16_fifty : NULL, "%u ms"); 1913 ImGui::DragScalar("drag s32", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL); 1914 ImGui::DragScalar("drag u32", ImGuiDataType_U32, &u32_v, drag_speed, drag_clamp ? &u32_zero : NULL, drag_clamp ? &u32_fifty : NULL, "%u ms"); 1915 ImGui::DragScalar("drag s64", ImGuiDataType_S64, &s64_v, drag_speed, drag_clamp ? &s64_zero : NULL, drag_clamp ? &s64_fifty : NULL); 1916 ImGui::DragScalar("drag u64", ImGuiDataType_U64, &u64_v, drag_speed, drag_clamp ? &u64_zero : NULL, drag_clamp ? &u64_fifty : NULL); 1917 ImGui::DragScalar("drag float", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f"); 1918 ImGui::DragScalar("drag float log", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f", ImGuiSliderFlags_Logarithmic); 1919 ImGui::DragScalar("drag double", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, NULL, "%.10f grams"); 1920 ImGui::DragScalar("drag double log",ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", ImGuiSliderFlags_Logarithmic); 1921 1922 ImGui::Text("Sliders"); 1923 ImGui::SliderScalar("slider s8 full", ImGuiDataType_S8, &s8_v, &s8_min, &s8_max, "%d"); 1924 ImGui::SliderScalar("slider u8 full", ImGuiDataType_U8, &u8_v, &u8_min, &u8_max, "%u"); 1925 ImGui::SliderScalar("slider s16 full", ImGuiDataType_S16, &s16_v, &s16_min, &s16_max, "%d"); 1926 ImGui::SliderScalar("slider u16 full", ImGuiDataType_U16, &u16_v, &u16_min, &u16_max, "%u"); 1927 ImGui::SliderScalar("slider s32 low", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty,"%d"); 1928 ImGui::SliderScalar("slider s32 high", ImGuiDataType_S32, &s32_v, &s32_hi_a, &s32_hi_b, "%d"); 1929 ImGui::SliderScalar("slider s32 full", ImGuiDataType_S32, &s32_v, &s32_min, &s32_max, "%d"); 1930 ImGui::SliderScalar("slider u32 low", ImGuiDataType_U32, &u32_v, &u32_zero, &u32_fifty,"%u"); 1931 ImGui::SliderScalar("slider u32 high", ImGuiDataType_U32, &u32_v, &u32_hi_a, &u32_hi_b, "%u"); 1932 ImGui::SliderScalar("slider u32 full", ImGuiDataType_U32, &u32_v, &u32_min, &u32_max, "%u"); 1933 ImGui::SliderScalar("slider s64 low", ImGuiDataType_S64, &s64_v, &s64_zero, &s64_fifty,"%" IM_PRId64); 1934 ImGui::SliderScalar("slider s64 high", ImGuiDataType_S64, &s64_v, &s64_hi_a, &s64_hi_b, "%" IM_PRId64); 1935 ImGui::SliderScalar("slider s64 full", ImGuiDataType_S64, &s64_v, &s64_min, &s64_max, "%" IM_PRId64); 1936 ImGui::SliderScalar("slider u64 low", ImGuiDataType_U64, &u64_v, &u64_zero, &u64_fifty,"%" IM_PRIu64 " ms"); 1937 ImGui::SliderScalar("slider u64 high", ImGuiDataType_U64, &u64_v, &u64_hi_a, &u64_hi_b, "%" IM_PRIu64 " ms"); 1938 ImGui::SliderScalar("slider u64 full", ImGuiDataType_U64, &u64_v, &u64_min, &u64_max, "%" IM_PRIu64 " ms"); 1939 ImGui::SliderScalar("slider float low", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one); 1940 ImGui::SliderScalar("slider float low log", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one, "%.10f", ImGuiSliderFlags_Logarithmic); 1941 ImGui::SliderScalar("slider float high", ImGuiDataType_Float, &f32_v, &f32_lo_a, &f32_hi_a, "%e"); 1942 ImGui::SliderScalar("slider double low", ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f grams"); 1943 ImGui::SliderScalar("slider double low log",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f", ImGuiSliderFlags_Logarithmic); 1944 ImGui::SliderScalar("slider double high", ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams"); 1945 1946 ImGui::Text("Sliders (reverse)"); 1947 ImGui::SliderScalar("slider s8 reverse", ImGuiDataType_S8, &s8_v, &s8_max, &s8_min, "%d"); 1948 ImGui::SliderScalar("slider u8 reverse", ImGuiDataType_U8, &u8_v, &u8_max, &u8_min, "%u"); 1949 ImGui::SliderScalar("slider s32 reverse", ImGuiDataType_S32, &s32_v, &s32_fifty, &s32_zero, "%d"); 1950 ImGui::SliderScalar("slider u32 reverse", ImGuiDataType_U32, &u32_v, &u32_fifty, &u32_zero, "%u"); 1951 ImGui::SliderScalar("slider s64 reverse", ImGuiDataType_S64, &s64_v, &s64_fifty, &s64_zero, "%" IM_PRId64); 1952 ImGui::SliderScalar("slider u64 reverse", ImGuiDataType_U64, &u64_v, &u64_fifty, &u64_zero, "%" IM_PRIu64 " ms"); 1953 1954 static bool inputs_step = true; 1955 ImGui::Text("Inputs"); 1956 ImGui::Checkbox("Show step buttons", &inputs_step); 1957 ImGui::InputScalar("input s8", ImGuiDataType_S8, &s8_v, inputs_step ? &s8_one : NULL, NULL, "%d"); 1958 ImGui::InputScalar("input u8", ImGuiDataType_U8, &u8_v, inputs_step ? &u8_one : NULL, NULL, "%u"); 1959 ImGui::InputScalar("input s16", ImGuiDataType_S16, &s16_v, inputs_step ? &s16_one : NULL, NULL, "%d"); 1960 ImGui::InputScalar("input u16", ImGuiDataType_U16, &u16_v, inputs_step ? &u16_one : NULL, NULL, "%u"); 1961 ImGui::InputScalar("input s32", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%d"); 1962 ImGui::InputScalar("input s32 hex", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%08X", ImGuiInputTextFlags_CharsHexadecimal); 1963 ImGui::InputScalar("input u32", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%u"); 1964 ImGui::InputScalar("input u32 hex", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%08X", ImGuiInputTextFlags_CharsHexadecimal); 1965 ImGui::InputScalar("input s64", ImGuiDataType_S64, &s64_v, inputs_step ? &s64_one : NULL); 1966 ImGui::InputScalar("input u64", ImGuiDataType_U64, &u64_v, inputs_step ? &u64_one : NULL); 1967 ImGui::InputScalar("input float", ImGuiDataType_Float, &f32_v, inputs_step ? &f32_one : NULL); 1968 ImGui::InputScalar("input double", ImGuiDataType_Double, &f64_v, inputs_step ? &f64_one : NULL); 1969 1970 ImGui::TreePop(); 1971 } 1972 1973 if (ImGui::TreeNode("Multi-component Widgets")) 1974 { 1975 static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; 1976 static int vec4i[4] = { 1, 5, 100, 255 }; 1977 1978 ImGui::InputFloat2("input float2", vec4f); 1979 ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f); 1980 ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f); 1981 ImGui::InputInt2("input int2", vec4i); 1982 ImGui::DragInt2("drag int2", vec4i, 1, 0, 255); 1983 ImGui::SliderInt2("slider int2", vec4i, 0, 255); 1984 ImGui::Spacing(); 1985 1986 ImGui::InputFloat3("input float3", vec4f); 1987 ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f); 1988 ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f); 1989 ImGui::InputInt3("input int3", vec4i); 1990 ImGui::DragInt3("drag int3", vec4i, 1, 0, 255); 1991 ImGui::SliderInt3("slider int3", vec4i, 0, 255); 1992 ImGui::Spacing(); 1993 1994 ImGui::InputFloat4("input float4", vec4f); 1995 ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f); 1996 ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f); 1997 ImGui::InputInt4("input int4", vec4i); 1998 ImGui::DragInt4("drag int4", vec4i, 1, 0, 255); 1999 ImGui::SliderInt4("slider int4", vec4i, 0, 255); 2000 2001 ImGui::TreePop(); 2002 } 2003 2004 if (ImGui::TreeNode("Vertical Sliders")) 2005 { 2006 const float spacing = 4; 2007 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing)); 2008 2009 static int int_value = 0; 2010 ImGui::VSliderInt("##int", ImVec2(18, 160), &int_value, 0, 5); 2011 ImGui::SameLine(); 2012 2013 static float values[7] = { 0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f }; 2014 ImGui::PushID("set1"); 2015 for (int i = 0; i < 7; i++) 2016 { 2017 if (i > 0) ImGui::SameLine(); 2018 ImGui::PushID(i); 2019 ImGui::PushStyleColor(ImGuiCol_FrameBg, (ImVec4)ImColor::HSV(i / 7.0f, 0.5f, 0.5f)); 2020 ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.5f)); 2021 ImGui::PushStyleColor(ImGuiCol_FrameBgActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.5f)); 2022 ImGui::PushStyleColor(ImGuiCol_SliderGrab, (ImVec4)ImColor::HSV(i / 7.0f, 0.9f, 0.9f)); 2023 ImGui::VSliderFloat("##v", ImVec2(18, 160), &values[i], 0.0f, 1.0f, ""); 2024 if (ImGui::IsItemActive() || ImGui::IsItemHovered()) 2025 ImGui::SetTooltip("%.3f", values[i]); 2026 ImGui::PopStyleColor(4); 2027 ImGui::PopID(); 2028 } 2029 ImGui::PopID(); 2030 2031 ImGui::SameLine(); 2032 ImGui::PushID("set2"); 2033 static float values2[4] = { 0.20f, 0.80f, 0.40f, 0.25f }; 2034 const int rows = 3; 2035 const ImVec2 small_slider_size(18, (float)(int)((160.0f - (rows - 1) * spacing) / rows)); 2036 for (int nx = 0; nx < 4; nx++) 2037 { 2038 if (nx > 0) ImGui::SameLine(); 2039 ImGui::BeginGroup(); 2040 for (int ny = 0; ny < rows; ny++) 2041 { 2042 ImGui::PushID(nx * rows + ny); 2043 ImGui::VSliderFloat("##v", small_slider_size, &values2[nx], 0.0f, 1.0f, ""); 2044 if (ImGui::IsItemActive() || ImGui::IsItemHovered()) 2045 ImGui::SetTooltip("%.3f", values2[nx]); 2046 ImGui::PopID(); 2047 } 2048 ImGui::EndGroup(); 2049 } 2050 ImGui::PopID(); 2051 2052 ImGui::SameLine(); 2053 ImGui::PushID("set3"); 2054 for (int i = 0; i < 4; i++) 2055 { 2056 if (i > 0) ImGui::SameLine(); 2057 ImGui::PushID(i); 2058 ImGui::PushStyleVar(ImGuiStyleVar_GrabMinSize, 40); 2059 ImGui::VSliderFloat("##v", ImVec2(40, 160), &values[i], 0.0f, 1.0f, "%.2f\nsec"); 2060 ImGui::PopStyleVar(); 2061 ImGui::PopID(); 2062 } 2063 ImGui::PopID(); 2064 ImGui::PopStyleVar(); 2065 ImGui::TreePop(); 2066 } 2067 2068 if (ImGui::TreeNode("Drag and Drop")) 2069 { 2070 if (ImGui::TreeNode("Drag and drop in standard widgets")) 2071 { 2072 // ColorEdit widgets automatically act as drag source and drag target. 2073 // They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F 2074 // to allow your own widgets to use colors in their drag and drop interaction. 2075 // Also see 'Demo->Widgets->Color/Picker Widgets->Palette' demo. 2076 HelpMarker("You can drag from the color squares."); 2077 static float col1[3] = { 1.0f, 0.0f, 0.2f }; 2078 static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f }; 2079 ImGui::ColorEdit3("color 1", col1); 2080 ImGui::ColorEdit4("color 2", col2); 2081 ImGui::TreePop(); 2082 } 2083 2084 if (ImGui::TreeNode("Drag and drop to copy/swap items")) 2085 { 2086 enum Mode 2087 { 2088 Mode_Copy, 2089 Mode_Move, 2090 Mode_Swap 2091 }; 2092 static int mode = 0; 2093 if (ImGui::RadioButton("Copy", mode == Mode_Copy)) { mode = Mode_Copy; } ImGui::SameLine(); 2094 if (ImGui::RadioButton("Move", mode == Mode_Move)) { mode = Mode_Move; } ImGui::SameLine(); 2095 if (ImGui::RadioButton("Swap", mode == Mode_Swap)) { mode = Mode_Swap; } 2096 static const char* names[9] = 2097 { 2098 "Bobby", "Beatrice", "Betty", 2099 "Brianna", "Barry", "Bernard", 2100 "Bibi", "Blaine", "Bryn" 2101 }; 2102 for (int n = 0; n < IM_ARRAYSIZE(names); n++) 2103 { 2104 ImGui::PushID(n); 2105 if ((n % 3) != 0) 2106 ImGui::SameLine(); 2107 ImGui::Button(names[n], ImVec2(60, 60)); 2108 2109 // Our buttons are both drag sources and drag targets here! 2110 if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) 2111 { 2112 // Set payload to carry the index of our item (could be anything) 2113 ImGui::SetDragDropPayload("DND_DEMO_CELL", &n, sizeof(int)); 2114 2115 // Display preview (could be anything, e.g. when dragging an image we could decide to display 2116 // the filename and a small preview of the image, etc.) 2117 if (mode == Mode_Copy) { ImGui::Text("Copy %s", names[n]); } 2118 if (mode == Mode_Move) { ImGui::Text("Move %s", names[n]); } 2119 if (mode == Mode_Swap) { ImGui::Text("Swap %s", names[n]); } 2120 ImGui::EndDragDropSource(); 2121 } 2122 if (ImGui::BeginDragDropTarget()) 2123 { 2124 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DND_DEMO_CELL")) 2125 { 2126 IM_ASSERT(payload->DataSize == sizeof(int)); 2127 int payload_n = *(const int*)payload->Data; 2128 if (mode == Mode_Copy) 2129 { 2130 names[n] = names[payload_n]; 2131 } 2132 if (mode == Mode_Move) 2133 { 2134 names[n] = names[payload_n]; 2135 names[payload_n] = ""; 2136 } 2137 if (mode == Mode_Swap) 2138 { 2139 const char* tmp = names[n]; 2140 names[n] = names[payload_n]; 2141 names[payload_n] = tmp; 2142 } 2143 } 2144 ImGui::EndDragDropTarget(); 2145 } 2146 ImGui::PopID(); 2147 } 2148 ImGui::TreePop(); 2149 } 2150 2151 if (ImGui::TreeNode("Drag to reorder items (simple)")) 2152 { 2153 // Simple reordering 2154 HelpMarker( 2155 "We don't use the drag and drop api at all here! " 2156 "Instead we query when the item is held but not hovered, and order items accordingly."); 2157 static const char* item_names[] = { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" }; 2158 for (int n = 0; n < IM_ARRAYSIZE(item_names); n++) 2159 { 2160 const char* item = item_names[n]; 2161 ImGui::Selectable(item); 2162 2163 if (ImGui::IsItemActive() && !ImGui::IsItemHovered()) 2164 { 2165 int n_next = n + (ImGui::GetMouseDragDelta(0).y < 0.f ? -1 : 1); 2166 if (n_next >= 0 && n_next < IM_ARRAYSIZE(item_names)) 2167 { 2168 item_names[n] = item_names[n_next]; 2169 item_names[n_next] = item; 2170 ImGui::ResetMouseDragDelta(); 2171 } 2172 } 2173 } 2174 ImGui::TreePop(); 2175 } 2176 2177 ImGui::TreePop(); 2178 } 2179 2180 if (ImGui::TreeNode("Querying Status (Edited/Active/Focused/Hovered etc.)")) 2181 { 2182 // Select an item type 2183 const char* item_names[] = 2184 { 2185 "Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputFloat", 2186 "InputFloat3", "ColorEdit4", "MenuItem", "TreeNode", "TreeNode (w/ double-click)", "Combo", "ListBox" 2187 }; 2188 static int item_type = 1; 2189 ImGui::Combo("Item Type", &item_type, item_names, IM_ARRAYSIZE(item_names), IM_ARRAYSIZE(item_names)); 2190 ImGui::SameLine(); 2191 HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions. Note that the bool return value of most ImGui function is generally equivalent to calling ImGui::IsItemHovered()."); 2192 2193 // Submit selected item item so we can query their status in the code following it. 2194 bool ret = false; 2195 static bool b = false; 2196 static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f }; 2197 static char str[16] = {}; 2198 if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction 2199 if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); } // Testing button 2200 if (item_type == 2) { ImGui::PushButtonRepeat(true); ret = ImGui::Button("ITEM: Button"); ImGui::PopButtonRepeat(); } // Testing button (with repeater) 2201 if (item_type == 3) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); } // Testing checkbox 2202 if (item_type == 4) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item 2203 if (item_type == 5) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which handles tabbing) 2204 if (item_type == 6) { ret = ImGui::InputFloat("ITEM: InputFloat", col4f, 1.0f); } // Testing +/- buttons on scalar input 2205 if (item_type == 7) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) 2206 if (item_type == 8) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) 2207 if (item_type == 9) { ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy) 2208 if (item_type == 10){ ret = ImGui::TreeNode("ITEM: TreeNode"); if (ret) ImGui::TreePop(); } // Testing tree node 2209 if (item_type == 11){ ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy. 2210 if (item_type == 12){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::Combo("ITEM: Combo", ¤t, items, IM_ARRAYSIZE(items)); } 2211 if (item_type == 13){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", ¤t, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); } 2212 2213 // Display the values of IsItemHovered() and other common item state functions. 2214 // Note that the ImGuiHoveredFlags_XXX flags can be combined. 2215 // Because BulletText is an item itself and that would affect the output of IsItemXXX functions, 2216 // we query every state in a single call to avoid storing them and to simplify the code. 2217 ImGui::BulletText( 2218 "Return value = %d\n" 2219 "IsItemFocused() = %d\n" 2220 "IsItemHovered() = %d\n" 2221 "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n" 2222 "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n" 2223 "IsItemHovered(_AllowWhenOverlapped) = %d\n" 2224 "IsItemHovered(_RectOnly) = %d\n" 2225 "IsItemActive() = %d\n" 2226 "IsItemEdited() = %d\n" 2227 "IsItemActivated() = %d\n" 2228 "IsItemDeactivated() = %d\n" 2229 "IsItemDeactivatedAfterEdit() = %d\n" 2230 "IsItemVisible() = %d\n" 2231 "IsItemClicked() = %d\n" 2232 "IsItemToggledOpen() = %d\n" 2233 "GetItemRectMin() = (%.1f, %.1f)\n" 2234 "GetItemRectMax() = (%.1f, %.1f)\n" 2235 "GetItemRectSize() = (%.1f, %.1f)", 2236 ret, 2237 ImGui::IsItemFocused(), 2238 ImGui::IsItemHovered(), 2239 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), 2240 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), 2241 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlapped), 2242 ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly), 2243 ImGui::IsItemActive(), 2244 ImGui::IsItemEdited(), 2245 ImGui::IsItemActivated(), 2246 ImGui::IsItemDeactivated(), 2247 ImGui::IsItemDeactivatedAfterEdit(), 2248 ImGui::IsItemVisible(), 2249 ImGui::IsItemClicked(), 2250 ImGui::IsItemToggledOpen(), 2251 ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y, 2252 ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y, 2253 ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y 2254 ); 2255 2256 static bool embed_all_inside_a_child_window = false; 2257 ImGui::Checkbox("Embed everything inside a child window (for additional testing)", &embed_all_inside_a_child_window); 2258 if (embed_all_inside_a_child_window) 2259 ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20.0f), true); 2260 2261 // Testing IsWindowFocused() function with its various flags. 2262 // Note that the ImGuiFocusedFlags_XXX flags can be combined. 2263 ImGui::BulletText( 2264 "IsWindowFocused() = %d\n" 2265 "IsWindowFocused(_ChildWindows) = %d\n" 2266 "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n" 2267 "IsWindowFocused(_RootWindow) = %d\n" 2268 "IsWindowFocused(_AnyWindow) = %d\n", 2269 ImGui::IsWindowFocused(), 2270 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows), 2271 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow), 2272 ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow), 2273 ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow)); 2274 2275 // Testing IsWindowHovered() function with its various flags. 2276 // Note that the ImGuiHoveredFlags_XXX flags can be combined. 2277 ImGui::BulletText( 2278 "IsWindowHovered() = %d\n" 2279 "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n" 2280 "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n" 2281 "IsWindowHovered(_ChildWindows) = %d\n" 2282 "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n" 2283 "IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n" 2284 "IsWindowHovered(_RootWindow) = %d\n" 2285 "IsWindowHovered(_AnyWindow) = %d\n", 2286 ImGui::IsWindowHovered(), 2287 ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), 2288 ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), 2289 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows), 2290 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow), 2291 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup), 2292 ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow), 2293 ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)); 2294 2295 ImGui::BeginChild("child", ImVec2(0, 50), true); 2296 ImGui::Text("This is another child window for testing the _ChildWindows flag."); 2297 ImGui::EndChild(); 2298 if (embed_all_inside_a_child_window) 2299 ImGui::EndChild(); 2300 2301 static char unused_str[] = "This widget is only here to be able to tab-out of the widgets above."; 2302 ImGui::InputText("unused", unused_str, IM_ARRAYSIZE(unused_str), ImGuiInputTextFlags_ReadOnly); 2303 2304 // Calling IsItemHovered() after begin returns the hovered status of the title bar. 2305 // This is useful in particular if you want to create a context menu associated to the title bar of a window. 2306 static bool test_window = false; 2307 ImGui::Checkbox("Hovered/Active tests after Begin() for title bar testing", &test_window); 2308 if (test_window) 2309 { 2310 ImGui::Begin("Title bar Hovered/Active tests", &test_window); 2311 if (ImGui::BeginPopupContextItem()) // <-- This is using IsItemHovered() 2312 { 2313 if (ImGui::MenuItem("Close")) { test_window = false; } 2314 ImGui::EndPopup(); 2315 } 2316 ImGui::Text( 2317 "IsItemHovered() after begin = %d (== is title bar hovered)\n" 2318 "IsItemActive() after begin = %d (== is window being clicked/moved)\n", 2319 ImGui::IsItemHovered(), ImGui::IsItemActive()); 2320 ImGui::End(); 2321 } 2322 2323 ImGui::TreePop(); 2324 } 2325 } 2326 2327 static void ShowDemoWindowLayout() 2328 { 2329 if (!ImGui::CollapsingHeader("Layout & Scrolling")) 2330 return; 2331 2332 if (ImGui::TreeNode("Child windows")) 2333 { 2334 HelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window."); 2335 static bool disable_mouse_wheel = false; 2336 static bool disable_menu = false; 2337 ImGui::Checkbox("Disable Mouse Wheel", &disable_mouse_wheel); 2338 ImGui::Checkbox("Disable Menu", &disable_menu); 2339 2340 // Child 1: no border, enable horizontal scrollbar 2341 { 2342 ImGuiWindowFlags window_flags = ImGuiWindowFlags_HorizontalScrollbar; 2343 if (disable_mouse_wheel) 2344 window_flags |= ImGuiWindowFlags_NoScrollWithMouse; 2345 ImGui::BeginChild("ChildL", ImVec2(ImGui::GetWindowContentRegionWidth() * 0.5f, 260), false, window_flags); 2346 for (int i = 0; i < 100; i++) 2347 ImGui::Text("%04d: scrollable region", i); 2348 ImGui::EndChild(); 2349 } 2350 2351 ImGui::SameLine(); 2352 2353 // Child 2: rounded border 2354 { 2355 ImGuiWindowFlags window_flags = ImGuiWindowFlags_None; 2356 if (disable_mouse_wheel) 2357 window_flags |= ImGuiWindowFlags_NoScrollWithMouse; 2358 if (!disable_menu) 2359 window_flags |= ImGuiWindowFlags_MenuBar; 2360 ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f); 2361 ImGui::BeginChild("ChildR", ImVec2(0, 260), true, window_flags); 2362 if (!disable_menu && ImGui::BeginMenuBar()) 2363 { 2364 if (ImGui::BeginMenu("Menu")) 2365 { 2366 ShowExampleMenuFile(); 2367 ImGui::EndMenu(); 2368 } 2369 ImGui::EndMenuBar(); 2370 } 2371 if (ImGui::BeginTable("split", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings)) 2372 { 2373 for (int i = 0; i < 100; i++) 2374 { 2375 char buf[32]; 2376 sprintf(buf, "%03d", i); 2377 ImGui::TableNextColumn(); 2378 ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f)); 2379 } 2380 ImGui::EndTable(); 2381 } 2382 ImGui::EndChild(); 2383 ImGui::PopStyleVar(); 2384 } 2385 2386 ImGui::Separator(); 2387 2388 // Demonstrate a few extra things 2389 // - Changing ImGuiCol_ChildBg (which is transparent black in default styles) 2390 // - Using SetCursorPos() to position child window (the child window is an item from the POV of parent window) 2391 // You can also call SetNextWindowPos() to position the child window. The parent window will effectively 2392 // layout from this position. 2393 // - Using ImGui::GetItemRectMin/Max() to query the "item" state (because the child window is an item from 2394 // the POV of the parent window). See 'Demo->Querying Status (Active/Focused/Hovered etc.)' for details. 2395 { 2396 static int offset_x = 0; 2397 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); 2398 ImGui::DragInt("Offset X", &offset_x, 1.0f, -1000, 1000); 2399 2400 ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (float)offset_x); 2401 ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(255, 0, 0, 100)); 2402 ImGui::BeginChild("Red", ImVec2(200, 100), true, ImGuiWindowFlags_None); 2403 for (int n = 0; n < 50; n++) 2404 ImGui::Text("Some test %d", n); 2405 ImGui::EndChild(); 2406 bool child_is_hovered = ImGui::IsItemHovered(); 2407 ImVec2 child_rect_min = ImGui::GetItemRectMin(); 2408 ImVec2 child_rect_max = ImGui::GetItemRectMax(); 2409 ImGui::PopStyleColor(); 2410 ImGui::Text("Hovered: %d", child_is_hovered); 2411 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); 2412 } 2413 2414 ImGui::TreePop(); 2415 } 2416 2417 if (ImGui::TreeNode("Widgets Width")) 2418 { 2419 static float f = 0.0f; 2420 static bool show_indented_items = true; 2421 ImGui::Checkbox("Show indented items", &show_indented_items); 2422 2423 // Use SetNextItemWidth() to set the width of a single upcoming item. 2424 // Use PushItemWidth()/PopItemWidth() to set the width of a group of items. 2425 // In real code use you'll probably want to choose width values that are proportional to your font size 2426 // e.g. Using '20.0f * GetFontSize()' as width instead of '200.0f', etc. 2427 2428 ImGui::Text("SetNextItemWidth/PushItemWidth(100)"); 2429 ImGui::SameLine(); HelpMarker("Fixed width."); 2430 ImGui::PushItemWidth(100); 2431 ImGui::DragFloat("float##1b", &f); 2432 if (show_indented_items) 2433 { 2434 ImGui::Indent(); 2435 ImGui::DragFloat("float (indented)##1b", &f); 2436 ImGui::Unindent(); 2437 } 2438 ImGui::PopItemWidth(); 2439 2440 ImGui::Text("SetNextItemWidth/PushItemWidth(-100)"); 2441 ImGui::SameLine(); HelpMarker("Align to right edge minus 100"); 2442 ImGui::PushItemWidth(-100); 2443 ImGui::DragFloat("float##2a", &f); 2444 if (show_indented_items) 2445 { 2446 ImGui::Indent(); 2447 ImGui::DragFloat("float (indented)##2b", &f); 2448 ImGui::Unindent(); 2449 } 2450 ImGui::PopItemWidth(); 2451 2452 ImGui::Text("SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)"); 2453 ImGui::SameLine(); HelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)"); 2454 ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * 0.5f); 2455 ImGui::DragFloat("float##3a", &f); 2456 if (show_indented_items) 2457 { 2458 ImGui::Indent(); 2459 ImGui::DragFloat("float (indented)##3b", &f); 2460 ImGui::Unindent(); 2461 } 2462 ImGui::PopItemWidth(); 2463 2464 ImGui::Text("SetNextItemWidth/PushItemWidth(-GetContentRegionAvail().x * 0.5f)"); 2465 ImGui::SameLine(); HelpMarker("Align to right edge minus half"); 2466 ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.5f); 2467 ImGui::DragFloat("float##4a", &f); 2468 if (show_indented_items) 2469 { 2470 ImGui::Indent(); 2471 ImGui::DragFloat("float (indented)##4b", &f); 2472 ImGui::Unindent(); 2473 } 2474 ImGui::PopItemWidth(); 2475 2476 // Demonstrate using PushItemWidth to surround three items. 2477 // Calling SetNextItemWidth() before each of them would have the same effect. 2478 ImGui::Text("SetNextItemWidth/PushItemWidth(-FLT_MIN)"); 2479 ImGui::SameLine(); HelpMarker("Align to right edge"); 2480 ImGui::PushItemWidth(-FLT_MIN); 2481 ImGui::DragFloat("##float5a", &f); 2482 if (show_indented_items) 2483 { 2484 ImGui::Indent(); 2485 ImGui::DragFloat("float (indented)##5b", &f); 2486 ImGui::Unindent(); 2487 } 2488 ImGui::PopItemWidth(); 2489 2490 ImGui::TreePop(); 2491 } 2492 2493 if (ImGui::TreeNode("Basic Horizontal Layout")) 2494 { 2495 ImGui::TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)"); 2496 2497 // Text 2498 ImGui::Text("Two items: Hello"); ImGui::SameLine(); 2499 ImGui::TextColored(ImVec4(1,1,0,1), "Sailor"); 2500 2501 // Adjust spacing 2502 ImGui::Text("More spacing: Hello"); ImGui::SameLine(0, 20); 2503 ImGui::TextColored(ImVec4(1,1,0,1), "Sailor"); 2504 2505 // Button 2506 ImGui::AlignTextToFramePadding(); 2507 ImGui::Text("Normal buttons"); ImGui::SameLine(); 2508 ImGui::Button("Banana"); ImGui::SameLine(); 2509 ImGui::Button("Apple"); ImGui::SameLine(); 2510 ImGui::Button("Corniflower"); 2511 2512 // Button 2513 ImGui::Text("Small buttons"); ImGui::SameLine(); 2514 ImGui::SmallButton("Like this one"); ImGui::SameLine(); 2515 ImGui::Text("can fit within a text block."); 2516 2517 // Aligned to arbitrary position. Easy/cheap column. 2518 ImGui::Text("Aligned"); 2519 ImGui::SameLine(150); ImGui::Text("x=150"); 2520 ImGui::SameLine(300); ImGui::Text("x=300"); 2521 ImGui::Text("Aligned"); 2522 ImGui::SameLine(150); ImGui::SmallButton("x=150"); 2523 ImGui::SameLine(300); ImGui::SmallButton("x=300"); 2524 2525 // Checkbox 2526 static bool c1 = false, c2 = false, c3 = false, c4 = false; 2527 ImGui::Checkbox("My", &c1); ImGui::SameLine(); 2528 ImGui::Checkbox("Tailor", &c2); ImGui::SameLine(); 2529 ImGui::Checkbox("Is", &c3); ImGui::SameLine(); 2530 ImGui::Checkbox("Rich", &c4); 2531 2532 // Various 2533 static float f0 = 1.0f, f1 = 2.0f, f2 = 3.0f; 2534 ImGui::PushItemWidth(80); 2535 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD" }; 2536 static int item = -1; 2537 ImGui::Combo("Combo", &item, items, IM_ARRAYSIZE(items)); ImGui::SameLine(); 2538 ImGui::SliderFloat("X", &f0, 0.0f, 5.0f); ImGui::SameLine(); 2539 ImGui::SliderFloat("Y", &f1, 0.0f, 5.0f); ImGui::SameLine(); 2540 ImGui::SliderFloat("Z", &f2, 0.0f, 5.0f); 2541 ImGui::PopItemWidth(); 2542 2543 ImGui::PushItemWidth(80); 2544 ImGui::Text("Lists:"); 2545 static int selection[4] = { 0, 1, 2, 3 }; 2546 for (int i = 0; i < 4; i++) 2547 { 2548 if (i > 0) ImGui::SameLine(); 2549 ImGui::PushID(i); 2550 ImGui::ListBox("", &selection[i], items, IM_ARRAYSIZE(items)); 2551 ImGui::PopID(); 2552 //if (ImGui::IsItemHovered()) ImGui::SetTooltip("ListBox %d hovered", i); 2553 } 2554 ImGui::PopItemWidth(); 2555 2556 // Dummy 2557 ImVec2 button_sz(40, 40); 2558 ImGui::Button("A", button_sz); ImGui::SameLine(); 2559 ImGui::Dummy(button_sz); ImGui::SameLine(); 2560 ImGui::Button("B", button_sz); 2561 2562 // Manually wrapping 2563 // (we should eventually provide this as an automatic layout feature, but for now you can do it manually) 2564 ImGui::Text("Manually wrapping:"); 2565 ImGuiStyle& style = ImGui::GetStyle(); 2566 int buttons_count = 20; 2567 float window_visible_x2 = ImGui::GetWindowPos().x + ImGui::GetWindowContentRegionMax().x; 2568 for (int n = 0; n < buttons_count; n++) 2569 { 2570 ImGui::PushID(n); 2571 ImGui::Button("Box", button_sz); 2572 float last_button_x2 = ImGui::GetItemRectMax().x; 2573 float next_button_x2 = last_button_x2 + style.ItemSpacing.x + button_sz.x; // Expected position if next button was on same line 2574 if (n + 1 < buttons_count && next_button_x2 < window_visible_x2) 2575 ImGui::SameLine(); 2576 ImGui::PopID(); 2577 } 2578 2579 ImGui::TreePop(); 2580 } 2581 2582 if (ImGui::TreeNode("Groups")) 2583 { 2584 HelpMarker( 2585 "BeginGroup() basically locks the horizontal position for new line. " 2586 "EndGroup() bundles the whole group so that you can use \"item\" functions such as " 2587 "IsItemHovered()/IsItemActive() or SameLine() etc. on the whole group."); 2588 ImGui::BeginGroup(); 2589 { 2590 ImGui::BeginGroup(); 2591 ImGui::Button("AAA"); 2592 ImGui::SameLine(); 2593 ImGui::Button("BBB"); 2594 ImGui::SameLine(); 2595 ImGui::BeginGroup(); 2596 ImGui::Button("CCC"); 2597 ImGui::Button("DDD"); 2598 ImGui::EndGroup(); 2599 ImGui::SameLine(); 2600 ImGui::Button("EEE"); 2601 ImGui::EndGroup(); 2602 if (ImGui::IsItemHovered()) 2603 ImGui::SetTooltip("First group hovered"); 2604 } 2605 // Capture the group size and create widgets using the same size 2606 ImVec2 size = ImGui::GetItemRectSize(); 2607 const float values[5] = { 0.5f, 0.20f, 0.80f, 0.60f, 0.25f }; 2608 ImGui::PlotHistogram("##values", values, IM_ARRAYSIZE(values), 0, NULL, 0.0f, 1.0f, size); 2609 2610 ImGui::Button("ACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y)); 2611 ImGui::SameLine(); 2612 ImGui::Button("REACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y)); 2613 ImGui::EndGroup(); 2614 ImGui::SameLine(); 2615 2616 ImGui::Button("LEVERAGE\nBUZZWORD", size); 2617 ImGui::SameLine(); 2618 2619 if (ImGui::BeginListBox("List", size)) 2620 { 2621 ImGui::Selectable("Selected", true); 2622 ImGui::Selectable("Not Selected", false); 2623 ImGui::EndListBox(); 2624 } 2625 2626 ImGui::TreePop(); 2627 } 2628 2629 if (ImGui::TreeNode("Text Baseline Alignment")) 2630 { 2631 { 2632 ImGui::BulletText("Text baseline:"); 2633 ImGui::SameLine(); HelpMarker( 2634 "This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. " 2635 "Lines only composed of text or \"small\" widgets use less vertical space than lines with framed widgets."); 2636 ImGui::Indent(); 2637 2638 ImGui::Text("KO Blahblah"); ImGui::SameLine(); 2639 ImGui::Button("Some framed item"); ImGui::SameLine(); 2640 HelpMarker("Baseline of button will look misaligned with text.."); 2641 2642 // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets. 2643 // (because we don't know what's coming after the Text() statement, we need to move the text baseline 2644 // down by FramePadding.y ahead of time) 2645 ImGui::AlignTextToFramePadding(); 2646 ImGui::Text("OK Blahblah"); ImGui::SameLine(); 2647 ImGui::Button("Some framed item"); ImGui::SameLine(); 2648 HelpMarker("We call AlignTextToFramePadding() to vertically align the text baseline by +FramePadding.y"); 2649 2650 // SmallButton() uses the same vertical padding as Text 2651 ImGui::Button("TEST##1"); ImGui::SameLine(); 2652 ImGui::Text("TEST"); ImGui::SameLine(); 2653 ImGui::SmallButton("TEST##2"); 2654 2655 // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets. 2656 ImGui::AlignTextToFramePadding(); 2657 ImGui::Text("Text aligned to framed item"); ImGui::SameLine(); 2658 ImGui::Button("Item##1"); ImGui::SameLine(); 2659 ImGui::Text("Item"); ImGui::SameLine(); 2660 ImGui::SmallButton("Item##2"); ImGui::SameLine(); 2661 ImGui::Button("Item##3"); 2662 2663 ImGui::Unindent(); 2664 } 2665 2666 ImGui::Spacing(); 2667 2668 { 2669 ImGui::BulletText("Multi-line text:"); 2670 ImGui::Indent(); 2671 ImGui::Text("One\nTwo\nThree"); ImGui::SameLine(); 2672 ImGui::Text("Hello\nWorld"); ImGui::SameLine(); 2673 ImGui::Text("Banana"); 2674 2675 ImGui::Text("Banana"); ImGui::SameLine(); 2676 ImGui::Text("Hello\nWorld"); ImGui::SameLine(); 2677 ImGui::Text("One\nTwo\nThree"); 2678 2679 ImGui::Button("HOP##1"); ImGui::SameLine(); 2680 ImGui::Text("Banana"); ImGui::SameLine(); 2681 ImGui::Text("Hello\nWorld"); ImGui::SameLine(); 2682 ImGui::Text("Banana"); 2683 2684 ImGui::Button("HOP##2"); ImGui::SameLine(); 2685 ImGui::Text("Hello\nWorld"); ImGui::SameLine(); 2686 ImGui::Text("Banana"); 2687 ImGui::Unindent(); 2688 } 2689 2690 ImGui::Spacing(); 2691 2692 { 2693 ImGui::BulletText("Misc items:"); 2694 ImGui::Indent(); 2695 2696 // SmallButton() sets FramePadding to zero. Text baseline is aligned to match baseline of previous Button. 2697 ImGui::Button("80x80", ImVec2(80, 80)); 2698 ImGui::SameLine(); 2699 ImGui::Button("50x50", ImVec2(50, 50)); 2700 ImGui::SameLine(); 2701 ImGui::Button("Button()"); 2702 ImGui::SameLine(); 2703 ImGui::SmallButton("SmallButton()"); 2704 2705 // Tree 2706 const float spacing = ImGui::GetStyle().ItemInnerSpacing.x; 2707 ImGui::Button("Button##1"); 2708 ImGui::SameLine(0.0f, spacing); 2709 if (ImGui::TreeNode("Node##1")) 2710 { 2711 // Placeholder tree data 2712 for (int i = 0; i < 6; i++) 2713 ImGui::BulletText("Item %d..", i); 2714 ImGui::TreePop(); 2715 } 2716 2717 // Vertically align text node a bit lower so it'll be vertically centered with upcoming widget. 2718 // Otherwise you can use SmallButton() (smaller fit). 2719 ImGui::AlignTextToFramePadding(); 2720 2721 // Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add 2722 // other contents below the node. 2723 bool node_open = ImGui::TreeNode("Node##2"); 2724 ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##2"); 2725 if (node_open) 2726 { 2727 // Placeholder tree data 2728 for (int i = 0; i < 6; i++) 2729 ImGui::BulletText("Item %d..", i); 2730 ImGui::TreePop(); 2731 } 2732 2733 // Bullet 2734 ImGui::Button("Button##3"); 2735 ImGui::SameLine(0.0f, spacing); 2736 ImGui::BulletText("Bullet text"); 2737 2738 ImGui::AlignTextToFramePadding(); 2739 ImGui::BulletText("Node"); 2740 ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##4"); 2741 ImGui::Unindent(); 2742 } 2743 2744 ImGui::TreePop(); 2745 } 2746 2747 if (ImGui::TreeNode("Scrolling")) 2748 { 2749 // Vertical scroll functions 2750 HelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given vertical position."); 2751 2752 static int track_item = 50; 2753 static bool enable_track = true; 2754 static bool enable_extra_decorations = false; 2755 static float scroll_to_off_px = 0.0f; 2756 static float scroll_to_pos_px = 200.0f; 2757 2758 ImGui::Checkbox("Decoration", &enable_extra_decorations); 2759 2760 ImGui::Checkbox("Track", &enable_track); 2761 ImGui::PushItemWidth(100); 2762 ImGui::SameLine(140); enable_track |= ImGui::DragInt("##item", &track_item, 0.25f, 0, 99, "Item = %d"); 2763 2764 bool scroll_to_off = ImGui::Button("Scroll Offset"); 2765 ImGui::SameLine(140); scroll_to_off |= ImGui::DragFloat("##off", &scroll_to_off_px, 1.00f, 0, FLT_MAX, "+%.0f px"); 2766 2767 bool scroll_to_pos = ImGui::Button("Scroll To Pos"); 2768 ImGui::SameLine(140); scroll_to_pos |= ImGui::DragFloat("##pos", &scroll_to_pos_px, 1.00f, -10, FLT_MAX, "X/Y = %.0f px"); 2769 ImGui::PopItemWidth(); 2770 2771 if (scroll_to_off || scroll_to_pos) 2772 enable_track = false; 2773 2774 ImGuiStyle& style = ImGui::GetStyle(); 2775 float child_w = (ImGui::GetContentRegionAvail().x - 4 * style.ItemSpacing.x) / 5; 2776 if (child_w < 1.0f) 2777 child_w = 1.0f; 2778 ImGui::PushID("##VerticalScrolling"); 2779 for (int i = 0; i < 5; i++) 2780 { 2781 if (i > 0) ImGui::SameLine(); 2782 ImGui::BeginGroup(); 2783 const char* names[] = { "Top", "25%", "Center", "75%", "Bottom" }; 2784 ImGui::TextUnformatted(names[i]); 2785 2786 const ImGuiWindowFlags child_flags = enable_extra_decorations ? ImGuiWindowFlags_MenuBar : 0; 2787 const ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i); 2788 const bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(child_w, 200.0f), true, child_flags); 2789 if (ImGui::BeginMenuBar()) 2790 { 2791 ImGui::TextUnformatted("abc"); 2792 ImGui::EndMenuBar(); 2793 } 2794 if (scroll_to_off) 2795 ImGui::SetScrollY(scroll_to_off_px); 2796 if (scroll_to_pos) 2797 ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_pos_px, i * 0.25f); 2798 if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items 2799 { 2800 for (int item = 0; item < 100; item++) 2801 { 2802 if (enable_track && item == track_item) 2803 { 2804 ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item); 2805 ImGui::SetScrollHereY(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom 2806 } 2807 else 2808 { 2809 ImGui::Text("Item %d", item); 2810 } 2811 } 2812 } 2813 float scroll_y = ImGui::GetScrollY(); 2814 float scroll_max_y = ImGui::GetScrollMaxY(); 2815 ImGui::EndChild(); 2816 ImGui::Text("%.0f/%.0f", scroll_y, scroll_max_y); 2817 ImGui::EndGroup(); 2818 } 2819 ImGui::PopID(); 2820 2821 // Horizontal scroll functions 2822 ImGui::Spacing(); 2823 HelpMarker( 2824 "Use SetScrollHereX() or SetScrollFromPosX() to scroll to a given horizontal position.\n\n" 2825 "Because the clipping rectangle of most window hides half worth of WindowPadding on the " 2826 "left/right, using SetScrollFromPosX(+1) will usually result in clipped text whereas the " 2827 "equivalent SetScrollFromPosY(+1) wouldn't."); 2828 ImGui::PushID("##HorizontalScrolling"); 2829 for (int i = 0; i < 5; i++) 2830 { 2831 float child_height = ImGui::GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0f; 2832 ImGuiWindowFlags child_flags = ImGuiWindowFlags_HorizontalScrollbar | (enable_extra_decorations ? ImGuiWindowFlags_AlwaysVerticalScrollbar : 0); 2833 ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i); 2834 bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(-100, child_height), true, child_flags); 2835 if (scroll_to_off) 2836 ImGui::SetScrollX(scroll_to_off_px); 2837 if (scroll_to_pos) 2838 ImGui::SetScrollFromPosX(ImGui::GetCursorStartPos().x + scroll_to_pos_px, i * 0.25f); 2839 if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items 2840 { 2841 for (int item = 0; item < 100; item++) 2842 { 2843 if (item > 0) 2844 ImGui::SameLine(); 2845 if (enable_track && item == track_item) 2846 { 2847 ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item); 2848 ImGui::SetScrollHereX(i * 0.25f); // 0.0f:left, 0.5f:center, 1.0f:right 2849 } 2850 else 2851 { 2852 ImGui::Text("Item %d", item); 2853 } 2854 } 2855 } 2856 float scroll_x = ImGui::GetScrollX(); 2857 float scroll_max_x = ImGui::GetScrollMaxX(); 2858 ImGui::EndChild(); 2859 ImGui::SameLine(); 2860 const char* names[] = { "Left", "25%", "Center", "75%", "Right" }; 2861 ImGui::Text("%s\n%.0f/%.0f", names[i], scroll_x, scroll_max_x); 2862 ImGui::Spacing(); 2863 } 2864 ImGui::PopID(); 2865 2866 // Miscellaneous Horizontal Scrolling Demo 2867 HelpMarker( 2868 "Horizontal scrolling for a window is enabled via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\n" 2869 "You may want to also explicitly specify content width by using SetNextWindowContentWidth() before Begin()."); 2870 static int lines = 7; 2871 ImGui::SliderInt("Lines", &lines, 1, 15); 2872 ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); 2873 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f)); 2874 ImVec2 scrolling_child_size = ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30); 2875 ImGui::BeginChild("scrolling", scrolling_child_size, true, ImGuiWindowFlags_HorizontalScrollbar); 2876 for (int line = 0; line < lines; line++) 2877 { 2878 // Display random stuff. For the sake of this trivial demo we are using basic Button() + SameLine() 2879 // If you want to create your own time line for a real application you may be better off manipulating 2880 // the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets 2881 // yourself. You may also want to use the lower-level ImDrawList API. 2882 int num_buttons = 10 + ((line & 1) ? line * 9 : line * 3); 2883 for (int n = 0; n < num_buttons; n++) 2884 { 2885 if (n > 0) ImGui::SameLine(); 2886 ImGui::PushID(n + line * 1000); 2887 char num_buf[16]; 2888 sprintf(num_buf, "%d", n); 2889 const char* label = (!(n % 15)) ? "FizzBuzz" : (!(n % 3)) ? "Fizz" : (!(n % 5)) ? "Buzz" : num_buf; 2890 float hue = n * 0.05f; 2891 ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(hue, 0.6f, 0.6f)); 2892 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(hue, 0.7f, 0.7f)); 2893 ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(hue, 0.8f, 0.8f)); 2894 ImGui::Button(label, ImVec2(40.0f + sinf((float)(line + n)) * 20.0f, 0.0f)); 2895 ImGui::PopStyleColor(3); 2896 ImGui::PopID(); 2897 } 2898 } 2899 float scroll_x = ImGui::GetScrollX(); 2900 float scroll_max_x = ImGui::GetScrollMaxX(); 2901 ImGui::EndChild(); 2902 ImGui::PopStyleVar(2); 2903 float scroll_x_delta = 0.0f; 2904 ImGui::SmallButton("<<"); 2905 if (ImGui::IsItemActive()) 2906 scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f; 2907 ImGui::SameLine(); 2908 ImGui::Text("Scroll from code"); ImGui::SameLine(); 2909 ImGui::SmallButton(">>"); 2910 if (ImGui::IsItemActive()) 2911 scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f; 2912 ImGui::SameLine(); 2913 ImGui::Text("%.0f/%.0f", scroll_x, scroll_max_x); 2914 if (scroll_x_delta != 0.0f) 2915 { 2916 // Demonstrate a trick: you can use Begin to set yourself in the context of another window 2917 // (here we are already out of your child window) 2918 ImGui::BeginChild("scrolling"); 2919 ImGui::SetScrollX(ImGui::GetScrollX() + scroll_x_delta); 2920 ImGui::EndChild(); 2921 } 2922 ImGui::Spacing(); 2923 2924 static bool show_horizontal_contents_size_demo_window = false; 2925 ImGui::Checkbox("Show Horizontal contents size demo window", &show_horizontal_contents_size_demo_window); 2926 2927 if (show_horizontal_contents_size_demo_window) 2928 { 2929 static bool show_h_scrollbar = true; 2930 static bool show_button = true; 2931 static bool show_tree_nodes = true; 2932 static bool show_text_wrapped = false; 2933 static bool show_columns = true; 2934 static bool show_tab_bar = true; 2935 static bool show_child = false; 2936 static bool explicit_content_size = false; 2937 static float contents_size_x = 300.0f; 2938 if (explicit_content_size) 2939 ImGui::SetNextWindowContentSize(ImVec2(contents_size_x, 0.0f)); 2940 ImGui::Begin("Horizontal contents size demo window", &show_horizontal_contents_size_demo_window, show_h_scrollbar ? ImGuiWindowFlags_HorizontalScrollbar : 0); 2941 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 0)); 2942 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 0)); 2943 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."); 2944 ImGui::Checkbox("H-scrollbar", &show_h_scrollbar); 2945 ImGui::Checkbox("Button", &show_button); // Will grow contents size (unless explicitly overwritten) 2946 ImGui::Checkbox("Tree nodes", &show_tree_nodes); // Will grow contents size and display highlight over full width 2947 ImGui::Checkbox("Text wrapped", &show_text_wrapped);// Will grow and use contents size 2948 ImGui::Checkbox("Columns", &show_columns); // Will use contents size 2949 ImGui::Checkbox("Tab bar", &show_tab_bar); // Will use contents size 2950 ImGui::Checkbox("Child", &show_child); // Will grow and use contents size 2951 ImGui::Checkbox("Explicit content size", &explicit_content_size); 2952 ImGui::Text("Scroll %.1f/%.1f %.1f/%.1f", ImGui::GetScrollX(), ImGui::GetScrollMaxX(), ImGui::GetScrollY(), ImGui::GetScrollMaxY()); 2953 if (explicit_content_size) 2954 { 2955 ImGui::SameLine(); 2956 ImGui::SetNextItemWidth(100); 2957 ImGui::DragFloat("##csx", &contents_size_x); 2958 ImVec2 p = ImGui::GetCursorScreenPos(); 2959 ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + 10, p.y + 10), IM_COL32_WHITE); 2960 ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(p.x + contents_size_x - 10, p.y), ImVec2(p.x + contents_size_x, p.y + 10), IM_COL32_WHITE); 2961 ImGui::Dummy(ImVec2(0, 10)); 2962 } 2963 ImGui::PopStyleVar(2); 2964 ImGui::Separator(); 2965 if (show_button) 2966 { 2967 ImGui::Button("this is a 300-wide button", ImVec2(300, 0)); 2968 } 2969 if (show_tree_nodes) 2970 { 2971 bool open = true; 2972 if (ImGui::TreeNode("this is a tree node")) 2973 { 2974 if (ImGui::TreeNode("another one of those tree node...")) 2975 { 2976 ImGui::Text("Some tree contents"); 2977 ImGui::TreePop(); 2978 } 2979 ImGui::TreePop(); 2980 } 2981 ImGui::CollapsingHeader("CollapsingHeader", &open); 2982 } 2983 if (show_text_wrapped) 2984 { 2985 ImGui::TextWrapped("This text should automatically wrap on the edge of the work rectangle."); 2986 } 2987 if (show_columns) 2988 { 2989 ImGui::Text("Tables:"); 2990 if (ImGui::BeginTable("table", 4, ImGuiTableFlags_Borders)) 2991 { 2992 for (int n = 0; n < 4; n++) 2993 { 2994 ImGui::TableNextColumn(); 2995 ImGui::Text("Width %.2f", ImGui::GetContentRegionAvail().x); 2996 } 2997 ImGui::EndTable(); 2998 } 2999 ImGui::Text("Columns:"); 3000 ImGui::Columns(4); 3001 for (int n = 0; n < 4; n++) 3002 { 3003 ImGui::Text("Width %.2f", ImGui::GetColumnWidth()); 3004 ImGui::NextColumn(); 3005 } 3006 ImGui::Columns(1); 3007 } 3008 if (show_tab_bar && ImGui::BeginTabBar("Hello")) 3009 { 3010 if (ImGui::BeginTabItem("OneOneOne")) { ImGui::EndTabItem(); } 3011 if (ImGui::BeginTabItem("TwoTwoTwo")) { ImGui::EndTabItem(); } 3012 if (ImGui::BeginTabItem("ThreeThreeThree")) { ImGui::EndTabItem(); } 3013 if (ImGui::BeginTabItem("FourFourFour")) { ImGui::EndTabItem(); } 3014 ImGui::EndTabBar(); 3015 } 3016 if (show_child) 3017 { 3018 ImGui::BeginChild("child", ImVec2(0, 0), true); 3019 ImGui::EndChild(); 3020 } 3021 ImGui::End(); 3022 } 3023 3024 ImGui::TreePop(); 3025 } 3026 3027 if (ImGui::TreeNode("Clipping")) 3028 { 3029 static ImVec2 size(100.0f, 100.0f); 3030 static ImVec2 offset(30.0f, 30.0f); 3031 ImGui::DragFloat2("size", (float*)&size, 0.5f, 1.0f, 200.0f, "%.0f"); 3032 ImGui::TextWrapped("(Click and drag to scroll)"); 3033 3034 for (int n = 0; n < 3; n++) 3035 { 3036 if (n > 0) 3037 ImGui::SameLine(); 3038 ImGui::PushID(n); 3039 ImGui::BeginGroup(); // Lock X position 3040 3041 ImGui::InvisibleButton("##empty", size); 3042 if (ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left)) 3043 { 3044 offset.x += ImGui::GetIO().MouseDelta.x; 3045 offset.y += ImGui::GetIO().MouseDelta.y; 3046 } 3047 const ImVec2 p0 = ImGui::GetItemRectMin(); 3048 const ImVec2 p1 = ImGui::GetItemRectMax(); 3049 const char* text_str = "Line 1 hello\nLine 2 clip me!"; 3050 const ImVec2 text_pos = ImVec2(p0.x + offset.x, p0.y + offset.y); 3051 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 3052 3053 switch (n) 3054 { 3055 case 0: 3056 HelpMarker( 3057 "Using ImGui::PushClipRect():\n" 3058 "Will alter ImGui hit-testing logic + ImDrawList rendering.\n" 3059 "(use this if you want your clipping rectangle to affect interactions)"); 3060 ImGui::PushClipRect(p0, p1, true); 3061 draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)); 3062 draw_list->AddText(text_pos, IM_COL32_WHITE, text_str); 3063 ImGui::PopClipRect(); 3064 break; 3065 case 1: 3066 HelpMarker( 3067 "Using ImDrawList::PushClipRect():\n" 3068 "Will alter ImDrawList rendering only.\n" 3069 "(use this as a shortcut if you are only using ImDrawList calls)"); 3070 draw_list->PushClipRect(p0, p1, true); 3071 draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)); 3072 draw_list->AddText(text_pos, IM_COL32_WHITE, text_str); 3073 draw_list->PopClipRect(); 3074 break; 3075 case 2: 3076 HelpMarker( 3077 "Using ImDrawList::AddText() with a fine ClipRect:\n" 3078 "Will alter only this specific ImDrawList::AddText() rendering.\n" 3079 "(this is often used internally to avoid altering the clipping rectangle and minimize draw calls)"); 3080 ImVec4 clip_rect(p0.x, p0.y, p1.x, p1.y); // AddText() takes a ImVec4* here so let's convert. 3081 draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)); 3082 draw_list->AddText(ImGui::GetFont(), ImGui::GetFontSize(), text_pos, IM_COL32_WHITE, text_str, NULL, 0.0f, &clip_rect); 3083 break; 3084 } 3085 ImGui::EndGroup(); 3086 ImGui::PopID(); 3087 } 3088 3089 ImGui::TreePop(); 3090 } 3091 } 3092 3093 static void ShowDemoWindowPopups() 3094 { 3095 if (!ImGui::CollapsingHeader("Popups & Modal windows")) 3096 return; 3097 3098 // The properties of popups windows are: 3099 // - They block normal mouse hovering detection outside them. (*) 3100 // - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE. 3101 // - Their visibility state (~bool) is held internally by Dear ImGui instead of being held by the programmer as 3102 // we are used to with regular Begin() calls. User can manipulate the visibility state by calling OpenPopup(). 3103 // (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even 3104 // when normally blocked by a popup. 3105 // Those three properties are connected. The library needs to hold their visibility state BECAUSE it can close 3106 // popups at any time. 3107 3108 // Typical use for regular windows: 3109 // 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(); 3110 // Typical use for popups: 3111 // if (ImGui::Button("Open")) ImGui::OpenPopup("MyPopup"); if (ImGui::BeginPopup("MyPopup") { [...] EndPopup(); } 3112 3113 // With popups we have to go through a library call (here OpenPopup) to manipulate the visibility state. 3114 // This may be a bit confusing at first but it should quickly make sense. Follow on the examples below. 3115 3116 if (ImGui::TreeNode("Popups")) 3117 { 3118 ImGui::TextWrapped( 3119 "When a popup is active, it inhibits interacting with windows that are behind the popup. " 3120 "Clicking outside the popup closes it."); 3121 3122 static int selected_fish = -1; 3123 const char* names[] = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" }; 3124 static bool toggles[] = { true, false, false, false, false }; 3125 3126 // Simple selection popup (if you want to show the current selection inside the Button itself, 3127 // you may want to build a string using the "###" operator to preserve a constant ID with a variable label) 3128 if (ImGui::Button("Select..")) 3129 ImGui::OpenPopup("my_select_popup"); 3130 ImGui::SameLine(); 3131 ImGui::TextUnformatted(selected_fish == -1 ? "<None>" : names[selected_fish]); 3132 if (ImGui::BeginPopup("my_select_popup")) 3133 { 3134 ImGui::Text("Aquarium"); 3135 ImGui::Separator(); 3136 for (int i = 0; i < IM_ARRAYSIZE(names); i++) 3137 if (ImGui::Selectable(names[i])) 3138 selected_fish = i; 3139 ImGui::EndPopup(); 3140 } 3141 3142 // Showing a menu with toggles 3143 if (ImGui::Button("Toggle..")) 3144 ImGui::OpenPopup("my_toggle_popup"); 3145 if (ImGui::BeginPopup("my_toggle_popup")) 3146 { 3147 for (int i = 0; i < IM_ARRAYSIZE(names); i++) 3148 ImGui::MenuItem(names[i], "", &toggles[i]); 3149 if (ImGui::BeginMenu("Sub-menu")) 3150 { 3151 ImGui::MenuItem("Click me"); 3152 ImGui::EndMenu(); 3153 } 3154 3155 ImGui::Separator(); 3156 ImGui::Text("Tooltip here"); 3157 if (ImGui::IsItemHovered()) 3158 ImGui::SetTooltip("I am a tooltip over a popup"); 3159 3160 if (ImGui::Button("Stacked Popup")) 3161 ImGui::OpenPopup("another popup"); 3162 if (ImGui::BeginPopup("another popup")) 3163 { 3164 for (int i = 0; i < IM_ARRAYSIZE(names); i++) 3165 ImGui::MenuItem(names[i], "", &toggles[i]); 3166 if (ImGui::BeginMenu("Sub-menu")) 3167 { 3168 ImGui::MenuItem("Click me"); 3169 if (ImGui::Button("Stacked Popup")) 3170 ImGui::OpenPopup("another popup"); 3171 if (ImGui::BeginPopup("another popup")) 3172 { 3173 ImGui::Text("I am the last one here."); 3174 ImGui::EndPopup(); 3175 } 3176 ImGui::EndMenu(); 3177 } 3178 ImGui::EndPopup(); 3179 } 3180 ImGui::EndPopup(); 3181 } 3182 3183 // Call the more complete ShowExampleMenuFile which we use in various places of this demo 3184 if (ImGui::Button("File Menu..")) 3185 ImGui::OpenPopup("my_file_popup"); 3186 if (ImGui::BeginPopup("my_file_popup")) 3187 { 3188 ShowExampleMenuFile(); 3189 ImGui::EndPopup(); 3190 } 3191 3192 ImGui::TreePop(); 3193 } 3194 3195 if (ImGui::TreeNode("Context menus")) 3196 { 3197 HelpMarker("\"Context\" functions are simple helpers to associate a Popup to a given Item or Window identifier."); 3198 3199 // BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing: 3200 // if (id == 0) 3201 // id = GetItemID(); // Use last item id 3202 // if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right)) 3203 // OpenPopup(id); 3204 // return BeginPopup(id); 3205 // For advanced advanced uses you may want to replicate and customize this code. 3206 // See more details in BeginPopupContextItem(). 3207 3208 // Example 1 3209 // When used after an item that has an ID (e.g. Button), we can skip providing an ID to BeginPopupContextItem(), 3210 // and BeginPopupContextItem() will use the last item ID as the popup ID. 3211 { 3212 const char* names[5] = { "Label1", "Label2", "Label3", "Label4", "Label5" }; 3213 for (int n = 0; n < 5; n++) 3214 { 3215 ImGui::Selectable(names[n]); 3216 if (ImGui::BeginPopupContextItem()) // <-- use last item id as popup id 3217 { 3218 ImGui::Text("This a popup for \"%s\"!", names[n]); 3219 if (ImGui::Button("Close")) 3220 ImGui::CloseCurrentPopup(); 3221 ImGui::EndPopup(); 3222 } 3223 if (ImGui::IsItemHovered()) 3224 ImGui::SetTooltip("Right-click to open popup"); 3225 } 3226 } 3227 3228 // Example 2 3229 // Popup on a Text() element which doesn't have an identifier: we need to provide an identifier to BeginPopupContextItem(). 3230 // Using an explicit identifier is also convenient if you want to activate the popups from different locations. 3231 { 3232 HelpMarker("Text() elements don't have stable identifiers so we need to provide one."); 3233 static float value = 0.5f; 3234 ImGui::Text("Value = %.3f <-- (1) right-click this value", value); 3235 if (ImGui::BeginPopupContextItem("my popup")) 3236 { 3237 if (ImGui::Selectable("Set to zero")) value = 0.0f; 3238 if (ImGui::Selectable("Set to PI")) value = 3.1415f; 3239 ImGui::SetNextItemWidth(-FLT_MIN); 3240 ImGui::DragFloat("##Value", &value, 0.1f, 0.0f, 0.0f); 3241 ImGui::EndPopup(); 3242 } 3243 3244 // We can also use OpenPopupOnItemClick() to toggle the visibility of a given popup. 3245 // Here we make it that right-clicking this other text element opens the same popup as above. 3246 // The popup itself will be submitted by the code above. 3247 ImGui::Text("(2) Or right-click this text"); 3248 ImGui::OpenPopupOnItemClick("my popup", ImGuiPopupFlags_MouseButtonRight); 3249 3250 // Back to square one: manually open the same popup. 3251 if (ImGui::Button("(3) Or click this button")) 3252 ImGui::OpenPopup("my popup"); 3253 } 3254 3255 // Example 3 3256 // When using BeginPopupContextItem() with an implicit identifier (NULL == use last item ID), 3257 // we need to make sure your item identifier is stable. 3258 // In this example we showcase altering the item label while preserving its identifier, using the ### operator (see FAQ). 3259 { 3260 HelpMarker("Showcase using a popup ID linked to item ID, with the item having a changing label + stable ID using the ### operator."); 3261 static char name[32] = "Label1"; 3262 char buf[64]; 3263 sprintf(buf, "Button: %s###Button", name); // ### operator override ID ignoring the preceding label 3264 ImGui::Button(buf); 3265 if (ImGui::BeginPopupContextItem()) 3266 { 3267 ImGui::Text("Edit name:"); 3268 ImGui::InputText("##edit", name, IM_ARRAYSIZE(name)); 3269 if (ImGui::Button("Close")) 3270 ImGui::CloseCurrentPopup(); 3271 ImGui::EndPopup(); 3272 } 3273 ImGui::SameLine(); ImGui::Text("(<-- right-click here)"); 3274 } 3275 3276 ImGui::TreePop(); 3277 } 3278 3279 if (ImGui::TreeNode("Modals")) 3280 { 3281 ImGui::TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside."); 3282 3283 if (ImGui::Button("Delete..")) 3284 ImGui::OpenPopup("Delete?"); 3285 3286 // Always center this window when appearing 3287 ImVec2 center = ImGui::GetMainViewport()->GetCenter(); 3288 ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); 3289 3290 if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize)) 3291 { 3292 ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!\n\n"); 3293 ImGui::Separator(); 3294 3295 //static int unused_i = 0; 3296 //ImGui::Combo("Combo", &unused_i, "Delete\0Delete harder\0"); 3297 3298 static bool dont_ask_me_next_time = false; 3299 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); 3300 ImGui::Checkbox("Don't ask me next time", &dont_ask_me_next_time); 3301 ImGui::PopStyleVar(); 3302 3303 if (ImGui::Button("OK", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); } 3304 ImGui::SetItemDefaultFocus(); 3305 ImGui::SameLine(); 3306 if (ImGui::Button("Cancel", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); } 3307 ImGui::EndPopup(); 3308 } 3309 3310 if (ImGui::Button("Stacked modals..")) 3311 ImGui::OpenPopup("Stacked 1"); 3312 if (ImGui::BeginPopupModal("Stacked 1", NULL, ImGuiWindowFlags_MenuBar)) 3313 { 3314 if (ImGui::BeginMenuBar()) 3315 { 3316 if (ImGui::BeginMenu("File")) 3317 { 3318 if (ImGui::MenuItem("Some menu item")) {} 3319 ImGui::EndMenu(); 3320 } 3321 ImGui::EndMenuBar(); 3322 } 3323 ImGui::Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it."); 3324 3325 // Testing behavior of widgets stacking their own regular popups over the modal. 3326 static int item = 1; 3327 static float color[4] = { 0.4f, 0.7f, 0.0f, 0.5f }; 3328 ImGui::Combo("Combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); 3329 ImGui::ColorEdit4("color", color); 3330 3331 if (ImGui::Button("Add another modal..")) 3332 ImGui::OpenPopup("Stacked 2"); 3333 3334 // Also demonstrate passing a bool* to BeginPopupModal(), this will create a regular close button which 3335 // will close the popup. Note that the visibility state of popups is owned by imgui, so the input value 3336 // of the bool actually doesn't matter here. 3337 bool unused_open = true; 3338 if (ImGui::BeginPopupModal("Stacked 2", &unused_open)) 3339 { 3340 ImGui::Text("Hello from Stacked The Second!"); 3341 if (ImGui::Button("Close")) 3342 ImGui::CloseCurrentPopup(); 3343 ImGui::EndPopup(); 3344 } 3345 3346 if (ImGui::Button("Close")) 3347 ImGui::CloseCurrentPopup(); 3348 ImGui::EndPopup(); 3349 } 3350 3351 ImGui::TreePop(); 3352 } 3353 3354 if (ImGui::TreeNode("Menus inside a regular window")) 3355 { 3356 ImGui::TextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!"); 3357 ImGui::Separator(); 3358 3359 // Note: As a quirk in this very specific example, we want to differentiate the parent of this menu from the 3360 // parent of the various popup menus above. To do so we are encloding the items in a PushID()/PopID() block 3361 // to make them two different menusets. If we don't, opening any popup above and hovering our menu here would 3362 // open it. This is because once a menu is active, we allow to switch to a sibling menu by just hovering on it, 3363 // which is the desired behavior for regular menus. 3364 ImGui::PushID("foo"); 3365 ImGui::MenuItem("Menu item", "CTRL+M"); 3366 if (ImGui::BeginMenu("Menu inside a regular window")) 3367 { 3368 ShowExampleMenuFile(); 3369 ImGui::EndMenu(); 3370 } 3371 ImGui::PopID(); 3372 ImGui::Separator(); 3373 ImGui::TreePop(); 3374 } 3375 } 3376 3377 // Dummy data structure that we use for the Table demo. 3378 // (pre-C++11 doesn't allow us to instantiate ImVector<MyItem> template if this structure if defined inside the demo function) 3379 namespace 3380 { 3381 // We are passing our own identifier to TableSetupColumn() to facilitate identifying columns in the sorting code. 3382 // This identifier will be passed down into ImGuiTableSortSpec::ColumnUserID. 3383 // But it is possible to omit the user id parameter of TableSetupColumn() and just use the column index instead! (ImGuiTableSortSpec::ColumnIndex) 3384 // If you don't use sorting, you will generally never care about giving column an ID! 3385 enum MyItemColumnID 3386 { 3387 MyItemColumnID_ID, 3388 MyItemColumnID_Name, 3389 MyItemColumnID_Action, 3390 MyItemColumnID_Quantity, 3391 MyItemColumnID_Description 3392 }; 3393 3394 struct MyItem 3395 { 3396 int ID; 3397 const char* Name; 3398 int Quantity; 3399 3400 // We have a problem which is affecting _only this demo_ and should not affect your code: 3401 // As we don't rely on std:: or other third-party library to compile dear imgui, we only have reliable access to qsort(), 3402 // however qsort doesn't allow passing user data to comparing function. 3403 // As a workaround, we are storing the sort specs in a static/global for the comparing function to access. 3404 // In your own use case you would probably pass the sort specs to your sorting/comparing functions directly and not use a global. 3405 // We could technically call ImGui::TableGetSortSpecs() in CompareWithSortSpecs(), but considering that this function is called 3406 // very often by the sorting algorithm it would be a little wasteful. 3407 static const ImGuiTableSortSpecs* s_current_sort_specs; 3408 3409 // Compare function to be used by qsort() 3410 static int IMGUI_CDECL CompareWithSortSpecs(const void* lhs, const void* rhs) 3411 { 3412 const MyItem* a = (const MyItem*)lhs; 3413 const MyItem* b = (const MyItem*)rhs; 3414 for (int n = 0; n < s_current_sort_specs->SpecsCount; n++) 3415 { 3416 // Here we identify columns using the ColumnUserID value that we ourselves passed to TableSetupColumn() 3417 // We could also choose to identify columns based on their index (sort_spec->ColumnIndex), which is simpler! 3418 const ImGuiTableColumnSortSpecs* sort_spec = &s_current_sort_specs->Specs[n]; 3419 int delta = 0; 3420 switch (sort_spec->ColumnUserID) 3421 { 3422 case MyItemColumnID_ID: delta = (a->ID - b->ID); break; 3423 case MyItemColumnID_Name: delta = (strcmp(a->Name, b->Name)); break; 3424 case MyItemColumnID_Quantity: delta = (a->Quantity - b->Quantity); break; 3425 case MyItemColumnID_Description: delta = (strcmp(a->Name, b->Name)); break; 3426 default: IM_ASSERT(0); break; 3427 } 3428 if (delta > 0) 3429 return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? +1 : -1; 3430 if (delta < 0) 3431 return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? -1 : +1; 3432 } 3433 3434 // qsort() is instable so always return a way to differenciate items. 3435 // Your own compare function may want to avoid fallback on implicit sort specs e.g. a Name compare if it wasn't already part of the sort specs. 3436 return (a->ID - b->ID); 3437 } 3438 }; 3439 const ImGuiTableSortSpecs* MyItem::s_current_sort_specs = NULL; 3440 } 3441 3442 // Make the UI compact because there are so many fields 3443 static void PushStyleCompact() 3444 { 3445 ImGuiStyle& style = ImGui::GetStyle(); 3446 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(style.FramePadding.x, (float)(int)(style.FramePadding.y * 0.60f))); 3447 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x, (float)(int)(style.ItemSpacing.y * 0.60f))); 3448 } 3449 3450 static void PopStyleCompact() 3451 { 3452 ImGui::PopStyleVar(2); 3453 } 3454 3455 // Show a combo box with a choice of sizing policies 3456 static void EditTableSizingFlags(ImGuiTableFlags* p_flags) 3457 { 3458 struct EnumDesc { ImGuiTableFlags Value; const char* Name; const char* Tooltip; }; 3459 static const EnumDesc policies[] = 3460 { 3461 { ImGuiTableFlags_None, "Default", "Use default sizing policy:\n- ImGuiTableFlags_SizingFixedFit if ScrollX is on or if host window has ImGuiWindowFlags_AlwaysAutoResize.\n- ImGuiTableFlags_SizingStretchSame otherwise." }, 3462 { ImGuiTableFlags_SizingFixedFit, "ImGuiTableFlags_SizingFixedFit", "Columns default to _WidthFixed (if resizable) or _WidthAuto (if not resizable), matching contents width." }, 3463 { ImGuiTableFlags_SizingFixedSame, "ImGuiTableFlags_SizingFixedSame", "Columns are all the same width, matching the maximum contents width.\nImplicitly disable ImGuiTableFlags_Resizable and enable ImGuiTableFlags_NoKeepColumnsVisible." }, 3464 { ImGuiTableFlags_SizingStretchProp, "ImGuiTableFlags_SizingStretchProp", "Columns default to _WidthStretch with weights proportional to their widths." }, 3465 { ImGuiTableFlags_SizingStretchSame, "ImGuiTableFlags_SizingStretchSame", "Columns default to _WidthStretch with same weights." } 3466 }; 3467 int idx; 3468 for (idx = 0; idx < IM_ARRAYSIZE(policies); idx++) 3469 if (policies[idx].Value == (*p_flags & ImGuiTableFlags_SizingMask_)) 3470 break; 3471 const char* preview_text = (idx < IM_ARRAYSIZE(policies)) ? policies[idx].Name + (idx > 0 ? strlen("ImGuiTableFlags") : 0) : ""; 3472 if (ImGui::BeginCombo("Sizing Policy", preview_text)) 3473 { 3474 for (int n = 0; n < IM_ARRAYSIZE(policies); n++) 3475 if (ImGui::Selectable(policies[n].Name, idx == n)) 3476 *p_flags = (*p_flags & ~ImGuiTableFlags_SizingMask_) | policies[n].Value; 3477 ImGui::EndCombo(); 3478 } 3479 ImGui::SameLine(); 3480 ImGui::TextDisabled("(?)"); 3481 if (ImGui::IsItemHovered()) 3482 { 3483 ImGui::BeginTooltip(); 3484 ImGui::PushTextWrapPos(ImGui::GetFontSize() * 50.0f); 3485 for (int m = 0; m < IM_ARRAYSIZE(policies); m++) 3486 { 3487 ImGui::Separator(); 3488 ImGui::Text("%s:", policies[m].Name); 3489 ImGui::Separator(); 3490 ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetStyle().IndentSpacing * 0.5f); 3491 ImGui::TextUnformatted(policies[m].Tooltip); 3492 } 3493 ImGui::PopTextWrapPos(); 3494 ImGui::EndTooltip(); 3495 } 3496 } 3497 3498 static void EditTableColumnsFlags(ImGuiTableColumnFlags* p_flags) 3499 { 3500 ImGui::CheckboxFlags("_DefaultHide", p_flags, ImGuiTableColumnFlags_DefaultHide); 3501 ImGui::CheckboxFlags("_DefaultSort", p_flags, ImGuiTableColumnFlags_DefaultSort); 3502 if (ImGui::CheckboxFlags("_WidthStretch", p_flags, ImGuiTableColumnFlags_WidthStretch)) 3503 *p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthStretch); 3504 if (ImGui::CheckboxFlags("_WidthFixed", p_flags, ImGuiTableColumnFlags_WidthFixed)) 3505 *p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthFixed); 3506 ImGui::CheckboxFlags("_NoResize", p_flags, ImGuiTableColumnFlags_NoResize); 3507 ImGui::CheckboxFlags("_NoReorder", p_flags, ImGuiTableColumnFlags_NoReorder); 3508 ImGui::CheckboxFlags("_NoHide", p_flags, ImGuiTableColumnFlags_NoHide); 3509 ImGui::CheckboxFlags("_NoClip", p_flags, ImGuiTableColumnFlags_NoClip); 3510 ImGui::CheckboxFlags("_NoSort", p_flags, ImGuiTableColumnFlags_NoSort); 3511 ImGui::CheckboxFlags("_NoSortAscending", p_flags, ImGuiTableColumnFlags_NoSortAscending); 3512 ImGui::CheckboxFlags("_NoSortDescending", p_flags, ImGuiTableColumnFlags_NoSortDescending); 3513 ImGui::CheckboxFlags("_NoHeaderWidth", p_flags, ImGuiTableColumnFlags_NoHeaderWidth); 3514 ImGui::CheckboxFlags("_PreferSortAscending", p_flags, ImGuiTableColumnFlags_PreferSortAscending); 3515 ImGui::CheckboxFlags("_PreferSortDescending", p_flags, ImGuiTableColumnFlags_PreferSortDescending); 3516 ImGui::CheckboxFlags("_IndentEnable", p_flags, ImGuiTableColumnFlags_IndentEnable); ImGui::SameLine(); HelpMarker("Default for column 0"); 3517 ImGui::CheckboxFlags("_IndentDisable", p_flags, ImGuiTableColumnFlags_IndentDisable); ImGui::SameLine(); HelpMarker("Default for column >0"); 3518 } 3519 3520 static void ShowTableColumnsStatusFlags(ImGuiTableColumnFlags flags) 3521 { 3522 ImGui::CheckboxFlags("_IsEnabled", &flags, ImGuiTableColumnFlags_IsEnabled); 3523 ImGui::CheckboxFlags("_IsVisible", &flags, ImGuiTableColumnFlags_IsVisible); 3524 ImGui::CheckboxFlags("_IsSorted", &flags, ImGuiTableColumnFlags_IsSorted); 3525 ImGui::CheckboxFlags("_IsHovered", &flags, ImGuiTableColumnFlags_IsHovered); 3526 } 3527 3528 static void ShowDemoWindowTables() 3529 { 3530 //ImGui::SetNextItemOpen(true, ImGuiCond_Once); 3531 if (!ImGui::CollapsingHeader("Tables & Columns")) 3532 return; 3533 3534 // Using those as a base value to create width/height that are factor of the size of our font 3535 const float TEXT_BASE_WIDTH = ImGui::CalcTextSize("A").x; 3536 const float TEXT_BASE_HEIGHT = ImGui::GetTextLineHeightWithSpacing(); 3537 3538 ImGui::PushID("Tables"); 3539 3540 int open_action = -1; 3541 if (ImGui::Button("Open all")) 3542 open_action = 1; 3543 ImGui::SameLine(); 3544 if (ImGui::Button("Close all")) 3545 open_action = 0; 3546 ImGui::SameLine(); 3547 3548 // Options 3549 static bool disable_indent = false; 3550 ImGui::Checkbox("Disable tree indentation", &disable_indent); 3551 ImGui::SameLine(); 3552 HelpMarker("Disable the indenting of tree nodes so demo tables can use the full window width."); 3553 ImGui::Separator(); 3554 if (disable_indent) 3555 ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0.0f); 3556 3557 // About Styling of tables 3558 // Most settings are configured on a per-table basis via the flags passed to BeginTable() and TableSetupColumns APIs. 3559 // There are however a few settings that a shared and part of the ImGuiStyle structure: 3560 // style.CellPadding // Padding within each cell 3561 // style.Colors[ImGuiCol_TableHeaderBg] // Table header background 3562 // style.Colors[ImGuiCol_TableBorderStrong] // Table outer and header borders 3563 // style.Colors[ImGuiCol_TableBorderLight] // Table inner borders 3564 // style.Colors[ImGuiCol_TableRowBg] // Table row background when ImGuiTableFlags_RowBg is enabled (even rows) 3565 // style.Colors[ImGuiCol_TableRowBgAlt] // Table row background when ImGuiTableFlags_RowBg is enabled (odds rows) 3566 3567 // Demos 3568 if (open_action != -1) 3569 ImGui::SetNextItemOpen(open_action != 0); 3570 if (ImGui::TreeNode("Basic")) 3571 { 3572 // Here we will showcase three different ways to output a table. 3573 // They are very simple variations of a same thing! 3574 3575 // [Method 1] Using TableNextRow() to create a new row, and TableSetColumnIndex() to select the column. 3576 // In many situations, this is the most flexible and easy to use pattern. 3577 HelpMarker("Using TableNextRow() + calling TableSetColumnIndex() _before_ each cell, in a loop."); 3578 if (ImGui::BeginTable("table1", 3)) 3579 { 3580 for (int row = 0; row < 4; row++) 3581 { 3582 ImGui::TableNextRow(); 3583 for (int column = 0; column < 3; column++) 3584 { 3585 ImGui::TableSetColumnIndex(column); 3586 ImGui::Text("Row %d Column %d", row, column); 3587 } 3588 } 3589 ImGui::EndTable(); 3590 } 3591 3592 // [Method 2] Using TableNextColumn() called multiple times, instead of using a for loop + TableSetColumnIndex(). 3593 // This is generally more convenient when you have code manually submitting the contents of each columns. 3594 HelpMarker("Using TableNextRow() + calling TableNextColumn() _before_ each cell, manually."); 3595 if (ImGui::BeginTable("table2", 3)) 3596 { 3597 for (int row = 0; row < 4; row++) 3598 { 3599 ImGui::TableNextRow(); 3600 ImGui::TableNextColumn(); 3601 ImGui::Text("Row %d", row); 3602 ImGui::TableNextColumn(); 3603 ImGui::Text("Some contents"); 3604 ImGui::TableNextColumn(); 3605 ImGui::Text("123.456"); 3606 } 3607 ImGui::EndTable(); 3608 } 3609 3610 // [Method 3] We call TableNextColumn() _before_ each cell. We never call TableNextRow(), 3611 // as TableNextColumn() will automatically wrap around and create new roes as needed. 3612 // This is generally more convenient when your cells all contains the same type of data. 3613 HelpMarker( 3614 "Only using TableNextColumn(), which tends to be convenient for tables where every cells contains the same type of contents.\n" 3615 "This is also more similar to the old NextColumn() function of the Columns API, and provided to facilitate the Columns->Tables API transition."); 3616 if (ImGui::BeginTable("table3", 3)) 3617 { 3618 for (int item = 0; item < 14; item++) 3619 { 3620 ImGui::TableNextColumn(); 3621 ImGui::Text("Item %d", item); 3622 } 3623 ImGui::EndTable(); 3624 } 3625 3626 ImGui::TreePop(); 3627 } 3628 3629 if (open_action != -1) 3630 ImGui::SetNextItemOpen(open_action != 0); 3631 if (ImGui::TreeNode("Borders, background")) 3632 { 3633 // Expose a few Borders related flags interactively 3634 enum ContentsType { CT_Text, CT_FillButton }; 3635 static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg; 3636 static bool display_headers = false; 3637 static int contents_type = CT_Text; 3638 3639 PushStyleCompact(); 3640 ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg); 3641 ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags, ImGuiTableFlags_Borders); 3642 ImGui::SameLine(); HelpMarker("ImGuiTableFlags_Borders\n = ImGuiTableFlags_BordersInnerV\n | ImGuiTableFlags_BordersOuterV\n | ImGuiTableFlags_BordersInnerV\n | ImGuiTableFlags_BordersOuterH"); 3643 ImGui::Indent(); 3644 3645 ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags, ImGuiTableFlags_BordersH); 3646 ImGui::Indent(); 3647 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterH", &flags, ImGuiTableFlags_BordersOuterH); 3648 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerH", &flags, ImGuiTableFlags_BordersInnerH); 3649 ImGui::Unindent(); 3650 3651 ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV); 3652 ImGui::Indent(); 3653 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags, ImGuiTableFlags_BordersOuterV); 3654 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags, ImGuiTableFlags_BordersInnerV); 3655 ImGui::Unindent(); 3656 3657 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuter", &flags, ImGuiTableFlags_BordersOuter); 3658 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInner", &flags, ImGuiTableFlags_BordersInner); 3659 ImGui::Unindent(); 3660 3661 ImGui::AlignTextToFramePadding(); ImGui::Text("Cell contents:"); 3662 ImGui::SameLine(); ImGui::RadioButton("Text", &contents_type, CT_Text); 3663 ImGui::SameLine(); ImGui::RadioButton("FillButton", &contents_type, CT_FillButton); 3664 ImGui::Checkbox("Display headers", &display_headers); 3665 ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appears in Headers"); 3666 PopStyleCompact(); 3667 3668 if (ImGui::BeginTable("table1", 3, flags)) 3669 { 3670 // Display headers so we can inspect their interaction with borders. 3671 // (Headers are not the main purpose of this section of the demo, so we are not elaborating on them too much. See other sections for details) 3672 if (display_headers) 3673 { 3674 ImGui::TableSetupColumn("One"); 3675 ImGui::TableSetupColumn("Two"); 3676 ImGui::TableSetupColumn("Three"); 3677 ImGui::TableHeadersRow(); 3678 } 3679 3680 for (int row = 0; row < 5; row++) 3681 { 3682 ImGui::TableNextRow(); 3683 for (int column = 0; column < 3; column++) 3684 { 3685 ImGui::TableSetColumnIndex(column); 3686 char buf[32]; 3687 sprintf(buf, "Hello %d,%d", column, row); 3688 if (contents_type == CT_Text) 3689 ImGui::TextUnformatted(buf); 3690 else if (contents_type) 3691 ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f)); 3692 } 3693 } 3694 ImGui::EndTable(); 3695 } 3696 ImGui::TreePop(); 3697 } 3698 3699 if (open_action != -1) 3700 ImGui::SetNextItemOpen(open_action != 0); 3701 if (ImGui::TreeNode("Resizable, stretch")) 3702 { 3703 // By default, if we don't enable ScrollX the sizing policy for each columns is "Stretch" 3704 // Each columns maintain a sizing weight, and they will occupy all available width. 3705 static ImGuiTableFlags flags = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody; 3706 PushStyleCompact(); 3707 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable); 3708 ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV); 3709 ImGui::SameLine(); HelpMarker("Using the _Resizable flag automatically enables the _BordersInnerV flag as well, this is why the resize borders are still showing when unchecking this."); 3710 PopStyleCompact(); 3711 3712 if (ImGui::BeginTable("table1", 3, flags)) 3713 { 3714 for (int row = 0; row < 5; row++) 3715 { 3716 ImGui::TableNextRow(); 3717 for (int column = 0; column < 3; column++) 3718 { 3719 ImGui::TableSetColumnIndex(column); 3720 ImGui::Text("Hello %d,%d", column, row); 3721 } 3722 } 3723 ImGui::EndTable(); 3724 } 3725 ImGui::TreePop(); 3726 } 3727 3728 if (open_action != -1) 3729 ImGui::SetNextItemOpen(open_action != 0); 3730 if (ImGui::TreeNode("Resizable, fixed")) 3731 { 3732 // Here we use ImGuiTableFlags_SizingFixedFit (even though _ScrollX is not set) 3733 // So columns will adopt the "Fixed" policy and will maintain a fixed width regardless of the whole available width (unless table is small) 3734 // If there is not enough available width to fit all columns, they will however be resized down. 3735 // FIXME-TABLE: Providing a stretch-on-init would make sense especially for tables which don't have saved settings 3736 HelpMarker( 3737 "Using _Resizable + _SizingFixedFit flags.\n" 3738 "Fixed-width columns generally makes more sense if you want to use horizontal scrolling.\n\n" 3739 "Double-click a column border to auto-fit the column to its contents."); 3740 PushStyleCompact(); 3741 static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody; 3742 ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX); 3743 PopStyleCompact(); 3744 3745 if (ImGui::BeginTable("table1", 3, flags)) 3746 { 3747 for (int row = 0; row < 5; row++) 3748 { 3749 ImGui::TableNextRow(); 3750 for (int column = 0; column < 3; column++) 3751 { 3752 ImGui::TableSetColumnIndex(column); 3753 ImGui::Text("Hello %d,%d", column, row); 3754 } 3755 } 3756 ImGui::EndTable(); 3757 } 3758 ImGui::TreePop(); 3759 } 3760 3761 if (open_action != -1) 3762 ImGui::SetNextItemOpen(open_action != 0); 3763 if (ImGui::TreeNode("Resizable, mixed")) 3764 { 3765 HelpMarker( 3766 "Using TableSetupColumn() to alter resizing policy on a per-column basis.\n\n" 3767 "When combining Fixed and Stretch columns, generally you only want one, maybe two trailing columns to use _WidthStretch."); 3768 static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable; 3769 3770 if (ImGui::BeginTable("table1", 3, flags)) 3771 { 3772 ImGui::TableSetupColumn("AAA", ImGuiTableColumnFlags_WidthFixed); 3773 ImGui::TableSetupColumn("BBB", ImGuiTableColumnFlags_WidthFixed); 3774 ImGui::TableSetupColumn("CCC", ImGuiTableColumnFlags_WidthStretch); 3775 ImGui::TableHeadersRow(); 3776 for (int row = 0; row < 5; row++) 3777 { 3778 ImGui::TableNextRow(); 3779 for (int column = 0; column < 3; column++) 3780 { 3781 ImGui::TableSetColumnIndex(column); 3782 ImGui::Text("%s %d,%d", (column == 2) ? "Stretch" : "Fixed", column, row); 3783 } 3784 } 3785 ImGui::EndTable(); 3786 } 3787 if (ImGui::BeginTable("table2", 6, flags)) 3788 { 3789 ImGui::TableSetupColumn("AAA", ImGuiTableColumnFlags_WidthFixed); 3790 ImGui::TableSetupColumn("BBB", ImGuiTableColumnFlags_WidthFixed); 3791 ImGui::TableSetupColumn("CCC", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_DefaultHide); 3792 ImGui::TableSetupColumn("DDD", ImGuiTableColumnFlags_WidthStretch); 3793 ImGui::TableSetupColumn("EEE", ImGuiTableColumnFlags_WidthStretch); 3794 ImGui::TableSetupColumn("FFF", ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_DefaultHide); 3795 ImGui::TableHeadersRow(); 3796 for (int row = 0; row < 5; row++) 3797 { 3798 ImGui::TableNextRow(); 3799 for (int column = 0; column < 6; column++) 3800 { 3801 ImGui::TableSetColumnIndex(column); 3802 ImGui::Text("%s %d,%d", (column >= 3) ? "Stretch" : "Fixed", column, row); 3803 } 3804 } 3805 ImGui::EndTable(); 3806 } 3807 ImGui::TreePop(); 3808 } 3809 3810 if (open_action != -1) 3811 ImGui::SetNextItemOpen(open_action != 0); 3812 if (ImGui::TreeNode("Reorderable, hideable, with headers")) 3813 { 3814 HelpMarker( 3815 "Click and drag column headers to reorder columns.\n\n" 3816 "Right-click on a header to open a context menu."); 3817 static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV; 3818 PushStyleCompact(); 3819 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable); 3820 ImGui::CheckboxFlags("ImGuiTableFlags_Reorderable", &flags, ImGuiTableFlags_Reorderable); 3821 ImGui::CheckboxFlags("ImGuiTableFlags_Hideable", &flags, ImGuiTableFlags_Hideable); 3822 ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); 3823 ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags, ImGuiTableFlags_NoBordersInBodyUntilResize); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body until hovered for resize (borders will always appears in Headers)"); 3824 PopStyleCompact(); 3825 3826 if (ImGui::BeginTable("table1", 3, flags)) 3827 { 3828 // Submit columns name with TableSetupColumn() and call TableHeadersRow() to create a row with a header in each column. 3829 // (Later we will show how TableSetupColumn() has other uses, optional flags, sizing weight etc.) 3830 ImGui::TableSetupColumn("One"); 3831 ImGui::TableSetupColumn("Two"); 3832 ImGui::TableSetupColumn("Three"); 3833 ImGui::TableHeadersRow(); 3834 for (int row = 0; row < 6; row++) 3835 { 3836 ImGui::TableNextRow(); 3837 for (int column = 0; column < 3; column++) 3838 { 3839 ImGui::TableSetColumnIndex(column); 3840 ImGui::Text("Hello %d,%d", column, row); 3841 } 3842 } 3843 ImGui::EndTable(); 3844 } 3845 3846 // Use outer_size.x == 0.0f instead of default to make the table as tight as possible (only valid when no scrolling and no stretch column) 3847 if (ImGui::BeginTable("table2", 3, flags | ImGuiTableFlags_SizingFixedFit, ImVec2(0.0f, 0.0f))) 3848 { 3849 ImGui::TableSetupColumn("One"); 3850 ImGui::TableSetupColumn("Two"); 3851 ImGui::TableSetupColumn("Three"); 3852 ImGui::TableHeadersRow(); 3853 for (int row = 0; row < 6; row++) 3854 { 3855 ImGui::TableNextRow(); 3856 for (int column = 0; column < 3; column++) 3857 { 3858 ImGui::TableSetColumnIndex(column); 3859 ImGui::Text("Fixed %d,%d", column, row); 3860 } 3861 } 3862 ImGui::EndTable(); 3863 } 3864 ImGui::TreePop(); 3865 } 3866 3867 if (open_action != -1) 3868 ImGui::SetNextItemOpen(open_action != 0); 3869 if (ImGui::TreeNode("Padding")) 3870 { 3871 // First example: showcase use of padding flags and effect of BorderOuterV/BorderInnerV on X padding. 3872 // We don't expose BorderOuterH/BorderInnerH here because they have no effect on X padding. 3873 HelpMarker( 3874 "We often want outer padding activated when any using features which makes the edges of a column visible:\n" 3875 "e.g.:\n" 3876 "- BorderOuterV\n" 3877 "- any form of row selection\n" 3878 "Because of this, activating BorderOuterV sets the default to PadOuterX. Using PadOuterX or NoPadOuterX you can override the default.\n\n" 3879 "Actual padding values are using style.CellPadding.\n\n" 3880 "In this demo we don't show horizontal borders to emphasis how they don't affect default horizontal padding."); 3881 3882 static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV; 3883 PushStyleCompact(); 3884 ImGui::CheckboxFlags("ImGuiTableFlags_PadOuterX", &flags1, ImGuiTableFlags_PadOuterX); 3885 ImGui::SameLine(); HelpMarker("Enable outer-most padding (default if ImGuiTableFlags_BordersOuterV is set)"); 3886 ImGui::CheckboxFlags("ImGuiTableFlags_NoPadOuterX", &flags1, ImGuiTableFlags_NoPadOuterX); 3887 ImGui::SameLine(); HelpMarker("Disable outer-most padding (default if ImGuiTableFlags_BordersOuterV is not set)"); 3888 ImGui::CheckboxFlags("ImGuiTableFlags_NoPadInnerX", &flags1, ImGuiTableFlags_NoPadInnerX); 3889 ImGui::SameLine(); HelpMarker("Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off)"); 3890 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags1, ImGuiTableFlags_BordersOuterV); 3891 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags1, ImGuiTableFlags_BordersInnerV); 3892 static bool show_headers = false; 3893 ImGui::Checkbox("show_headers", &show_headers); 3894 PopStyleCompact(); 3895 3896 if (ImGui::BeginTable("table_padding", 3, flags1)) 3897 { 3898 if (show_headers) 3899 { 3900 ImGui::TableSetupColumn("One"); 3901 ImGui::TableSetupColumn("Two"); 3902 ImGui::TableSetupColumn("Three"); 3903 ImGui::TableHeadersRow(); 3904 } 3905 3906 for (int row = 0; row < 5; row++) 3907 { 3908 ImGui::TableNextRow(); 3909 for (int column = 0; column < 3; column++) 3910 { 3911 ImGui::TableSetColumnIndex(column); 3912 if (row == 0) 3913 { 3914 ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x); 3915 } 3916 else 3917 { 3918 char buf[32]; 3919 sprintf(buf, "Hello %d,%d", column, row); 3920 ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f)); 3921 } 3922 //if (ImGui::TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered) 3923 // ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, IM_COL32(0, 100, 0, 255)); 3924 } 3925 } 3926 ImGui::EndTable(); 3927 } 3928 3929 // Second example: set style.CellPadding to (0.0) or a custom value. 3930 // FIXME-TABLE: Vertical border effectively not displayed the same way as horizontal one... 3931 HelpMarker("Setting style.CellPadding to (0,0) or a custom value."); 3932 static ImGuiTableFlags flags2 = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg; 3933 static ImVec2 cell_padding(0.0f, 0.0f); 3934 static bool show_widget_frame_bg = true; 3935 3936 PushStyleCompact(); 3937 ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags2, ImGuiTableFlags_Borders); 3938 ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags2, ImGuiTableFlags_BordersH); 3939 ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags2, ImGuiTableFlags_BordersV); 3940 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInner", &flags2, ImGuiTableFlags_BordersInner); 3941 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuter", &flags2, ImGuiTableFlags_BordersOuter); 3942 ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags2, ImGuiTableFlags_RowBg); 3943 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags2, ImGuiTableFlags_Resizable); 3944 ImGui::Checkbox("show_widget_frame_bg", &show_widget_frame_bg); 3945 ImGui::SliderFloat2("CellPadding", &cell_padding.x, 0.0f, 10.0f, "%.0f"); 3946 PopStyleCompact(); 3947 3948 ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, cell_padding); 3949 if (ImGui::BeginTable("table_padding_2", 3, flags2)) 3950 { 3951 static char text_bufs[3 * 5][16]; // Mini text storage for 3x5 cells 3952 static bool init = true; 3953 if (!show_widget_frame_bg) 3954 ImGui::PushStyleColor(ImGuiCol_FrameBg, 0); 3955 for (int cell = 0; cell < 3 * 5; cell++) 3956 { 3957 ImGui::TableNextColumn(); 3958 if (init) 3959 strcpy(text_bufs[cell], "edit me"); 3960 ImGui::SetNextItemWidth(-FLT_MIN); 3961 ImGui::PushID(cell); 3962 ImGui::InputText("##cell", text_bufs[cell], IM_ARRAYSIZE(text_bufs[cell])); 3963 ImGui::PopID(); 3964 } 3965 if (!show_widget_frame_bg) 3966 ImGui::PopStyleColor(); 3967 init = false; 3968 ImGui::EndTable(); 3969 } 3970 ImGui::PopStyleVar(); 3971 3972 ImGui::TreePop(); 3973 } 3974 3975 if (open_action != -1) 3976 ImGui::SetNextItemOpen(open_action != 0); 3977 if (ImGui::TreeNode("Sizing policies")) 3978 { 3979 static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody; 3980 PushStyleCompact(); 3981 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags1, ImGuiTableFlags_Resizable); 3982 ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags1, ImGuiTableFlags_NoHostExtendX); 3983 PopStyleCompact(); 3984 3985 static ImGuiTableFlags sizing_policy_flags[4] = { ImGuiTableFlags_SizingFixedFit, ImGuiTableFlags_SizingFixedSame, ImGuiTableFlags_SizingStretchProp, ImGuiTableFlags_SizingStretchSame }; 3986 for (int table_n = 0; table_n < 4; table_n++) 3987 { 3988 ImGui::PushID(table_n); 3989 ImGui::SetNextItemWidth(TEXT_BASE_WIDTH * 30); 3990 EditTableSizingFlags(&sizing_policy_flags[table_n]); 3991 3992 // To make it easier to understand the different sizing policy, 3993 // For each policy: we display one table where the columns have equal contents width, and one where the columns have different contents width. 3994 if (ImGui::BeginTable("table1", 3, sizing_policy_flags[table_n] | flags1)) 3995 { 3996 for (int row = 0; row < 3; row++) 3997 { 3998 ImGui::TableNextRow(); 3999 ImGui::TableNextColumn(); ImGui::Text("Oh dear"); 4000 ImGui::TableNextColumn(); ImGui::Text("Oh dear"); 4001 ImGui::TableNextColumn(); ImGui::Text("Oh dear"); 4002 } 4003 ImGui::EndTable(); 4004 } 4005 if (ImGui::BeginTable("table2", 3, sizing_policy_flags[table_n] | flags1)) 4006 { 4007 for (int row = 0; row < 3; row++) 4008 { 4009 ImGui::TableNextRow(); 4010 ImGui::TableNextColumn(); ImGui::Text("AAAA"); 4011 ImGui::TableNextColumn(); ImGui::Text("BBBBBBBB"); 4012 ImGui::TableNextColumn(); ImGui::Text("CCCCCCCCCCCC"); 4013 } 4014 ImGui::EndTable(); 4015 } 4016 ImGui::PopID(); 4017 } 4018 4019 ImGui::Spacing(); 4020 ImGui::TextUnformatted("Advanced"); 4021 ImGui::SameLine(); 4022 HelpMarker("This section allows you to interact and see the effect of various sizing policies depending on whether Scroll is enabled and the contents of your columns."); 4023 4024 enum ContentsType { CT_ShowWidth, CT_ShortText, CT_LongText, CT_Button, CT_FillButton, CT_InputText }; 4025 static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable; 4026 static int contents_type = CT_ShowWidth; 4027 static int column_count = 3; 4028 4029 PushStyleCompact(); 4030 ImGui::PushID("Advanced"); 4031 ImGui::PushItemWidth(TEXT_BASE_WIDTH * 30); 4032 EditTableSizingFlags(&flags); 4033 ImGui::Combo("Contents", &contents_type, "Show width\0Short Text\0Long Text\0Button\0Fill Button\0InputText\0"); 4034 if (contents_type == CT_FillButton) 4035 { 4036 ImGui::SameLine(); 4037 HelpMarker("Be mindful that using right-alignment (e.g. size.x = -FLT_MIN) creates a feedback loop where contents width can feed into auto-column width can feed into contents width."); 4038 } 4039 ImGui::DragInt("Columns", &column_count, 0.1f, 1, 64, "%d", ImGuiSliderFlags_AlwaysClamp); 4040 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable); 4041 ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths); 4042 ImGui::SameLine(); HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth."); 4043 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX); 4044 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY); 4045 ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip); 4046 ImGui::PopItemWidth(); 4047 ImGui::PopID(); 4048 PopStyleCompact(); 4049 4050 if (ImGui::BeginTable("table2", column_count, flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 7))) 4051 { 4052 for (int cell = 0; cell < 10 * column_count; cell++) 4053 { 4054 ImGui::TableNextColumn(); 4055 int column = ImGui::TableGetColumnIndex(); 4056 int row = ImGui::TableGetRowIndex(); 4057 4058 ImGui::PushID(cell); 4059 char label[32]; 4060 static char text_buf[32] = ""; 4061 sprintf(label, "Hello %d,%d", column, row); 4062 switch (contents_type) 4063 { 4064 case CT_ShortText: ImGui::TextUnformatted(label); break; 4065 case CT_LongText: ImGui::Text("Some %s text %d,%d\nOver two lines..", column == 0 ? "long" : "longeeer", column, row); break; 4066 case CT_ShowWidth: ImGui::Text("W: %.1f", ImGui::GetContentRegionAvail().x); break; 4067 case CT_Button: ImGui::Button(label); break; 4068 case CT_FillButton: ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f)); break; 4069 case CT_InputText: ImGui::SetNextItemWidth(-FLT_MIN); ImGui::InputText("##", text_buf, IM_ARRAYSIZE(text_buf)); break; 4070 } 4071 ImGui::PopID(); 4072 } 4073 ImGui::EndTable(); 4074 } 4075 ImGui::TreePop(); 4076 } 4077 4078 if (open_action != -1) 4079 ImGui::SetNextItemOpen(open_action != 0); 4080 if (ImGui::TreeNode("Vertical scrolling, with clipping")) 4081 { 4082 HelpMarker("Here we activate ScrollY, which will create a child window container to allow hosting scrollable contents.\n\nWe also demonstrate using ImGuiListClipper to virtualize the submission of many items."); 4083 static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable; 4084 4085 PushStyleCompact(); 4086 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY); 4087 PopStyleCompact(); 4088 4089 // When using ScrollX or ScrollY we need to specify a size for our table container! 4090 // Otherwise by default the table will fit all available space, like a BeginChild() call. 4091 ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 8); 4092 if (ImGui::BeginTable("table_scrolly", 3, flags, outer_size)) 4093 { 4094 ImGui::TableSetupScrollFreeze(0, 1); // Make top row always visible 4095 ImGui::TableSetupColumn("One", ImGuiTableColumnFlags_None); 4096 ImGui::TableSetupColumn("Two", ImGuiTableColumnFlags_None); 4097 ImGui::TableSetupColumn("Three", ImGuiTableColumnFlags_None); 4098 ImGui::TableHeadersRow(); 4099 4100 // Demonstrate using clipper for large vertical lists 4101 ImGuiListClipper clipper; 4102 clipper.Begin(1000); 4103 while (clipper.Step()) 4104 { 4105 for (int row = clipper.DisplayStart; row < clipper.DisplayEnd; row++) 4106 { 4107 ImGui::TableNextRow(); 4108 for (int column = 0; column < 3; column++) 4109 { 4110 ImGui::TableSetColumnIndex(column); 4111 ImGui::Text("Hello %d,%d", column, row); 4112 } 4113 } 4114 } 4115 ImGui::EndTable(); 4116 } 4117 ImGui::TreePop(); 4118 } 4119 4120 if (open_action != -1) 4121 ImGui::SetNextItemOpen(open_action != 0); 4122 if (ImGui::TreeNode("Horizontal scrolling")) 4123 { 4124 HelpMarker( 4125 "When ScrollX is enabled, the default sizing policy becomes ImGuiTableFlags_SizingFixedFit, " 4126 "as automatically stretching columns doesn't make much sense with horizontal scrolling.\n\n" 4127 "Also note that as of the current version, you will almost always want to enable ScrollY along with ScrollX," 4128 "because the container window won't automatically extend vertically to fix contents (this may be improved in future versions)."); 4129 static ImGuiTableFlags flags = ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable; 4130 static int freeze_cols = 1; 4131 static int freeze_rows = 1; 4132 4133 PushStyleCompact(); 4134 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable); 4135 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX); 4136 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY); 4137 ImGui::SetNextItemWidth(ImGui::GetFrameHeight()); 4138 ImGui::DragInt("freeze_cols", &freeze_cols, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput); 4139 ImGui::SetNextItemWidth(ImGui::GetFrameHeight()); 4140 ImGui::DragInt("freeze_rows", &freeze_rows, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput); 4141 PopStyleCompact(); 4142 4143 // When using ScrollX or ScrollY we need to specify a size for our table container! 4144 // Otherwise by default the table will fit all available space, like a BeginChild() call. 4145 ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 8); 4146 if (ImGui::BeginTable("table_scrollx", 7, flags, outer_size)) 4147 { 4148 ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows); 4149 ImGui::TableSetupColumn("Line #", ImGuiTableColumnFlags_NoHide); // Make the first column not hideable to match our use of TableSetupScrollFreeze() 4150 ImGui::TableSetupColumn("One"); 4151 ImGui::TableSetupColumn("Two"); 4152 ImGui::TableSetupColumn("Three"); 4153 ImGui::TableSetupColumn("Four"); 4154 ImGui::TableSetupColumn("Five"); 4155 ImGui::TableSetupColumn("Six"); 4156 ImGui::TableHeadersRow(); 4157 for (int row = 0; row < 20; row++) 4158 { 4159 ImGui::TableNextRow(); 4160 for (int column = 0; column < 7; column++) 4161 { 4162 // Both TableNextColumn() and TableSetColumnIndex() return true when a column is visible or performing width measurement. 4163 // Because here we know that: 4164 // - A) all our columns are contributing the same to row height 4165 // - B) column 0 is always visible, 4166 // We only always submit this one column and can skip others. 4167 // More advanced per-column clipping behaviors may benefit from polling the status flags via TableGetColumnFlags(). 4168 if (!ImGui::TableSetColumnIndex(column) && column > 0) 4169 continue; 4170 if (column == 0) 4171 ImGui::Text("Line %d", row); 4172 else 4173 ImGui::Text("Hello world %d,%d", column, row); 4174 } 4175 } 4176 ImGui::EndTable(); 4177 } 4178 4179 ImGui::Spacing(); 4180 ImGui::TextUnformatted("Stretch + ScrollX"); 4181 ImGui::SameLine(); 4182 HelpMarker( 4183 "Showcase using Stretch columns + ScrollX together: " 4184 "this is rather unusual and only makes sense when specifying an 'inner_width' for the table!\n" 4185 "Without an explicit value, inner_width is == outer_size.x and therefore using Stretch columns + ScrollX together doesn't make sense."); 4186 static ImGuiTableFlags flags2 = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody; 4187 static float inner_width = 1000.0f; 4188 PushStyleCompact(); 4189 ImGui::PushID("flags3"); 4190 ImGui::PushItemWidth(TEXT_BASE_WIDTH * 30); 4191 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags2, ImGuiTableFlags_ScrollX); 4192 ImGui::DragFloat("inner_width", &inner_width, 1.0f, 0.0f, FLT_MAX, "%.1f"); 4193 ImGui::PopItemWidth(); 4194 ImGui::PopID(); 4195 PopStyleCompact(); 4196 if (ImGui::BeginTable("table2", 7, flags2, outer_size, inner_width)) 4197 { 4198 for (int cell = 0; cell < 20 * 7; cell++) 4199 { 4200 ImGui::TableNextColumn(); 4201 ImGui::Text("Hello world %d,%d", ImGui::TableGetColumnIndex(), ImGui::TableGetRowIndex()); 4202 } 4203 ImGui::EndTable(); 4204 } 4205 ImGui::TreePop(); 4206 } 4207 4208 if (open_action != -1) 4209 ImGui::SetNextItemOpen(open_action != 0); 4210 if (ImGui::TreeNode("Columns flags")) 4211 { 4212 // Create a first table just to show all the options/flags we want to make visible in our example! 4213 const int column_count = 3; 4214 const char* column_names[column_count] = { "One", "Two", "Three" }; 4215 static ImGuiTableColumnFlags column_flags[column_count] = { ImGuiTableColumnFlags_DefaultSort, ImGuiTableColumnFlags_None, ImGuiTableColumnFlags_DefaultHide }; 4216 static ImGuiTableColumnFlags column_flags_out[column_count] = { 0, 0, 0 }; // Output from TableGetColumnFlags() 4217 4218 if (ImGui::BeginTable("table_columns_flags_checkboxes", column_count, ImGuiTableFlags_None)) 4219 { 4220 PushStyleCompact(); 4221 for (int column = 0; column < column_count; column++) 4222 { 4223 ImGui::TableNextColumn(); 4224 ImGui::PushID(column); 4225 ImGui::AlignTextToFramePadding(); // FIXME-TABLE: Workaround for wrong text baseline propagation 4226 ImGui::Text("'%s'", column_names[column]); 4227 ImGui::Spacing(); 4228 ImGui::Text("Input flags:"); 4229 EditTableColumnsFlags(&column_flags[column]); 4230 ImGui::Spacing(); 4231 ImGui::Text("Output flags:"); 4232 ShowTableColumnsStatusFlags(column_flags_out[column]); 4233 ImGui::PopID(); 4234 } 4235 PopStyleCompact(); 4236 ImGui::EndTable(); 4237 } 4238 4239 // Create the real table we care about for the example! 4240 // We use a scrolling table to be able to showcase the difference between the _IsEnabled and _IsVisible flags above, otherwise in 4241 // a non-scrolling table columns are always visible (unless using ImGuiTableFlags_NoKeepColumnsVisible + resizing the parent window down) 4242 const ImGuiTableFlags flags 4243 = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY 4244 | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV 4245 | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable; 4246 ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 9); 4247 if (ImGui::BeginTable("table_columns_flags", column_count, flags, outer_size)) 4248 { 4249 for (int column = 0; column < column_count; column++) 4250 ImGui::TableSetupColumn(column_names[column], column_flags[column]); 4251 ImGui::TableHeadersRow(); 4252 for (int column = 0; column < column_count; column++) 4253 column_flags_out[column] = ImGui::TableGetColumnFlags(column); 4254 float indent_step = (float)((int)TEXT_BASE_WIDTH / 2); 4255 for (int row = 0; row < 8; row++) 4256 { 4257 ImGui::Indent(indent_step); // Add some indentation to demonstrate usage of per-column IndentEnable/IndentDisable flags. 4258 ImGui::TableNextRow(); 4259 for (int column = 0; column < column_count; column++) 4260 { 4261 ImGui::TableSetColumnIndex(column); 4262 ImGui::Text("%s %s", (column == 0) ? "Indented" : "Hello", ImGui::TableGetColumnName(column)); 4263 } 4264 } 4265 ImGui::Unindent(indent_step * 8.0f); 4266 4267 ImGui::EndTable(); 4268 } 4269 ImGui::TreePop(); 4270 } 4271 4272 if (open_action != -1) 4273 ImGui::SetNextItemOpen(open_action != 0); 4274 if (ImGui::TreeNode("Columns widths")) 4275 { 4276 HelpMarker("Using TableSetupColumn() to setup default width."); 4277 4278 static ImGuiTableFlags flags1 = ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBodyUntilResize; 4279 PushStyleCompact(); 4280 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags1, ImGuiTableFlags_Resizable); 4281 ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags1, ImGuiTableFlags_NoBordersInBodyUntilResize); 4282 PopStyleCompact(); 4283 if (ImGui::BeginTable("table1", 3, flags1)) 4284 { 4285 // We could also set ImGuiTableFlags_SizingFixedFit on the table and all columns will default to ImGuiTableColumnFlags_WidthFixed. 4286 ImGui::TableSetupColumn("one", ImGuiTableColumnFlags_WidthFixed, 100.0f); // Default to 100.0f 4287 ImGui::TableSetupColumn("two", ImGuiTableColumnFlags_WidthFixed, 200.0f); // Default to 200.0f 4288 ImGui::TableSetupColumn("three", ImGuiTableColumnFlags_WidthFixed); // Default to auto 4289 ImGui::TableHeadersRow(); 4290 for (int row = 0; row < 4; row++) 4291 { 4292 ImGui::TableNextRow(); 4293 for (int column = 0; column < 3; column++) 4294 { 4295 ImGui::TableSetColumnIndex(column); 4296 if (row == 0) 4297 ImGui::Text("(w: %5.1f)", ImGui::GetContentRegionAvail().x); 4298 else 4299 ImGui::Text("Hello %d,%d", column, row); 4300 } 4301 } 4302 ImGui::EndTable(); 4303 } 4304 4305 HelpMarker("Using TableSetupColumn() to setup explicit width.\n\nUnless _NoKeepColumnsVisible is set, fixed columns with set width may still be shrunk down if there's not enough space in the host."); 4306 4307 static ImGuiTableFlags flags2 = ImGuiTableFlags_None; 4308 PushStyleCompact(); 4309 ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags2, ImGuiTableFlags_NoKeepColumnsVisible); 4310 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags2, ImGuiTableFlags_BordersInnerV); 4311 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags2, ImGuiTableFlags_BordersOuterV); 4312 PopStyleCompact(); 4313 if (ImGui::BeginTable("table2", 4, flags2)) 4314 { 4315 // We could also set ImGuiTableFlags_SizingFixedFit on the table and all columns will default to ImGuiTableColumnFlags_WidthFixed. 4316 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 100.0f); 4317 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f); 4318 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 30.0f); 4319 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f); 4320 for (int row = 0; row < 5; row++) 4321 { 4322 ImGui::TableNextRow(); 4323 for (int column = 0; column < 4; column++) 4324 { 4325 ImGui::TableSetColumnIndex(column); 4326 if (row == 0) 4327 ImGui::Text("(w: %5.1f)", ImGui::GetContentRegionAvail().x); 4328 else 4329 ImGui::Text("Hello %d,%d", column, row); 4330 } 4331 } 4332 ImGui::EndTable(); 4333 } 4334 ImGui::TreePop(); 4335 } 4336 4337 if (open_action != -1) 4338 ImGui::SetNextItemOpen(open_action != 0); 4339 if (ImGui::TreeNode("Nested tables")) 4340 { 4341 HelpMarker("This demonstrate embedding a table into another table cell."); 4342 4343 if (ImGui::BeginTable("table_nested1", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable)) 4344 { 4345 ImGui::TableSetupColumn("A0"); 4346 ImGui::TableSetupColumn("A1"); 4347 ImGui::TableHeadersRow(); 4348 4349 ImGui::TableNextColumn(); 4350 ImGui::Text("A0 Row 0"); 4351 { 4352 float rows_height = TEXT_BASE_HEIGHT * 2; 4353 if (ImGui::BeginTable("table_nested2", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable)) 4354 { 4355 ImGui::TableSetupColumn("B0"); 4356 ImGui::TableSetupColumn("B1"); 4357 ImGui::TableHeadersRow(); 4358 4359 ImGui::TableNextRow(ImGuiTableRowFlags_None, rows_height); 4360 ImGui::TableNextColumn(); 4361 ImGui::Text("B0 Row 0"); 4362 ImGui::TableNextColumn(); 4363 ImGui::Text("B1 Row 0"); 4364 ImGui::TableNextRow(ImGuiTableRowFlags_None, rows_height); 4365 ImGui::TableNextColumn(); 4366 ImGui::Text("B0 Row 1"); 4367 ImGui::TableNextColumn(); 4368 ImGui::Text("B1 Row 1"); 4369 4370 ImGui::EndTable(); 4371 } 4372 } 4373 ImGui::TableNextColumn(); ImGui::Text("A1 Row 0"); 4374 ImGui::TableNextColumn(); ImGui::Text("A0 Row 1"); 4375 ImGui::TableNextColumn(); ImGui::Text("A1 Row 1"); 4376 ImGui::EndTable(); 4377 } 4378 ImGui::TreePop(); 4379 } 4380 4381 if (open_action != -1) 4382 ImGui::SetNextItemOpen(open_action != 0); 4383 if (ImGui::TreeNode("Row height")) 4384 { 4385 HelpMarker("You can pass a 'min_row_height' to TableNextRow().\n\nRows are padded with 'style.CellPadding.y' on top and bottom, so effectively the minimum row height will always be >= 'style.CellPadding.y * 2.0f'.\n\nWe cannot honor a _maximum_ row height as that would requires a unique clipping rectangle per row."); 4386 if (ImGui::BeginTable("table_row_height", 1, ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersInnerV)) 4387 { 4388 for (int row = 0; row < 10; row++) 4389 { 4390 float min_row_height = (float)(int)(TEXT_BASE_HEIGHT * 0.30f * row); 4391 ImGui::TableNextRow(ImGuiTableRowFlags_None, min_row_height); 4392 ImGui::TableNextColumn(); 4393 ImGui::Text("min_row_height = %.2f", min_row_height); 4394 } 4395 ImGui::EndTable(); 4396 } 4397 ImGui::TreePop(); 4398 } 4399 4400 if (open_action != -1) 4401 ImGui::SetNextItemOpen(open_action != 0); 4402 if (ImGui::TreeNode("Outer size")) 4403 { 4404 // Showcasing use of ImGuiTableFlags_NoHostExtendX and ImGuiTableFlags_NoHostExtendY 4405 // Important to that note how the two flags have slightly different behaviors! 4406 ImGui::Text("Using NoHostExtendX and NoHostExtendY:"); 4407 PushStyleCompact(); 4408 static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_ContextMenuInBody | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX; 4409 ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX); 4410 ImGui::SameLine(); HelpMarker("Make outer width auto-fit to columns, overriding outer_size.x value.\n\nOnly available when ScrollX/ScrollY are disabled and Stretch columns are not used."); 4411 ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendY", &flags, ImGuiTableFlags_NoHostExtendY); 4412 ImGui::SameLine(); HelpMarker("Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).\n\nOnly available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible."); 4413 PopStyleCompact(); 4414 4415 ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 5.5f); 4416 if (ImGui::BeginTable("table1", 3, flags, outer_size)) 4417 { 4418 for (int row = 0; row < 10; row++) 4419 { 4420 ImGui::TableNextRow(); 4421 for (int column = 0; column < 3; column++) 4422 { 4423 ImGui::TableNextColumn(); 4424 ImGui::Text("Cell %d,%d", column, row); 4425 } 4426 } 4427 ImGui::EndTable(); 4428 } 4429 ImGui::SameLine(); 4430 ImGui::Text("Hello!"); 4431 4432 ImGui::Spacing(); 4433 4434 ImGui::Text("Using explicit size:"); 4435 if (ImGui::BeginTable("table2", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(TEXT_BASE_WIDTH * 30, 0.0f))) 4436 { 4437 for (int row = 0; row < 5; row++) 4438 { 4439 ImGui::TableNextRow(); 4440 for (int column = 0; column < 3; column++) 4441 { 4442 ImGui::TableNextColumn(); 4443 ImGui::Text("Cell %d,%d", column, row); 4444 } 4445 } 4446 ImGui::EndTable(); 4447 } 4448 ImGui::SameLine(); 4449 if (ImGui::BeginTable("table3", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(TEXT_BASE_WIDTH * 30, 0.0f))) 4450 { 4451 for (int row = 0; row < 3; row++) 4452 { 4453 ImGui::TableNextRow(0, TEXT_BASE_HEIGHT * 1.5f); 4454 for (int column = 0; column < 3; column++) 4455 { 4456 ImGui::TableNextColumn(); 4457 ImGui::Text("Cell %d,%d", column, row); 4458 } 4459 } 4460 ImGui::EndTable(); 4461 } 4462 4463 ImGui::TreePop(); 4464 } 4465 4466 if (open_action != -1) 4467 ImGui::SetNextItemOpen(open_action != 0); 4468 if (ImGui::TreeNode("Background color")) 4469 { 4470 static ImGuiTableFlags flags = ImGuiTableFlags_RowBg; 4471 static int row_bg_type = 1; 4472 static int row_bg_target = 1; 4473 static int cell_bg_type = 1; 4474 4475 PushStyleCompact(); 4476 ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags, ImGuiTableFlags_Borders); 4477 ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg); 4478 ImGui::SameLine(); HelpMarker("ImGuiTableFlags_RowBg automatically sets RowBg0 to alternative colors pulled from the Style."); 4479 ImGui::Combo("row bg type", (int*)&row_bg_type, "None\0Red\0Gradient\0"); 4480 ImGui::Combo("row bg target", (int*)&row_bg_target, "RowBg0\0RowBg1\0"); ImGui::SameLine(); HelpMarker("Target RowBg0 to override the alternating odd/even colors,\nTarget RowBg1 to blend with them."); 4481 ImGui::Combo("cell bg type", (int*)&cell_bg_type, "None\0Blue\0"); ImGui::SameLine(); HelpMarker("We are colorizing cells to B1->C2 here."); 4482 IM_ASSERT(row_bg_type >= 0 && row_bg_type <= 2); 4483 IM_ASSERT(row_bg_target >= 0 && row_bg_target <= 1); 4484 IM_ASSERT(cell_bg_type >= 0 && cell_bg_type <= 1); 4485 PopStyleCompact(); 4486 4487 if (ImGui::BeginTable("table1", 5, flags)) 4488 { 4489 for (int row = 0; row < 6; row++) 4490 { 4491 ImGui::TableNextRow(); 4492 4493 // Demonstrate setting a row background color with 'ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBgX, ...)' 4494 // We use a transparent color so we can see the one behind in case our target is RowBg1 and RowBg0 was already targeted by the ImGuiTableFlags_RowBg flag. 4495 if (row_bg_type != 0) 4496 { 4497 ImU32 row_bg_color = ImGui::GetColorU32(row_bg_type == 1 ? ImVec4(0.7f, 0.3f, 0.3f, 0.65f) : ImVec4(0.2f + row * 0.1f, 0.2f, 0.2f, 0.65f)); // Flat or Gradient? 4498 ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0 + row_bg_target, row_bg_color); 4499 } 4500 4501 // Fill cells 4502 for (int column = 0; column < 5; column++) 4503 { 4504 ImGui::TableSetColumnIndex(column); 4505 ImGui::Text("%c%c", 'A' + row, '0' + column); 4506 4507 // Change background of Cells B1->C2 4508 // Demonstrate setting a cell background color with 'ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ...)' 4509 // (the CellBg color will be blended over the RowBg and ColumnBg colors) 4510 // We can also pass a column number as a third parameter to TableSetBgColor() and do this outside the column loop. 4511 if (row >= 1 && row <= 2 && column >= 1 && column <= 2 && cell_bg_type == 1) 4512 { 4513 ImU32 cell_bg_color = ImGui::GetColorU32(ImVec4(0.3f, 0.3f, 0.7f, 0.65f)); 4514 ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, cell_bg_color); 4515 } 4516 } 4517 } 4518 ImGui::EndTable(); 4519 } 4520 ImGui::TreePop(); 4521 } 4522 4523 if (open_action != -1) 4524 ImGui::SetNextItemOpen(open_action != 0); 4525 if (ImGui::TreeNode("Tree view")) 4526 { 4527 static ImGuiTableFlags flags = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody; 4528 4529 if (ImGui::BeginTable("3ways", 3, flags)) 4530 { 4531 // The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On 4532 ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_NoHide); 4533 ImGui::TableSetupColumn("Size", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f); 4534 ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 18.0f); 4535 ImGui::TableHeadersRow(); 4536 4537 // Simple storage to output a dummy file-system. 4538 struct MyTreeNode 4539 { 4540 const char* Name; 4541 const char* Type; 4542 int Size; 4543 int ChildIdx; 4544 int ChildCount; 4545 static void DisplayNode(const MyTreeNode* node, const MyTreeNode* all_nodes) 4546 { 4547 ImGui::TableNextRow(); 4548 ImGui::TableNextColumn(); 4549 const bool is_folder = (node->ChildCount > 0); 4550 if (is_folder) 4551 { 4552 bool open = ImGui::TreeNodeEx(node->Name, ImGuiTreeNodeFlags_SpanFullWidth); 4553 ImGui::TableNextColumn(); 4554 ImGui::TextDisabled("--"); 4555 ImGui::TableNextColumn(); 4556 ImGui::TextUnformatted(node->Type); 4557 if (open) 4558 { 4559 for (int child_n = 0; child_n < node->ChildCount; child_n++) 4560 DisplayNode(&all_nodes[node->ChildIdx + child_n], all_nodes); 4561 ImGui::TreePop(); 4562 } 4563 } 4564 else 4565 { 4566 ImGui::TreeNodeEx(node->Name, ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth); 4567 ImGui::TableNextColumn(); 4568 ImGui::Text("%d", node->Size); 4569 ImGui::TableNextColumn(); 4570 ImGui::TextUnformatted(node->Type); 4571 } 4572 } 4573 }; 4574 static const MyTreeNode nodes[] = 4575 { 4576 { "Root", "Folder", -1, 1, 3 }, // 0 4577 { "Music", "Folder", -1, 4, 2 }, // 1 4578 { "Textures", "Folder", -1, 6, 3 }, // 2 4579 { "desktop.ini", "System file", 1024, -1,-1 }, // 3 4580 { "File1_a.wav", "Audio file", 123000, -1,-1 }, // 4 4581 { "File1_b.wav", "Audio file", 456000, -1,-1 }, // 5 4582 { "Image001.png", "Image file", 203128, -1,-1 }, // 6 4583 { "Copy of Image001.png", "Image file", 203256, -1,-1 }, // 7 4584 { "Copy of Image001 (Final2).png","Image file", 203512, -1,-1 }, // 8 4585 }; 4586 4587 MyTreeNode::DisplayNode(&nodes[0], nodes); 4588 4589 ImGui::EndTable(); 4590 } 4591 ImGui::TreePop(); 4592 } 4593 4594 if (open_action != -1) 4595 ImGui::SetNextItemOpen(open_action != 0); 4596 if (ImGui::TreeNode("Item width")) 4597 { 4598 HelpMarker( 4599 "Showcase using PushItemWidth() and how it is preserved on a per-column basis.\n\n" 4600 "Note that on auto-resizing non-resizable fixed columns, querying the content width for e.g. right-alignment doesn't make sense."); 4601 if (ImGui::BeginTable("table_item_width", 3, ImGuiTableFlags_Borders)) 4602 { 4603 ImGui::TableSetupColumn("small"); 4604 ImGui::TableSetupColumn("half"); 4605 ImGui::TableSetupColumn("right-align"); 4606 ImGui::TableHeadersRow(); 4607 4608 for (int row = 0; row < 3; row++) 4609 { 4610 ImGui::TableNextRow(); 4611 if (row == 0) 4612 { 4613 // Setup ItemWidth once (instead of setting up every time, which is also possible but less efficient) 4614 ImGui::TableSetColumnIndex(0); 4615 ImGui::PushItemWidth(TEXT_BASE_WIDTH * 3.0f); // Small 4616 ImGui::TableSetColumnIndex(1); 4617 ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.5f); 4618 ImGui::TableSetColumnIndex(2); 4619 ImGui::PushItemWidth(-FLT_MIN); // Right-aligned 4620 } 4621 4622 // Draw our contents 4623 static float dummy_f = 0.0f; 4624 ImGui::PushID(row); 4625 ImGui::TableSetColumnIndex(0); 4626 ImGui::SliderFloat("float0", &dummy_f, 0.0f, 1.0f); 4627 ImGui::TableSetColumnIndex(1); 4628 ImGui::SliderFloat("float1", &dummy_f, 0.0f, 1.0f); 4629 ImGui::TableSetColumnIndex(2); 4630 ImGui::SliderFloat("float2", &dummy_f, 0.0f, 1.0f); 4631 ImGui::PopID(); 4632 } 4633 ImGui::EndTable(); 4634 } 4635 ImGui::TreePop(); 4636 } 4637 4638 // Demonstrate using TableHeader() calls instead of TableHeadersRow() 4639 if (open_action != -1) 4640 ImGui::SetNextItemOpen(open_action != 0); 4641 if (ImGui::TreeNode("Custom headers")) 4642 { 4643 const int COLUMNS_COUNT = 3; 4644 if (ImGui::BeginTable("table_custom_headers", COLUMNS_COUNT, ImGuiTableFlags_Borders | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable)) 4645 { 4646 ImGui::TableSetupColumn("Apricot"); 4647 ImGui::TableSetupColumn("Banana"); 4648 ImGui::TableSetupColumn("Cherry"); 4649 4650 // Dummy entire-column selection storage 4651 // FIXME: It would be nice to actually demonstrate full-featured selection using those checkbox. 4652 static bool column_selected[3] = {}; 4653 4654 // Instead of calling TableHeadersRow() we'll submit custom headers ourselves 4655 ImGui::TableNextRow(ImGuiTableRowFlags_Headers); 4656 for (int column = 0; column < COLUMNS_COUNT; column++) 4657 { 4658 ImGui::TableSetColumnIndex(column); 4659 const char* column_name = ImGui::TableGetColumnName(column); // Retrieve name passed to TableSetupColumn() 4660 ImGui::PushID(column); 4661 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); 4662 ImGui::Checkbox("##checkall", &column_selected[column]); 4663 ImGui::PopStyleVar(); 4664 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); 4665 ImGui::TableHeader(column_name); 4666 ImGui::PopID(); 4667 } 4668 4669 for (int row = 0; row < 5; row++) 4670 { 4671 ImGui::TableNextRow(); 4672 for (int column = 0; column < 3; column++) 4673 { 4674 char buf[32]; 4675 sprintf(buf, "Cell %d,%d", column, row); 4676 ImGui::TableSetColumnIndex(column); 4677 ImGui::Selectable(buf, column_selected[column]); 4678 } 4679 } 4680 ImGui::EndTable(); 4681 } 4682 ImGui::TreePop(); 4683 } 4684 4685 // Demonstrate creating custom context menus inside columns, while playing it nice with context menus provided by TableHeadersRow()/TableHeader() 4686 if (open_action != -1) 4687 ImGui::SetNextItemOpen(open_action != 0); 4688 if (ImGui::TreeNode("Context menus")) 4689 { 4690 HelpMarker("By default, right-clicking over a TableHeadersRow()/TableHeader() line will open the default context-menu.\nUsing ImGuiTableFlags_ContextMenuInBody we also allow right-clicking over columns body."); 4691 static ImGuiTableFlags flags1 = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_ContextMenuInBody; 4692 4693 PushStyleCompact(); 4694 ImGui::CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", &flags1, ImGuiTableFlags_ContextMenuInBody); 4695 PopStyleCompact(); 4696 4697 // Context Menus: first example 4698 // [1.1] Right-click on the TableHeadersRow() line to open the default table context menu. 4699 // [1.2] Right-click in columns also open the default table context menu (if ImGuiTableFlags_ContextMenuInBody is set) 4700 const int COLUMNS_COUNT = 3; 4701 if (ImGui::BeginTable("table_context_menu", COLUMNS_COUNT, flags1)) 4702 { 4703 ImGui::TableSetupColumn("One"); 4704 ImGui::TableSetupColumn("Two"); 4705 ImGui::TableSetupColumn("Three"); 4706 4707 // [1.1]] Right-click on the TableHeadersRow() line to open the default table context menu. 4708 ImGui::TableHeadersRow(); 4709 4710 // Submit dummy contents 4711 for (int row = 0; row < 4; row++) 4712 { 4713 ImGui::TableNextRow(); 4714 for (int column = 0; column < COLUMNS_COUNT; column++) 4715 { 4716 ImGui::TableSetColumnIndex(column); 4717 ImGui::Text("Cell %d,%d", column, row); 4718 } 4719 } 4720 ImGui::EndTable(); 4721 } 4722 4723 // Context Menus: second example 4724 // [2.1] Right-click on the TableHeadersRow() line to open the default table context menu. 4725 // [2.2] Right-click on the ".." to open a custom popup 4726 // [2.3] Right-click in columns to open another custom popup 4727 HelpMarker("Demonstrate mixing table context menu (over header), item context button (over button) and custom per-colum context menu (over column body)."); 4728 ImGuiTableFlags flags2 = ImGuiTableFlags_Resizable | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders; 4729 if (ImGui::BeginTable("table_context_menu_2", COLUMNS_COUNT, flags2)) 4730 { 4731 ImGui::TableSetupColumn("One"); 4732 ImGui::TableSetupColumn("Two"); 4733 ImGui::TableSetupColumn("Three"); 4734 4735 // [2.1] Right-click on the TableHeadersRow() line to open the default table context menu. 4736 ImGui::TableHeadersRow(); 4737 for (int row = 0; row < 4; row++) 4738 { 4739 ImGui::TableNextRow(); 4740 for (int column = 0; column < COLUMNS_COUNT; column++) 4741 { 4742 // Submit dummy contents 4743 ImGui::TableSetColumnIndex(column); 4744 ImGui::Text("Cell %d,%d", column, row); 4745 ImGui::SameLine(); 4746 4747 // [2.2] Right-click on the ".." to open a custom popup 4748 ImGui::PushID(row * COLUMNS_COUNT + column); 4749 ImGui::SmallButton(".."); 4750 if (ImGui::BeginPopupContextItem()) 4751 { 4752 ImGui::Text("This is the popup for Button(\"..\") in Cell %d,%d", column, row); 4753 if (ImGui::Button("Close")) 4754 ImGui::CloseCurrentPopup(); 4755 ImGui::EndPopup(); 4756 } 4757 ImGui::PopID(); 4758 } 4759 } 4760 4761 // [2.3] Right-click anywhere in columns to open another custom popup 4762 // (instead of testing for !IsAnyItemHovered() we could also call OpenPopup() with ImGuiPopupFlags_NoOpenOverExistingPopup 4763 // to manage popup priority as the popups triggers, here "are we hovering a column" are overlapping) 4764 int hovered_column = -1; 4765 for (int column = 0; column < COLUMNS_COUNT + 1; column++) 4766 { 4767 ImGui::PushID(column); 4768 if (ImGui::TableGetColumnFlags(column) & ImGuiTableColumnFlags_IsHovered) 4769 hovered_column = column; 4770 if (hovered_column == column && !ImGui::IsAnyItemHovered() && ImGui::IsMouseReleased(1)) 4771 ImGui::OpenPopup("MyPopup"); 4772 if (ImGui::BeginPopup("MyPopup")) 4773 { 4774 if (column == COLUMNS_COUNT) 4775 ImGui::Text("This is a custom popup for unused space after the last column."); 4776 else 4777 ImGui::Text("This is a custom popup for Column %d", column); 4778 if (ImGui::Button("Close")) 4779 ImGui::CloseCurrentPopup(); 4780 ImGui::EndPopup(); 4781 } 4782 ImGui::PopID(); 4783 } 4784 4785 ImGui::EndTable(); 4786 ImGui::Text("Hovered column: %d", hovered_column); 4787 } 4788 ImGui::TreePop(); 4789 } 4790 4791 // Demonstrate creating multiple tables with the same ID 4792 if (open_action != -1) 4793 ImGui::SetNextItemOpen(open_action != 0); 4794 if (ImGui::TreeNode("Synced instances")) 4795 { 4796 HelpMarker("Multiple tables with the same identifier will share their settings, width, visibility, order etc."); 4797 for (int n = 0; n < 3; n++) 4798 { 4799 char buf[32]; 4800 sprintf(buf, "Synced Table %d", n); 4801 bool open = ImGui::CollapsingHeader(buf, ImGuiTreeNodeFlags_DefaultOpen); 4802 if (open && ImGui::BeginTable("Table", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoSavedSettings)) 4803 { 4804 ImGui::TableSetupColumn("One"); 4805 ImGui::TableSetupColumn("Two"); 4806 ImGui::TableSetupColumn("Three"); 4807 ImGui::TableHeadersRow(); 4808 for (int cell = 0; cell < 9; cell++) 4809 { 4810 ImGui::TableNextColumn(); 4811 ImGui::Text("this cell %d", cell); 4812 } 4813 ImGui::EndTable(); 4814 } 4815 } 4816 ImGui::TreePop(); 4817 } 4818 4819 // Demonstrate using Sorting facilities 4820 // This is a simplified version of the "Advanced" example, where we mostly focus on the code necessary to handle sorting. 4821 // Note that the "Advanced" example also showcase manually triggering a sort (e.g. if item quantities have been modified) 4822 static const char* template_items_names[] = 4823 { 4824 "Banana", "Apple", "Cherry", "Watermelon", "Grapefruit", "Strawberry", "Mango", 4825 "Kiwi", "Orange", "Pineapple", "Blueberry", "Plum", "Coconut", "Pear", "Apricot" 4826 }; 4827 if (open_action != -1) 4828 ImGui::SetNextItemOpen(open_action != 0); 4829 if (ImGui::TreeNode("Sorting")) 4830 { 4831 // Create item list 4832 static ImVector<MyItem> items; 4833 if (items.Size == 0) 4834 { 4835 items.resize(50, MyItem()); 4836 for (int n = 0; n < items.Size; n++) 4837 { 4838 const int template_n = n % IM_ARRAYSIZE(template_items_names); 4839 MyItem& item = items[n]; 4840 item.ID = n; 4841 item.Name = template_items_names[template_n]; 4842 item.Quantity = (n * n - n) % 20; // Assign default quantities 4843 } 4844 } 4845 4846 // Options 4847 static ImGuiTableFlags flags = 4848 ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti 4849 | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_NoBordersInBody 4850 | ImGuiTableFlags_ScrollY; 4851 PushStyleCompact(); 4852 ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti); 4853 ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1)."); 4854 ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate); 4855 ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0)."); 4856 PopStyleCompact(); 4857 4858 if (ImGui::BeginTable("table_sorting", 4, flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 15), 0.0f)) 4859 { 4860 // Declare columns 4861 // We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications. 4862 // This is so our sort function can identify a column given our own identifier. We could also identify them based on their index! 4863 // Demonstrate using a mixture of flags among available sort-related flags: 4864 // - ImGuiTableColumnFlags_DefaultSort 4865 // - ImGuiTableColumnFlags_NoSort / ImGuiTableColumnFlags_NoSortAscending / ImGuiTableColumnFlags_NoSortDescending 4866 // - ImGuiTableColumnFlags_PreferSortAscending / ImGuiTableColumnFlags_PreferSortDescending 4867 ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_ID); 4868 ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Name); 4869 ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Action); 4870 ImGui::TableSetupColumn("Quantity", ImGuiTableColumnFlags_PreferSortDescending | ImGuiTableColumnFlags_WidthStretch, 0.0f, MyItemColumnID_Quantity); 4871 ImGui::TableSetupScrollFreeze(0, 1); // Make row always visible 4872 ImGui::TableHeadersRow(); 4873 4874 // Sort our data if sort specs have been changed! 4875 if (ImGuiTableSortSpecs* sorts_specs = ImGui::TableGetSortSpecs()) 4876 if (sorts_specs->SpecsDirty) 4877 { 4878 MyItem::s_current_sort_specs = sorts_specs; // Store in variable accessible by the sort function. 4879 if (items.Size > 1) 4880 qsort(&items[0], (size_t)items.Size, sizeof(items[0]), MyItem::CompareWithSortSpecs); 4881 MyItem::s_current_sort_specs = NULL; 4882 sorts_specs->SpecsDirty = false; 4883 } 4884 4885 // Demonstrate using clipper for large vertical lists 4886 ImGuiListClipper clipper; 4887 clipper.Begin(items.Size); 4888 while (clipper.Step()) 4889 for (int row_n = clipper.DisplayStart; row_n < clipper.DisplayEnd; row_n++) 4890 { 4891 // Display a data item 4892 MyItem* item = &items[row_n]; 4893 ImGui::PushID(item->ID); 4894 ImGui::TableNextRow(); 4895 ImGui::TableNextColumn(); 4896 ImGui::Text("%04d", item->ID); 4897 ImGui::TableNextColumn(); 4898 ImGui::TextUnformatted(item->Name); 4899 ImGui::TableNextColumn(); 4900 ImGui::SmallButton("None"); 4901 ImGui::TableNextColumn(); 4902 ImGui::Text("%d", item->Quantity); 4903 ImGui::PopID(); 4904 } 4905 ImGui::EndTable(); 4906 } 4907 ImGui::TreePop(); 4908 } 4909 4910 // In this example we'll expose most table flags and settings. 4911 // For specific flags and settings refer to the corresponding section for more detailed explanation. 4912 // This section is mostly useful to experiment with combining certain flags or settings with each others. 4913 //ImGui::SetNextItemOpen(true, ImGuiCond_Once); // [DEBUG] 4914 if (open_action != -1) 4915 ImGui::SetNextItemOpen(open_action != 0); 4916 if (ImGui::TreeNode("Advanced")) 4917 { 4918 static ImGuiTableFlags flags = 4919 ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable 4920 | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti 4921 | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBody 4922 | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY 4923 | ImGuiTableFlags_SizingFixedFit; 4924 4925 enum ContentsType { CT_Text, CT_Button, CT_SmallButton, CT_FillButton, CT_Selectable, CT_SelectableSpanRow }; 4926 static int contents_type = CT_SelectableSpanRow; 4927 const char* contents_type_names[] = { "Text", "Button", "SmallButton", "FillButton", "Selectable", "Selectable (span row)" }; 4928 static int freeze_cols = 1; 4929 static int freeze_rows = 1; 4930 static int items_count = IM_ARRAYSIZE(template_items_names) * 2; 4931 static ImVec2 outer_size_value = ImVec2(0.0f, TEXT_BASE_HEIGHT * 12); 4932 static float row_min_height = 0.0f; // Auto 4933 static float inner_width_with_scroll = 0.0f; // Auto-extend 4934 static bool outer_size_enabled = true; 4935 static bool show_headers = true; 4936 static bool show_wrapped_text = false; 4937 //static ImGuiTextFilter filter; 4938 //ImGui::SetNextItemOpen(true, ImGuiCond_Once); // FIXME-TABLE: Enabling this results in initial clipped first pass on table which tend to affects column sizing 4939 if (ImGui::TreeNode("Options")) 4940 { 4941 // Make the UI compact because there are so many fields 4942 PushStyleCompact(); 4943 ImGui::PushItemWidth(TEXT_BASE_WIDTH * 28.0f); 4944 4945 if (ImGui::TreeNodeEx("Features:", ImGuiTreeNodeFlags_DefaultOpen)) 4946 { 4947 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable); 4948 ImGui::CheckboxFlags("ImGuiTableFlags_Reorderable", &flags, ImGuiTableFlags_Reorderable); 4949 ImGui::CheckboxFlags("ImGuiTableFlags_Hideable", &flags, ImGuiTableFlags_Hideable); 4950 ImGui::CheckboxFlags("ImGuiTableFlags_Sortable", &flags, ImGuiTableFlags_Sortable); 4951 ImGui::CheckboxFlags("ImGuiTableFlags_NoSavedSettings", &flags, ImGuiTableFlags_NoSavedSettings); 4952 ImGui::CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", &flags, ImGuiTableFlags_ContextMenuInBody); 4953 ImGui::TreePop(); 4954 } 4955 4956 if (ImGui::TreeNodeEx("Decorations:", ImGuiTreeNodeFlags_DefaultOpen)) 4957 { 4958 ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg); 4959 ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV); 4960 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags, ImGuiTableFlags_BordersOuterV); 4961 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags, ImGuiTableFlags_BordersInnerV); 4962 ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags, ImGuiTableFlags_BordersH); 4963 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterH", &flags, ImGuiTableFlags_BordersOuterH); 4964 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerH", &flags, ImGuiTableFlags_BordersInnerH); 4965 ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appears in Headers"); 4966 ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags, ImGuiTableFlags_NoBordersInBodyUntilResize); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body until hovered for resize (borders will always appears in Headers)"); 4967 ImGui::TreePop(); 4968 } 4969 4970 if (ImGui::TreeNodeEx("Sizing:", ImGuiTreeNodeFlags_DefaultOpen)) 4971 { 4972 EditTableSizingFlags(&flags); 4973 ImGui::SameLine(); HelpMarker("In the Advanced demo we override the policy of each column so those table-wide settings have less effect that typical."); 4974 ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX); 4975 ImGui::SameLine(); HelpMarker("Make outer width auto-fit to columns, overriding outer_size.x value.\n\nOnly available when ScrollX/ScrollY are disabled and Stretch columns are not used."); 4976 ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendY", &flags, ImGuiTableFlags_NoHostExtendY); 4977 ImGui::SameLine(); HelpMarker("Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).\n\nOnly available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible."); 4978 ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags, ImGuiTableFlags_NoKeepColumnsVisible); 4979 ImGui::SameLine(); HelpMarker("Only available if ScrollX is disabled."); 4980 ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths); 4981 ImGui::SameLine(); HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth."); 4982 ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip); 4983 ImGui::SameLine(); HelpMarker("Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with ScrollFreeze options."); 4984 ImGui::TreePop(); 4985 } 4986 4987 if (ImGui::TreeNodeEx("Padding:", ImGuiTreeNodeFlags_DefaultOpen)) 4988 { 4989 ImGui::CheckboxFlags("ImGuiTableFlags_PadOuterX", &flags, ImGuiTableFlags_PadOuterX); 4990 ImGui::CheckboxFlags("ImGuiTableFlags_NoPadOuterX", &flags, ImGuiTableFlags_NoPadOuterX); 4991 ImGui::CheckboxFlags("ImGuiTableFlags_NoPadInnerX", &flags, ImGuiTableFlags_NoPadInnerX); 4992 ImGui::TreePop(); 4993 } 4994 4995 if (ImGui::TreeNodeEx("Scrolling:", ImGuiTreeNodeFlags_DefaultOpen)) 4996 { 4997 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX); 4998 ImGui::SameLine(); 4999 ImGui::SetNextItemWidth(ImGui::GetFrameHeight()); 5000 ImGui::DragInt("freeze_cols", &freeze_cols, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput); 5001 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY); 5002 ImGui::SameLine(); 5003 ImGui::SetNextItemWidth(ImGui::GetFrameHeight()); 5004 ImGui::DragInt("freeze_rows", &freeze_rows, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput); 5005 ImGui::TreePop(); 5006 } 5007 5008 if (ImGui::TreeNodeEx("Sorting:", ImGuiTreeNodeFlags_DefaultOpen)) 5009 { 5010 ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti); 5011 ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1)."); 5012 ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate); 5013 ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0)."); 5014 ImGui::TreePop(); 5015 } 5016 5017 if (ImGui::TreeNodeEx("Other:", ImGuiTreeNodeFlags_DefaultOpen)) 5018 { 5019 ImGui::Checkbox("show_headers", &show_headers); 5020 ImGui::Checkbox("show_wrapped_text", &show_wrapped_text); 5021 5022 ImGui::DragFloat2("##OuterSize", &outer_size_value.x); 5023 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); 5024 ImGui::Checkbox("outer_size", &outer_size_enabled); 5025 ImGui::SameLine(); 5026 HelpMarker("If scrolling is disabled (ScrollX and ScrollY not set):\n" 5027 "- The table is output directly in the parent window.\n" 5028 "- OuterSize.x < 0.0f will right-align the table.\n" 5029 "- OuterSize.x = 0.0f will narrow fit the table unless there are any Stretch column.\n" 5030 "- OuterSize.y then becomes the minimum size for the table, which will extend vertically if there are more rows (unless NoHostExtendY is set)."); 5031 5032 // From a user point of view we will tend to use 'inner_width' differently depending on whether our table is embedding scrolling. 5033 // To facilitate toying with this demo we will actually pass 0.0f to the BeginTable() when ScrollX is disabled. 5034 ImGui::DragFloat("inner_width (when ScrollX active)", &inner_width_with_scroll, 1.0f, 0.0f, FLT_MAX); 5035 5036 ImGui::DragFloat("row_min_height", &row_min_height, 1.0f, 0.0f, FLT_MAX); 5037 ImGui::SameLine(); HelpMarker("Specify height of the Selectable item."); 5038 5039 ImGui::DragInt("items_count", &items_count, 0.1f, 0, 9999); 5040 ImGui::Combo("items_type (first column)", &contents_type, contents_type_names, IM_ARRAYSIZE(contents_type_names)); 5041 //filter.Draw("filter"); 5042 ImGui::TreePop(); 5043 } 5044 5045 ImGui::PopItemWidth(); 5046 PopStyleCompact(); 5047 ImGui::Spacing(); 5048 ImGui::TreePop(); 5049 } 5050 5051 // Update item list if we changed the number of items 5052 static ImVector<MyItem> items; 5053 static ImVector<int> selection; 5054 static bool items_need_sort = false; 5055 if (items.Size != items_count) 5056 { 5057 items.resize(items_count, MyItem()); 5058 for (int n = 0; n < items_count; n++) 5059 { 5060 const int template_n = n % IM_ARRAYSIZE(template_items_names); 5061 MyItem& item = items[n]; 5062 item.ID = n; 5063 item.Name = template_items_names[template_n]; 5064 item.Quantity = (template_n == 3) ? 10 : (template_n == 4) ? 20 : 0; // Assign default quantities 5065 } 5066 } 5067 5068 const ImDrawList* parent_draw_list = ImGui::GetWindowDrawList(); 5069 const int parent_draw_list_draw_cmd_count = parent_draw_list->CmdBuffer.Size; 5070 ImVec2 table_scroll_cur, table_scroll_max; // For debug display 5071 const ImDrawList* table_draw_list = NULL; // " 5072 5073 // Submit table 5074 const float inner_width_to_use = (flags & ImGuiTableFlags_ScrollX) ? inner_width_with_scroll : 0.0f; 5075 if (ImGui::BeginTable("table_advanced", 6, flags, outer_size_enabled ? outer_size_value : ImVec2(0, 0), inner_width_to_use)) 5076 { 5077 // Declare columns 5078 // We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications. 5079 // This is so our sort function can identify a column given our own identifier. We could also identify them based on their index! 5080 ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoHide, 0.0f, MyItemColumnID_ID); 5081 ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Name); 5082 ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Action); 5083 ImGui::TableSetupColumn("Quantity", ImGuiTableColumnFlags_PreferSortDescending, 0.0f, MyItemColumnID_Quantity); 5084 ImGui::TableSetupColumn("Description", (flags & ImGuiTableFlags_NoHostExtendX) ? 0 : ImGuiTableColumnFlags_WidthStretch, 0.0f, MyItemColumnID_Description); 5085 ImGui::TableSetupColumn("Hidden", ImGuiTableColumnFlags_DefaultHide | ImGuiTableColumnFlags_NoSort); 5086 ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows); 5087 5088 // Sort our data if sort specs have been changed! 5089 ImGuiTableSortSpecs* sorts_specs = ImGui::TableGetSortSpecs(); 5090 if (sorts_specs && sorts_specs->SpecsDirty) 5091 items_need_sort = true; 5092 if (sorts_specs && items_need_sort && items.Size > 1) 5093 { 5094 MyItem::s_current_sort_specs = sorts_specs; // Store in variable accessible by the sort function. 5095 qsort(&items[0], (size_t)items.Size, sizeof(items[0]), MyItem::CompareWithSortSpecs); 5096 MyItem::s_current_sort_specs = NULL; 5097 sorts_specs->SpecsDirty = false; 5098 } 5099 items_need_sort = false; 5100 5101 // Take note of whether we are currently sorting based on the Quantity field, 5102 // we will use this to trigger sorting when we know the data of this column has been modified. 5103 const bool sorts_specs_using_quantity = (ImGui::TableGetColumnFlags(3) & ImGuiTableColumnFlags_IsSorted) != 0; 5104 5105 // Show headers 5106 if (show_headers) 5107 ImGui::TableHeadersRow(); 5108 5109 // Show data 5110 // FIXME-TABLE FIXME-NAV: How we can get decent up/down even though we have the buttons here? 5111 ImGui::PushButtonRepeat(true); 5112 #if 1 5113 // Demonstrate using clipper for large vertical lists 5114 ImGuiListClipper clipper; 5115 clipper.Begin(items.Size); 5116 while (clipper.Step()) 5117 { 5118 for (int row_n = clipper.DisplayStart; row_n < clipper.DisplayEnd; row_n++) 5119 #else 5120 // Without clipper 5121 { 5122 for (int row_n = 0; row_n < items.Size; row_n++) 5123 #endif 5124 { 5125 MyItem* item = &items[row_n]; 5126 //if (!filter.PassFilter(item->Name)) 5127 // continue; 5128 5129 const bool item_is_selected = selection.contains(item->ID); 5130 ImGui::PushID(item->ID); 5131 ImGui::TableNextRow(ImGuiTableRowFlags_None, row_min_height); 5132 5133 // For the demo purpose we can select among different type of items submitted in the first column 5134 ImGui::TableSetColumnIndex(0); 5135 char label[32]; 5136 sprintf(label, "%04d", item->ID); 5137 if (contents_type == CT_Text) 5138 ImGui::TextUnformatted(label); 5139 else if (contents_type == CT_Button) 5140 ImGui::Button(label); 5141 else if (contents_type == CT_SmallButton) 5142 ImGui::SmallButton(label); 5143 else if (contents_type == CT_FillButton) 5144 ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f)); 5145 else if (contents_type == CT_Selectable || contents_type == CT_SelectableSpanRow) 5146 { 5147 ImGuiSelectableFlags selectable_flags = (contents_type == CT_SelectableSpanRow) ? ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap : ImGuiSelectableFlags_None; 5148 if (ImGui::Selectable(label, item_is_selected, selectable_flags, ImVec2(0, row_min_height))) 5149 { 5150 if (ImGui::GetIO().KeyCtrl) 5151 { 5152 if (item_is_selected) 5153 selection.find_erase_unsorted(item->ID); 5154 else 5155 selection.push_back(item->ID); 5156 } 5157 else 5158 { 5159 selection.clear(); 5160 selection.push_back(item->ID); 5161 } 5162 } 5163 } 5164 5165 if (ImGui::TableSetColumnIndex(1)) 5166 ImGui::TextUnformatted(item->Name); 5167 5168 // Here we demonstrate marking our data set as needing to be sorted again if we modified a quantity, 5169 // and we are currently sorting on the column showing the Quantity. 5170 // To avoid triggering a sort while holding the button, we only trigger it when the button has been released. 5171 // You will probably need a more advanced system in your code if you want to automatically sort when a specific entry changes. 5172 if (ImGui::TableSetColumnIndex(2)) 5173 { 5174 if (ImGui::SmallButton("Chop")) { item->Quantity += 1; } 5175 if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) { items_need_sort = true; } 5176 ImGui::SameLine(); 5177 if (ImGui::SmallButton("Eat")) { item->Quantity -= 1; } 5178 if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) { items_need_sort = true; } 5179 } 5180 5181 if (ImGui::TableSetColumnIndex(3)) 5182 ImGui::Text("%d", item->Quantity); 5183 5184 ImGui::TableSetColumnIndex(4); 5185 if (show_wrapped_text) 5186 ImGui::TextWrapped("Lorem ipsum dolor sit amet"); 5187 else 5188 ImGui::Text("Lorem ipsum dolor sit amet"); 5189 5190 if (ImGui::TableSetColumnIndex(5)) 5191 ImGui::Text("1234"); 5192 5193 ImGui::PopID(); 5194 } 5195 } 5196 ImGui::PopButtonRepeat(); 5197 5198 // Store some info to display debug details below 5199 table_scroll_cur = ImVec2(ImGui::GetScrollX(), ImGui::GetScrollY()); 5200 table_scroll_max = ImVec2(ImGui::GetScrollMaxX(), ImGui::GetScrollMaxY()); 5201 table_draw_list = ImGui::GetWindowDrawList(); 5202 ImGui::EndTable(); 5203 } 5204 static bool show_debug_details = false; 5205 ImGui::Checkbox("Debug details", &show_debug_details); 5206 if (show_debug_details && table_draw_list) 5207 { 5208 ImGui::SameLine(0.0f, 0.0f); 5209 const int table_draw_list_draw_cmd_count = table_draw_list->CmdBuffer.Size; 5210 if (table_draw_list == parent_draw_list) 5211 ImGui::Text(": DrawCmd: +%d (in same window)", 5212 table_draw_list_draw_cmd_count - parent_draw_list_draw_cmd_count); 5213 else 5214 ImGui::Text(": DrawCmd: +%d (in child window), Scroll: (%.f/%.f) (%.f/%.f)", 5215 table_draw_list_draw_cmd_count - 1, table_scroll_cur.x, table_scroll_max.x, table_scroll_cur.y, table_scroll_max.y); 5216 } 5217 ImGui::TreePop(); 5218 } 5219 5220 ImGui::PopID(); 5221 5222 ShowDemoWindowColumns(); 5223 5224 if (disable_indent) 5225 ImGui::PopStyleVar(); 5226 } 5227 5228 // Demonstrate old/legacy Columns API! 5229 // [2020: Columns are under-featured and not maintained. Prefer using the more flexible and powerful BeginTable() API!] 5230 static void ShowDemoWindowColumns() 5231 { 5232 bool open = ImGui::TreeNode("Legacy Columns API"); 5233 ImGui::SameLine(); 5234 HelpMarker("Columns() is an old API! Prefer using the more flexible and powerful BeginTable() API!"); 5235 if (!open) 5236 return; 5237 5238 // Basic columns 5239 if (ImGui::TreeNode("Basic")) 5240 { 5241 ImGui::Text("Without border:"); 5242 ImGui::Columns(3, "mycolumns3", false); // 3-ways, no border 5243 ImGui::Separator(); 5244 for (int n = 0; n < 14; n++) 5245 { 5246 char label[32]; 5247 sprintf(label, "Item %d", n); 5248 if (ImGui::Selectable(label)) {} 5249 //if (ImGui::Button(label, ImVec2(-FLT_MIN,0.0f))) {} 5250 ImGui::NextColumn(); 5251 } 5252 ImGui::Columns(1); 5253 ImGui::Separator(); 5254 5255 ImGui::Text("With border:"); 5256 ImGui::Columns(4, "mycolumns"); // 4-ways, with border 5257 ImGui::Separator(); 5258 ImGui::Text("ID"); ImGui::NextColumn(); 5259 ImGui::Text("Name"); ImGui::NextColumn(); 5260 ImGui::Text("Path"); ImGui::NextColumn(); 5261 ImGui::Text("Hovered"); ImGui::NextColumn(); 5262 ImGui::Separator(); 5263 const char* names[3] = { "One", "Two", "Three" }; 5264 const char* paths[3] = { "/path/one", "/path/two", "/path/three" }; 5265 static int selected = -1; 5266 for (int i = 0; i < 3; i++) 5267 { 5268 char label[32]; 5269 sprintf(label, "%04d", i); 5270 if (ImGui::Selectable(label, selected == i, ImGuiSelectableFlags_SpanAllColumns)) 5271 selected = i; 5272 bool hovered = ImGui::IsItemHovered(); 5273 ImGui::NextColumn(); 5274 ImGui::Text(names[i]); ImGui::NextColumn(); 5275 ImGui::Text(paths[i]); ImGui::NextColumn(); 5276 ImGui::Text("%d", hovered); ImGui::NextColumn(); 5277 } 5278 ImGui::Columns(1); 5279 ImGui::Separator(); 5280 ImGui::TreePop(); 5281 } 5282 5283 if (ImGui::TreeNode("Borders")) 5284 { 5285 // NB: Future columns API should allow automatic horizontal borders. 5286 static bool h_borders = true; 5287 static bool v_borders = true; 5288 static int columns_count = 4; 5289 const int lines_count = 3; 5290 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); 5291 ImGui::DragInt("##columns_count", &columns_count, 0.1f, 2, 10, "%d columns"); 5292 if (columns_count < 2) 5293 columns_count = 2; 5294 ImGui::SameLine(); 5295 ImGui::Checkbox("horizontal", &h_borders); 5296 ImGui::SameLine(); 5297 ImGui::Checkbox("vertical", &v_borders); 5298 ImGui::Columns(columns_count, NULL, v_borders); 5299 for (int i = 0; i < columns_count * lines_count; i++) 5300 { 5301 if (h_borders && ImGui::GetColumnIndex() == 0) 5302 ImGui::Separator(); 5303 ImGui::Text("%c%c%c", 'a' + i, 'a' + i, 'a' + i); 5304 ImGui::Text("Width %.2f", ImGui::GetColumnWidth()); 5305 ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x); 5306 ImGui::Text("Offset %.2f", ImGui::GetColumnOffset()); 5307 ImGui::Text("Long text that is likely to clip"); 5308 ImGui::Button("Button", ImVec2(-FLT_MIN, 0.0f)); 5309 ImGui::NextColumn(); 5310 } 5311 ImGui::Columns(1); 5312 if (h_borders) 5313 ImGui::Separator(); 5314 ImGui::TreePop(); 5315 } 5316 5317 // Create multiple items in a same cell before switching to next column 5318 if (ImGui::TreeNode("Mixed items")) 5319 { 5320 ImGui::Columns(3, "mixed"); 5321 ImGui::Separator(); 5322 5323 ImGui::Text("Hello"); 5324 ImGui::Button("Banana"); 5325 ImGui::NextColumn(); 5326 5327 ImGui::Text("ImGui"); 5328 ImGui::Button("Apple"); 5329 static float foo = 1.0f; 5330 ImGui::InputFloat("red", &foo, 0.05f, 0, "%.3f"); 5331 ImGui::Text("An extra line here."); 5332 ImGui::NextColumn(); 5333 5334 ImGui::Text("Sailor"); 5335 ImGui::Button("Corniflower"); 5336 static float bar = 1.0f; 5337 ImGui::InputFloat("blue", &bar, 0.05f, 0, "%.3f"); 5338 ImGui::NextColumn(); 5339 5340 if (ImGui::CollapsingHeader("Category A")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); 5341 if (ImGui::CollapsingHeader("Category B")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); 5342 if (ImGui::CollapsingHeader("Category C")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); 5343 ImGui::Columns(1); 5344 ImGui::Separator(); 5345 ImGui::TreePop(); 5346 } 5347 5348 // Word wrapping 5349 if (ImGui::TreeNode("Word-wrapping")) 5350 { 5351 ImGui::Columns(2, "word-wrapping"); 5352 ImGui::Separator(); 5353 ImGui::TextWrapped("The quick brown fox jumps over the lazy dog."); 5354 ImGui::TextWrapped("Hello Left"); 5355 ImGui::NextColumn(); 5356 ImGui::TextWrapped("The quick brown fox jumps over the lazy dog."); 5357 ImGui::TextWrapped("Hello Right"); 5358 ImGui::Columns(1); 5359 ImGui::Separator(); 5360 ImGui::TreePop(); 5361 } 5362 5363 if (ImGui::TreeNode("Horizontal Scrolling")) 5364 { 5365 ImGui::SetNextWindowContentSize(ImVec2(1500.0f, 0.0f)); 5366 ImVec2 child_size = ImVec2(0, ImGui::GetFontSize() * 20.0f); 5367 ImGui::BeginChild("##ScrollingRegion", child_size, false, ImGuiWindowFlags_HorizontalScrollbar); 5368 ImGui::Columns(10); 5369 5370 // Also demonstrate using clipper for large vertical lists 5371 int ITEMS_COUNT = 2000; 5372 ImGuiListClipper clipper; 5373 clipper.Begin(ITEMS_COUNT); 5374 while (clipper.Step()) 5375 { 5376 for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) 5377 for (int j = 0; j < 10; j++) 5378 { 5379 ImGui::Text("Line %d Column %d...", i, j); 5380 ImGui::NextColumn(); 5381 } 5382 } 5383 ImGui::Columns(1); 5384 ImGui::EndChild(); 5385 ImGui::TreePop(); 5386 } 5387 5388 if (ImGui::TreeNode("Tree")) 5389 { 5390 ImGui::Columns(2, "tree", true); 5391 for (int x = 0; x < 3; x++) 5392 { 5393 bool open1 = ImGui::TreeNode((void*)(intptr_t)x, "Node%d", x); 5394 ImGui::NextColumn(); 5395 ImGui::Text("Node contents"); 5396 ImGui::NextColumn(); 5397 if (open1) 5398 { 5399 for (int y = 0; y < 3; y++) 5400 { 5401 bool open2 = ImGui::TreeNode((void*)(intptr_t)y, "Node%d.%d", x, y); 5402 ImGui::NextColumn(); 5403 ImGui::Text("Node contents"); 5404 if (open2) 5405 { 5406 ImGui::Text("Even more contents"); 5407 if (ImGui::TreeNode("Tree in column")) 5408 { 5409 ImGui::Text("The quick brown fox jumps over the lazy dog"); 5410 ImGui::TreePop(); 5411 } 5412 } 5413 ImGui::NextColumn(); 5414 if (open2) 5415 ImGui::TreePop(); 5416 } 5417 ImGui::TreePop(); 5418 } 5419 } 5420 ImGui::Columns(1); 5421 ImGui::TreePop(); 5422 } 5423 5424 ImGui::TreePop(); 5425 } 5426 5427 static void ShowDemoWindowMisc() 5428 { 5429 if (ImGui::CollapsingHeader("Filtering")) 5430 { 5431 // Helper class to easy setup a text filter. 5432 // You may want to implement a more feature-full filtering scheme in your own application. 5433 static ImGuiTextFilter filter; 5434 ImGui::Text("Filter usage:\n" 5435 " \"\" display all lines\n" 5436 " \"xxx\" display lines containing \"xxx\"\n" 5437 " \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n" 5438 " \"-xxx\" hide lines containing \"xxx\""); 5439 filter.Draw(); 5440 const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" }; 5441 for (int i = 0; i < IM_ARRAYSIZE(lines); i++) 5442 if (filter.PassFilter(lines[i])) 5443 ImGui::BulletText("%s", lines[i]); 5444 } 5445 5446 if (ImGui::CollapsingHeader("Inputs, Navigation & Focus")) 5447 { 5448 ImGuiIO& io = ImGui::GetIO(); 5449 5450 // Display ImGuiIO output flags 5451 ImGui::Text("WantCaptureMouse: %d", io.WantCaptureMouse); 5452 ImGui::Text("WantCaptureKeyboard: %d", io.WantCaptureKeyboard); 5453 ImGui::Text("WantTextInput: %d", io.WantTextInput); 5454 ImGui::Text("WantSetMousePos: %d", io.WantSetMousePos); 5455 ImGui::Text("NavActive: %d, NavVisible: %d", io.NavActive, io.NavVisible); 5456 5457 // Display Mouse state 5458 if (ImGui::TreeNode("Mouse State")) 5459 { 5460 if (ImGui::IsMousePosValid()) 5461 ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y); 5462 else 5463 ImGui::Text("Mouse pos: <INVALID>"); 5464 ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y); 5465 ImGui::Text("Mouse down:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDown(i)) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); } 5466 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); } 5467 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); } 5468 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); } 5469 ImGui::Text("Mouse wheel: %.1f", io.MouseWheel); 5470 ImGui::Text("Pen Pressure: %.1f", io.PenPressure); // Note: currently unused 5471 ImGui::TreePop(); 5472 } 5473 5474 // Display Keyboard/Mouse state 5475 if (ImGui::TreeNode("Keyboard & Navigation State")) 5476 { 5477 ImGui::Text("Keys down:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyDown(i)) { ImGui::SameLine(); ImGui::Text("%d (0x%X) (%.02f secs)", i, i, io.KeysDownDuration[i]); } 5478 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); } 5479 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); } 5480 ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); 5481 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. 5482 5483 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 (%.02f secs)", i, io.NavInputs[i], io.NavInputsDownDuration[i]); } 5484 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); } 5485 5486 ImGui::Button("Hovering me sets the\nkeyboard capture flag"); 5487 if (ImGui::IsItemHovered()) 5488 ImGui::CaptureKeyboardFromApp(true); 5489 ImGui::SameLine(); 5490 ImGui::Button("Holding me clears the\nthe keyboard capture flag"); 5491 if (ImGui::IsItemActive()) 5492 ImGui::CaptureKeyboardFromApp(false); 5493 ImGui::TreePop(); 5494 } 5495 5496 if (ImGui::TreeNode("Tabbing")) 5497 { 5498 ImGui::Text("Use TAB/SHIFT+TAB to cycle through keyboard editable fields."); 5499 static char buf[32] = "hello"; 5500 ImGui::InputText("1", buf, IM_ARRAYSIZE(buf)); 5501 ImGui::InputText("2", buf, IM_ARRAYSIZE(buf)); 5502 ImGui::InputText("3", buf, IM_ARRAYSIZE(buf)); 5503 ImGui::PushAllowKeyboardFocus(false); 5504 ImGui::InputText("4 (tab skip)", buf, IM_ARRAYSIZE(buf)); 5505 ImGui::SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab."); 5506 ImGui::PopAllowKeyboardFocus(); 5507 ImGui::InputText("5", buf, IM_ARRAYSIZE(buf)); 5508 ImGui::TreePop(); 5509 } 5510 5511 if (ImGui::TreeNode("Focus from code")) 5512 { 5513 bool focus_1 = ImGui::Button("Focus on 1"); ImGui::SameLine(); 5514 bool focus_2 = ImGui::Button("Focus on 2"); ImGui::SameLine(); 5515 bool focus_3 = ImGui::Button("Focus on 3"); 5516 int has_focus = 0; 5517 static char buf[128] = "click on a button to set focus"; 5518 5519 if (focus_1) ImGui::SetKeyboardFocusHere(); 5520 ImGui::InputText("1", buf, IM_ARRAYSIZE(buf)); 5521 if (ImGui::IsItemActive()) has_focus = 1; 5522 5523 if (focus_2) ImGui::SetKeyboardFocusHere(); 5524 ImGui::InputText("2", buf, IM_ARRAYSIZE(buf)); 5525 if (ImGui::IsItemActive()) has_focus = 2; 5526 5527 ImGui::PushAllowKeyboardFocus(false); 5528 if (focus_3) ImGui::SetKeyboardFocusHere(); 5529 ImGui::InputText("3 (tab skip)", buf, IM_ARRAYSIZE(buf)); 5530 if (ImGui::IsItemActive()) has_focus = 3; 5531 ImGui::SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab."); 5532 ImGui::PopAllowKeyboardFocus(); 5533 5534 if (has_focus) 5535 ImGui::Text("Item with focus: %d", has_focus); 5536 else 5537 ImGui::Text("Item with focus: <none>"); 5538 5539 // Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item 5540 static float f3[3] = { 0.0f, 0.0f, 0.0f }; 5541 int focus_ahead = -1; 5542 if (ImGui::Button("Focus on X")) { focus_ahead = 0; } ImGui::SameLine(); 5543 if (ImGui::Button("Focus on Y")) { focus_ahead = 1; } ImGui::SameLine(); 5544 if (ImGui::Button("Focus on Z")) { focus_ahead = 2; } 5545 if (focus_ahead != -1) ImGui::SetKeyboardFocusHere(focus_ahead); 5546 ImGui::SliderFloat3("Float3", &f3[0], 0.0f, 1.0f); 5547 5548 ImGui::TextWrapped("NB: Cursor & selection are preserved when refocusing last used item in code."); 5549 ImGui::TreePop(); 5550 } 5551 5552 if (ImGui::TreeNode("Dragging")) 5553 { 5554 ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget."); 5555 for (int button = 0; button < 3; button++) 5556 { 5557 ImGui::Text("IsMouseDragging(%d):", button); 5558 ImGui::Text(" w/ default threshold: %d,", ImGui::IsMouseDragging(button)); 5559 ImGui::Text(" w/ zero threshold: %d,", ImGui::IsMouseDragging(button, 0.0f)); 5560 ImGui::Text(" w/ large threshold: %d,", ImGui::IsMouseDragging(button, 20.0f)); 5561 } 5562 5563 ImGui::Button("Drag Me"); 5564 if (ImGui::IsItemActive()) 5565 ImGui::GetForegroundDrawList()->AddLine(io.MouseClickedPos[0], io.MousePos, ImGui::GetColorU32(ImGuiCol_Button), 4.0f); // Draw a line between the button and the mouse cursor 5566 5567 // Drag operations gets "unlocked" when the mouse has moved past a certain threshold 5568 // (the default threshold is stored in io.MouseDragThreshold). You can request a lower or higher 5569 // threshold using the second parameter of IsMouseDragging() and GetMouseDragDelta(). 5570 ImVec2 value_raw = ImGui::GetMouseDragDelta(0, 0.0f); 5571 ImVec2 value_with_lock_threshold = ImGui::GetMouseDragDelta(0); 5572 ImVec2 mouse_delta = io.MouseDelta; 5573 ImGui::Text("GetMouseDragDelta(0):"); 5574 ImGui::Text(" w/ default threshold: (%.1f, %.1f)", value_with_lock_threshold.x, value_with_lock_threshold.y); 5575 ImGui::Text(" w/ zero threshold: (%.1f, %.1f)", value_raw.x, value_raw.y); 5576 ImGui::Text("io.MouseDelta: (%.1f, %.1f)", mouse_delta.x, mouse_delta.y); 5577 ImGui::TreePop(); 5578 } 5579 5580 if (ImGui::TreeNode("Mouse cursors")) 5581 { 5582 const char* mouse_cursors_names[] = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "NotAllowed" }; 5583 IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT); 5584 5585 ImGuiMouseCursor current = ImGui::GetMouseCursor(); 5586 ImGui::Text("Current mouse cursor = %d: %s", current, mouse_cursors_names[current]); 5587 ImGui::Text("Hover to see mouse cursors:"); 5588 ImGui::SameLine(); HelpMarker( 5589 "Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. " 5590 "If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, " 5591 "otherwise your backend needs to handle it."); 5592 for (int i = 0; i < ImGuiMouseCursor_COUNT; i++) 5593 { 5594 char label[32]; 5595 sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]); 5596 ImGui::Bullet(); ImGui::Selectable(label, false); 5597 if (ImGui::IsItemHovered()) 5598 ImGui::SetMouseCursor(i); 5599 } 5600 ImGui::TreePop(); 5601 } 5602 } 5603 } 5604 5605 //----------------------------------------------------------------------------- 5606 // [SECTION] About Window / ShowAboutWindow() 5607 // Access from Dear ImGui Demo -> Tools -> About 5608 //----------------------------------------------------------------------------- 5609 5610 void ImGui::ShowAboutWindow(bool* p_open) 5611 { 5612 if (!ImGui::Begin("About Dear ImGui", p_open, ImGuiWindowFlags_AlwaysAutoResize)) 5613 { 5614 ImGui::End(); 5615 return; 5616 } 5617 ImGui::Text("Dear ImGui %s", ImGui::GetVersion()); 5618 ImGui::Separator(); 5619 ImGui::Text("By Omar Cornut and all Dear ImGui contributors."); 5620 ImGui::Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information."); 5621 5622 static bool show_config_info = false; 5623 ImGui::Checkbox("Config/Build Information", &show_config_info); 5624 if (show_config_info) 5625 { 5626 ImGuiIO& io = ImGui::GetIO(); 5627 ImGuiStyle& style = ImGui::GetStyle(); 5628 5629 bool copy_to_clipboard = ImGui::Button("Copy to clipboard"); 5630 ImVec2 child_size = ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 18); 5631 ImGui::BeginChildFrame(ImGui::GetID("cfg_infos"), child_size, ImGuiWindowFlags_NoMove); 5632 if (copy_to_clipboard) 5633 { 5634 ImGui::LogToClipboard(); 5635 ImGui::LogText("```\n"); // Back quotes will make text appears without formatting when pasting on GitHub 5636 } 5637 5638 ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM); 5639 ImGui::Separator(); 5640 ImGui::Text("sizeof(size_t): %d, sizeof(ImDrawIdx): %d, sizeof(ImDrawVert): %d", (int)sizeof(size_t), (int)sizeof(ImDrawIdx), (int)sizeof(ImDrawVert)); 5641 ImGui::Text("define: __cplusplus=%d", (int)__cplusplus); 5642 #ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS 5643 ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_FUNCTIONS"); 5644 #endif 5645 #ifdef IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS 5646 ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS"); 5647 #endif 5648 #ifdef IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS 5649 ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS"); 5650 #endif 5651 #ifdef IMGUI_DISABLE_WIN32_FUNCTIONS 5652 ImGui::Text("define: IMGUI_DISABLE_WIN32_FUNCTIONS"); 5653 #endif 5654 #ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS 5655 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS"); 5656 #endif 5657 #ifdef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS 5658 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS"); 5659 #endif 5660 #ifdef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS 5661 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS"); 5662 #endif 5663 #ifdef IMGUI_DISABLE_FILE_FUNCTIONS 5664 ImGui::Text("define: IMGUI_DISABLE_FILE_FUNCTIONS"); 5665 #endif 5666 #ifdef IMGUI_DISABLE_DEFAULT_ALLOCATORS 5667 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_ALLOCATORS"); 5668 #endif 5669 #ifdef IMGUI_USE_BGRA_PACKED_COLOR 5670 ImGui::Text("define: IMGUI_USE_BGRA_PACKED_COLOR"); 5671 #endif 5672 #ifdef _WIN32 5673 ImGui::Text("define: _WIN32"); 5674 #endif 5675 #ifdef _WIN64 5676 ImGui::Text("define: _WIN64"); 5677 #endif 5678 #ifdef __linux__ 5679 ImGui::Text("define: __linux__"); 5680 #endif 5681 #ifdef __APPLE__ 5682 ImGui::Text("define: __APPLE__"); 5683 #endif 5684 #ifdef _MSC_VER 5685 ImGui::Text("define: _MSC_VER=%d", _MSC_VER); 5686 #endif 5687 #ifdef _MSVC_LANG 5688 ImGui::Text("define: _MSVC_LANG=%d", (int)_MSVC_LANG); 5689 #endif 5690 #ifdef __MINGW32__ 5691 ImGui::Text("define: __MINGW32__"); 5692 #endif 5693 #ifdef __MINGW64__ 5694 ImGui::Text("define: __MINGW64__"); 5695 #endif 5696 #ifdef __GNUC__ 5697 ImGui::Text("define: __GNUC__=%d", (int)__GNUC__); 5698 #endif 5699 #ifdef __clang_version__ 5700 ImGui::Text("define: __clang_version__=%s", __clang_version__); 5701 #endif 5702 ImGui::Separator(); 5703 ImGui::Text("io.BackendPlatformName: %s", io.BackendPlatformName ? io.BackendPlatformName : "NULL"); 5704 ImGui::Text("io.BackendRendererName: %s", io.BackendRendererName ? io.BackendRendererName : "NULL"); 5705 ImGui::Text("io.ConfigFlags: 0x%08X", io.ConfigFlags); 5706 if (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) ImGui::Text(" NavEnableKeyboard"); 5707 if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) ImGui::Text(" NavEnableGamepad"); 5708 if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) ImGui::Text(" NavEnableSetMousePos"); 5709 if (io.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard) ImGui::Text(" NavNoCaptureKeyboard"); 5710 if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) ImGui::Text(" NoMouse"); 5711 if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) ImGui::Text(" NoMouseCursorChange"); 5712 if (io.MouseDrawCursor) ImGui::Text("io.MouseDrawCursor"); 5713 if (io.ConfigMacOSXBehaviors) ImGui::Text("io.ConfigMacOSXBehaviors"); 5714 if (io.ConfigInputTextCursorBlink) ImGui::Text("io.ConfigInputTextCursorBlink"); 5715 if (io.ConfigWindowsResizeFromEdges) ImGui::Text("io.ConfigWindowsResizeFromEdges"); 5716 if (io.ConfigWindowsMoveFromTitleBarOnly) ImGui::Text("io.ConfigWindowsMoveFromTitleBarOnly"); 5717 if (io.ConfigMemoryCompactTimer >= 0.0f) ImGui::Text("io.ConfigMemoryCompactTimer = %.1f", io.ConfigMemoryCompactTimer); 5718 ImGui::Text("io.BackendFlags: 0x%08X", io.BackendFlags); 5719 if (io.BackendFlags & ImGuiBackendFlags_HasGamepad) ImGui::Text(" HasGamepad"); 5720 if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) ImGui::Text(" HasMouseCursors"); 5721 if (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos) ImGui::Text(" HasSetMousePos"); 5722 if (io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) ImGui::Text(" RendererHasVtxOffset"); 5723 ImGui::Separator(); 5724 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); 5725 ImGui::Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y); 5726 ImGui::Text("io.DisplayFramebufferScale: %.2f,%.2f", io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y); 5727 ImGui::Separator(); 5728 ImGui::Text("style.WindowPadding: %.2f,%.2f", style.WindowPadding.x, style.WindowPadding.y); 5729 ImGui::Text("style.WindowBorderSize: %.2f", style.WindowBorderSize); 5730 ImGui::Text("style.FramePadding: %.2f,%.2f", style.FramePadding.x, style.FramePadding.y); 5731 ImGui::Text("style.FrameRounding: %.2f", style.FrameRounding); 5732 ImGui::Text("style.FrameBorderSize: %.2f", style.FrameBorderSize); 5733 ImGui::Text("style.ItemSpacing: %.2f,%.2f", style.ItemSpacing.x, style.ItemSpacing.y); 5734 ImGui::Text("style.ItemInnerSpacing: %.2f,%.2f", style.ItemInnerSpacing.x, style.ItemInnerSpacing.y); 5735 5736 if (copy_to_clipboard) 5737 { 5738 ImGui::LogText("\n```\n"); 5739 ImGui::LogFinish(); 5740 } 5741 ImGui::EndChildFrame(); 5742 } 5743 ImGui::End(); 5744 } 5745 5746 //----------------------------------------------------------------------------- 5747 // [SECTION] Font viewer / ShowFontAtlas() 5748 //----------------------------------------------------------------------------- 5749 // - ShowFontSelector() 5750 // - ShowFont() 5751 // - ShowFontAtlas() 5752 //----------------------------------------------------------------------------- 5753 5754 // This isn't worth putting in public API but we want Metrics to use it 5755 namespace ImGui { void ShowFontAtlas(ImFontAtlas* atlas); } 5756 5757 // Demo helper function to select among loaded fonts. 5758 // Here we use the regular BeginCombo()/EndCombo() api which is more the more flexible one. 5759 void ImGui::ShowFontSelector(const char* label) 5760 { 5761 ImGuiIO& io = ImGui::GetIO(); 5762 ImFont* font_current = ImGui::GetFont(); 5763 if (ImGui::BeginCombo(label, font_current->GetDebugName())) 5764 { 5765 for (int n = 0; n < io.Fonts->Fonts.Size; n++) 5766 { 5767 ImFont* font = io.Fonts->Fonts[n]; 5768 ImGui::PushID((void*)font); 5769 if (ImGui::Selectable(font->GetDebugName(), font == font_current)) 5770 io.FontDefault = font; 5771 ImGui::PopID(); 5772 } 5773 ImGui::EndCombo(); 5774 } 5775 ImGui::SameLine(); 5776 HelpMarker( 5777 "- Load additional fonts with io.Fonts->AddFontFromFileTTF().\n" 5778 "- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n" 5779 "- Read FAQ and docs/FONTS.md for more details.\n" 5780 "- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame()."); 5781 } 5782 5783 // [Internal] Display details for a single font, called by ShowStyleEditor(). 5784 static void ShowFont(ImFont* font) 5785 { 5786 ImGuiIO& io = ImGui::GetIO(); 5787 ImGuiStyle& style = ImGui::GetStyle(); 5788 bool font_details_opened = ImGui::TreeNode(font, "Font: \"%s\"\n%.2f px, %d glyphs, %d file(s)", 5789 font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size, font->ConfigDataCount); 5790 ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) { io.FontDefault = font; } 5791 if (!font_details_opened) 5792 return; 5793 5794 // Display preview text 5795 ImGui::PushFont(font); 5796 ImGui::Text("The quick brown fox jumps over the lazy dog"); 5797 ImGui::PopFont(); 5798 5799 // Display details 5800 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); 5801 ImGui::DragFloat("Font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f"); // Scale only this font 5802 ImGui::SameLine(); HelpMarker( 5803 "Note than the default embedded font is NOT meant to be scaled.\n\n" 5804 "Font are currently rendered into bitmaps at a given size at the time of building the atlas. " 5805 "You may oversample them to get some flexibility with scaling. " 5806 "You can also render at multiple sizes and select which one to use at runtime.\n\n" 5807 "(Glimmer of hope: the atlas system will be rewritten in the future to make scaling more flexible.)"); 5808 ImGui::Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent); 5809 ImGui::Text("Fallback character: '%c' (U+%04X)", font->FallbackChar, font->FallbackChar); 5810 ImGui::Text("Ellipsis character: '%c' (U+%04X)", font->EllipsisChar, font->EllipsisChar); 5811 const int surface_sqrt = (int)sqrtf((float)font->MetricsTotalSurface); 5812 ImGui::Text("Texture Area: about %d px ~%dx%d px", font->MetricsTotalSurface, surface_sqrt, surface_sqrt); 5813 for (int config_i = 0; config_i < font->ConfigDataCount; config_i++) 5814 if (font->ConfigData) 5815 if (const ImFontConfig* cfg = &font->ConfigData[config_i]) 5816 ImGui::BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d, Offset: (%.1f,%.1f)", 5817 config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH, cfg->GlyphOffset.x, cfg->GlyphOffset.y); 5818 5819 // Display all glyphs of the fonts in separate pages of 256 characters 5820 if (ImGui::TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size)) 5821 { 5822 const ImU32 glyph_col = ImGui::GetColorU32(ImGuiCol_Text); 5823 for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256) 5824 { 5825 // Skip ahead if a large bunch of glyphs are not present in the font (test in chunks of 4k) 5826 // This is only a small optimization to reduce the number of iterations when IM_UNICODE_MAX_CODEPOINT 5827 // is large // (if ImWchar==ImWchar32 we will do at least about 272 queries here) 5828 if (!(base & 4095) && font->IsGlyphRangeUnused(base, base + 4095)) 5829 { 5830 base += 4096 - 256; 5831 continue; 5832 } 5833 5834 int count = 0; 5835 for (unsigned int n = 0; n < 256; n++) 5836 if (font->FindGlyphNoFallback((ImWchar)(base + n))) 5837 count++; 5838 if (count <= 0) 5839 continue; 5840 if (!ImGui::TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph")) 5841 continue; 5842 float cell_size = font->FontSize * 1; 5843 float cell_spacing = style.ItemSpacing.y; 5844 ImVec2 base_pos = ImGui::GetCursorScreenPos(); 5845 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 5846 for (unsigned int n = 0; n < 256; n++) 5847 { 5848 // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions 5849 // available here and thus cannot easily generate a zero-terminated UTF-8 encoded string. 5850 ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing)); 5851 ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size); 5852 const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base + n)); 5853 draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50)); 5854 if (glyph) 5855 font->RenderChar(draw_list, cell_size, cell_p1, glyph_col, (ImWchar)(base + n)); 5856 if (glyph && ImGui::IsMouseHoveringRect(cell_p1, cell_p2)) 5857 { 5858 ImGui::BeginTooltip(); 5859 ImGui::Text("Codepoint: U+%04X", base + n); 5860 ImGui::Separator(); 5861 ImGui::Text("Visible: %d", glyph->Visible); 5862 ImGui::Text("AdvanceX: %.1f", glyph->AdvanceX); 5863 ImGui::Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1); 5864 ImGui::Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1); 5865 ImGui::EndTooltip(); 5866 } 5867 } 5868 ImGui::Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16)); 5869 ImGui::TreePop(); 5870 } 5871 ImGui::TreePop(); 5872 } 5873 ImGui::TreePop(); 5874 } 5875 5876 void ImGui::ShowFontAtlas(ImFontAtlas* atlas) 5877 { 5878 for (int i = 0; i < atlas->Fonts.Size; i++) 5879 { 5880 ImFont* font = atlas->Fonts[i]; 5881 ImGui::PushID(font); 5882 ShowFont(font); 5883 ImGui::PopID(); 5884 } 5885 if (ImGui::TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight)) 5886 { 5887 ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); 5888 ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f); 5889 ImGui::Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0, 0), ImVec2(1, 1), tint_col, border_col); 5890 ImGui::TreePop(); 5891 } 5892 } 5893 5894 //----------------------------------------------------------------------------- 5895 // [SECTION] Style Editor / ShowStyleEditor() 5896 //----------------------------------------------------------------------------- 5897 // - ShowStyleSelector() 5898 // - ShowStyleEditor() 5899 //----------------------------------------------------------------------------- 5900 5901 // Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options. 5902 // Here we use the simplified Combo() api that packs items into a single literal string. 5903 // Useful for quick combo boxes where the choices are known locally. 5904 bool ImGui::ShowStyleSelector(const char* label) 5905 { 5906 static int style_idx = -1; 5907 if (ImGui::Combo(label, &style_idx, "Dark\0Light\0Classic\0")) 5908 { 5909 switch (style_idx) 5910 { 5911 case 0: ImGui::StyleColorsDark(); break; 5912 case 1: ImGui::StyleColorsLight(); break; 5913 case 2: ImGui::StyleColorsClassic(); break; 5914 } 5915 return true; 5916 } 5917 return false; 5918 } 5919 5920 void ImGui::ShowStyleEditor(ImGuiStyle* ref) 5921 { 5922 // You can pass in a reference ImGuiStyle structure to compare to, revert to and save to 5923 // (without a reference style pointer, we will use one compared locally as a reference) 5924 ImGuiStyle& style = ImGui::GetStyle(); 5925 static ImGuiStyle ref_saved_style; 5926 5927 // Default to using internal storage as reference 5928 static bool init = true; 5929 if (init && ref == NULL) 5930 ref_saved_style = style; 5931 init = false; 5932 if (ref == NULL) 5933 ref = &ref_saved_style; 5934 5935 ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.50f); 5936 5937 if (ImGui::ShowStyleSelector("Colors##Selector")) 5938 ref_saved_style = style; 5939 ImGui::ShowFontSelector("Fonts##Selector"); 5940 5941 // Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f) 5942 if (ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f")) 5943 style.GrabRounding = style.FrameRounding; // Make GrabRounding always the same value as FrameRounding 5944 { bool border = (style.WindowBorderSize > 0.0f); if (ImGui::Checkbox("WindowBorder", &border)) { style.WindowBorderSize = border ? 1.0f : 0.0f; } } 5945 ImGui::SameLine(); 5946 { bool border = (style.FrameBorderSize > 0.0f); if (ImGui::Checkbox("FrameBorder", &border)) { style.FrameBorderSize = border ? 1.0f : 0.0f; } } 5947 ImGui::SameLine(); 5948 { bool border = (style.PopupBorderSize > 0.0f); if (ImGui::Checkbox("PopupBorder", &border)) { style.PopupBorderSize = border ? 1.0f : 0.0f; } } 5949 5950 // Save/Revert button 5951 if (ImGui::Button("Save Ref")) 5952 *ref = ref_saved_style = style; 5953 ImGui::SameLine(); 5954 if (ImGui::Button("Revert Ref")) 5955 style = *ref; 5956 ImGui::SameLine(); 5957 HelpMarker( 5958 "Save/Revert in local non-persistent storage. Default Colors definition are not affected. " 5959 "Use \"Export\" below to save them somewhere."); 5960 5961 ImGui::Separator(); 5962 5963 if (ImGui::BeginTabBar("##tabs", ImGuiTabBarFlags_None)) 5964 { 5965 if (ImGui::BeginTabItem("Sizes")) 5966 { 5967 ImGui::Text("Main"); 5968 ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f"); 5969 ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f"); 5970 ImGui::SliderFloat2("CellPadding", (float*)&style.CellPadding, 0.0f, 20.0f, "%.0f"); 5971 ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f"); 5972 ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f"); 5973 ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f"); 5974 ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f"); 5975 ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f"); 5976 ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f"); 5977 ImGui::Text("Borders"); 5978 ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f"); 5979 ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f"); 5980 ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f"); 5981 ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f"); 5982 ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f"); 5983 ImGui::Text("Rounding"); 5984 ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f"); 5985 ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f"); 5986 ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"); 5987 ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f, "%.0f"); 5988 ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f"); 5989 ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f"); 5990 ImGui::SliderFloat("LogSliderDeadzone", &style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f"); 5991 ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f"); 5992 ImGui::Text("Alignment"); 5993 ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); 5994 int window_menu_button_position = style.WindowMenuButtonPosition + 1; 5995 if (ImGui::Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0")) 5996 style.WindowMenuButtonPosition = window_menu_button_position - 1; 5997 ImGui::Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, "Left\0Right\0"); 5998 ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); 5999 ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content."); 6000 ImGui::SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f"); 6001 ImGui::SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content."); 6002 ImGui::Text("Safe Area Padding"); 6003 ImGui::SameLine(); HelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured)."); 6004 ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); 6005 ImGui::EndTabItem(); 6006 } 6007 6008 if (ImGui::BeginTabItem("Colors")) 6009 { 6010 static int output_dest = 0; 6011 static bool output_only_modified = true; 6012 if (ImGui::Button("Export")) 6013 { 6014 if (output_dest == 0) 6015 ImGui::LogToClipboard(); 6016 else 6017 ImGui::LogToTTY(); 6018 ImGui::LogText("ImVec4* colors = ImGui::GetStyle().Colors;" IM_NEWLINE); 6019 for (int i = 0; i < ImGuiCol_COUNT; i++) 6020 { 6021 const ImVec4& col = style.Colors[i]; 6022 const char* name = ImGui::GetStyleColorName(i); 6023 if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0) 6024 ImGui::LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE, 6025 name, 23 - (int)strlen(name), "", col.x, col.y, col.z, col.w); 6026 } 6027 ImGui::LogFinish(); 6028 } 6029 ImGui::SameLine(); ImGui::SetNextItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0"); 6030 ImGui::SameLine(); ImGui::Checkbox("Only Modified Colors", &output_only_modified); 6031 6032 static ImGuiTextFilter filter; 6033 filter.Draw("Filter colors", ImGui::GetFontSize() * 16); 6034 6035 static ImGuiColorEditFlags alpha_flags = 0; 6036 if (ImGui::RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_None)) { alpha_flags = ImGuiColorEditFlags_None; } ImGui::SameLine(); 6037 if (ImGui::RadioButton("Alpha", alpha_flags == ImGuiColorEditFlags_AlphaPreview)) { alpha_flags = ImGuiColorEditFlags_AlphaPreview; } ImGui::SameLine(); 6038 if (ImGui::RadioButton("Both", alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } ImGui::SameLine(); 6039 HelpMarker( 6040 "In the color list:\n" 6041 "Left-click on color square to open color picker,\n" 6042 "Right-click to open edit options menu."); 6043 6044 ImGui::BeginChild("##colors", ImVec2(0, 0), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened); 6045 ImGui::PushItemWidth(-160); 6046 for (int i = 0; i < ImGuiCol_COUNT; i++) 6047 { 6048 const char* name = ImGui::GetStyleColorName(i); 6049 if (!filter.PassFilter(name)) 6050 continue; 6051 ImGui::PushID(i); 6052 ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags); 6053 if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0) 6054 { 6055 // Tips: in a real user application, you may want to merge and use an icon font into the main font, 6056 // so instead of "Save"/"Revert" you'd use icons! 6057 // Read the FAQ and docs/FONTS.md about using icon fonts. It's really easy and super convenient! 6058 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) { ref->Colors[i] = style.Colors[i]; } 6059 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) { style.Colors[i] = ref->Colors[i]; } 6060 } 6061 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); 6062 ImGui::TextUnformatted(name); 6063 ImGui::PopID(); 6064 } 6065 ImGui::PopItemWidth(); 6066 ImGui::EndChild(); 6067 6068 ImGui::EndTabItem(); 6069 } 6070 6071 if (ImGui::BeginTabItem("Fonts")) 6072 { 6073 ImGuiIO& io = ImGui::GetIO(); 6074 ImFontAtlas* atlas = io.Fonts; 6075 HelpMarker("Read FAQ and docs/FONTS.md for details on font loading."); 6076 ImGui::ShowFontAtlas(atlas); 6077 6078 // Post-baking font scaling. Note that this is NOT the nice way of scaling fonts, read below. 6079 // (we enforce hard clamping manually as by default DragFloat/SliderFloat allows CTRL+Click text to get out of bounds). 6080 const float MIN_SCALE = 0.3f; 6081 const float MAX_SCALE = 2.0f; 6082 HelpMarker( 6083 "Those are old settings provided for convenience.\n" 6084 "However, the _correct_ way of scaling your UI is currently to reload your font at the designed size, " 6085 "rebuild the font atlas, and call style.ScaleAllSizes() on a reference ImGuiStyle structure.\n" 6086 "Using those settings here will give you poor quality results."); 6087 static float window_scale = 1.0f; 6088 ImGui::PushItemWidth(ImGui::GetFontSize() * 8); 6089 if (ImGui::DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp)) // Scale only this window 6090 ImGui::SetWindowFontScale(window_scale); 6091 ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp); // Scale everything 6092 ImGui::PopItemWidth(); 6093 6094 ImGui::EndTabItem(); 6095 } 6096 6097 if (ImGui::BeginTabItem("Rendering")) 6098 { 6099 ImGui::Checkbox("Anti-aliased lines", &style.AntiAliasedLines); 6100 ImGui::SameLine(); 6101 HelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well."); 6102 6103 ImGui::Checkbox("Anti-aliased lines use texture", &style.AntiAliasedLinesUseTex); 6104 ImGui::SameLine(); 6105 HelpMarker("Faster lines using texture data. Require backend to render with bilinear filtering (not point/nearest filtering)."); 6106 6107 ImGui::Checkbox("Anti-aliased fill", &style.AntiAliasedFill); 6108 ImGui::PushItemWidth(ImGui::GetFontSize() * 8); 6109 ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, 10.0f, "%.2f"); 6110 if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f; 6111 6112 // When editing the "Circle Segment Max Error" value, draw a preview of its effect on auto-tessellated circles. 6113 ImGui::DragFloat("Circle Tessellation Max Error", &style.CircleTessellationMaxError , 0.005f, 0.10f, 5.0f, "%.2f", ImGuiSliderFlags_AlwaysClamp); 6114 if (ImGui::IsItemActive()) 6115 { 6116 ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos()); 6117 ImGui::BeginTooltip(); 6118 ImGui::TextUnformatted("(R = radius, N = number of segments)"); 6119 ImGui::Spacing(); 6120 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 6121 const float min_widget_width = ImGui::CalcTextSize("N: MMM\nR: MMM").x; 6122 for (int n = 0; n < 8; n++) 6123 { 6124 const float RAD_MIN = 5.0f; 6125 const float RAD_MAX = 70.0f; 6126 const float rad = RAD_MIN + (RAD_MAX - RAD_MIN) * (float)n / (8.0f - 1.0f); 6127 6128 ImGui::BeginGroup(); 6129 6130 ImGui::Text("R: %.f\nN: %d", rad, draw_list->_CalcCircleAutoSegmentCount(rad)); 6131 6132 const float canvas_width = IM_MAX(min_widget_width, rad * 2.0f); 6133 const float offset_x = floorf(canvas_width * 0.5f); 6134 const float offset_y = floorf(RAD_MAX); 6135 6136 const ImVec2 p1 = ImGui::GetCursorScreenPos(); 6137 draw_list->AddCircle(ImVec2(p1.x + offset_x, p1.y + offset_y), rad, ImGui::GetColorU32(ImGuiCol_Text)); 6138 ImGui::Dummy(ImVec2(canvas_width, RAD_MAX * 2)); 6139 6140 /* 6141 const ImVec2 p2 = ImGui::GetCursorScreenPos(); 6142 draw_list->AddCircleFilled(ImVec2(p2.x + offset_x, p2.y + offset_y), rad, ImGui::GetColorU32(ImGuiCol_Text)); 6143 ImGui::Dummy(ImVec2(canvas_width, RAD_MAX * 2)); 6144 */ 6145 6146 ImGui::EndGroup(); 6147 ImGui::SameLine(); 6148 } 6149 ImGui::EndTooltip(); 6150 } 6151 ImGui::SameLine(); 6152 HelpMarker("When drawing circle primitives with \"num_segments == 0\" tesselation will be calculated automatically."); 6153 6154 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. 6155 ImGui::PopItemWidth(); 6156 6157 ImGui::EndTabItem(); 6158 } 6159 6160 ImGui::EndTabBar(); 6161 } 6162 6163 ImGui::PopItemWidth(); 6164 } 6165 6166 //----------------------------------------------------------------------------- 6167 // [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar() 6168 //----------------------------------------------------------------------------- 6169 // - ShowExampleAppMainMenuBar() 6170 // - ShowExampleMenuFile() 6171 //----------------------------------------------------------------------------- 6172 6173 // Demonstrate creating a "main" fullscreen menu bar and populating it. 6174 // Note the difference between BeginMainMenuBar() and BeginMenuBar(): 6175 // - BeginMenuBar() = menu-bar inside current window (which needs the ImGuiWindowFlags_MenuBar flag!) 6176 // - BeginMainMenuBar() = helper to create menu-bar-sized window at the top of the main viewport + call BeginMenuBar() into it. 6177 static void ShowExampleAppMainMenuBar() 6178 { 6179 if (ImGui::BeginMainMenuBar()) 6180 { 6181 if (ImGui::BeginMenu("File")) 6182 { 6183 ShowExampleMenuFile(); 6184 ImGui::EndMenu(); 6185 } 6186 if (ImGui::BeginMenu("Edit")) 6187 { 6188 if (ImGui::MenuItem("Undo", "CTRL+Z")) {} 6189 if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) {} // Disabled item 6190 ImGui::Separator(); 6191 if (ImGui::MenuItem("Cut", "CTRL+X")) {} 6192 if (ImGui::MenuItem("Copy", "CTRL+C")) {} 6193 if (ImGui::MenuItem("Paste", "CTRL+V")) {} 6194 ImGui::EndMenu(); 6195 } 6196 ImGui::EndMainMenuBar(); 6197 } 6198 } 6199 6200 // Note that shortcuts are currently provided for display only 6201 // (future version will add explicit flags to BeginMenu() to request processing shortcuts) 6202 static void ShowExampleMenuFile() 6203 { 6204 ImGui::MenuItem("(demo menu)", NULL, false, false); 6205 if (ImGui::MenuItem("New")) {} 6206 if (ImGui::MenuItem("Open", "Ctrl+O")) {} 6207 if (ImGui::BeginMenu("Open Recent")) 6208 { 6209 ImGui::MenuItem("fish_hat.c"); 6210 ImGui::MenuItem("fish_hat.inl"); 6211 ImGui::MenuItem("fish_hat.h"); 6212 if (ImGui::BeginMenu("More..")) 6213 { 6214 ImGui::MenuItem("Hello"); 6215 ImGui::MenuItem("Sailor"); 6216 if (ImGui::BeginMenu("Recurse..")) 6217 { 6218 ShowExampleMenuFile(); 6219 ImGui::EndMenu(); 6220 } 6221 ImGui::EndMenu(); 6222 } 6223 ImGui::EndMenu(); 6224 } 6225 if (ImGui::MenuItem("Save", "Ctrl+S")) {} 6226 if (ImGui::MenuItem("Save As..")) {} 6227 6228 ImGui::Separator(); 6229 if (ImGui::BeginMenu("Options")) 6230 { 6231 static bool enabled = true; 6232 ImGui::MenuItem("Enabled", "", &enabled); 6233 ImGui::BeginChild("child", ImVec2(0, 60), true); 6234 for (int i = 0; i < 10; i++) 6235 ImGui::Text("Scrolling Text %d", i); 6236 ImGui::EndChild(); 6237 static float f = 0.5f; 6238 static int n = 0; 6239 ImGui::SliderFloat("Value", &f, 0.0f, 1.0f); 6240 ImGui::InputFloat("Input", &f, 0.1f); 6241 ImGui::Combo("Combo", &n, "Yes\0No\0Maybe\0\0"); 6242 ImGui::EndMenu(); 6243 } 6244 6245 if (ImGui::BeginMenu("Colors")) 6246 { 6247 float sz = ImGui::GetTextLineHeight(); 6248 for (int i = 0; i < ImGuiCol_COUNT; i++) 6249 { 6250 const char* name = ImGui::GetStyleColorName((ImGuiCol)i); 6251 ImVec2 p = ImGui::GetCursorScreenPos(); 6252 ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + sz, p.y + sz), ImGui::GetColorU32((ImGuiCol)i)); 6253 ImGui::Dummy(ImVec2(sz, sz)); 6254 ImGui::SameLine(); 6255 ImGui::MenuItem(name); 6256 } 6257 ImGui::EndMenu(); 6258 } 6259 6260 // Here we demonstrate appending again to the "Options" menu (which we already created above) 6261 // Of course in this demo it is a little bit silly that this function calls BeginMenu("Options") twice. 6262 // In a real code-base using it would make senses to use this feature from very different code locations. 6263 if (ImGui::BeginMenu("Options")) // <-- Append! 6264 { 6265 static bool b = true; 6266 ImGui::Checkbox("SomeOption", &b); 6267 ImGui::EndMenu(); 6268 } 6269 6270 if (ImGui::BeginMenu("Disabled", false)) // Disabled 6271 { 6272 IM_ASSERT(0); 6273 } 6274 if (ImGui::MenuItem("Checked", NULL, true)) {} 6275 if (ImGui::MenuItem("Quit", "Alt+F4")) {} 6276 } 6277 6278 //----------------------------------------------------------------------------- 6279 // [SECTION] Example App: Debug Console / ShowExampleAppConsole() 6280 //----------------------------------------------------------------------------- 6281 6282 // Demonstrate creating a simple console window, with scrolling, filtering, completion and history. 6283 // For the console example, we are using a more C++ like approach of declaring a class to hold both data and functions. 6284 struct ExampleAppConsole 6285 { 6286 char InputBuf[256]; 6287 ImVector<char*> Items; 6288 ImVector<const char*> Commands; 6289 ImVector<char*> History; 6290 int HistoryPos; // -1: new line, 0..History.Size-1 browsing history. 6291 ImGuiTextFilter Filter; 6292 bool AutoScroll; 6293 bool ScrollToBottom; 6294 6295 ExampleAppConsole() 6296 { 6297 ClearLog(); 6298 memset(InputBuf, 0, sizeof(InputBuf)); 6299 HistoryPos = -1; 6300 6301 // "CLASSIFY" is here to provide the test case where "C"+[tab] completes to "CL" and display multiple matches. 6302 Commands.push_back("HELP"); 6303 Commands.push_back("HISTORY"); 6304 Commands.push_back("CLEAR"); 6305 Commands.push_back("CLASSIFY"); 6306 AutoScroll = true; 6307 ScrollToBottom = false; 6308 AddLog("Welcome to Dear ImGui!"); 6309 } 6310 ~ExampleAppConsole() 6311 { 6312 ClearLog(); 6313 for (int i = 0; i < History.Size; i++) 6314 free(History[i]); 6315 } 6316 6317 // Portable helpers 6318 static int Stricmp(const char* s1, const char* s2) { int d; while ((d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; } return d; } 6319 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; } 6320 static char* Strdup(const char* s) { IM_ASSERT(s); size_t len = strlen(s) + 1; void* buf = malloc(len); IM_ASSERT(buf); return (char*)memcpy(buf, (const void*)s, len); } 6321 static void Strtrim(char* s) { char* str_end = s + strlen(s); while (str_end > s && str_end[-1] == ' ') str_end--; *str_end = 0; } 6322 6323 void ClearLog() 6324 { 6325 for (int i = 0; i < Items.Size; i++) 6326 free(Items[i]); 6327 Items.clear(); 6328 } 6329 6330 void AddLog(const char* fmt, ...) IM_FMTARGS(2) 6331 { 6332 // FIXME-OPT 6333 char buf[1024]; 6334 va_list args; 6335 va_start(args, fmt); 6336 vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args); 6337 buf[IM_ARRAYSIZE(buf)-1] = 0; 6338 va_end(args); 6339 Items.push_back(Strdup(buf)); 6340 } 6341 6342 void Draw(const char* title, bool* p_open) 6343 { 6344 ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); 6345 if (!ImGui::Begin(title, p_open)) 6346 { 6347 ImGui::End(); 6348 return; 6349 } 6350 6351 // As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar. 6352 // So e.g. IsItemHovered() will return true when hovering the title bar. 6353 // Here we create a context menu only available from the title bar. 6354 if (ImGui::BeginPopupContextItem()) 6355 { 6356 if (ImGui::MenuItem("Close Console")) 6357 *p_open = false; 6358 ImGui::EndPopup(); 6359 } 6360 6361 ImGui::TextWrapped( 6362 "This example implements a console with basic coloring, completion (TAB key) and history (Up/Down keys). A more elaborate " 6363 "implementation may want to store entries along with extra data such as timestamp, emitter, etc."); 6364 ImGui::TextWrapped("Enter 'HELP' for help."); 6365 6366 // TODO: display items starting from the bottom 6367 6368 if (ImGui::SmallButton("Add Debug Text")) { AddLog("%d some text", Items.Size); AddLog("some more text"); AddLog("display very important message here!"); } 6369 ImGui::SameLine(); 6370 if (ImGui::SmallButton("Add Debug Error")) { AddLog("[error] something went wrong"); } 6371 ImGui::SameLine(); 6372 if (ImGui::SmallButton("Clear")) { ClearLog(); } 6373 ImGui::SameLine(); 6374 bool copy_to_clipboard = ImGui::SmallButton("Copy"); 6375 //static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); } 6376 6377 ImGui::Separator(); 6378 6379 // Options menu 6380 if (ImGui::BeginPopup("Options")) 6381 { 6382 ImGui::Checkbox("Auto-scroll", &AutoScroll); 6383 ImGui::EndPopup(); 6384 } 6385 6386 // Options, Filter 6387 if (ImGui::Button("Options")) 6388 ImGui::OpenPopup("Options"); 6389 ImGui::SameLine(); 6390 Filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180); 6391 ImGui::Separator(); 6392 6393 // Reserve enough left-over height for 1 separator + 1 input text 6394 const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); 6395 ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), false, ImGuiWindowFlags_HorizontalScrollbar); 6396 if (ImGui::BeginPopupContextWindow()) 6397 { 6398 if (ImGui::Selectable("Clear")) ClearLog(); 6399 ImGui::EndPopup(); 6400 } 6401 6402 // Display every line as a separate entry so we can change their color or add custom widgets. 6403 // If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end()); 6404 // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping 6405 // to only process visible items. The clipper will automatically measure the height of your first item and then 6406 // "seek" to display only items in the visible area. 6407 // To use the clipper we can replace your standard loop: 6408 // for (int i = 0; i < Items.Size; i++) 6409 // With: 6410 // ImGuiListClipper clipper; 6411 // clipper.Begin(Items.Size); 6412 // while (clipper.Step()) 6413 // for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) 6414 // - That your items are evenly spaced (same height) 6415 // - That you have cheap random access to your elements (you can access them given their index, 6416 // without processing all the ones before) 6417 // You cannot this code as-is if a filter is active because it breaks the 'cheap random-access' property. 6418 // We would need random-access on the post-filtered list. 6419 // A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices 6420 // or offsets of items that passed the filtering test, recomputing this array when user changes the filter, 6421 // and appending newly elements as they are inserted. This is left as a task to the user until we can manage 6422 // to improve this example code! 6423 // If your items are of variable height: 6424 // - Split them into same height items would be simpler and facilitate random-seeking into your list. 6425 // - Consider using manual call to IsRectVisible() and skipping extraneous decoration from your items. 6426 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing 6427 if (copy_to_clipboard) 6428 ImGui::LogToClipboard(); 6429 for (int i = 0; i < Items.Size; i++) 6430 { 6431 const char* item = Items[i]; 6432 if (!Filter.PassFilter(item)) 6433 continue; 6434 6435 // Normally you would store more information in your item than just a string. 6436 // (e.g. make Items[] an array of structure, store color/type etc.) 6437 ImVec4 color; 6438 bool has_color = false; 6439 if (strstr(item, "[error]")) { color = ImVec4(1.0f, 0.4f, 0.4f, 1.0f); has_color = true; } 6440 else if (strncmp(item, "# ", 2) == 0) { color = ImVec4(1.0f, 0.8f, 0.6f, 1.0f); has_color = true; } 6441 if (has_color) 6442 ImGui::PushStyleColor(ImGuiCol_Text, color); 6443 ImGui::TextUnformatted(item); 6444 if (has_color) 6445 ImGui::PopStyleColor(); 6446 } 6447 if (copy_to_clipboard) 6448 ImGui::LogFinish(); 6449 6450 if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())) 6451 ImGui::SetScrollHereY(1.0f); 6452 ScrollToBottom = false; 6453 6454 ImGui::PopStyleVar(); 6455 ImGui::EndChild(); 6456 ImGui::Separator(); 6457 6458 // Command-line 6459 bool reclaim_focus = false; 6460 ImGuiInputTextFlags input_text_flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory; 6461 if (ImGui::InputText("Input", InputBuf, IM_ARRAYSIZE(InputBuf), input_text_flags, &TextEditCallbackStub, (void*)this)) 6462 { 6463 char* s = InputBuf; 6464 Strtrim(s); 6465 if (s[0]) 6466 ExecCommand(s); 6467 strcpy(s, ""); 6468 reclaim_focus = true; 6469 } 6470 6471 // Auto-focus on window apparition 6472 ImGui::SetItemDefaultFocus(); 6473 if (reclaim_focus) 6474 ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget 6475 6476 ImGui::End(); 6477 } 6478 6479 void ExecCommand(const char* command_line) 6480 { 6481 AddLog("# %s\n", command_line); 6482 6483 // Insert into history. First find match and delete it so it can be pushed to the back. 6484 // This isn't trying to be smart or optimal. 6485 HistoryPos = -1; 6486 for (int i = History.Size - 1; i >= 0; i--) 6487 if (Stricmp(History[i], command_line) == 0) 6488 { 6489 free(History[i]); 6490 History.erase(History.begin() + i); 6491 break; 6492 } 6493 History.push_back(Strdup(command_line)); 6494 6495 // Process command 6496 if (Stricmp(command_line, "CLEAR") == 0) 6497 { 6498 ClearLog(); 6499 } 6500 else if (Stricmp(command_line, "HELP") == 0) 6501 { 6502 AddLog("Commands:"); 6503 for (int i = 0; i < Commands.Size; i++) 6504 AddLog("- %s", Commands[i]); 6505 } 6506 else if (Stricmp(command_line, "HISTORY") == 0) 6507 { 6508 int first = History.Size - 10; 6509 for (int i = first > 0 ? first : 0; i < History.Size; i++) 6510 AddLog("%3d: %s\n", i, History[i]); 6511 } 6512 else 6513 { 6514 AddLog("Unknown command: '%s'\n", command_line); 6515 } 6516 6517 // On command input, we scroll to bottom even if AutoScroll==false 6518 ScrollToBottom = true; 6519 } 6520 6521 // In C++11 you'd be better off using lambdas for this sort of forwarding callbacks 6522 static int TextEditCallbackStub(ImGuiInputTextCallbackData* data) 6523 { 6524 ExampleAppConsole* console = (ExampleAppConsole*)data->UserData; 6525 return console->TextEditCallback(data); 6526 } 6527 6528 int TextEditCallback(ImGuiInputTextCallbackData* data) 6529 { 6530 //AddLog("cursor: %d, selection: %d-%d", data->CursorPos, data->SelectionStart, data->SelectionEnd); 6531 switch (data->EventFlag) 6532 { 6533 case ImGuiInputTextFlags_CallbackCompletion: 6534 { 6535 // Example of TEXT COMPLETION 6536 6537 // Locate beginning of current word 6538 const char* word_end = data->Buf + data->CursorPos; 6539 const char* word_start = word_end; 6540 while (word_start > data->Buf) 6541 { 6542 const char c = word_start[-1]; 6543 if (c == ' ' || c == '\t' || c == ',' || c == ';') 6544 break; 6545 word_start--; 6546 } 6547 6548 // Build a list of candidates 6549 ImVector<const char*> candidates; 6550 for (int i = 0; i < Commands.Size; i++) 6551 if (Strnicmp(Commands[i], word_start, (int)(word_end - word_start)) == 0) 6552 candidates.push_back(Commands[i]); 6553 6554 if (candidates.Size == 0) 6555 { 6556 // No match 6557 AddLog("No match for \"%.*s\"!\n", (int)(word_end - word_start), word_start); 6558 } 6559 else if (candidates.Size == 1) 6560 { 6561 // Single match. Delete the beginning of the word and replace it entirely so we've got nice casing. 6562 data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start)); 6563 data->InsertChars(data->CursorPos, candidates[0]); 6564 data->InsertChars(data->CursorPos, " "); 6565 } 6566 else 6567 { 6568 // Multiple matches. Complete as much as we can.. 6569 // So inputing "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches. 6570 int match_len = (int)(word_end - word_start); 6571 for (;;) 6572 { 6573 int c = 0; 6574 bool all_candidates_matches = true; 6575 for (int i = 0; i < candidates.Size && all_candidates_matches; i++) 6576 if (i == 0) 6577 c = toupper(candidates[i][match_len]); 6578 else if (c == 0 || c != toupper(candidates[i][match_len])) 6579 all_candidates_matches = false; 6580 if (!all_candidates_matches) 6581 break; 6582 match_len++; 6583 } 6584 6585 if (match_len > 0) 6586 { 6587 data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start)); 6588 data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len); 6589 } 6590 6591 // List matches 6592 AddLog("Possible matches:\n"); 6593 for (int i = 0; i < candidates.Size; i++) 6594 AddLog("- %s\n", candidates[i]); 6595 } 6596 6597 break; 6598 } 6599 case ImGuiInputTextFlags_CallbackHistory: 6600 { 6601 // Example of HISTORY 6602 const int prev_history_pos = HistoryPos; 6603 if (data->EventKey == ImGuiKey_UpArrow) 6604 { 6605 if (HistoryPos == -1) 6606 HistoryPos = History.Size - 1; 6607 else if (HistoryPos > 0) 6608 HistoryPos--; 6609 } 6610 else if (data->EventKey == ImGuiKey_DownArrow) 6611 { 6612 if (HistoryPos != -1) 6613 if (++HistoryPos >= History.Size) 6614 HistoryPos = -1; 6615 } 6616 6617 // A better implementation would preserve the data on the current input line along with cursor position. 6618 if (prev_history_pos != HistoryPos) 6619 { 6620 const char* history_str = (HistoryPos >= 0) ? History[HistoryPos] : ""; 6621 data->DeleteChars(0, data->BufTextLen); 6622 data->InsertChars(0, history_str); 6623 } 6624 } 6625 } 6626 return 0; 6627 } 6628 }; 6629 6630 static void ShowExampleAppConsole(bool* p_open) 6631 { 6632 static ExampleAppConsole console; 6633 console.Draw("Example: Console", p_open); 6634 } 6635 6636 //----------------------------------------------------------------------------- 6637 // [SECTION] Example App: Debug Log / ShowExampleAppLog() 6638 //----------------------------------------------------------------------------- 6639 6640 // Usage: 6641 // static ExampleAppLog my_log; 6642 // my_log.AddLog("Hello %d world\n", 123); 6643 // my_log.Draw("title"); 6644 struct ExampleAppLog 6645 { 6646 ImGuiTextBuffer Buf; 6647 ImGuiTextFilter Filter; 6648 ImVector<int> LineOffsets; // Index to lines offset. We maintain this with AddLog() calls. 6649 bool AutoScroll; // Keep scrolling if already at the bottom. 6650 6651 ExampleAppLog() 6652 { 6653 AutoScroll = true; 6654 Clear(); 6655 } 6656 6657 void Clear() 6658 { 6659 Buf.clear(); 6660 LineOffsets.clear(); 6661 LineOffsets.push_back(0); 6662 } 6663 6664 void AddLog(const char* fmt, ...) IM_FMTARGS(2) 6665 { 6666 int old_size = Buf.size(); 6667 va_list args; 6668 va_start(args, fmt); 6669 Buf.appendfv(fmt, args); 6670 va_end(args); 6671 for (int new_size = Buf.size(); old_size < new_size; old_size++) 6672 if (Buf[old_size] == '\n') 6673 LineOffsets.push_back(old_size + 1); 6674 } 6675 6676 void Draw(const char* title, bool* p_open = NULL) 6677 { 6678 if (!ImGui::Begin(title, p_open)) 6679 { 6680 ImGui::End(); 6681 return; 6682 } 6683 6684 // Options menu 6685 if (ImGui::BeginPopup("Options")) 6686 { 6687 ImGui::Checkbox("Auto-scroll", &AutoScroll); 6688 ImGui::EndPopup(); 6689 } 6690 6691 // Main window 6692 if (ImGui::Button("Options")) 6693 ImGui::OpenPopup("Options"); 6694 ImGui::SameLine(); 6695 bool clear = ImGui::Button("Clear"); 6696 ImGui::SameLine(); 6697 bool copy = ImGui::Button("Copy"); 6698 ImGui::SameLine(); 6699 Filter.Draw("Filter", -100.0f); 6700 6701 ImGui::Separator(); 6702 ImGui::BeginChild("scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar); 6703 6704 if (clear) 6705 Clear(); 6706 if (copy) 6707 ImGui::LogToClipboard(); 6708 6709 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); 6710 const char* buf = Buf.begin(); 6711 const char* buf_end = Buf.end(); 6712 if (Filter.IsActive()) 6713 { 6714 // In this example we don't use the clipper when Filter is enabled. 6715 // This is because we don't have a random access on the result on our filter. 6716 // A real application processing logs with ten of thousands of entries may want to store the result of 6717 // search/filter.. especially if the filtering function is not trivial (e.g. reg-exp). 6718 for (int line_no = 0; line_no < LineOffsets.Size; line_no++) 6719 { 6720 const char* line_start = buf + LineOffsets[line_no]; 6721 const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; 6722 if (Filter.PassFilter(line_start, line_end)) 6723 ImGui::TextUnformatted(line_start, line_end); 6724 } 6725 } 6726 else 6727 { 6728 // The simplest and easy way to display the entire buffer: 6729 // ImGui::TextUnformatted(buf_begin, buf_end); 6730 // And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward 6731 // to skip non-visible lines. Here we instead demonstrate using the clipper to only process lines that are 6732 // within the visible area. 6733 // If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them 6734 // on your side is recommended. Using ImGuiListClipper requires 6735 // - A) random access into your data 6736 // - B) items all being the same height, 6737 // both of which we can handle since we an array pointing to the beginning of each line of text. 6738 // When using the filter (in the block of code above) we don't have random access into the data to display 6739 // anymore, which is why we don't use the clipper. Storing or skimming through the search result would make 6740 // it possible (and would be recommended if you want to search through tens of thousands of entries). 6741 ImGuiListClipper clipper; 6742 clipper.Begin(LineOffsets.Size); 6743 while (clipper.Step()) 6744 { 6745 for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++) 6746 { 6747 const char* line_start = buf + LineOffsets[line_no]; 6748 const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; 6749 ImGui::TextUnformatted(line_start, line_end); 6750 } 6751 } 6752 clipper.End(); 6753 } 6754 ImGui::PopStyleVar(); 6755 6756 if (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) 6757 ImGui::SetScrollHereY(1.0f); 6758 6759 ImGui::EndChild(); 6760 ImGui::End(); 6761 } 6762 }; 6763 6764 // Demonstrate creating a simple log window with basic filtering. 6765 static void ShowExampleAppLog(bool* p_open) 6766 { 6767 static ExampleAppLog log; 6768 6769 // For the demo: add a debug button _BEFORE_ the normal log window contents 6770 // We take advantage of a rarely used feature: multiple calls to Begin()/End() are appending to the _same_ window. 6771 // Most of the contents of the window will be added by the log.Draw() call. 6772 ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver); 6773 ImGui::Begin("Example: Log", p_open); 6774 if (ImGui::SmallButton("[Debug] Add 5 entries")) 6775 { 6776 static int counter = 0; 6777 const char* categories[3] = { "info", "warn", "error" }; 6778 const char* words[] = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" }; 6779 for (int n = 0; n < 5; n++) 6780 { 6781 const char* category = categories[counter % IM_ARRAYSIZE(categories)]; 6782 const char* word = words[counter % IM_ARRAYSIZE(words)]; 6783 log.AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n", 6784 ImGui::GetFrameCount(), category, ImGui::GetTime(), word); 6785 counter++; 6786 } 6787 } 6788 ImGui::End(); 6789 6790 // Actually call in the regular Log helper (which will Begin() into the same window as we just did) 6791 log.Draw("Example: Log", p_open); 6792 } 6793 6794 //----------------------------------------------------------------------------- 6795 // [SECTION] Example App: Simple Layout / ShowExampleAppLayout() 6796 //----------------------------------------------------------------------------- 6797 6798 // Demonstrate create a window with multiple child windows. 6799 static void ShowExampleAppLayout(bool* p_open) 6800 { 6801 ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiCond_FirstUseEver); 6802 if (ImGui::Begin("Example: Simple layout", p_open, ImGuiWindowFlags_MenuBar)) 6803 { 6804 if (ImGui::BeginMenuBar()) 6805 { 6806 if (ImGui::BeginMenu("File")) 6807 { 6808 if (ImGui::MenuItem("Close")) *p_open = false; 6809 ImGui::EndMenu(); 6810 } 6811 ImGui::EndMenuBar(); 6812 } 6813 6814 // Left 6815 static int selected = 0; 6816 { 6817 ImGui::BeginChild("left pane", ImVec2(150, 0), true); 6818 for (int i = 0; i < 100; i++) 6819 { 6820 char label[128]; 6821 sprintf(label, "MyObject %d", i); 6822 if (ImGui::Selectable(label, selected == i)) 6823 selected = i; 6824 } 6825 ImGui::EndChild(); 6826 } 6827 ImGui::SameLine(); 6828 6829 // Right 6830 { 6831 ImGui::BeginGroup(); 6832 ImGui::BeginChild("item view", ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us 6833 ImGui::Text("MyObject: %d", selected); 6834 ImGui::Separator(); 6835 if (ImGui::BeginTabBar("##Tabs", ImGuiTabBarFlags_None)) 6836 { 6837 if (ImGui::BeginTabItem("Description")) 6838 { 6839 ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "); 6840 ImGui::EndTabItem(); 6841 } 6842 if (ImGui::BeginTabItem("Details")) 6843 { 6844 ImGui::Text("ID: 0123456789"); 6845 ImGui::EndTabItem(); 6846 } 6847 ImGui::EndTabBar(); 6848 } 6849 ImGui::EndChild(); 6850 if (ImGui::Button("Revert")) {} 6851 ImGui::SameLine(); 6852 if (ImGui::Button("Save")) {} 6853 ImGui::EndGroup(); 6854 } 6855 } 6856 ImGui::End(); 6857 } 6858 6859 //----------------------------------------------------------------------------- 6860 // [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor() 6861 //----------------------------------------------------------------------------- 6862 6863 static void ShowPlaceholderObject(const char* prefix, int uid) 6864 { 6865 // Use object uid as identifier. Most commonly you could also use the object pointer as a base ID. 6866 ImGui::PushID(uid); 6867 6868 // Text and Tree nodes are less high than framed widgets, using AlignTextToFramePadding() we add vertical spacing to make the tree lines equal high. 6869 ImGui::TableNextRow(); 6870 ImGui::TableSetColumnIndex(0); 6871 ImGui::AlignTextToFramePadding(); 6872 bool node_open = ImGui::TreeNode("Object", "%s_%u", prefix, uid); 6873 ImGui::TableSetColumnIndex(1); 6874 ImGui::Text("my sailor is rich"); 6875 6876 if (node_open) 6877 { 6878 static float placeholder_members[8] = { 0.0f, 0.0f, 1.0f, 3.1416f, 100.0f, 999.0f }; 6879 for (int i = 0; i < 8; i++) 6880 { 6881 ImGui::PushID(i); // Use field index as identifier. 6882 if (i < 2) 6883 { 6884 ShowPlaceholderObject("Child", 424242); 6885 } 6886 else 6887 { 6888 // Here we use a TreeNode to highlight on hover (we could use e.g. Selectable as well) 6889 ImGui::TableNextRow(); 6890 ImGui::TableSetColumnIndex(0); 6891 ImGui::AlignTextToFramePadding(); 6892 ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_Bullet; 6893 ImGui::TreeNodeEx("Field", flags, "Field_%d", i); 6894 6895 ImGui::TableSetColumnIndex(1); 6896 ImGui::SetNextItemWidth(-FLT_MIN); 6897 if (i >= 5) 6898 ImGui::InputFloat("##value", &placeholder_members[i], 1.0f); 6899 else 6900 ImGui::DragFloat("##value", &placeholder_members[i], 0.01f); 6901 ImGui::NextColumn(); 6902 } 6903 ImGui::PopID(); 6904 } 6905 ImGui::TreePop(); 6906 } 6907 ImGui::PopID(); 6908 } 6909 6910 // Demonstrate create a simple property editor. 6911 static void ShowExampleAppPropertyEditor(bool* p_open) 6912 { 6913 ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver); 6914 if (!ImGui::Begin("Example: Property editor", p_open)) 6915 { 6916 ImGui::End(); 6917 return; 6918 } 6919 6920 HelpMarker( 6921 "This example shows how you may implement a property editor using two columns.\n" 6922 "All objects/fields data are dummies here.\n" 6923 "Remember that in many simple cases, you can use ImGui::SameLine(xxx) to position\n" 6924 "your cursor horizontally instead of using the Columns() API."); 6925 6926 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 2)); 6927 if (ImGui::BeginTable("split", 2, ImGuiTableFlags_BordersOuter | ImGuiTableFlags_Resizable)) 6928 { 6929 // Iterate placeholder objects (all the same data) 6930 for (int obj_i = 0; obj_i < 4; obj_i++) 6931 { 6932 ShowPlaceholderObject("Object", obj_i); 6933 //ImGui::Separator(); 6934 } 6935 ImGui::EndTable(); 6936 } 6937 ImGui::PopStyleVar(); 6938 ImGui::End(); 6939 } 6940 6941 //----------------------------------------------------------------------------- 6942 // [SECTION] Example App: Long Text / ShowExampleAppLongText() 6943 //----------------------------------------------------------------------------- 6944 6945 // Demonstrate/test rendering huge amount of text, and the incidence of clipping. 6946 static void ShowExampleAppLongText(bool* p_open) 6947 { 6948 ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); 6949 if (!ImGui::Begin("Example: Long text display", p_open)) 6950 { 6951 ImGui::End(); 6952 return; 6953 } 6954 6955 static int test_type = 0; 6956 static ImGuiTextBuffer log; 6957 static int lines = 0; 6958 ImGui::Text("Printing unusually long amount of text."); 6959 ImGui::Combo("Test type", &test_type, 6960 "Single call to TextUnformatted()\0" 6961 "Multiple calls to Text(), clipped\0" 6962 "Multiple calls to Text(), not clipped (slow)\0"); 6963 ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size()); 6964 if (ImGui::Button("Clear")) { log.clear(); lines = 0; } 6965 ImGui::SameLine(); 6966 if (ImGui::Button("Add 1000 lines")) 6967 { 6968 for (int i = 0; i < 1000; i++) 6969 log.appendf("%i The quick brown fox jumps over the lazy dog\n", lines + i); 6970 lines += 1000; 6971 } 6972 ImGui::BeginChild("Log"); 6973 switch (test_type) 6974 { 6975 case 0: 6976 // Single call to TextUnformatted() with a big buffer 6977 ImGui::TextUnformatted(log.begin(), log.end()); 6978 break; 6979 case 1: 6980 { 6981 // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper. 6982 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); 6983 ImGuiListClipper clipper; 6984 clipper.Begin(lines); 6985 while (clipper.Step()) 6986 for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) 6987 ImGui::Text("%i The quick brown fox jumps over the lazy dog", i); 6988 ImGui::PopStyleVar(); 6989 break; 6990 } 6991 case 2: 6992 // Multiple calls to Text(), not clipped (slow) 6993 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); 6994 for (int i = 0; i < lines; i++) 6995 ImGui::Text("%i The quick brown fox jumps over the lazy dog", i); 6996 ImGui::PopStyleVar(); 6997 break; 6998 } 6999 ImGui::EndChild(); 7000 ImGui::End(); 7001 } 7002 7003 //----------------------------------------------------------------------------- 7004 // [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize() 7005 //----------------------------------------------------------------------------- 7006 7007 // Demonstrate creating a window which gets auto-resized according to its content. 7008 static void ShowExampleAppAutoResize(bool* p_open) 7009 { 7010 if (!ImGui::Begin("Example: Auto-resizing window", p_open, ImGuiWindowFlags_AlwaysAutoResize)) 7011 { 7012 ImGui::End(); 7013 return; 7014 } 7015 7016 static int lines = 10; 7017 ImGui::TextUnformatted( 7018 "Window will resize every-frame to the size of its content.\n" 7019 "Note that you probably don't want to query the window size to\n" 7020 "output your content because that would create a feedback loop."); 7021 ImGui::SliderInt("Number of lines", &lines, 1, 20); 7022 for (int i = 0; i < lines; i++) 7023 ImGui::Text("%*sThis is line %d", i * 4, "", i); // Pad with space to extend size horizontally 7024 ImGui::End(); 7025 } 7026 7027 //----------------------------------------------------------------------------- 7028 // [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize() 7029 //----------------------------------------------------------------------------- 7030 7031 // Demonstrate creating a window with custom resize constraints. 7032 static void ShowExampleAppConstrainedResize(bool* p_open) 7033 { 7034 struct CustomConstraints 7035 { 7036 // Helper functions to demonstrate programmatic constraints 7037 static void Square(ImGuiSizeCallbackData* data) { data->DesiredSize.x = data->DesiredSize.y = IM_MAX(data->DesiredSize.x, data->DesiredSize.y); } 7038 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); } 7039 }; 7040 7041 const char* test_desc[] = 7042 { 7043 "Resize vertical only", 7044 "Resize horizontal only", 7045 "Width > 100, Height > 100", 7046 "Width 400-500", 7047 "Height 400-500", 7048 "Custom: Always Square", 7049 "Custom: Fixed Steps (100)", 7050 }; 7051 7052 static bool auto_resize = false; 7053 static int type = 0; 7054 static int display_lines = 10; 7055 if (type == 0) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, FLT_MAX)); // Vertical only 7056 if (type == 1) ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(FLT_MAX, -1)); // Horizontal only 7057 if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100 7058 if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)); // Width 400-500 7059 if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, 500)); // Height 400-500 7060 if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square 7061 if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)(intptr_t)100); // Fixed Step 7062 7063 ImGuiWindowFlags flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0; 7064 if (ImGui::Begin("Example: Constrained Resize", p_open, flags)) 7065 { 7066 if (ImGui::Button("200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine(); 7067 if (ImGui::Button("500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine(); 7068 if (ImGui::Button("800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); } 7069 ImGui::SetNextItemWidth(200); 7070 ImGui::Combo("Constraint", &type, test_desc, IM_ARRAYSIZE(test_desc)); 7071 ImGui::SetNextItemWidth(200); 7072 ImGui::DragInt("Lines", &display_lines, 0.2f, 1, 100); 7073 ImGui::Checkbox("Auto-resize", &auto_resize); 7074 for (int i = 0; i < display_lines; i++) 7075 ImGui::Text("%*sHello, sailor! Making this line long enough for the example.", i * 4, ""); 7076 } 7077 ImGui::End(); 7078 } 7079 7080 //----------------------------------------------------------------------------- 7081 // [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay() 7082 //----------------------------------------------------------------------------- 7083 7084 // Demonstrate creating a simple static window with no decoration 7085 // + a context-menu to choose which corner of the screen to use. 7086 static void ShowExampleAppSimpleOverlay(bool* p_open) 7087 { 7088 const float PAD = 10.0f; 7089 static int corner = 0; 7090 ImGuiIO& io = ImGui::GetIO(); 7091 ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav; 7092 if (corner != -1) 7093 { 7094 const ImGuiViewport* viewport = ImGui::GetMainViewport(); 7095 ImVec2 work_pos = viewport->WorkPos; // Use work area to avoid menu-bar/task-bar, if any! 7096 ImVec2 work_size = viewport->WorkSize; 7097 ImVec2 window_pos, window_pos_pivot; 7098 window_pos.x = (corner & 1) ? (work_pos.x + work_size.x - PAD) : (work_pos.x + PAD); 7099 window_pos.y = (corner & 2) ? (work_pos.y + work_size.y - PAD) : (work_pos.y + PAD); 7100 window_pos_pivot.x = (corner & 1) ? 1.0f : 0.0f; 7101 window_pos_pivot.y = (corner & 2) ? 1.0f : 0.0f; 7102 ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot); 7103 window_flags |= ImGuiWindowFlags_NoMove; 7104 } 7105 ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background 7106 if (ImGui::Begin("Example: Simple overlay", p_open, window_flags)) 7107 { 7108 ImGui::Text("Simple overlay\n" "in the corner of the screen.\n" "(right-click to change position)"); 7109 ImGui::Separator(); 7110 if (ImGui::IsMousePosValid()) 7111 ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y); 7112 else 7113 ImGui::Text("Mouse Position: <invalid>"); 7114 if (ImGui::BeginPopupContextWindow()) 7115 { 7116 if (ImGui::MenuItem("Custom", NULL, corner == -1)) corner = -1; 7117 if (ImGui::MenuItem("Top-left", NULL, corner == 0)) corner = 0; 7118 if (ImGui::MenuItem("Top-right", NULL, corner == 1)) corner = 1; 7119 if (ImGui::MenuItem("Bottom-left", NULL, corner == 2)) corner = 2; 7120 if (ImGui::MenuItem("Bottom-right", NULL, corner == 3)) corner = 3; 7121 if (p_open && ImGui::MenuItem("Close")) *p_open = false; 7122 ImGui::EndPopup(); 7123 } 7124 } 7125 ImGui::End(); 7126 } 7127 7128 //----------------------------------------------------------------------------- 7129 // [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen() 7130 //----------------------------------------------------------------------------- 7131 7132 // Demonstrate creating a window covering the entire screen/viewport 7133 static void ShowExampleAppFullscreen(bool* p_open) 7134 { 7135 static bool use_work_area = true; 7136 static ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings; 7137 7138 // We demonstrate using the full viewport area or the work area (without menu-bars, task-bars etc.) 7139 // Based on your use case you may want one of the other. 7140 const ImGuiViewport* viewport = ImGui::GetMainViewport(); 7141 ImGui::SetNextWindowPos(use_work_area ? viewport->WorkPos : viewport->Pos); 7142 ImGui::SetNextWindowSize(use_work_area ? viewport->WorkSize : viewport->Size); 7143 7144 if (ImGui::Begin("Example: Fullscreen window", p_open, flags)) 7145 { 7146 ImGui::Checkbox("Use work area instead of main area", &use_work_area); 7147 ImGui::SameLine(); 7148 HelpMarker("Main Area = entire viewport,\nWork Area = entire viewport minus sections used by the main menu bars, task bars etc.\n\nEnable the main-menu bar in Examples menu to see the difference."); 7149 7150 ImGui::CheckboxFlags("ImGuiWindowFlags_NoBackground", &flags, ImGuiWindowFlags_NoBackground); 7151 ImGui::CheckboxFlags("ImGuiWindowFlags_NoDecoration", &flags, ImGuiWindowFlags_NoDecoration); 7152 ImGui::Indent(); 7153 ImGui::CheckboxFlags("ImGuiWindowFlags_NoTitleBar", &flags, ImGuiWindowFlags_NoTitleBar); 7154 ImGui::CheckboxFlags("ImGuiWindowFlags_NoCollapse", &flags, ImGuiWindowFlags_NoCollapse); 7155 ImGui::CheckboxFlags("ImGuiWindowFlags_NoScrollbar", &flags, ImGuiWindowFlags_NoScrollbar); 7156 ImGui::Unindent(); 7157 7158 if (p_open && ImGui::Button("Close this window")) 7159 *p_open = false; 7160 } 7161 ImGui::End(); 7162 } 7163 7164 //----------------------------------------------------------------------------- 7165 // [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles() 7166 //----------------------------------------------------------------------------- 7167 7168 // Demonstrate using "##" and "###" in identifiers to manipulate ID generation. 7169 // This apply to all regular items as well. 7170 // Read FAQ section "How can I have multiple widgets with the same label?" for details. 7171 static void ShowExampleAppWindowTitles(bool*) 7172 { 7173 const ImGuiViewport* viewport = ImGui::GetMainViewport(); 7174 const ImVec2 base_pos = viewport->Pos; 7175 7176 // By default, Windows are uniquely identified by their title. 7177 // You can use the "##" and "###" markers to manipulate the display/ID. 7178 7179 // Using "##" to display same title but have unique identifier. 7180 ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 100), ImGuiCond_FirstUseEver); 7181 ImGui::Begin("Same title as another window##1"); 7182 ImGui::Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique."); 7183 ImGui::End(); 7184 7185 ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 200), ImGuiCond_FirstUseEver); 7186 ImGui::Begin("Same title as another window##2"); 7187 ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique."); 7188 ImGui::End(); 7189 7190 // Using "###" to display a changing title but keep a static identifier "AnimatedTitle" 7191 char buf[128]; 7192 sprintf(buf, "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime() / 0.25f) & 3], ImGui::GetFrameCount()); 7193 ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 300), ImGuiCond_FirstUseEver); 7194 ImGui::Begin(buf); 7195 ImGui::Text("This window has a changing title."); 7196 ImGui::End(); 7197 } 7198 7199 //----------------------------------------------------------------------------- 7200 // [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering() 7201 //----------------------------------------------------------------------------- 7202 7203 // Demonstrate using the low-level ImDrawList to draw custom shapes. 7204 static void ShowExampleAppCustomRendering(bool* p_open) 7205 { 7206 if (!ImGui::Begin("Example: Custom rendering", p_open)) 7207 { 7208 ImGui::End(); 7209 return; 7210 } 7211 7212 // Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of 7213 // overloaded operators, etc. Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your 7214 // types and ImVec2/ImVec4. Dear ImGui defines overloaded operators but they are internal to imgui.cpp and not 7215 // exposed outside (to avoid messing with your types) In this example we are not using the maths operators! 7216 7217 if (ImGui::BeginTabBar("##TabBar")) 7218 { 7219 if (ImGui::BeginTabItem("Primitives")) 7220 { 7221 ImGui::PushItemWidth(-ImGui::GetFontSize() * 15); 7222 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 7223 7224 // Draw gradients 7225 // (note that those are currently exacerbating our sRGB/Linear issues) 7226 // Calling ImGui::GetColorU32() multiplies the given colors by the current Style Alpha, but you may pass the IM_COL32() directly as well.. 7227 ImGui::Text("Gradients"); 7228 ImVec2 gradient_size = ImVec2(ImGui::CalcItemWidth(), ImGui::GetFrameHeight()); 7229 { 7230 ImVec2 p0 = ImGui::GetCursorScreenPos(); 7231 ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y); 7232 ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 0, 0, 255)); 7233 ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 255, 255, 255)); 7234 draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a); 7235 ImGui::InvisibleButton("##gradient1", gradient_size); 7236 } 7237 { 7238 ImVec2 p0 = ImGui::GetCursorScreenPos(); 7239 ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y); 7240 ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 255, 0, 255)); 7241 ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 0, 0, 255)); 7242 draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a); 7243 ImGui::InvisibleButton("##gradient2", gradient_size); 7244 } 7245 7246 // Draw a bunch of primitives 7247 ImGui::Text("All primitives"); 7248 static float sz = 36.0f; 7249 static float thickness = 3.0f; 7250 static int ngon_sides = 6; 7251 static bool circle_segments_override = false; 7252 static int circle_segments_override_v = 12; 7253 static bool curve_segments_override = false; 7254 static int curve_segments_override_v = 8; 7255 static ImVec4 colf = ImVec4(1.0f, 1.0f, 0.4f, 1.0f); 7256 ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 100.0f, "%.0f"); 7257 ImGui::DragFloat("Thickness", &thickness, 0.05f, 1.0f, 8.0f, "%.02f"); 7258 ImGui::SliderInt("N-gon sides", &ngon_sides, 3, 12); 7259 ImGui::Checkbox("##circlesegmentoverride", &circle_segments_override); 7260 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); 7261 circle_segments_override |= ImGui::SliderInt("Circle segments override", &circle_segments_override_v, 3, 40); 7262 ImGui::Checkbox("##curvessegmentoverride", &curve_segments_override); 7263 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); 7264 curve_segments_override |= ImGui::SliderInt("Curves segments override", &curve_segments_override_v, 3, 40); 7265 ImGui::ColorEdit4("Color", &colf.x); 7266 7267 const ImVec2 p = ImGui::GetCursorScreenPos(); 7268 const ImU32 col = ImColor(colf); 7269 const float spacing = 10.0f; 7270 const ImDrawFlags corners_tl_br = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersBottomRight; 7271 const float rounding = sz / 5.0f; 7272 const int circle_segments = circle_segments_override ? circle_segments_override_v : 0; 7273 const int curve_segments = curve_segments_override ? curve_segments_override_v : 0; 7274 float x = p.x + 4.0f; 7275 float y = p.y + 4.0f; 7276 for (int n = 0; n < 2; n++) 7277 { 7278 // First line uses a thickness of 1.0f, second line uses the configurable thickness 7279 float th = (n == 0) ? 1.0f : thickness; 7280 draw_list->AddNgon(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, ngon_sides, th); x += sz + spacing; // N-gon 7281 draw_list->AddCircle(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments, th); x += sz + spacing; // Circle 7282 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0f, ImDrawFlags_None, th); x += sz + spacing; // Square 7283 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, ImDrawFlags_None, th); x += sz + spacing; // Square with all rounded corners 7284 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, corners_tl_br, th); x += sz + spacing; // Square with two rounded corners 7285 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 7286 //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 7287 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!) 7288 draw_list->AddLine(ImVec2(x, y), ImVec2(x, y + sz), col, th); x += spacing; // Vertical line (note: drawing a filled rectangle will be faster!) 7289 draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y + sz), col, th); x += sz + spacing; // Diagonal line 7290 7291 // Quadratic Bezier Curve (3 control points) 7292 ImVec2 cp3[3] = { ImVec2(x, y + sz * 0.6f), ImVec2(x + sz * 0.5f, y - sz * 0.4f), ImVec2(x + sz, y + sz) }; 7293 draw_list->AddBezierQuadratic(cp3[0], cp3[1], cp3[2], col, th, curve_segments); x += sz + spacing; 7294 7295 // Cubic Bezier Curve (4 control points) 7296 ImVec2 cp4[4] = { 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) }; 7297 draw_list->AddBezierCubic(cp4[0], cp4[1], cp4[2], cp4[3], col, th, curve_segments); 7298 7299 x = p.x + 4; 7300 y += sz + spacing; 7301 } 7302 draw_list->AddNgonFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz*0.5f, col, ngon_sides); x += sz + spacing; // N-gon 7303 draw_list->AddCircleFilled(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments); x += sz + spacing; // Circle 7304 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col); x += sz + spacing; // Square 7305 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f); x += sz + spacing; // Square with all rounded corners 7306 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 7307 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 7308 //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 7309 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) 7310 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) 7311 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + 1, y + 1), col); x += sz; // Pixel (faster than AddLine) 7312 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)); 7313 7314 ImGui::Dummy(ImVec2((sz + spacing) * 10.2f, (sz + spacing) * 3.0f)); 7315 ImGui::PopItemWidth(); 7316 ImGui::EndTabItem(); 7317 } 7318 7319 if (ImGui::BeginTabItem("Canvas")) 7320 { 7321 static ImVector<ImVec2> points; 7322 static ImVec2 scrolling(0.0f, 0.0f); 7323 static bool opt_enable_grid = true; 7324 static bool opt_enable_context_menu = true; 7325 static bool adding_line = false; 7326 7327 ImGui::Checkbox("Enable grid", &opt_enable_grid); 7328 ImGui::Checkbox("Enable context menu", &opt_enable_context_menu); 7329 ImGui::Text("Mouse Left: drag to add lines,\nMouse Right: drag to scroll, click for context menu."); 7330 7331 // Typically you would use a BeginChild()/EndChild() pair to benefit from a clipping region + own scrolling. 7332 // Here we demonstrate that this can be replaced by simple offsetting + custom drawing + PushClipRect/PopClipRect() calls. 7333 // To use a child window instead we could use, e.g: 7334 // ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); // Disable padding 7335 // ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(50, 50, 50, 255)); // Set a background color 7336 // ImGui::BeginChild("canvas", ImVec2(0.0f, 0.0f), true, ImGuiWindowFlags_NoMove); 7337 // ImGui::PopStyleColor(); 7338 // ImGui::PopStyleVar(); 7339 // [...] 7340 // ImGui::EndChild(); 7341 7342 // Using InvisibleButton() as a convenience 1) it will advance the layout cursor and 2) allows us to use IsItemHovered()/IsItemActive() 7343 ImVec2 canvas_p0 = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates! 7344 ImVec2 canvas_sz = ImGui::GetContentRegionAvail(); // Resize canvas to what's available 7345 if (canvas_sz.x < 50.0f) canvas_sz.x = 50.0f; 7346 if (canvas_sz.y < 50.0f) canvas_sz.y = 50.0f; 7347 ImVec2 canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y); 7348 7349 // Draw border and background color 7350 ImGuiIO& io = ImGui::GetIO(); 7351 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 7352 draw_list->AddRectFilled(canvas_p0, canvas_p1, IM_COL32(50, 50, 50, 255)); 7353 draw_list->AddRect(canvas_p0, canvas_p1, IM_COL32(255, 255, 255, 255)); 7354 7355 // This will catch our interactions 7356 ImGui::InvisibleButton("canvas", canvas_sz, ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight); 7357 const bool is_hovered = ImGui::IsItemHovered(); // Hovered 7358 const bool is_active = ImGui::IsItemActive(); // Held 7359 const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y); // Lock scrolled origin 7360 const ImVec2 mouse_pos_in_canvas(io.MousePos.x - origin.x, io.MousePos.y - origin.y); 7361 7362 // Add first and second point 7363 if (is_hovered && !adding_line && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) 7364 { 7365 points.push_back(mouse_pos_in_canvas); 7366 points.push_back(mouse_pos_in_canvas); 7367 adding_line = true; 7368 } 7369 if (adding_line) 7370 { 7371 points.back() = mouse_pos_in_canvas; 7372 if (!ImGui::IsMouseDown(ImGuiMouseButton_Left)) 7373 adding_line = false; 7374 } 7375 7376 // Pan (we use a zero mouse threshold when there's no context menu) 7377 // You may decide to make that threshold dynamic based on whether the mouse is hovering something etc. 7378 const float mouse_threshold_for_pan = opt_enable_context_menu ? -1.0f : 0.0f; 7379 if (is_active && ImGui::IsMouseDragging(ImGuiMouseButton_Right, mouse_threshold_for_pan)) 7380 { 7381 scrolling.x += io.MouseDelta.x; 7382 scrolling.y += io.MouseDelta.y; 7383 } 7384 7385 // Context menu (under default mouse threshold) 7386 ImVec2 drag_delta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Right); 7387 if (opt_enable_context_menu && ImGui::IsMouseReleased(ImGuiMouseButton_Right) && drag_delta.x == 0.0f && drag_delta.y == 0.0f) 7388 ImGui::OpenPopupOnItemClick("context"); 7389 if (ImGui::BeginPopup("context")) 7390 { 7391 if (adding_line) 7392 points.resize(points.size() - 2); 7393 adding_line = false; 7394 if (ImGui::MenuItem("Remove one", NULL, false, points.Size > 0)) { points.resize(points.size() - 2); } 7395 if (ImGui::MenuItem("Remove all", NULL, false, points.Size > 0)) { points.clear(); } 7396 ImGui::EndPopup(); 7397 } 7398 7399 // Draw grid + all lines in the canvas 7400 draw_list->PushClipRect(canvas_p0, canvas_p1, true); 7401 if (opt_enable_grid) 7402 { 7403 const float GRID_STEP = 64.0f; 7404 for (float x = fmodf(scrolling.x, GRID_STEP); x < canvas_sz.x; x += GRID_STEP) 7405 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)); 7406 for (float y = fmodf(scrolling.y, GRID_STEP); y < canvas_sz.y; y += GRID_STEP) 7407 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)); 7408 } 7409 for (int n = 0; n < points.Size; n += 2) 7410 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); 7411 draw_list->PopClipRect(); 7412 7413 ImGui::EndTabItem(); 7414 } 7415 7416 if (ImGui::BeginTabItem("BG/FG draw lists")) 7417 { 7418 static bool draw_bg = true; 7419 static bool draw_fg = true; 7420 ImGui::Checkbox("Draw in Background draw list", &draw_bg); 7421 ImGui::SameLine(); HelpMarker("The Background draw list will be rendered below every Dear ImGui windows."); 7422 ImGui::Checkbox("Draw in Foreground draw list", &draw_fg); 7423 ImGui::SameLine(); HelpMarker("The Foreground draw list will be rendered over every Dear ImGui windows."); 7424 ImVec2 window_pos = ImGui::GetWindowPos(); 7425 ImVec2 window_size = ImGui::GetWindowSize(); 7426 ImVec2 window_center = ImVec2(window_pos.x + window_size.x * 0.5f, window_pos.y + window_size.y * 0.5f); 7427 if (draw_bg) 7428 ImGui::GetBackgroundDrawList()->AddCircle(window_center, window_size.x * 0.6f, IM_COL32(255, 0, 0, 200), 0, 10 + 4); 7429 if (draw_fg) 7430 ImGui::GetForegroundDrawList()->AddCircle(window_center, window_size.y * 0.6f, IM_COL32(0, 255, 0, 200), 0, 10); 7431 ImGui::EndTabItem(); 7432 } 7433 7434 ImGui::EndTabBar(); 7435 } 7436 7437 ImGui::End(); 7438 } 7439 7440 //----------------------------------------------------------------------------- 7441 // [SECTION] Example App: Documents Handling / ShowExampleAppDocuments() 7442 //----------------------------------------------------------------------------- 7443 7444 // Simplified structure to mimic a Document model 7445 struct MyDocument 7446 { 7447 const char* Name; // Document title 7448 bool Open; // Set when open (we keep an array of all available documents to simplify demo code!) 7449 bool OpenPrev; // Copy of Open from last update. 7450 bool Dirty; // Set when the document has been modified 7451 bool WantClose; // Set when the document 7452 ImVec4 Color; // An arbitrary variable associated to the document 7453 7454 MyDocument(const char* name, bool open = true, const ImVec4& color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f)) 7455 { 7456 Name = name; 7457 Open = OpenPrev = open; 7458 Dirty = false; 7459 WantClose = false; 7460 Color = color; 7461 } 7462 void DoOpen() { Open = true; } 7463 void DoQueueClose() { WantClose = true; } 7464 void DoForceClose() { Open = false; Dirty = false; } 7465 void DoSave() { Dirty = false; } 7466 7467 // Display placeholder contents for the Document 7468 static void DisplayContents(MyDocument* doc) 7469 { 7470 ImGui::PushID(doc); 7471 ImGui::Text("Document \"%s\"", doc->Name); 7472 ImGui::PushStyleColor(ImGuiCol_Text, doc->Color); 7473 ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."); 7474 ImGui::PopStyleColor(); 7475 if (ImGui::Button("Modify", ImVec2(100, 0))) 7476 doc->Dirty = true; 7477 ImGui::SameLine(); 7478 if (ImGui::Button("Save", ImVec2(100, 0))) 7479 doc->DoSave(); 7480 ImGui::ColorEdit3("color", &doc->Color.x); // Useful to test drag and drop and hold-dragged-to-open-tab behavior. 7481 ImGui::PopID(); 7482 } 7483 7484 // Display context menu for the Document 7485 static void DisplayContextMenu(MyDocument* doc) 7486 { 7487 if (!ImGui::BeginPopupContextItem()) 7488 return; 7489 7490 char buf[256]; 7491 sprintf(buf, "Save %s", doc->Name); 7492 if (ImGui::MenuItem(buf, "CTRL+S", false, doc->Open)) 7493 doc->DoSave(); 7494 if (ImGui::MenuItem("Close", "CTRL+W", false, doc->Open)) 7495 doc->DoQueueClose(); 7496 ImGui::EndPopup(); 7497 } 7498 }; 7499 7500 struct ExampleAppDocuments 7501 { 7502 ImVector<MyDocument> Documents; 7503 7504 ExampleAppDocuments() 7505 { 7506 Documents.push_back(MyDocument("Lettuce", true, ImVec4(0.4f, 0.8f, 0.4f, 1.0f))); 7507 Documents.push_back(MyDocument("Eggplant", true, ImVec4(0.8f, 0.5f, 1.0f, 1.0f))); 7508 Documents.push_back(MyDocument("Carrot", true, ImVec4(1.0f, 0.8f, 0.5f, 1.0f))); 7509 Documents.push_back(MyDocument("Tomato", false, ImVec4(1.0f, 0.3f, 0.4f, 1.0f))); 7510 Documents.push_back(MyDocument("A Rather Long Title", false)); 7511 Documents.push_back(MyDocument("Some Document", false)); 7512 } 7513 }; 7514 7515 // [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface. 7516 // If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo, 7517 // as opposed to clicking on the regular tab closing button) and stops being submitted, it will take a frame for 7518 // 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 7519 // disappeared was the selected one, the tab bar will report no selected tab during the frame. This will effectively 7520 // give the impression of a flicker for one frame. 7521 // We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch. 7522 // Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag. 7523 static void NotifyOfDocumentsClosedElsewhere(ExampleAppDocuments& app) 7524 { 7525 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) 7526 { 7527 MyDocument* doc = &app.Documents[doc_n]; 7528 if (!doc->Open && doc->OpenPrev) 7529 ImGui::SetTabItemClosed(doc->Name); 7530 doc->OpenPrev = doc->Open; 7531 } 7532 } 7533 7534 void ShowExampleAppDocuments(bool* p_open) 7535 { 7536 static ExampleAppDocuments app; 7537 7538 // Options 7539 static bool opt_reorderable = true; 7540 static ImGuiTabBarFlags opt_fitting_flags = ImGuiTabBarFlags_FittingPolicyDefault_; 7541 7542 bool window_contents_visible = ImGui::Begin("Example: Documents", p_open, ImGuiWindowFlags_MenuBar); 7543 if (!window_contents_visible) 7544 { 7545 ImGui::End(); 7546 return; 7547 } 7548 7549 // Menu 7550 if (ImGui::BeginMenuBar()) 7551 { 7552 if (ImGui::BeginMenu("File")) 7553 { 7554 int open_count = 0; 7555 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) 7556 open_count += app.Documents[doc_n].Open ? 1 : 0; 7557 7558 if (ImGui::BeginMenu("Open", open_count < app.Documents.Size)) 7559 { 7560 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) 7561 { 7562 MyDocument* doc = &app.Documents[doc_n]; 7563 if (!doc->Open) 7564 if (ImGui::MenuItem(doc->Name)) 7565 doc->DoOpen(); 7566 } 7567 ImGui::EndMenu(); 7568 } 7569 if (ImGui::MenuItem("Close All Documents", NULL, false, open_count > 0)) 7570 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) 7571 app.Documents[doc_n].DoQueueClose(); 7572 if (ImGui::MenuItem("Exit", "Alt+F4")) {} 7573 ImGui::EndMenu(); 7574 } 7575 ImGui::EndMenuBar(); 7576 } 7577 7578 // [Debug] List documents with one checkbox for each 7579 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) 7580 { 7581 MyDocument* doc = &app.Documents[doc_n]; 7582 if (doc_n > 0) 7583 ImGui::SameLine(); 7584 ImGui::PushID(doc); 7585 if (ImGui::Checkbox(doc->Name, &doc->Open)) 7586 if (!doc->Open) 7587 doc->DoForceClose(); 7588 ImGui::PopID(); 7589 } 7590 7591 ImGui::Separator(); 7592 7593 // Submit Tab Bar and Tabs 7594 { 7595 ImGuiTabBarFlags tab_bar_flags = (opt_fitting_flags) | (opt_reorderable ? ImGuiTabBarFlags_Reorderable : 0); 7596 if (ImGui::BeginTabBar("##tabs", tab_bar_flags)) 7597 { 7598 if (opt_reorderable) 7599 NotifyOfDocumentsClosedElsewhere(app); 7600 7601 // [DEBUG] Stress tests 7602 //if ((ImGui::GetFrameCount() % 30) == 0) docs[1].Open ^= 1; // [DEBUG] Automatically show/hide a tab. Test various interactions e.g. dragging with this on. 7603 //if (ImGui::GetIO().KeyCtrl) ImGui::SetTabItemSelected(docs[1].Name); // [DEBUG] Test SetTabItemSelected(), probably not very useful as-is anyway.. 7604 7605 // Submit Tabs 7606 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) 7607 { 7608 MyDocument* doc = &app.Documents[doc_n]; 7609 if (!doc->Open) 7610 continue; 7611 7612 ImGuiTabItemFlags tab_flags = (doc->Dirty ? ImGuiTabItemFlags_UnsavedDocument : 0); 7613 bool visible = ImGui::BeginTabItem(doc->Name, &doc->Open, tab_flags); 7614 7615 // Cancel attempt to close when unsaved add to save queue so we can display a popup. 7616 if (!doc->Open && doc->Dirty) 7617 { 7618 doc->Open = true; 7619 doc->DoQueueClose(); 7620 } 7621 7622 MyDocument::DisplayContextMenu(doc); 7623 if (visible) 7624 { 7625 MyDocument::DisplayContents(doc); 7626 ImGui::EndTabItem(); 7627 } 7628 } 7629 7630 ImGui::EndTabBar(); 7631 } 7632 } 7633 7634 // Update closing queue 7635 static ImVector<MyDocument*> close_queue; 7636 if (close_queue.empty()) 7637 { 7638 // Close queue is locked once we started a popup 7639 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) 7640 { 7641 MyDocument* doc = &app.Documents[doc_n]; 7642 if (doc->WantClose) 7643 { 7644 doc->WantClose = false; 7645 close_queue.push_back(doc); 7646 } 7647 } 7648 } 7649 7650 // Display closing confirmation UI 7651 if (!close_queue.empty()) 7652 { 7653 int close_queue_unsaved_documents = 0; 7654 for (int n = 0; n < close_queue.Size; n++) 7655 if (close_queue[n]->Dirty) 7656 close_queue_unsaved_documents++; 7657 7658 if (close_queue_unsaved_documents == 0) 7659 { 7660 // Close documents when all are unsaved 7661 for (int n = 0; n < close_queue.Size; n++) 7662 close_queue[n]->DoForceClose(); 7663 close_queue.clear(); 7664 } 7665 else 7666 { 7667 if (!ImGui::IsPopupOpen("Save?")) 7668 ImGui::OpenPopup("Save?"); 7669 if (ImGui::BeginPopupModal("Save?", NULL, ImGuiWindowFlags_AlwaysAutoResize)) 7670 { 7671 ImGui::Text("Save change to the following items?"); 7672 float item_height = ImGui::GetTextLineHeightWithSpacing(); 7673 if (ImGui::BeginChildFrame(ImGui::GetID("frame"), ImVec2(-FLT_MIN, 6.25f * item_height))) 7674 { 7675 for (int n = 0; n < close_queue.Size; n++) 7676 if (close_queue[n]->Dirty) 7677 ImGui::Text("%s", close_queue[n]->Name); 7678 ImGui::EndChildFrame(); 7679 } 7680 7681 ImVec2 button_size(ImGui::GetFontSize() * 7.0f, 0.0f); 7682 if (ImGui::Button("Yes", button_size)) 7683 { 7684 for (int n = 0; n < close_queue.Size; n++) 7685 { 7686 if (close_queue[n]->Dirty) 7687 close_queue[n]->DoSave(); 7688 close_queue[n]->DoForceClose(); 7689 } 7690 close_queue.clear(); 7691 ImGui::CloseCurrentPopup(); 7692 } 7693 ImGui::SameLine(); 7694 if (ImGui::Button("No", button_size)) 7695 { 7696 for (int n = 0; n < close_queue.Size; n++) 7697 close_queue[n]->DoForceClose(); 7698 close_queue.clear(); 7699 ImGui::CloseCurrentPopup(); 7700 } 7701 ImGui::SameLine(); 7702 if (ImGui::Button("Cancel", button_size)) 7703 { 7704 close_queue.clear(); 7705 ImGui::CloseCurrentPopup(); 7706 } 7707 ImGui::EndPopup(); 7708 } 7709 } 7710 } 7711 7712 ImGui::End(); 7713 } 7714 7715 // End of Demo code 7716 #else 7717 7718 void ImGui::ShowAboutWindow(bool*) {} 7719 void ImGui::ShowDemoWindow(bool*) {} 7720 void ImGui::ShowUserGuide() {} 7721 void ImGui::ShowStyleEditor(ImGuiStyle*) {} 7722 7723 #endif 7724 7725 #endif // #ifndef IMGUI_DISABLE