imgui_demo.cpp (256268B)
1// dear imgui, v1.76 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 for demo code. All applications in examples/ are doing that. 8// Read imgui.cpp for more details, documentation and comments. 9// Get latest version at https://github.com/ocornut/imgui 10 11// Message to the person tempted to delete this file when integrating Dear ImGui into their code base: 12// Do NOT remove this file from your project! Think again! It is the most useful reference code that you and other coders 13// will want to refer to and call. Have the ImGui::ShowDemoWindow() function wired in an always-available debug menu of 14// your game/app! Removing this file from your project is hindering access to documentation for everyone in your team, 15// 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 linked, 18// you can setup your imconfig.h with #define IMGUI_DISABLE_DEMO_WINDOWS and those functions will be empty. 19// In other situation, whenever you have Dear ImGui available you probably want this to be available for reference. 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 we use 'static' variables inside functions. A static variable persist across calls, so it is 25// essentially like a global variable but declared inside the scope of the function. We do this as a way to gather code and data 26// in the same place, to make the demo source code faster to read, faster to write, and smaller in size. 27// It also happens to be a convenient way of storing simple UI related information as long as your function doesn't need to be 28// reentrant or used in multiple threads. This might be a pattern you will want to use in your code, but most of the real data 29// you would be editing is likely going to be stored outside your functions. 30 31// The Demo code in this file is designed to be easy to copy-and-paste in into your application! 32// Because of this: 33// - We never omit the ImGui:: namespace when calling functions, even though most of our code is already 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 it has been exposed in the public API (imgui.h). 36// - We never use maths operators on ImVec2/ImVec4. For other of our sources files, they are provided by imgui_internal.h w/ IMGUI_DEFINE_MATH_OPERATORS. 37// For your own sources file they are optional and require you either enable those, either provide your own via IM_VEC2_CLASS_EXTRA in imconfig.h. 38// Because we don't want to assume anything about your support of maths operators, we don't use them in imgui_demo.cpp. 39 40/* 41 42Index of this file: 43 44// [SECTION] Forward Declarations, Helpers 45// [SECTION] Demo Window / ShowDemoWindow() 46// [SECTION] About Window / ShowAboutWindow() 47// [SECTION] Style Editor / ShowStyleEditor() 48// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar() 49// [SECTION] Example App: Debug Console / ShowExampleAppConsole() 50// [SECTION] Example App: Debug Log / ShowExampleAppLog() 51// [SECTION] Example App: Simple Layout / ShowExampleAppLayout() 52// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor() 53// [SECTION] Example App: Long Text / ShowExampleAppLongText() 54// [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize() 55// [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize() 56// [SECTION] Example App: Simple Overlay / ShowExampleAppSimpleOverlay() 57// [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles() 58// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering() 59// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments() 60 61*/ 62 63#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) 64#define _CRT_SECURE_NO_WARNINGS 65#endif 66 67#include "imgui.h" 68#ifndef IMGUI_DISABLE 69 70#include <ctype.h> // toupper 71#include <limits.h> // INT_MIN, INT_MAX 72#include <math.h> // sqrtf, powf, cosf, sinf, floorf, ceilf 73#include <stdio.h> // vsnprintf, sscanf, printf 74#include <stdlib.h> // NULL, malloc, free, atoi 75#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier 76#include <stddef.h> // intptr_t 77#else 78#include <stdint.h> // intptr_t 79#endif 80 81#ifdef _MSC_VER 82#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen 83#endif 84#if defined(__clang__) 85#pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse. 86#pragma clang diagnostic ignored "-Wdeprecated-declarations" // warning : 'xx' is deprecated: The POSIX name for this item.. // for strdup used in demo code (so user can copy & paste the code) 87#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int' 88#pragma clang diagnostic ignored "-Wformat-security" // warning : warning: format string is not a string literal 89#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. 90#pragma clang diagnostic ignored "-Wunused-macros" // warning : warning: macro is not used // we define snprintf/vsnprintf on Windows so they are available, but not always used. 91#if __has_warning("-Wzero-as-null-pointer-constant") 92#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0 93#endif 94#if __has_warning("-Wdouble-promotion") 95#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. 96#endif 97#if __has_warning("-Wreserved-id-macro") 98#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier // 99#endif 100#elif defined(__GNUC__) 101#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind 102#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size 103#pragma GCC diagnostic ignored "-Wformat-security" // warning : format string is not a string literal (potentially insecure) 104#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function 105#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value 106#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. 107#endif 108 109// Play it nice with Windows users (Update: since 2018-05, Notepad finally appears to support Unix-style carriage returns!) 110#ifdef _WIN32 111#define IM_NEWLINE "\r\n" 112#else 113#define IM_NEWLINE "\n" 114#endif 115 116#if defined(_MSC_VER) && !defined(snprintf) 117#define snprintf _snprintf 118#endif 119#if defined(_MSC_VER) && !defined(vsnprintf) 120#define vsnprintf _vsnprintf 121#endif 122 123//----------------------------------------------------------------------------- 124// [SECTION] Forward Declarations, Helpers 125//----------------------------------------------------------------------------- 126 127#if !defined(IMGUI_DISABLE_DEMO_WINDOWS) 128 129// Forward Declarations 130static void ShowExampleAppDocuments(bool* p_open); 131static void ShowExampleAppMainMenuBar(); 132static void ShowExampleAppConsole(bool* p_open); 133static void ShowExampleAppLog(bool* p_open); 134static void ShowExampleAppLayout(bool* p_open); 135static void ShowExampleAppPropertyEditor(bool* p_open); 136static void ShowExampleAppLongText(bool* p_open); 137static void ShowExampleAppAutoResize(bool* p_open); 138static void ShowExampleAppConstrainedResize(bool* p_open); 139static void ShowExampleAppSimpleOverlay(bool* p_open); 140static void ShowExampleAppWindowTitles(bool* p_open); 141static void ShowExampleAppCustomRendering(bool* p_open); 142static void ShowExampleMenuFile(); 143 144// Helper to display a little (?) mark which shows a tooltip when hovered. 145// In your own code you may want to display an actual icon if you are using a merged icon fonts (see docs/FONTS.txt) 146static void HelpMarker(const char* desc) 147{ 148 ImGui::TextDisabled("(?)"); 149 if (ImGui::IsItemHovered()) 150 { 151 ImGui::BeginTooltip(); 152 ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); 153 ImGui::TextUnformatted(desc); 154 ImGui::PopTextWrapPos(); 155 ImGui::EndTooltip(); 156 } 157} 158 159// Helper to display basic user controls. 160void ImGui::ShowUserGuide() 161{ 162 ImGuiIO& io = ImGui::GetIO(); 163 ImGui::BulletText("Double-click on title bar to collapse window."); 164 ImGui::BulletText("Click and drag on lower corner to resize window\n(double-click to auto fit window to its contents)."); 165 ImGui::BulletText("CTRL+Click on a slider or drag box to input value as text."); 166 ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields."); 167 if (io.FontAllowUserScaling) 168 ImGui::BulletText("CTRL+Mouse Wheel to zoom window contents."); 169 ImGui::BulletText("While inputing text:\n"); 170 ImGui::Indent(); 171 ImGui::BulletText("CTRL+Left/Right to word jump."); 172 ImGui::BulletText("CTRL+A or double-click to select all."); 173 ImGui::BulletText("CTRL+X/C/V to use clipboard cut/copy/paste."); 174 ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo."); 175 ImGui::BulletText("ESCAPE to revert."); 176 ImGui::BulletText("You can apply arithmetic operators +,*,/ on numerical values.\nUse +- to subtract."); 177 ImGui::Unindent(); 178 ImGui::BulletText("With keyboard navigation enabled:"); 179 ImGui::Indent(); 180 ImGui::BulletText("Arrow keys to navigate."); 181 ImGui::BulletText("Space to activate a widget."); 182 ImGui::BulletText("Return to input text into a widget."); 183 ImGui::BulletText("Escape to deactivate a widget, close popup, exit child window."); 184 ImGui::BulletText("Alt to jump to the menu layer of a window."); 185 ImGui::BulletText("CTRL+Tab to select a window."); 186 ImGui::Unindent(); 187} 188 189//----------------------------------------------------------------------------- 190// [SECTION] Demo Window / ShowDemoWindow() 191//----------------------------------------------------------------------------- 192// - ShowDemoWindowWidgets() 193// - ShowDemoWindowLayout() 194// - ShowDemoWindowPopups() 195// - ShowDemoWindowColumns() 196// - ShowDemoWindowMisc() 197//----------------------------------------------------------------------------- 198 199// We split the contents of the big ShowDemoWindow() function into smaller functions (because the link time of very large functions grow non-linearly) 200static void ShowDemoWindowWidgets(); 201static void ShowDemoWindowLayout(); 202static void ShowDemoWindowPopups(); 203static void ShowDemoWindowColumns(); 204static void ShowDemoWindowMisc(); 205 206// Demonstrate most Dear ImGui features (this is big function!) 207// You may execute this function to experiment with the UI and understand what it does. You may then search for keywords in the code when you are interested by a specific feature. 208void ImGui::ShowDemoWindow(bool* p_open) 209{ 210 IM_ASSERT(ImGui::GetCurrentContext() != NULL && "Missing dear imgui context. Refer to examples app!"); // Exceptionally add an extra assert here for people confused with initial dear imgui setup 211 212 // Examples Apps (accessible from the "Examples" menu) 213 static bool show_app_documents = false; 214 static bool show_app_main_menu_bar = false; 215 static bool show_app_console = false; 216 static bool show_app_log = false; 217 static bool show_app_layout = false; 218 static bool show_app_property_editor = false; 219 static bool show_app_long_text = false; 220 static bool show_app_auto_resize = false; 221 static bool show_app_constrained_resize = false; 222 static bool show_app_simple_overlay = false; 223 static bool show_app_window_titles = false; 224 static bool show_app_custom_rendering = false; 225 226 if (show_app_documents) ShowExampleAppDocuments(&show_app_documents); 227 if (show_app_main_menu_bar) ShowExampleAppMainMenuBar(); 228 if (show_app_console) ShowExampleAppConsole(&show_app_console); 229 if (show_app_log) ShowExampleAppLog(&show_app_log); 230 if (show_app_layout) ShowExampleAppLayout(&show_app_layout); 231 if (show_app_property_editor) ShowExampleAppPropertyEditor(&show_app_property_editor); 232 if (show_app_long_text) ShowExampleAppLongText(&show_app_long_text); 233 if (show_app_auto_resize) ShowExampleAppAutoResize(&show_app_auto_resize); 234 if (show_app_constrained_resize) ShowExampleAppConstrainedResize(&show_app_constrained_resize); 235 if (show_app_simple_overlay) ShowExampleAppSimpleOverlay(&show_app_simple_overlay); 236 if (show_app_window_titles) ShowExampleAppWindowTitles(&show_app_window_titles); 237 if (show_app_custom_rendering) ShowExampleAppCustomRendering(&show_app_custom_rendering); 238 239 // Dear ImGui Apps (accessible from the "Tools" menu) 240 static bool show_app_metrics = false; 241 static bool show_app_style_editor = false; 242 static bool show_app_about = false; 243 244 if (show_app_metrics) { ImGui::ShowMetricsWindow(&show_app_metrics); } 245 if (show_app_style_editor) { ImGui::Begin("Style Editor", &show_app_style_editor); ImGui::ShowStyleEditor(); ImGui::End(); } 246 if (show_app_about) { ImGui::ShowAboutWindow(&show_app_about); } 247 248 // Demonstrate the various window flags. Typically you would just use the default! 249 static bool no_titlebar = false; 250 static bool no_scrollbar = false; 251 static bool no_menu = false; 252 static bool no_move = false; 253 static bool no_resize = false; 254 static bool no_collapse = false; 255 static bool no_close = false; 256 static bool no_nav = false; 257 static bool no_background = false; 258 static bool no_bring_to_front = false; 259 260 ImGuiWindowFlags window_flags = 0; 261 if (no_titlebar) window_flags |= ImGuiWindowFlags_NoTitleBar; 262 if (no_scrollbar) window_flags |= ImGuiWindowFlags_NoScrollbar; 263 if (!no_menu) window_flags |= ImGuiWindowFlags_MenuBar; 264 if (no_move) window_flags |= ImGuiWindowFlags_NoMove; 265 if (no_resize) window_flags |= ImGuiWindowFlags_NoResize; 266 if (no_collapse) window_flags |= ImGuiWindowFlags_NoCollapse; 267 if (no_nav) window_flags |= ImGuiWindowFlags_NoNav; 268 if (no_background) window_flags |= ImGuiWindowFlags_NoBackground; 269 if (no_bring_to_front) window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus; 270 if (no_close) p_open = NULL; // Don't pass our bool* to Begin 271 272 // We specify a default position/size in case there's no data in the .ini file. Typically this isn't required! We only do it to make the Demo applications a little more welcoming. 273 ImGui::SetNextWindowPos(ImVec2(650, 20), ImGuiCond_FirstUseEver); 274 ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver); 275 276 // Main body of the Demo window starts here. 277 if (!ImGui::Begin("Dear ImGui Demo", p_open, window_flags)) 278 { 279 // Early out if the window is collapsed, as an optimization. 280 ImGui::End(); 281 return; 282 } 283 284 // Most "big" widgets share a common width settings by default. 285 //ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.65f); // Use 2/3 of the space for widgets and 1/3 for labels (default) 286 ImGui::PushItemWidth(ImGui::GetFontSize() * -12); // Use fixed width for labels (by passing a negative value), the rest goes to widgets. We choose a width proportional to our font size. 287 288 // Menu Bar 289 if (ImGui::BeginMenuBar()) 290 { 291 if (ImGui::BeginMenu("Menu")) 292 { 293 ShowExampleMenuFile(); 294 ImGui::EndMenu(); 295 } 296 if (ImGui::BeginMenu("Examples")) 297 { 298 ImGui::MenuItem("Main menu bar", NULL, &show_app_main_menu_bar); 299 ImGui::MenuItem("Console", NULL, &show_app_console); 300 ImGui::MenuItem("Log", NULL, &show_app_log); 301 ImGui::MenuItem("Simple layout", NULL, &show_app_layout); 302 ImGui::MenuItem("Property editor", NULL, &show_app_property_editor); 303 ImGui::MenuItem("Long text display", NULL, &show_app_long_text); 304 ImGui::MenuItem("Auto-resizing window", NULL, &show_app_auto_resize); 305 ImGui::MenuItem("Constrained-resizing window", NULL, &show_app_constrained_resize); 306 ImGui::MenuItem("Simple overlay", NULL, &show_app_simple_overlay); 307 ImGui::MenuItem("Manipulating window titles", NULL, &show_app_window_titles); 308 ImGui::MenuItem("Custom rendering", NULL, &show_app_custom_rendering); 309 ImGui::MenuItem("Documents", NULL, &show_app_documents); 310 ImGui::EndMenu(); 311 } 312 if (ImGui::BeginMenu("Tools")) 313 { 314 ImGui::MenuItem("Metrics", NULL, &show_app_metrics); 315 ImGui::MenuItem("Style Editor", NULL, &show_app_style_editor); 316 ImGui::MenuItem("About Dear ImGui", NULL, &show_app_about); 317 ImGui::EndMenu(); 318 } 319 ImGui::EndMenuBar(); 320 } 321 322 ImGui::Text("dear imgui says hello. (%s)", IMGUI_VERSION); 323 ImGui::Spacing(); 324 325 if (ImGui::CollapsingHeader("Help")) 326 { 327 ImGui::Text("ABOUT THIS DEMO:"); 328 ImGui::BulletText("Sections below are demonstrating many aspects of the library."); 329 ImGui::BulletText("The \"Examples\" menu above leads to more demo contents."); 330 ImGui::BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n" 331 "and Metrics (general purpose Dear ImGui debugging tool)."); 332 ImGui::Separator(); 333 334 ImGui::Text("PROGRAMMER GUIDE:"); 335 ImGui::BulletText("See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!"); 336 ImGui::BulletText("See comments in imgui.cpp."); 337 ImGui::BulletText("See example applications in the examples/ folder."); 338 ImGui::BulletText("Read the FAQ at http://www.dearimgui.org/faq/"); 339 ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls."); 340 ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls."); 341 ImGui::Separator(); 342 343 ImGui::Text("USER GUIDE:"); 344 ImGui::ShowUserGuide(); 345 } 346 347 if (ImGui::CollapsingHeader("Configuration")) 348 { 349 ImGuiIO& io = ImGui::GetIO(); 350 351 if (ImGui::TreeNode("Configuration##2")) 352 { 353 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard); 354 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad); 355 ImGui::SameLine(); HelpMarker("Required back-end to feed in gamepad inputs in io.NavInputs[] and set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details."); 356 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableSetMousePos", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NavEnableSetMousePos); 357 ImGui::SameLine(); HelpMarker("Instruct navigation to move the mouse cursor. See comment for ImGuiConfigFlags_NavEnableSetMousePos."); 358 ImGui::CheckboxFlags("io.ConfigFlags: NoMouse", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NoMouse); 359 if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) // Create a way to restore this flag otherwise we could be stuck completely! 360 { 361 if (fmodf((float)ImGui::GetTime(), 0.40f) < 0.20f) 362 { 363 ImGui::SameLine(); 364 ImGui::Text("<<PRESS SPACE TO DISABLE>>"); 365 } 366 if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Space))) 367 io.ConfigFlags &= ~ImGuiConfigFlags_NoMouse; 368 } 369 ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange); 370 ImGui::SameLine(); HelpMarker("Instruct back-end to not alter mouse cursor shape and visibility."); 371 ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink); 372 ImGui::SameLine(); HelpMarker("Set to false to disable blinking cursor, for users who consider it distracting"); 373 ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges); 374 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."); 375 ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly); 376 ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor); 377 ImGui::SameLine(); HelpMarker("Instruct Dear ImGui to render a mouse cursor for you. 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)."); 378 ImGui::TreePop(); 379 ImGui::Separator(); 380 } 381 382 if (ImGui::TreeNode("Backend Flags")) 383 { 384 HelpMarker("Those flags are set by the back-ends (imgui_impl_xxx files) to specify their capabilities.\nHere we expose then as read-only fields to avoid breaking interactions with your back-end."); 385 ImGuiBackendFlags backend_flags = io.BackendFlags; // Make a local copy to avoid modifying actual back-end flags. 386 ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasGamepad); 387 ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasMouseCursors); 388 ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasSetMousePos); 389 ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", (unsigned int *)&backend_flags, ImGuiBackendFlags_RendererHasVtxOffset); 390 ImGui::TreePop(); 391 ImGui::Separator(); 392 } 393 394 if (ImGui::TreeNode("Style")) 395 { 396 HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function."); 397 ImGui::ShowStyleEditor(); 398 ImGui::TreePop(); 399 ImGui::Separator(); 400 } 401 402 if (ImGui::TreeNode("Capture/Logging")) 403 { 404 ImGui::TextWrapped("The logging API redirects all text output so you can easily capture the content of a window or a block. Tree nodes can be automatically expanded."); 405 HelpMarker("Try opening any of the contents below in this window and then click one of the \"Log To\" button."); 406 ImGui::LogButtons(); 407 ImGui::TextWrapped("You can also call ImGui::LogText() to output directly to the log without a visual output."); 408 if (ImGui::Button("Copy \"Hello, world!\" to clipboard")) 409 { 410 ImGui::LogToClipboard(); 411 ImGui::LogText("Hello, world!"); 412 ImGui::LogFinish(); 413 } 414 ImGui::TreePop(); 415 } 416 } 417 418 if (ImGui::CollapsingHeader("Window options")) 419 { 420 ImGui::Checkbox("No titlebar", &no_titlebar); ImGui::SameLine(150); 421 ImGui::Checkbox("No scrollbar", &no_scrollbar); ImGui::SameLine(300); 422 ImGui::Checkbox("No menu", &no_menu); 423 ImGui::Checkbox("No move", &no_move); ImGui::SameLine(150); 424 ImGui::Checkbox("No resize", &no_resize); ImGui::SameLine(300); 425 ImGui::Checkbox("No collapse", &no_collapse); 426 ImGui::Checkbox("No close", &no_close); ImGui::SameLine(150); 427 ImGui::Checkbox("No nav", &no_nav); ImGui::SameLine(300); 428 ImGui::Checkbox("No background", &no_background); 429 ImGui::Checkbox("No bring to front", &no_bring_to_front); 430 } 431 432 // All demo contents 433 ShowDemoWindowWidgets(); 434 ShowDemoWindowLayout(); 435 ShowDemoWindowPopups(); 436 ShowDemoWindowColumns(); 437 ShowDemoWindowMisc(); 438 439 // End of ShowDemoWindow() 440 ImGui::End(); 441} 442 443static void ShowDemoWindowWidgets() 444{ 445 if (!ImGui::CollapsingHeader("Widgets")) 446 return; 447 448 if (ImGui::TreeNode("Basic")) 449 { 450 static int clicked = 0; 451 if (ImGui::Button("Button")) 452 clicked++; 453 if (clicked & 1) 454 { 455 ImGui::SameLine(); 456 ImGui::Text("Thanks for clicking me!"); 457 } 458 459 static bool check = true; 460 ImGui::Checkbox("checkbox", &check); 461 462 static int e = 0; 463 ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine(); 464 ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine(); 465 ImGui::RadioButton("radio c", &e, 2); 466 467 // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style. 468 for (int i = 0; i < 7; i++) 469 { 470 if (i > 0) 471 ImGui::SameLine(); 472 ImGui::PushID(i); 473 ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i/7.0f, 0.6f, 0.6f)); 474 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i/7.0f, 0.7f, 0.7f)); 475 ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i/7.0f, 0.8f, 0.8f)); 476 ImGui::Button("Click"); 477 ImGui::PopStyleColor(3); 478 ImGui::PopID(); 479 } 480 481 // Use AlignTextToFramePadding() to align text baseline to the baseline of framed elements (otherwise a Text+SameLine+Button sequence will have the text a little too high by default) 482 ImGui::AlignTextToFramePadding(); 483 ImGui::Text("Hold to repeat:"); 484 ImGui::SameLine(); 485 486 // Arrow buttons with Repeater 487 static int counter = 0; 488 float spacing = ImGui::GetStyle().ItemInnerSpacing.x; 489 ImGui::PushButtonRepeat(true); 490 if (ImGui::ArrowButton("##left", ImGuiDir_Left)) { counter--; } 491 ImGui::SameLine(0.0f, spacing); 492 if (ImGui::ArrowButton("##right", ImGuiDir_Right)) { counter++; } 493 ImGui::PopButtonRepeat(); 494 ImGui::SameLine(); 495 ImGui::Text("%d", counter); 496 497 ImGui::Text("Hover over me"); 498 if (ImGui::IsItemHovered()) 499 ImGui::SetTooltip("I am a tooltip"); 500 501 ImGui::SameLine(); 502 ImGui::Text("- or me"); 503 if (ImGui::IsItemHovered()) 504 { 505 ImGui::BeginTooltip(); 506 ImGui::Text("I am a fancy tooltip"); 507 static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; 508 ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr)); 509 ImGui::EndTooltip(); 510 } 511 512 ImGui::Separator(); 513 514 ImGui::LabelText("label", "Value"); 515 516 { 517 // Using the _simplified_ one-liner Combo() api here 518 // See "Combo" section for examples of how to use the more complete BeginCombo()/EndCombo() api. 519 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; 520 static int item_current = 0; 521 ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items)); 522 ImGui::SameLine(); HelpMarker("Refer to the \"Combo\" section below for an explanation of the full BeginCombo/EndCombo API, and demonstration of various flags.\n"); 523 } 524 525 { 526 // To wire InputText() with std::string or any other custom string type, 527 // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file. 528 static char str0[128] = "Hello, world!"; 529 ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0)); 530 ImGui::SameLine(); HelpMarker("USER:\nHold SHIFT or use mouse to select text.\n" "CTRL+Left/Right to word jump.\n" "CTRL+A or double-click to select all.\n" "CTRL+X,CTRL+C,CTRL+V clipboard.\n" "CTRL+Z,CTRL+Y undo/redo.\n" "ESCAPE to revert.\n\nPROGRAMMER:\nYou can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example (this is not demonstrated in imgui_demo.cpp)."); 531 532 static char str1[128] = ""; 533 ImGui::InputTextWithHint("input text (w/ hint)", "enter text here", str1, IM_ARRAYSIZE(str1)); 534 535 static int i0 = 123; 536 ImGui::InputInt("input int", &i0); 537 ImGui::SameLine(); HelpMarker("You can apply arithmetic operators +,*,/ on numerical values.\n e.g. [ 100 ], input \'*2\', result becomes [ 200 ]\nUse +- to subtract.\n"); 538 539 static float f0 = 0.001f; 540 ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f"); 541 542 static double d0 = 999999.00000001; 543 ImGui::InputDouble("input double", &d0, 0.01f, 1.0f, "%.8f"); 544 545 static float f1 = 1.e10f; 546 ImGui::InputFloat("input scientific", &f1, 0.0f, 0.0f, "%e"); 547 ImGui::SameLine(); HelpMarker("You can input value using the scientific notation,\n e.g. \"1e+8\" becomes \"100000000\".\n"); 548 549 static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; 550 ImGui::InputFloat3("input float3", vec4a); 551 } 552 553 { 554 static int i1 = 50, i2 = 42; 555 ImGui::DragInt("drag int", &i1, 1); 556 ImGui::SameLine(); HelpMarker("Click and drag to edit value.\nHold SHIFT/ALT for faster/slower edit.\nDouble-click or CTRL+click to input value."); 557 558 ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%"); 559 560 static float f1=1.00f, f2=0.0067f; 561 ImGui::DragFloat("drag float", &f1, 0.005f); 562 ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns"); 563 } 564 565 { 566 static int i1=0; 567 ImGui::SliderInt("slider int", &i1, -1, 3); 568 ImGui::SameLine(); HelpMarker("CTRL+click to input value."); 569 570 static float f1=0.123f, f2=0.0f; 571 ImGui::SliderFloat("slider float", &f1, 0.0f, 1.0f, "ratio = %.3f"); 572 ImGui::SliderFloat("slider float (curve)", &f2, -10.0f, 10.0f, "%.4f", 2.0f); 573 574 static float angle = 0.0f; 575 ImGui::SliderAngle("slider angle", &angle); 576 577 // Using the format string to display a name instead of an integer. 578 // Here we completely omit '%d' from the format string, so it'll only display a name. 579 // This technique can also be used with DragInt(). 580 enum Element { Element_Fire, Element_Earth, Element_Air, Element_Water, Element_COUNT }; 581 const char* element_names[Element_COUNT] = { "Fire", "Earth", "Air", "Water" }; 582 static int current_element = Element_Fire; 583 const char* current_element_name = (current_element >= 0 && current_element < Element_COUNT) ? element_names[current_element] : "Unknown"; 584 ImGui::SliderInt("slider enum", ¤t_element, 0, Element_COUNT - 1, current_element_name); 585 ImGui::SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer."); 586 } 587 588 { 589 static float col1[3] = { 1.0f,0.0f,0.2f }; 590 static float col2[4] = { 0.4f,0.7f,0.0f,0.5f }; 591 ImGui::ColorEdit3("color 1", col1); 592 ImGui::SameLine(); HelpMarker("Click on the colored square to open a color picker.\nClick and hold to use drag and drop.\nRight-click on the colored square to show options.\nCTRL+click on individual component to input value.\n"); 593 594 ImGui::ColorEdit4("color 2", col2); 595 } 596 597 { 598 // List box 599 const char* listbox_items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" }; 600 static int listbox_item_current = 1; 601 ImGui::ListBox("listbox\n(single select)", &listbox_item_current, listbox_items, IM_ARRAYSIZE(listbox_items), 4); 602 603 //static int listbox_item_current2 = 2; 604 //ImGui::SetNextItemWidth(-1); 605 //ImGui::ListBox("##listbox2", &listbox_item_current2, listbox_items, IM_ARRAYSIZE(listbox_items), 4); 606 } 607 608 ImGui::TreePop(); 609 } 610 611 // Testing ImGuiOnceUponAFrame helper. 612 //static ImGuiOnceUponAFrame once; 613 //for (int i = 0; i < 5; i++) 614 // if (once) 615 // ImGui::Text("This will be displayed only once."); 616 617 if (ImGui::TreeNode("Trees")) 618 { 619 if (ImGui::TreeNode("Basic trees")) 620 { 621 for (int i = 0; i < 5; i++) 622 { 623 // Use SetNextItemOpen() so set the default state of a node to be open. 624 // We could also use TreeNodeEx() with the ImGuiTreeNodeFlags_DefaultOpen flag to achieve the same thing! 625 if (i == 0) 626 ImGui::SetNextItemOpen(true, ImGuiCond_Once); 627 628 if (ImGui::TreeNode((void*)(intptr_t)i, "Child %d", i)) 629 { 630 ImGui::Text("blah blah"); 631 ImGui::SameLine(); 632 if (ImGui::SmallButton("button")) {} 633 ImGui::TreePop(); 634 } 635 } 636 ImGui::TreePop(); 637 } 638 639 if (ImGui::TreeNode("Advanced, with Selectable nodes")) 640 { 641 HelpMarker("This is a more typical looking tree with selectable nodes.\nClick to select, CTRL+Click to toggle, click on arrows or double-click to open."); 642 static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth; 643 static bool align_label_with_current_x_position = false; 644 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnArrow", (unsigned int*)&base_flags, ImGuiTreeNodeFlags_OpenOnArrow); 645 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", (unsigned int*)&base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick); 646 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAvailWidth", (unsigned int*)&base_flags, ImGuiTreeNodeFlags_SpanAvailWidth); ImGui::SameLine(); HelpMarker("Extend hit area to all available width instead of allowing more items to be layed out after the node."); 647 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", (unsigned int*)&base_flags, ImGuiTreeNodeFlags_SpanFullWidth); 648 ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position); 649 ImGui::Text("Hello!"); 650 if (align_label_with_current_x_position) 651 ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing()); 652 653 static int selection_mask = (1 << 2); // Dumb representation of what may be user-side selection state. You may carry selection state inside or outside your objects in whatever format you see fit. 654 int node_clicked = -1; // Temporary storage of what node we have clicked to process selection at the end of the loop. May be a pointer to your own node type, etc. 655 for (int i = 0; i < 6; i++) 656 { 657 // Disable the default open on single-click behavior and pass in Selected flag according to our selection state. 658 ImGuiTreeNodeFlags node_flags = base_flags; 659 const bool is_selected = (selection_mask & (1 << i)) != 0; 660 if (is_selected) 661 node_flags |= ImGuiTreeNodeFlags_Selected; 662 if (i < 3) 663 { 664 // Items 0..2 are Tree Node 665 bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Node %d", i); 666 if (ImGui::IsItemClicked()) 667 node_clicked = i; 668 if (node_open) 669 { 670 ImGui::BulletText("Blah blah\nBlah Blah"); 671 ImGui::TreePop(); 672 } 673 } 674 else 675 { 676 // Items 3..5 are Tree Leaves 677 // The only reason we use TreeNode at all is to allow selection of the leaf. 678 // Otherwise we can use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text(). 679 node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet 680 ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i); 681 if (ImGui::IsItemClicked()) 682 node_clicked = i; 683 } 684 } 685 if (node_clicked != -1) 686 { 687 // Update selection state. Process outside of tree loop to avoid visual inconsistencies during the clicking-frame. 688 if (ImGui::GetIO().KeyCtrl) 689 selection_mask ^= (1 << node_clicked); // CTRL+click to toggle 690 else //if (!(selection_mask & (1 << node_clicked))) // Depending on selection behavior you want, this commented bit preserve selection when clicking on item that is part of the selection 691 selection_mask = (1 << node_clicked); // Click to single-select 692 } 693 if (align_label_with_current_x_position) 694 ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing()); 695 ImGui::TreePop(); 696 } 697 ImGui::TreePop(); 698 } 699 700 if (ImGui::TreeNode("Collapsing Headers")) 701 { 702 static bool closable_group = true; 703 ImGui::Checkbox("Show 2nd header", &closable_group); 704 if (ImGui::CollapsingHeader("Header", ImGuiTreeNodeFlags_None)) 705 { 706 ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered()); 707 for (int i = 0; i < 5; i++) 708 ImGui::Text("Some content %d", i); 709 } 710 if (ImGui::CollapsingHeader("Header with a close button", &closable_group)) 711 { 712 ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered()); 713 for (int i = 0; i < 5; i++) 714 ImGui::Text("More content %d", i); 715 } 716 /* 717 if (ImGui::CollapsingHeader("Header with a bullet", ImGuiTreeNodeFlags_Bullet)) 718 ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered()); 719 */ 720 ImGui::TreePop(); 721 } 722 723 if (ImGui::TreeNode("Bullets")) 724 { 725 ImGui::BulletText("Bullet point 1"); 726 ImGui::BulletText("Bullet point 2\nOn multiple lines"); 727 if (ImGui::TreeNode("Tree node")) 728 { 729 ImGui::BulletText("Another bullet point"); 730 ImGui::TreePop(); 731 } 732 ImGui::Bullet(); ImGui::Text("Bullet point 3 (two calls)"); 733 ImGui::Bullet(); ImGui::SmallButton("Button"); 734 ImGui::TreePop(); 735 } 736 737 if (ImGui::TreeNode("Text")) 738 { 739 if (ImGui::TreeNode("Colored Text")) 740 { 741 // Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility. 742 ImGui::TextColored(ImVec4(1.0f,0.0f,1.0f,1.0f), "Pink"); 743 ImGui::TextColored(ImVec4(1.0f,1.0f,0.0f,1.0f), "Yellow"); 744 ImGui::TextDisabled("Disabled"); 745 ImGui::SameLine(); HelpMarker("The TextDisabled color is stored in ImGuiStyle."); 746 ImGui::TreePop(); 747 } 748 749 if (ImGui::TreeNode("Word Wrapping")) 750 { 751 // Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility. 752 ImGui::TextWrapped("This text should automatically wrap on the edge of the window. The current implementation for text wrapping follows simple rules suitable for English and possibly other languages."); 753 ImGui::Spacing(); 754 755 static float wrap_width = 200.0f; 756 ImGui::SliderFloat("Wrap width", &wrap_width, -20, 600, "%.0f"); 757 758 ImGui::Text("Test paragraph 1:"); 759 ImVec2 pos = ImGui::GetCursorScreenPos(); 760 ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(pos.x + wrap_width, pos.y), ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight()), IM_COL32(255,0,255,255)); 761 ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width); 762 ImGui::Text("The lazy dog is a good dog. This paragraph is made to fit within %.0f pixels. Testing a 1 character word. The quick brown fox jumps over the lazy dog.", wrap_width); 763 ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255,255,0,255)); 764 ImGui::PopTextWrapPos(); 765 766 ImGui::Text("Test paragraph 2:"); 767 pos = ImGui::GetCursorScreenPos(); 768 ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(pos.x + wrap_width, pos.y), ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight()), IM_COL32(255,0,255,255)); 769 ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width); 770 ImGui::Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh"); 771 ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255,255,0,255)); 772 ImGui::PopTextWrapPos(); 773 774 ImGui::TreePop(); 775 } 776 777 if (ImGui::TreeNode("UTF-8 Text")) 778 { 779 // UTF-8 test with Japanese characters 780 // (Needs a suitable font, try Noto, or Arial Unicode, or M+ fonts. Read docs/FONTS.txt for details.) 781 // - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8 782 // - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. Visual Studio save your file as 'UTF-8 without signature') 783 // - FOR THIS DEMO FILE ONLY, BECAUSE WE WANT TO SUPPORT OLD COMPILERS, WE ARE *NOT* INCLUDING RAW UTF-8 CHARACTERS IN THIS SOURCE FILE. 784 // Instead we are encoding a few strings with hexadecimal constants. Don't do this in your application! 785 // Please use u8"text in any language" in your application! 786 // Note that characters values are preserved even by InputText() if the font cannot be displayed, so you can safely copy & paste garbled characters into another application. 787 ImGui::TextWrapped("CJK text will only appears if the font was loaded with the appropriate CJK character ranges. Call io.Font->AddFontFromFileTTF() manually to load extra character ranges. Read docs/FONTS.txt for details."); 788 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. 789 ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)"); 790 static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"; 791 //static char buf[32] = u8"NIHONGO"; // <- this is how you would write it with C++11, using real kanjis 792 ImGui::InputText("UTF-8 input", buf, IM_ARRAYSIZE(buf)); 793 ImGui::TreePop(); 794 } 795 ImGui::TreePop(); 796 } 797 798 if (ImGui::TreeNode("Images")) 799 { 800 ImGuiIO& io = ImGui::GetIO(); 801 ImGui::TextWrapped("Below we are displaying the font texture (which is the only texture we have access to in this demo). Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. Hover the texture for a zoomed view!"); 802 803 // Here we are grabbing the font texture because that's the only one we have access to inside the demo code. 804 // Remember that ImTextureID is just storage for whatever you want it to be, it is essentially a value that will be passed to the render function inside the ImDrawCmd structure. 805 // If you use one of the default imgui_impl_XXXX.cpp renderer, they all have comments at the top of their file to specify what they expect to be stored in ImTextureID. 806 // (for example, the imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer. The imgui_impl_opengl3.cpp renderer expect a GLuint OpenGL texture identifier etc.) 807 // If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers to ImGui::Image(), and gather width/height through your own functions, etc. 808 // Using ShowMetricsWindow() as a "debugger" to inspect the draw data that are being passed to your render will help you debug issues if you are confused about this. 809 // Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage(). 810 ImTextureID my_tex_id = io.Fonts->TexID; 811 float my_tex_w = (float)io.Fonts->TexWidth; 812 float my_tex_h = (float)io.Fonts->TexHeight; 813 814 ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h); 815 ImVec2 pos = ImGui::GetCursorScreenPos(); 816 ImGui::Image(my_tex_id, ImVec2(my_tex_w, my_tex_h), ImVec2(0,0), ImVec2(1,1), ImVec4(1.0f,1.0f,1.0f,1.0f), ImVec4(1.0f,1.0f,1.0f,0.5f)); 817 if (ImGui::IsItemHovered()) 818 { 819 ImGui::BeginTooltip(); 820 float region_sz = 32.0f; 821 float region_x = io.MousePos.x - pos.x - region_sz * 0.5f; if (region_x < 0.0f) region_x = 0.0f; else if (region_x > my_tex_w - region_sz) region_x = my_tex_w - region_sz; 822 float region_y = io.MousePos.y - pos.y - region_sz * 0.5f; if (region_y < 0.0f) region_y = 0.0f; else if (region_y > my_tex_h - region_sz) region_y = my_tex_h - region_sz; 823 float zoom = 4.0f; 824 ImGui::Text("Min: (%.2f, %.2f)", region_x, region_y); 825 ImGui::Text("Max: (%.2f, %.2f)", region_x + region_sz, region_y + region_sz); 826 ImVec2 uv0 = ImVec2((region_x) / my_tex_w, (region_y) / my_tex_h); 827 ImVec2 uv1 = ImVec2((region_x + region_sz) / my_tex_w, (region_y + region_sz) / my_tex_h); 828 ImGui::Image(my_tex_id, ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, ImVec4(1.0f, 1.0f, 1.0f, 1.0f), ImVec4(1.0f, 1.0f, 1.0f, 0.5f)); 829 ImGui::EndTooltip(); 830 } 831 ImGui::TextWrapped("And now some textured buttons.."); 832 static int pressed_count = 0; 833 for (int i = 0; i < 8; i++) 834 { 835 ImGui::PushID(i); 836 int frame_padding = -1 + i; // -1 = uses default padding 837 if (ImGui::ImageButton(my_tex_id, ImVec2(32,32), ImVec2(0,0), ImVec2(32.0f/my_tex_w,32/my_tex_h), frame_padding, ImVec4(0.0f,0.0f,0.0f,1.0f))) 838 pressed_count += 1; 839 ImGui::PopID(); 840 ImGui::SameLine(); 841 } 842 ImGui::NewLine(); 843 ImGui::Text("Pressed %d times.", pressed_count); 844 ImGui::TreePop(); 845 } 846 847 if (ImGui::TreeNode("Combo")) 848 { 849 // Expose flags as checkbox for the demo 850 static ImGuiComboFlags flags = 0; 851 ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", (unsigned int*)&flags, ImGuiComboFlags_PopupAlignLeft); 852 ImGui::SameLine(); HelpMarker("Only makes a difference if the popup is larger than the combo"); 853 if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", (unsigned int*)&flags, ImGuiComboFlags_NoArrowButton)) 854 flags &= ~ImGuiComboFlags_NoPreview; // Clear the other flag, as we cannot combine both 855 if (ImGui::CheckboxFlags("ImGuiComboFlags_NoPreview", (unsigned int*)&flags, ImGuiComboFlags_NoPreview)) 856 flags &= ~ImGuiComboFlags_NoArrowButton; // Clear the other flag, as we cannot combine both 857 858 // General BeginCombo() API, you have full control over your selection data and display type. 859 // (your selection data could be an index, a pointer to the object, an id for the object, a flag stored in the object itself, etc.) 860 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; 861 static const char* item_current = items[0]; // Here our selection is a single pointer stored outside the object. 862 if (ImGui::BeginCombo("combo 1", item_current, flags)) // The second parameter is the label previewed before opening the combo. 863 { 864 for (int n = 0; n < IM_ARRAYSIZE(items); n++) 865 { 866 bool is_selected = (item_current == items[n]); 867 if (ImGui::Selectable(items[n], is_selected)) 868 item_current = items[n]; 869 if (is_selected) 870 ImGui::SetItemDefaultFocus(); // Set the initial focus when opening the combo (scrolling + for keyboard navigation support in the upcoming navigation branch) 871 } 872 ImGui::EndCombo(); 873 } 874 875 // Simplified one-liner Combo() API, using values packed in a single constant string 876 static int item_current_2 = 0; 877 ImGui::Combo("combo 2 (one-liner)", &item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); 878 879 // Simplified one-liner Combo() using an array of const char* 880 static int item_current_3 = -1; // If the selection isn't within 0..count, Combo won't display a preview 881 ImGui::Combo("combo 3 (array)", &item_current_3, items, IM_ARRAYSIZE(items)); 882 883 // Simplified one-liner Combo() using an accessor function 884 struct FuncHolder { static bool ItemGetter(void* data, int idx, const char** out_str) { *out_str = ((const char**)data)[idx]; return true; } }; 885 static int item_current_4 = 0; 886 ImGui::Combo("combo 4 (function)", &item_current_4, &FuncHolder::ItemGetter, items, IM_ARRAYSIZE(items)); 887 888 ImGui::TreePop(); 889 } 890 891 if (ImGui::TreeNode("Selectables")) 892 { 893 // Selectable() has 2 overloads: 894 // - The one taking "bool selected" as a read-only selection information. When Selectable() has been clicked is returns true and you can alter selection state accordingly. 895 // - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases) 896 // The earlier is more flexible, as in real application your selection may be stored in a different manner (in flags within objects, as an external list, etc). 897 if (ImGui::TreeNode("Basic")) 898 { 899 static bool selection[5] = { false, true, false, false, false }; 900 ImGui::Selectable("1. I am selectable", &selection[0]); 901 ImGui::Selectable("2. I am selectable", &selection[1]); 902 ImGui::Text("3. I am not selectable"); 903 ImGui::Selectable("4. I am selectable", &selection[3]); 904 if (ImGui::Selectable("5. I am double clickable", selection[4], ImGuiSelectableFlags_AllowDoubleClick)) 905 if (ImGui::IsMouseDoubleClicked(0)) 906 selection[4] = !selection[4]; 907 ImGui::TreePop(); 908 } 909 if (ImGui::TreeNode("Selection State: Single Selection")) 910 { 911 static int selected = -1; 912 for (int n = 0; n < 5; n++) 913 { 914 char buf[32]; 915 sprintf(buf, "Object %d", n); 916 if (ImGui::Selectable(buf, selected == n)) 917 selected = n; 918 } 919 ImGui::TreePop(); 920 } 921 if (ImGui::TreeNode("Selection State: Multiple Selection")) 922 { 923 HelpMarker("Hold CTRL and click to select multiple items."); 924 static bool selection[5] = { false, false, false, false, false }; 925 for (int n = 0; n < 5; n++) 926 { 927 char buf[32]; 928 sprintf(buf, "Object %d", n); 929 if (ImGui::Selectable(buf, selection[n])) 930 { 931 if (!ImGui::GetIO().KeyCtrl) // Clear selection when CTRL is not held 932 memset(selection, 0, sizeof(selection)); 933 selection[n] ^= 1; 934 } 935 } 936 ImGui::TreePop(); 937 } 938 if (ImGui::TreeNode("Rendering more text into the same line")) 939 { 940 // Using the Selectable() override that takes "bool* p_selected" parameter and toggle your booleans automatically. 941 static bool selected[3] = { false, false, false }; 942 ImGui::Selectable("main.c", &selected[0]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes"); 943 ImGui::Selectable("Hello.cpp", &selected[1]); ImGui::SameLine(300); ImGui::Text("12,345 bytes"); 944 ImGui::Selectable("Hello.h", &selected[2]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes"); 945 ImGui::TreePop(); 946 } 947 if (ImGui::TreeNode("In columns")) 948 { 949 ImGui::Columns(3, NULL, false); 950 static bool selected[16] = {}; 951 for (int i = 0; i < 16; i++) 952 { 953 char label[32]; sprintf(label, "Item %d", i); 954 if (ImGui::Selectable(label, &selected[i])) {} 955 ImGui::NextColumn(); 956 } 957 ImGui::Columns(1); 958 ImGui::TreePop(); 959 } 960 if (ImGui::TreeNode("Grid")) 961 { 962 static bool selected[4*4] = { true, false, false, false, false, true, false, false, false, false, true, false, false, false, false, true }; 963 for (int i = 0; i < 4*4; i++) 964 { 965 ImGui::PushID(i); 966 if (ImGui::Selectable("Sailor", &selected[i], 0, ImVec2(50,50))) 967 { 968 // Note: We _unnecessarily_ test for both x/y and i here only to silence some static analyzer. The second part of each test is unnecessary. 969 int x = i % 4; 970 int y = i / 4; 971 if (x > 0) { selected[i - 1] ^= 1; } 972 if (x < 3 && i < 15) { selected[i + 1] ^= 1; } 973 if (y > 0 && i > 3) { selected[i - 4] ^= 1; } 974 if (y < 3 && i < 12) { selected[i + 4] ^= 1; } 975 } 976 if ((i % 4) < 3) ImGui::SameLine(); 977 ImGui::PopID(); 978 } 979 ImGui::TreePop(); 980 } 981 if (ImGui::TreeNode("Alignment")) 982 { 983 HelpMarker("By default, Selectables uses style.SelectableTextAlign but it can be overriden on a per-item basis using PushStyleVar(). You'll probably want to always keep your default situation to left-align otherwise it becomes difficult to layout multiple items on a same line"); 984 static bool selected[3*3] = { true, false, true, false, true, false, true, false, true }; 985 for (int y = 0; y < 3; y++) 986 { 987 for (int x = 0; x < 3; x++) 988 { 989 ImVec2 alignment = ImVec2((float)x / 2.0f, (float)y / 2.0f); 990 char name[32]; 991 sprintf(name, "(%.1f,%.1f)", alignment.x, alignment.y); 992 if (x > 0) ImGui::SameLine(); 993 ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, alignment); 994 ImGui::Selectable(name, &selected[3*y+x], ImGuiSelectableFlags_None, ImVec2(80,80)); 995 ImGui::PopStyleVar(); 996 } 997 } 998 ImGui::TreePop(); 999 } 1000 ImGui::TreePop(); 1001 } 1002 1003 // To wire InputText() with std::string or any other custom string type, 1004 // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file. 1005 if (ImGui::TreeNode("Text Input")) 1006 { 1007 if (ImGui::TreeNode("Multi-line Text Input")) 1008 { 1009 // Note: we are using a fixed-sized buffer for simplicity here. See ImGuiInputTextFlags_CallbackResize 1010 // and the code in misc/cpp/imgui_stdlib.h for how to setup InputText() for dynamically resizing strings. 1011 static char text[1024 * 16] = 1012 "/*\n" 1013 " The Pentium F00F bug, shorthand for F0 0F C7 C8,\n" 1014 " the hexadecimal encoding of one offending instruction,\n" 1015 " more formally, the invalid operand with locked CMPXCHG8B\n" 1016 " instruction bug, is a design flaw in the majority of\n" 1017 " Intel Pentium, Pentium MMX, and Pentium OverDrive\n" 1018 " processors (all in the P5 microarchitecture).\n" 1019 "*/\n\n" 1020 "label:\n" 1021 "\tlock cmpxchg8b eax\n"; 1022 1023 static ImGuiInputTextFlags flags = ImGuiInputTextFlags_AllowTabInput; 1024 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)"); 1025 ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", (unsigned int*)&flags, ImGuiInputTextFlags_ReadOnly); 1026 ImGui::CheckboxFlags("ImGuiInputTextFlags_AllowTabInput", (unsigned int*)&flags, ImGuiInputTextFlags_AllowTabInput); 1027 ImGui::CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", (unsigned int*)&flags, ImGuiInputTextFlags_CtrlEnterForNewLine); 1028 ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16), flags); 1029 ImGui::TreePop(); 1030 } 1031 1032 if (ImGui::TreeNode("Filtered Text Input")) 1033 { 1034 static char buf1[64] = ""; ImGui::InputText("default", buf1, 64); 1035 static char buf2[64] = ""; ImGui::InputText("decimal", buf2, 64, ImGuiInputTextFlags_CharsDecimal); 1036 static char buf3[64] = ""; ImGui::InputText("hexadecimal", buf3, 64, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase); 1037 static char buf4[64] = ""; ImGui::InputText("uppercase", buf4, 64, ImGuiInputTextFlags_CharsUppercase); 1038 static char buf5[64] = ""; ImGui::InputText("no blank", buf5, 64, ImGuiInputTextFlags_CharsNoBlank); 1039 struct TextFilters { static int FilterImGuiLetters(ImGuiInputTextCallbackData* data) { if (data->EventChar < 256 && strchr("imgui", (char)data->EventChar)) return 0; return 1; } }; 1040 static char buf6[64] = ""; ImGui::InputText("\"imgui\" letters", buf6, 64, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters); 1041 1042 ImGui::Text("Password input"); 1043 static char password[64] = "password123"; 1044 ImGui::InputText("password", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password); 1045 ImGui::SameLine(); HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n"); 1046 ImGui::InputTextWithHint("password (w/ hint)", "<password>", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password); 1047 ImGui::InputText("password (clear)", password, IM_ARRAYSIZE(password)); 1048 ImGui::TreePop(); 1049 } 1050 1051 if (ImGui::TreeNode("Resize Callback")) 1052 { 1053 // To wire InputText() with std::string or any other custom string type, 1054 // you can use the ImGuiInputTextFlags_CallbackResize flag + create a custom ImGui::InputText() wrapper using your prefered type. 1055 // See misc/cpp/imgui_stdlib.h for an implementation of this using std::string. 1056 HelpMarker("Demonstrate using ImGuiInputTextFlags_CallbackResize to wire your resizable string type to InputText().\n\nSee misc/cpp/imgui_stdlib.h for an implementation of this for std::string."); 1057 struct Funcs 1058 { 1059 static int MyResizeCallback(ImGuiInputTextCallbackData* data) 1060 { 1061 if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) 1062 { 1063 ImVector<char>* my_str = (ImVector<char>*)data->UserData; 1064 IM_ASSERT(my_str->begin() == data->Buf); 1065 my_str->resize(data->BufSize); // NB: On resizing calls, generally data->BufSize == data->BufTextLen + 1 1066 data->Buf = my_str->begin(); 1067 } 1068 return 0; 1069 } 1070 1071 // Tip: Because ImGui:: is a namespace you would typicall add your own function into the namespace in your own source files. 1072 // For example, you may add a function called ImGui::InputText(const char* label, MyString* my_str). 1073 static bool MyInputTextMultiline(const char* label, ImVector<char>* my_str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0) 1074 { 1075 IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); 1076 return ImGui::InputTextMultiline(label, my_str->begin(), (size_t)my_str->size(), size, flags | ImGuiInputTextFlags_CallbackResize, Funcs::MyResizeCallback, (void*)my_str); 1077 } 1078 }; 1079 1080 // For this demo we are using ImVector as a string container. 1081 // Note that because we need to store a terminating zero character, our size/capacity are 1 more than usually reported by a typical string class. 1082 static ImVector<char> my_str; 1083 if (my_str.empty()) 1084 my_str.push_back(0); 1085 Funcs::MyInputTextMultiline("##MyStr", &my_str, ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16)); 1086 ImGui::Text("Data: %p\nSize: %d\nCapacity: %d", (void*)my_str.begin(), my_str.size(), my_str.capacity()); 1087 ImGui::TreePop(); 1088 } 1089 1090 ImGui::TreePop(); 1091 } 1092 1093 // Plot/Graph widgets are currently fairly limited. 1094 // Consider writing your own plotting widget, or using a third-party one (see "Wiki->Useful Widgets", or github.com/ocornut/imgui/issues/2747) 1095 if (ImGui::TreeNode("Plots Widgets")) 1096 { 1097 static bool animate = true; 1098 ImGui::Checkbox("Animate", &animate); 1099 1100 static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; 1101 ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr)); 1102 1103 // Create a dummy array of contiguous float values to plot 1104 // Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float and the sizeof() of your structure in the Stride parameter. 1105 static float values[90] = {}; 1106 static int values_offset = 0; 1107 static double refresh_time = 0.0; 1108 if (!animate || refresh_time == 0.0) 1109 refresh_time = ImGui::GetTime(); 1110 while (refresh_time < ImGui::GetTime()) // Create dummy data at fixed 60 hz rate for the demo 1111 { 1112 static float phase = 0.0f; 1113 values[values_offset] = cosf(phase); 1114 values_offset = (values_offset+1) % IM_ARRAYSIZE(values); 1115 phase += 0.10f*values_offset; 1116 refresh_time += 1.0f/60.0f; 1117 } 1118 1119 // Plots can display overlay texts 1120 // (in this example, we will display an average value) 1121 { 1122 float average = 0.0f; 1123 for (int n = 0; n < IM_ARRAYSIZE(values); n++) 1124 average += values[n]; 1125 average /= (float)IM_ARRAYSIZE(values); 1126 char overlay[32]; 1127 sprintf(overlay, "avg %f", average); 1128 ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, overlay, -1.0f, 1.0f, ImVec2(0,80)); 1129 } 1130 ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0,80)); 1131 1132 // Use functions to generate output 1133 // FIXME: This is rather awkward because current plot API only pass in indices. We probably want an API passing floats and user provide sample rate/count. 1134 struct Funcs 1135 { 1136 static float Sin(void*, int i) { return sinf(i * 0.1f); } 1137 static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; } 1138 }; 1139 static int func_type = 0, display_count = 70; 1140 ImGui::Separator(); 1141 ImGui::SetNextItemWidth(100); 1142 ImGui::Combo("func", &func_type, "Sin\0Saw\0"); 1143 ImGui::SameLine(); 1144 ImGui::SliderInt("Sample count", &display_count, 1, 400); 1145 float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw; 1146 ImGui::PlotLines("Lines", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0,80)); 1147 ImGui::PlotHistogram("Histogram", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0,80)); 1148 ImGui::Separator(); 1149 1150 // Animate a simple progress bar 1151 static float progress = 0.0f, progress_dir = 1.0f; 1152 if (animate) 1153 { 1154 progress += progress_dir * 0.4f * ImGui::GetIO().DeltaTime; 1155 if (progress >= +1.1f) { progress = +1.1f; progress_dir *= -1.0f; } 1156 if (progress <= -0.1f) { progress = -0.1f; progress_dir *= -1.0f; } 1157 } 1158 1159 // Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width, 1160 // or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth. 1161 ImGui::ProgressBar(progress, ImVec2(0.0f,0.0f)); 1162 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); 1163 ImGui::Text("Progress Bar"); 1164 1165 float progress_saturated = (progress < 0.0f) ? 0.0f : (progress > 1.0f) ? 1.0f : progress; 1166 char buf[32]; 1167 sprintf(buf, "%d/%d", (int)(progress_saturated*1753), 1753); 1168 ImGui::ProgressBar(progress, ImVec2(0.f,0.f), buf); 1169 ImGui::TreePop(); 1170 } 1171 1172 if (ImGui::TreeNode("Color/Picker Widgets")) 1173 { 1174 static ImVec4 color = ImVec4(114.0f/255.0f, 144.0f/255.0f, 154.0f/255.0f, 200.0f/255.0f); 1175 1176 static bool alpha_preview = true; 1177 static bool alpha_half_preview = false; 1178 static bool drag_and_drop = true; 1179 static bool options_menu = true; 1180 static bool hdr = false; 1181 ImGui::Checkbox("With Alpha Preview", &alpha_preview); 1182 ImGui::Checkbox("With Half Alpha Preview", &alpha_half_preview); 1183 ImGui::Checkbox("With Drag and Drop", &drag_and_drop); 1184 ImGui::Checkbox("With Options Menu", &options_menu); ImGui::SameLine(); HelpMarker("Right-click on the individual color widget to show options."); 1185 ImGui::Checkbox("With HDR", &hdr); ImGui::SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets."); 1186 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); 1187 1188 ImGui::Text("Color widget:"); 1189 ImGui::SameLine(); HelpMarker("Click on the colored square to open a color picker.\nCTRL+click on individual component to input value.\n"); 1190 ImGui::ColorEdit3("MyColor##1", (float*)&color, misc_flags); 1191 1192 ImGui::Text("Color widget HSV with Alpha:"); 1193 ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_DisplayHSV | misc_flags); 1194 1195 ImGui::Text("Color widget with Float Display:"); 1196 ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | misc_flags); 1197 1198 ImGui::Text("Color button with Picker:"); 1199 ImGui::SameLine(); HelpMarker("With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\nWith the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only be used for the tooltip and picker popup."); 1200 ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | misc_flags); 1201 1202 ImGui::Text("Color button with Custom Picker Popup:"); 1203 1204 // Generate a dummy default palette. The palette will persist and can be edited. 1205 static bool saved_palette_init = true; 1206 static ImVec4 saved_palette[32] = {}; 1207 if (saved_palette_init) 1208 { 1209 for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++) 1210 { 1211 ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f, saved_palette[n].x, saved_palette[n].y, saved_palette[n].z); 1212 saved_palette[n].w = 1.0f; // Alpha 1213 } 1214 saved_palette_init = false; 1215 } 1216 1217 static ImVec4 backup_color; 1218 bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags); 1219 ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x); 1220 open_popup |= ImGui::Button("Palette"); 1221 if (open_popup) 1222 { 1223 ImGui::OpenPopup("mypicker"); 1224 backup_color = color; 1225 } 1226 if (ImGui::BeginPopup("mypicker")) 1227 { 1228 ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!"); 1229 ImGui::Separator(); 1230 ImGui::ColorPicker4("##picker", (float*)&color, misc_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview); 1231 ImGui::SameLine(); 1232 1233 ImGui::BeginGroup(); // Lock X position 1234 ImGui::Text("Current"); 1235 ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60,40)); 1236 ImGui::Text("Previous"); 1237 if (ImGui::ColorButton("##previous", backup_color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60,40))) 1238 color = backup_color; 1239 ImGui::Separator(); 1240 ImGui::Text("Palette"); 1241 for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++) 1242 { 1243 ImGui::PushID(n); 1244 if ((n % 8) != 0) 1245 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y); 1246 if (ImGui::ColorButton("##palette", saved_palette[n], ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip, ImVec2(20,20))) 1247 color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha! 1248 1249 // Allow user to drop colors into each palette entry 1250 // (Note that ColorButton is already a drag source by default, unless using ImGuiColorEditFlags_NoDragDrop) 1251 if (ImGui::BeginDragDropTarget()) 1252 { 1253 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) 1254 memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3); 1255 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) 1256 memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4); 1257 ImGui::EndDragDropTarget(); 1258 } 1259 1260 ImGui::PopID(); 1261 } 1262 ImGui::EndGroup(); 1263 ImGui::EndPopup(); 1264 } 1265 1266 ImGui::Text("Color button only:"); 1267 static bool no_border = false; 1268 ImGui::Checkbox("ImGuiColorEditFlags_NoBorder", &no_border); 1269 ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, misc_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80,80)); 1270 1271 ImGui::Text("Color picker:"); 1272 static bool alpha = true; 1273 static bool alpha_bar = true; 1274 static bool side_preview = true; 1275 static bool ref_color = false; 1276 static ImVec4 ref_color_v(1.0f,0.0f,1.0f,0.5f); 1277 static int display_mode = 0; 1278 static int picker_mode = 0; 1279 ImGui::Checkbox("With Alpha", &alpha); 1280 ImGui::Checkbox("With Alpha Bar", &alpha_bar); 1281 ImGui::Checkbox("With Side Preview", &side_preview); 1282 if (side_preview) 1283 { 1284 ImGui::SameLine(); 1285 ImGui::Checkbox("With Ref Color", &ref_color); 1286 if (ref_color) 1287 { 1288 ImGui::SameLine(); 1289 ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | misc_flags); 1290 } 1291 } 1292 ImGui::Combo("Display Mode", &display_mode, "Auto/Current\0None\0RGB Only\0HSV Only\0Hex Only\0"); 1293 ImGui::SameLine(); HelpMarker("ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, but the user can change it with a right-click.\n\nColorPicker defaults to displaying RGB+HSV+Hex if you don't specify a display mode.\n\nYou can change the defaults using SetColorEditOptions()."); 1294 ImGui::Combo("Picker Mode", &picker_mode, "Auto/Current\0Hue bar + SV rect\0Hue wheel + SV triangle\0"); 1295 ImGui::SameLine(); HelpMarker("User can right-click the picker to change mode."); 1296 ImGuiColorEditFlags flags = misc_flags; 1297 if (!alpha) flags |= ImGuiColorEditFlags_NoAlpha; // This is by default if you call ColorPicker3() instead of ColorPicker4() 1298 if (alpha_bar) flags |= ImGuiColorEditFlags_AlphaBar; 1299 if (!side_preview) flags |= ImGuiColorEditFlags_NoSidePreview; 1300 if (picker_mode == 1) flags |= ImGuiColorEditFlags_PickerHueBar; 1301 if (picker_mode == 2) flags |= ImGuiColorEditFlags_PickerHueWheel; 1302 if (display_mode == 1) flags |= ImGuiColorEditFlags_NoInputs; // Disable all RGB/HSV/Hex displays 1303 if (display_mode == 2) flags |= ImGuiColorEditFlags_DisplayRGB; // Override display mode 1304 if (display_mode == 3) flags |= ImGuiColorEditFlags_DisplayHSV; 1305 if (display_mode == 4) flags |= ImGuiColorEditFlags_DisplayHex; 1306 ImGui::ColorPicker4("MyColor##4", (float*)&color, flags, ref_color ? &ref_color_v.x : NULL); 1307 1308 ImGui::Text("Programmatically set defaults:"); 1309 ImGui::SameLine(); HelpMarker("SetColorEditOptions() is designed to allow you to set boot-time default.\nWe don't have Push/Pop functions because you can force options on a per-widget basis if needed, and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid encouraging you to persistently save values that aren't forward-compatible."); 1310 if (ImGui::Button("Default: Uint8 + HSV + Hue Bar")) 1311 ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_PickerHueBar); 1312 if (ImGui::Button("Default: Float + HDR + Hue Wheel")) 1313 ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel); 1314 1315 // HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0) 1316 static ImVec4 color_stored_as_hsv(0.23f, 1.0f, 1.0f, 1.0f); 1317 ImGui::Spacing(); 1318 ImGui::Text("HSV encoded colors"); 1319 ImGui::SameLine(); HelpMarker("By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV. This comes with the added benefit that you can manipulate hue values with the picker even when saturation or value are zero."); 1320 ImGui::Text("Color widget with InputHSV:"); 1321 ImGui::ColorEdit4("HSV shown as RGB##1", (float*)&color_stored_as_hsv, ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float); 1322 ImGui::ColorEdit4("HSV shown as HSV##1", (float*)&color_stored_as_hsv, ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float); 1323 ImGui::DragFloat4("Raw HSV values", (float*)&color_stored_as_hsv, 0.01f, 0.0f, 1.0f); 1324 1325 ImGui::TreePop(); 1326 } 1327 1328 if (ImGui::TreeNode("Range Widgets")) 1329 { 1330 static float begin = 10, end = 90; 1331 static int begin_i = 100, end_i = 1000; 1332 ImGui::DragFloatRange2("range", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%"); 1333 ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %d units", "Max: %d units"); 1334 ImGui::TreePop(); 1335 } 1336 1337 if (ImGui::TreeNode("Data Types")) 1338 { 1339 // The DragScalar/InputScalar/SliderScalar functions allow various data types: signed/unsigned int/long long and float/double 1340 // To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum to pass the type, 1341 // and passing all arguments by address. 1342 // This is the reason the test code below creates local variables to hold "zero" "one" etc. for each types. 1343 // In practice, if you frequently use a given type that is not covered by the normal API entry points, you can wrap it 1344 // yourself inside a 1 line function which can take typed argument as value instead of void*, and then pass their address 1345 // to the generic function. For example: 1346 // bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld") 1347 // { 1348 // return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format); 1349 // } 1350 1351 // Limits (as helper variables that we can take the address of) 1352 // Note that the SliderScalar function has a maximum usable range of half the natural type maximum, hence the /2 below. 1353 #ifndef LLONG_MIN 1354 ImS64 LLONG_MIN = -9223372036854775807LL - 1; 1355 ImS64 LLONG_MAX = 9223372036854775807LL; 1356 ImU64 ULLONG_MAX = (2ULL * 9223372036854775807LL + 1); 1357 #endif 1358 const char s8_zero = 0, s8_one = 1, s8_fifty = 50, s8_min = -128, s8_max = 127; 1359 const ImU8 u8_zero = 0, u8_one = 1, u8_fifty = 50, u8_min = 0, u8_max = 255; 1360 const short s16_zero = 0, s16_one = 1, s16_fifty = 50, s16_min = -32768, s16_max = 32767; 1361 const ImU16 u16_zero = 0, u16_one = 1, u16_fifty = 50, u16_min = 0, u16_max = 65535; 1362 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; 1363 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; 1364 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; 1365 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; 1366 const float f32_zero = 0.f, f32_one = 1.f, f32_lo_a = -10000000000.0f, f32_hi_a = +10000000000.0f; 1367 const double f64_zero = 0., f64_one = 1., f64_lo_a = -1000000000000000.0, f64_hi_a = +1000000000000000.0; 1368 1369 // State 1370 static char s8_v = 127; 1371 static ImU8 u8_v = 255; 1372 static short s16_v = 32767; 1373 static ImU16 u16_v = 65535; 1374 static ImS32 s32_v = -1; 1375 static ImU32 u32_v = (ImU32)-1; 1376 static ImS64 s64_v = -1; 1377 static ImU64 u64_v = (ImU64)-1; 1378 static float f32_v = 0.123f; 1379 static double f64_v = 90000.01234567890123456789; 1380 1381 const float drag_speed = 0.2f; 1382 static bool drag_clamp = false; 1383 ImGui::Text("Drags:"); 1384 ImGui::Checkbox("Clamp integers to 0..50", &drag_clamp); ImGui::SameLine(); HelpMarker("As with every widgets in dear imgui, we never modify values unless there is a user interaction.\nYou can override the clamping limits by using CTRL+Click to input a value."); 1385 ImGui::DragScalar("drag s8", ImGuiDataType_S8, &s8_v, drag_speed, drag_clamp ? &s8_zero : NULL, drag_clamp ? &s8_fifty : NULL); 1386 ImGui::DragScalar("drag u8", ImGuiDataType_U8, &u8_v, drag_speed, drag_clamp ? &u8_zero : NULL, drag_clamp ? &u8_fifty : NULL, "%u ms"); 1387 ImGui::DragScalar("drag s16", ImGuiDataType_S16, &s16_v, drag_speed, drag_clamp ? &s16_zero : NULL, drag_clamp ? &s16_fifty : NULL); 1388 ImGui::DragScalar("drag u16", ImGuiDataType_U16, &u16_v, drag_speed, drag_clamp ? &u16_zero : NULL, drag_clamp ? &u16_fifty : NULL, "%u ms"); 1389 ImGui::DragScalar("drag s32", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL); 1390 ImGui::DragScalar("drag u32", ImGuiDataType_U32, &u32_v, drag_speed, drag_clamp ? &u32_zero : NULL, drag_clamp ? &u32_fifty : NULL, "%u ms"); 1391 ImGui::DragScalar("drag s64", ImGuiDataType_S64, &s64_v, drag_speed, drag_clamp ? &s64_zero : NULL, drag_clamp ? &s64_fifty : NULL); 1392 ImGui::DragScalar("drag u64", ImGuiDataType_U64, &u64_v, drag_speed, drag_clamp ? &u64_zero : NULL, drag_clamp ? &u64_fifty : NULL); 1393 ImGui::DragScalar("drag float", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f", 1.0f); 1394 ImGui::DragScalar("drag float ^2", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f", 2.0f); ImGui::SameLine(); HelpMarker("You can use the 'power' parameter to increase tweaking precision on one side of the range."); 1395 ImGui::DragScalar("drag double", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, NULL, "%.10f grams", 1.0f); 1396 ImGui::DragScalar("drag double ^2", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", 2.0f); 1397 1398 ImGui::Text("Sliders"); 1399 ImGui::SliderScalar("slider s8 full", ImGuiDataType_S8, &s8_v, &s8_min, &s8_max, "%d"); 1400 ImGui::SliderScalar("slider u8 full", ImGuiDataType_U8, &u8_v, &u8_min, &u8_max, "%u"); 1401 ImGui::SliderScalar("slider s16 full", ImGuiDataType_S16, &s16_v, &s16_min, &s16_max, "%d"); 1402 ImGui::SliderScalar("slider u16 full", ImGuiDataType_U16, &u16_v, &u16_min, &u16_max, "%u"); 1403 ImGui::SliderScalar("slider s32 low", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty,"%d"); 1404 ImGui::SliderScalar("slider s32 high", ImGuiDataType_S32, &s32_v, &s32_hi_a, &s32_hi_b, "%d"); 1405 ImGui::SliderScalar("slider s32 full", ImGuiDataType_S32, &s32_v, &s32_min, &s32_max, "%d"); 1406 ImGui::SliderScalar("slider u32 low", ImGuiDataType_U32, &u32_v, &u32_zero, &u32_fifty,"%u"); 1407 ImGui::SliderScalar("slider u32 high", ImGuiDataType_U32, &u32_v, &u32_hi_a, &u32_hi_b, "%u"); 1408 ImGui::SliderScalar("slider u32 full", ImGuiDataType_U32, &u32_v, &u32_min, &u32_max, "%u"); 1409 ImGui::SliderScalar("slider s64 low", ImGuiDataType_S64, &s64_v, &s64_zero, &s64_fifty,"%I64d"); 1410 ImGui::SliderScalar("slider s64 high", ImGuiDataType_S64, &s64_v, &s64_hi_a, &s64_hi_b, "%I64d"); 1411 ImGui::SliderScalar("slider s64 full", ImGuiDataType_S64, &s64_v, &s64_min, &s64_max, "%I64d"); 1412 ImGui::SliderScalar("slider u64 low", ImGuiDataType_U64, &u64_v, &u64_zero, &u64_fifty,"%I64u ms"); 1413 ImGui::SliderScalar("slider u64 high", ImGuiDataType_U64, &u64_v, &u64_hi_a, &u64_hi_b, "%I64u ms"); 1414 ImGui::SliderScalar("slider u64 full", ImGuiDataType_U64, &u64_v, &u64_min, &u64_max, "%I64u ms"); 1415 ImGui::SliderScalar("slider float low", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one); 1416 ImGui::SliderScalar("slider float low^2", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one, "%.10f", 2.0f); 1417 ImGui::SliderScalar("slider float high", ImGuiDataType_Float, &f32_v, &f32_lo_a, &f32_hi_a, "%e"); 1418 ImGui::SliderScalar("slider double low", ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f grams", 1.0f); 1419 ImGui::SliderScalar("slider double low^2",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f", 2.0f); 1420 ImGui::SliderScalar("slider double high", ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams", 1.0f); 1421 1422 static bool inputs_step = true; 1423 ImGui::Text("Inputs"); 1424 ImGui::Checkbox("Show step buttons", &inputs_step); 1425 ImGui::InputScalar("input s8", ImGuiDataType_S8, &s8_v, inputs_step ? &s8_one : NULL, NULL, "%d"); 1426 ImGui::InputScalar("input u8", ImGuiDataType_U8, &u8_v, inputs_step ? &u8_one : NULL, NULL, "%u"); 1427 ImGui::InputScalar("input s16", ImGuiDataType_S16, &s16_v, inputs_step ? &s16_one : NULL, NULL, "%d"); 1428 ImGui::InputScalar("input u16", ImGuiDataType_U16, &u16_v, inputs_step ? &u16_one : NULL, NULL, "%u"); 1429 ImGui::InputScalar("input s32", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%d"); 1430 ImGui::InputScalar("input s32 hex", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%08X", ImGuiInputTextFlags_CharsHexadecimal); 1431 ImGui::InputScalar("input u32", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%u"); 1432 ImGui::InputScalar("input u32 hex", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%08X", ImGuiInputTextFlags_CharsHexadecimal); 1433 ImGui::InputScalar("input s64", ImGuiDataType_S64, &s64_v, inputs_step ? &s64_one : NULL); 1434 ImGui::InputScalar("input u64", ImGuiDataType_U64, &u64_v, inputs_step ? &u64_one : NULL); 1435 ImGui::InputScalar("input float", ImGuiDataType_Float, &f32_v, inputs_step ? &f32_one : NULL); 1436 ImGui::InputScalar("input double", ImGuiDataType_Double, &f64_v, inputs_step ? &f64_one : NULL); 1437 1438 ImGui::TreePop(); 1439 } 1440 1441 if (ImGui::TreeNode("Multi-component Widgets")) 1442 { 1443 static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; 1444 static int vec4i[4] = { 1, 5, 100, 255 }; 1445 1446 ImGui::InputFloat2("input float2", vec4f); 1447 ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f); 1448 ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f); 1449 ImGui::InputInt2("input int2", vec4i); 1450 ImGui::DragInt2("drag int2", vec4i, 1, 0, 255); 1451 ImGui::SliderInt2("slider int2", vec4i, 0, 255); 1452 ImGui::Spacing(); 1453 1454 ImGui::InputFloat3("input float3", vec4f); 1455 ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f); 1456 ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f); 1457 ImGui::InputInt3("input int3", vec4i); 1458 ImGui::DragInt3("drag int3", vec4i, 1, 0, 255); 1459 ImGui::SliderInt3("slider int3", vec4i, 0, 255); 1460 ImGui::Spacing(); 1461 1462 ImGui::InputFloat4("input float4", vec4f); 1463 ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f); 1464 ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f); 1465 ImGui::InputInt4("input int4", vec4i); 1466 ImGui::DragInt4("drag int4", vec4i, 1, 0, 255); 1467 ImGui::SliderInt4("slider int4", vec4i, 0, 255); 1468 1469 ImGui::TreePop(); 1470 } 1471 1472 if (ImGui::TreeNode("Vertical Sliders")) 1473 { 1474 const float spacing = 4; 1475 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing)); 1476 1477 static int int_value = 0; 1478 ImGui::VSliderInt("##int", ImVec2(18,160), &int_value, 0, 5); 1479 ImGui::SameLine(); 1480 1481 static float values[7] = { 0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f }; 1482 ImGui::PushID("set1"); 1483 for (int i = 0; i < 7; i++) 1484 { 1485 if (i > 0) ImGui::SameLine(); 1486 ImGui::PushID(i); 1487 ImGui::PushStyleColor(ImGuiCol_FrameBg, (ImVec4)ImColor::HSV(i/7.0f, 0.5f, 0.5f)); 1488 ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, (ImVec4)ImColor::HSV(i/7.0f, 0.6f, 0.5f)); 1489 ImGui::PushStyleColor(ImGuiCol_FrameBgActive, (ImVec4)ImColor::HSV(i/7.0f, 0.7f, 0.5f)); 1490 ImGui::PushStyleColor(ImGuiCol_SliderGrab, (ImVec4)ImColor::HSV(i/7.0f, 0.9f, 0.9f)); 1491 ImGui::VSliderFloat("##v", ImVec2(18,160), &values[i], 0.0f, 1.0f, ""); 1492 if (ImGui::IsItemActive() || ImGui::IsItemHovered()) 1493 ImGui::SetTooltip("%.3f", values[i]); 1494 ImGui::PopStyleColor(4); 1495 ImGui::PopID(); 1496 } 1497 ImGui::PopID(); 1498 1499 ImGui::SameLine(); 1500 ImGui::PushID("set2"); 1501 static float values2[4] = { 0.20f, 0.80f, 0.40f, 0.25f }; 1502 const int rows = 3; 1503 const ImVec2 small_slider_size(18, (float)(int)((160.0f - (rows - 1) * spacing) / rows)); 1504 for (int nx = 0; nx < 4; nx++) 1505 { 1506 if (nx > 0) ImGui::SameLine(); 1507 ImGui::BeginGroup(); 1508 for (int ny = 0; ny < rows; ny++) 1509 { 1510 ImGui::PushID(nx*rows+ny); 1511 ImGui::VSliderFloat("##v", small_slider_size, &values2[nx], 0.0f, 1.0f, ""); 1512 if (ImGui::IsItemActive() || ImGui::IsItemHovered()) 1513 ImGui::SetTooltip("%.3f", values2[nx]); 1514 ImGui::PopID(); 1515 } 1516 ImGui::EndGroup(); 1517 } 1518 ImGui::PopID(); 1519 1520 ImGui::SameLine(); 1521 ImGui::PushID("set3"); 1522 for (int i = 0; i < 4; i++) 1523 { 1524 if (i > 0) ImGui::SameLine(); 1525 ImGui::PushID(i); 1526 ImGui::PushStyleVar(ImGuiStyleVar_GrabMinSize, 40); 1527 ImGui::VSliderFloat("##v", ImVec2(40,160), &values[i], 0.0f, 1.0f, "%.2f\nsec"); 1528 ImGui::PopStyleVar(); 1529 ImGui::PopID(); 1530 } 1531 ImGui::PopID(); 1532 ImGui::PopStyleVar(); 1533 ImGui::TreePop(); 1534 } 1535 1536 if (ImGui::TreeNode("Drag and Drop")) 1537 { 1538 if (ImGui::TreeNode("Drag and drop in standard widgets")) 1539 { 1540 // ColorEdit widgets automatically act as drag source and drag target. 1541 // They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F to allow your own widgets 1542 // to use colors in their drag and drop interaction. Also see the demo in Color Picker -> Palette demo. 1543 HelpMarker("You can drag from the colored squares."); 1544 static float col1[3] = { 1.0f, 0.0f, 0.2f }; 1545 static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f }; 1546 ImGui::ColorEdit3("color 1", col1); 1547 ImGui::ColorEdit4("color 2", col2); 1548 ImGui::TreePop(); 1549 } 1550 1551 if (ImGui::TreeNode("Drag and drop to copy/swap items")) 1552 { 1553 enum Mode 1554 { 1555 Mode_Copy, 1556 Mode_Move, 1557 Mode_Swap 1558 }; 1559 static int mode = 0; 1560 if (ImGui::RadioButton("Copy", mode == Mode_Copy)) { mode = Mode_Copy; } ImGui::SameLine(); 1561 if (ImGui::RadioButton("Move", mode == Mode_Move)) { mode = Mode_Move; } ImGui::SameLine(); 1562 if (ImGui::RadioButton("Swap", mode == Mode_Swap)) { mode = Mode_Swap; } 1563 static const char* names[9] = { "Bobby", "Beatrice", "Betty", "Brianna", "Barry", "Bernard", "Bibi", "Blaine", "Bryn" }; 1564 for (int n = 0; n < IM_ARRAYSIZE(names); n++) 1565 { 1566 ImGui::PushID(n); 1567 if ((n % 3) != 0) 1568 ImGui::SameLine(); 1569 ImGui::Button(names[n], ImVec2(60,60)); 1570 1571 // Our buttons are both drag sources and drag targets here! 1572 if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) 1573 { 1574 ImGui::SetDragDropPayload("DND_DEMO_CELL", &n, sizeof(int)); // Set payload to carry the index of our item (could be anything) 1575 if (mode == Mode_Copy) { ImGui::Text("Copy %s", names[n]); } // Display preview (could be anything, e.g. when dragging an image we could decide to display the filename and a small preview of the image, etc.) 1576 if (mode == Mode_Move) { ImGui::Text("Move %s", names[n]); } 1577 if (mode == Mode_Swap) { ImGui::Text("Swap %s", names[n]); } 1578 ImGui::EndDragDropSource(); 1579 } 1580 if (ImGui::BeginDragDropTarget()) 1581 { 1582 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DND_DEMO_CELL")) 1583 { 1584 IM_ASSERT(payload->DataSize == sizeof(int)); 1585 int payload_n = *(const int*)payload->Data; 1586 if (mode == Mode_Copy) 1587 { 1588 names[n] = names[payload_n]; 1589 } 1590 if (mode == Mode_Move) 1591 { 1592 names[n] = names[payload_n]; 1593 names[payload_n] = ""; 1594 } 1595 if (mode == Mode_Swap) 1596 { 1597 const char* tmp = names[n]; 1598 names[n] = names[payload_n]; 1599 names[payload_n] = tmp; 1600 } 1601 } 1602 ImGui::EndDragDropTarget(); 1603 } 1604 ImGui::PopID(); 1605 } 1606 ImGui::TreePop(); 1607 } 1608 1609 if (ImGui::TreeNode("Drag to reorder items (simple)")) 1610 { 1611 // Simple reordering 1612 HelpMarker("We don't use the drag and drop api at all here! Instead we query when the item is held but not hovered, and order items accordingly."); 1613 static const char* item_names[] = { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" }; 1614 for (int n = 0; n < IM_ARRAYSIZE(item_names); n++) 1615 { 1616 const char* item = item_names[n]; 1617 ImGui::Selectable(item); 1618 1619 if (ImGui::IsItemActive() && !ImGui::IsItemHovered()) 1620 { 1621 int n_next = n + (ImGui::GetMouseDragDelta(0).y < 0.f ? -1 : 1); 1622 if (n_next >= 0 && n_next < IM_ARRAYSIZE(item_names)) 1623 { 1624 item_names[n] = item_names[n_next]; 1625 item_names[n_next] = item; 1626 ImGui::ResetMouseDragDelta(); 1627 } 1628 } 1629 } 1630 ImGui::TreePop(); 1631 } 1632 1633 ImGui::TreePop(); 1634 } 1635 1636 if (ImGui::TreeNode("Querying Status (Active/Focused/Hovered etc.)")) 1637 { 1638 // Submit an item (various types available) so we can query their status in the following block. 1639 static int item_type = 1; 1640 ImGui::Combo("Item Type", &item_type, "Text\0Button\0Button (w/ repeat)\0Checkbox\0SliderFloat\0InputText\0InputFloat\0InputFloat3\0ColorEdit4\0MenuItem\0TreeNode\0TreeNode (w/ double-click)\0ListBox\0", 20); 1641 ImGui::SameLine(); 1642 HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions."); 1643 bool ret = false; 1644 static bool b = false; 1645 static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f }; 1646 static char str[16] = {}; 1647 if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction 1648 if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); } // Testing button 1649 if (item_type == 2) { ImGui::PushButtonRepeat(true); ret = ImGui::Button("ITEM: Button"); ImGui::PopButtonRepeat(); } // Testing button (with repeater) 1650 if (item_type == 3) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); } // Testing checkbox 1651 if (item_type == 4) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item 1652 if (item_type == 5) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which handles tabbing) 1653 if (item_type == 6) { ret = ImGui::InputFloat("ITEM: InputFloat", col4f, 1.0f); } // Testing +/- buttons on scalar input 1654 if (item_type == 7) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) 1655 if (item_type == 8) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) 1656 if (item_type == 9) { ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy) 1657 if (item_type == 10){ ret = ImGui::TreeNode("ITEM: TreeNode"); if (ret) ImGui::TreePop(); } // Testing tree node 1658 if (item_type == 11){ ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy. 1659 if (item_type == 12){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", ¤t, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); } 1660 1661 // Display the value of IsItemHovered() and other common item state functions. 1662 // Note that the ImGuiHoveredFlags_XXX flags can be combined. 1663 // Because BulletText is an item itself and that would affect the output of IsItemXXX functions, 1664 // we query every state in a single call to avoid storing them and to simplify the code 1665 ImGui::BulletText( 1666 "Return value = %d\n" 1667 "IsItemFocused() = %d\n" 1668 "IsItemHovered() = %d\n" 1669 "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n" 1670 "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n" 1671 "IsItemHovered(_AllowWhenOverlapped) = %d\n" 1672 "IsItemHovered(_RectOnly) = %d\n" 1673 "IsItemActive() = %d\n" 1674 "IsItemEdited() = %d\n" 1675 "IsItemActivated() = %d\n" 1676 "IsItemDeactivated() = %d\n" 1677 "IsItemDeactivatedAfterEdit() = %d\n" 1678 "IsItemVisible() = %d\n" 1679 "IsItemClicked() = %d\n" 1680 "IsItemToggledOpen() = %d\n" 1681 "GetItemRectMin() = (%.1f, %.1f)\n" 1682 "GetItemRectMax() = (%.1f, %.1f)\n" 1683 "GetItemRectSize() = (%.1f, %.1f)", 1684 ret, 1685 ImGui::IsItemFocused(), 1686 ImGui::IsItemHovered(), 1687 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), 1688 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), 1689 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlapped), 1690 ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly), 1691 ImGui::IsItemActive(), 1692 ImGui::IsItemEdited(), 1693 ImGui::IsItemActivated(), 1694 ImGui::IsItemDeactivated(), 1695 ImGui::IsItemDeactivatedAfterEdit(), 1696 ImGui::IsItemVisible(), 1697 ImGui::IsItemClicked(), 1698 ImGui::IsItemToggledOpen(), 1699 ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y, 1700 ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y, 1701 ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y 1702 ); 1703 1704 static bool embed_all_inside_a_child_window = false; 1705 ImGui::Checkbox("Embed everything inside a child window (for additional testing)", &embed_all_inside_a_child_window); 1706 if (embed_all_inside_a_child_window) 1707 ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20), true); 1708 1709 // Testing IsWindowFocused() function with its various flags. 1710 // Note that the ImGuiFocusedFlags_XXX flags can be combined. 1711 ImGui::BulletText( 1712 "IsWindowFocused() = %d\n" 1713 "IsWindowFocused(_ChildWindows) = %d\n" 1714 "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n" 1715 "IsWindowFocused(_RootWindow) = %d\n" 1716 "IsWindowFocused(_AnyWindow) = %d\n", 1717 ImGui::IsWindowFocused(), 1718 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows), 1719 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow), 1720 ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow), 1721 ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow)); 1722 1723 // Testing IsWindowHovered() function with its various flags. 1724 // Note that the ImGuiHoveredFlags_XXX flags can be combined. 1725 ImGui::BulletText( 1726 "IsWindowHovered() = %d\n" 1727 "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n" 1728 "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n" 1729 "IsWindowHovered(_ChildWindows) = %d\n" 1730 "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n" 1731 "IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n" 1732 "IsWindowHovered(_RootWindow) = %d\n" 1733 "IsWindowHovered(_AnyWindow) = %d\n", 1734 ImGui::IsWindowHovered(), 1735 ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), 1736 ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), 1737 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows), 1738 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow), 1739 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup), 1740 ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow), 1741 ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)); 1742 1743 ImGui::BeginChild("child", ImVec2(0, 50), true); 1744 ImGui::Text("This is another child window for testing the _ChildWindows flag."); 1745 ImGui::EndChild(); 1746 if (embed_all_inside_a_child_window) 1747 ImGui::EndChild(); 1748 1749 static char dummy_str[] = "This is a dummy field to be able to tab-out of the widgets above."; 1750 ImGui::InputText("dummy", dummy_str, IM_ARRAYSIZE(dummy_str), ImGuiInputTextFlags_ReadOnly); 1751 1752 // Calling IsItemHovered() after begin returns the hovered status of the title bar. 1753 // This is useful in particular if you want to create a context menu (with BeginPopupContextItem) associated to the title bar of a window. 1754 static bool test_window = false; 1755 ImGui::Checkbox("Hovered/Active tests after Begin() for title bar testing", &test_window); 1756 if (test_window) 1757 { 1758 ImGui::Begin("Title bar Hovered/Active tests", &test_window); 1759 if (ImGui::BeginPopupContextItem()) // <-- This is using IsItemHovered() 1760 { 1761 if (ImGui::MenuItem("Close")) { test_window = false; } 1762 ImGui::EndPopup(); 1763 } 1764 ImGui::Text( 1765 "IsItemHovered() after begin = %d (== is title bar hovered)\n" 1766 "IsItemActive() after begin = %d (== is window being clicked/moved)\n", 1767 ImGui::IsItemHovered(), ImGui::IsItemActive()); 1768 ImGui::End(); 1769 } 1770 1771 ImGui::TreePop(); 1772 } 1773} 1774 1775static void ShowDemoWindowLayout() 1776{ 1777 if (!ImGui::CollapsingHeader("Layout")) 1778 return; 1779 1780 if (ImGui::TreeNode("Child windows")) 1781 { 1782 HelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window."); 1783 static bool disable_mouse_wheel = false; 1784 static bool disable_menu = false; 1785 ImGui::Checkbox("Disable Mouse Wheel", &disable_mouse_wheel); 1786 ImGui::Checkbox("Disable Menu", &disable_menu); 1787 1788 static int line = 50; 1789 bool goto_line = ImGui::Button("Goto"); 1790 ImGui::SameLine(); 1791 ImGui::SetNextItemWidth(100); 1792 goto_line |= ImGui::InputInt("##Line", &line, 0, 0, ImGuiInputTextFlags_EnterReturnsTrue); 1793 1794 // Child 1: no border, enable horizontal scrollbar 1795 { 1796 ImGuiWindowFlags window_flags = ImGuiWindowFlags_HorizontalScrollbar | (disable_mouse_wheel ? ImGuiWindowFlags_NoScrollWithMouse : 0); 1797 ImGui::BeginChild("ChildL", ImVec2(ImGui::GetWindowContentRegionWidth() * 0.5f, 260), false, window_flags); 1798 for (int i = 0; i < 100; i++) 1799 { 1800 ImGui::Text("%04d: scrollable region", i); 1801 if (goto_line && line == i) 1802 ImGui::SetScrollHereY(); 1803 } 1804 if (goto_line && line >= 100) 1805 ImGui::SetScrollHereY(); 1806 ImGui::EndChild(); 1807 } 1808 1809 ImGui::SameLine(); 1810 1811 // Child 2: rounded border 1812 { 1813 ImGuiWindowFlags window_flags = (disable_mouse_wheel ? ImGuiWindowFlags_NoScrollWithMouse : 0) | (disable_menu ? 0 : ImGuiWindowFlags_MenuBar); 1814 ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f); 1815 ImGui::BeginChild("ChildR", ImVec2(0, 260), true, window_flags); 1816 if (!disable_menu && ImGui::BeginMenuBar()) 1817 { 1818 if (ImGui::BeginMenu("Menu")) 1819 { 1820 ShowExampleMenuFile(); 1821 ImGui::EndMenu(); 1822 } 1823 ImGui::EndMenuBar(); 1824 } 1825 ImGui::Columns(2); 1826 for (int i = 0; i < 100; i++) 1827 { 1828 char buf[32]; 1829 sprintf(buf, "%03d", i); 1830 ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f)); 1831 ImGui::NextColumn(); 1832 } 1833 ImGui::EndChild(); 1834 ImGui::PopStyleVar(); 1835 } 1836 1837 ImGui::Separator(); 1838 1839 // Demonstrate a few extra things 1840 // - Changing ImGuiCol_ChildBg (which is transparent black in default styles) 1841 // - Using SetCursorPos() to position the child window (because the child window is an item from the POV of the parent window) 1842 // You can also call SetNextWindowPos() to position the child window. The parent window will effectively layout from this position. 1843 // - Using ImGui::GetItemRectMin/Max() to query the "item" state (because the child window is an item from the POV of the parent window) 1844 // See "Widgets" -> "Querying Status (Active/Focused/Hovered etc.)" section for more details about this. 1845 { 1846 ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 10); 1847 ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(255, 0, 0, 100)); 1848 ImGui::BeginChild("Red", ImVec2(200, 100), true, ImGuiWindowFlags_None); 1849 for (int n = 0; n < 50; n++) 1850 ImGui::Text("Some test %d", n); 1851 ImGui::EndChild(); 1852 ImVec2 child_rect_min = ImGui::GetItemRectMin(); 1853 ImVec2 child_rect_max = ImGui::GetItemRectMax(); 1854 ImGui::PopStyleColor(); 1855 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); 1856 } 1857 1858 ImGui::TreePop(); 1859 } 1860 1861 if (ImGui::TreeNode("Widgets Width")) 1862 { 1863 // Use SetNextItemWidth() to set the width of a single upcoming item. 1864 // Use PushItemWidth()/PopItemWidth() to set the width of a group of items. 1865 static float f = 0.0f; 1866 ImGui::Text("SetNextItemWidth/PushItemWidth(100)"); 1867 ImGui::SameLine(); HelpMarker("Fixed width."); 1868 ImGui::SetNextItemWidth(100); 1869 ImGui::DragFloat("float##1", &f); 1870 1871 ImGui::Text("SetNextItemWidth/PushItemWidth(GetWindowWidth() * 0.5f)"); 1872 ImGui::SameLine(); HelpMarker("Half of window width."); 1873 ImGui::SetNextItemWidth(ImGui::GetWindowWidth() * 0.5f); 1874 ImGui::DragFloat("float##2", &f); 1875 1876 ImGui::Text("SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)"); 1877 ImGui::SameLine(); HelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)"); 1878 ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x * 0.5f); 1879 ImGui::DragFloat("float##3", &f); 1880 1881 ImGui::Text("SetNextItemWidth/PushItemWidth(-100)"); 1882 ImGui::SameLine(); HelpMarker("Align to right edge minus 100"); 1883 ImGui::SetNextItemWidth(-100); 1884 ImGui::DragFloat("float##4", &f); 1885 1886 // Demonstrate using PushItemWidth to surround three items. Calling SetNextItemWidth() before each of them would have the same effect. 1887 ImGui::Text("SetNextItemWidth/PushItemWidth(-1)"); 1888 ImGui::SameLine(); HelpMarker("Align to right edge"); 1889 ImGui::PushItemWidth(-1); 1890 ImGui::DragFloat("##float5a", &f); 1891 ImGui::DragFloat("##float5b", &f); 1892 ImGui::DragFloat("##float5c", &f); 1893 ImGui::PopItemWidth(); 1894 1895 ImGui::TreePop(); 1896 } 1897 1898 if (ImGui::TreeNode("Basic Horizontal Layout")) 1899 { 1900 ImGui::TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)"); 1901 1902 // Text 1903 ImGui::Text("Two items: Hello"); ImGui::SameLine(); 1904 ImGui::TextColored(ImVec4(1,1,0,1), "Sailor"); 1905 1906 // Adjust spacing 1907 ImGui::Text("More spacing: Hello"); ImGui::SameLine(0, 20); 1908 ImGui::TextColored(ImVec4(1,1,0,1), "Sailor"); 1909 1910 // Button 1911 ImGui::AlignTextToFramePadding(); 1912 ImGui::Text("Normal buttons"); ImGui::SameLine(); 1913 ImGui::Button("Banana"); ImGui::SameLine(); 1914 ImGui::Button("Apple"); ImGui::SameLine(); 1915 ImGui::Button("Corniflower"); 1916 1917 // Button 1918 ImGui::Text("Small buttons"); ImGui::SameLine(); 1919 ImGui::SmallButton("Like this one"); ImGui::SameLine(); 1920 ImGui::Text("can fit within a text block."); 1921 1922 // Aligned to arbitrary position. Easy/cheap column. 1923 ImGui::Text("Aligned"); 1924 ImGui::SameLine(150); ImGui::Text("x=150"); 1925 ImGui::SameLine(300); ImGui::Text("x=300"); 1926 ImGui::Text("Aligned"); 1927 ImGui::SameLine(150); ImGui::SmallButton("x=150"); 1928 ImGui::SameLine(300); ImGui::SmallButton("x=300"); 1929 1930 // Checkbox 1931 static bool c1 = false, c2 = false, c3 = false, c4 = false; 1932 ImGui::Checkbox("My", &c1); ImGui::SameLine(); 1933 ImGui::Checkbox("Tailor", &c2); ImGui::SameLine(); 1934 ImGui::Checkbox("Is", &c3); ImGui::SameLine(); 1935 ImGui::Checkbox("Rich", &c4); 1936 1937 // Various 1938 static float f0 = 1.0f, f1 = 2.0f, f2 = 3.0f; 1939 ImGui::PushItemWidth(80); 1940 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD" }; 1941 static int item = -1; 1942 ImGui::Combo("Combo", &item, items, IM_ARRAYSIZE(items)); ImGui::SameLine(); 1943 ImGui::SliderFloat("X", &f0, 0.0f, 5.0f); ImGui::SameLine(); 1944 ImGui::SliderFloat("Y", &f1, 0.0f, 5.0f); ImGui::SameLine(); 1945 ImGui::SliderFloat("Z", &f2, 0.0f, 5.0f); 1946 ImGui::PopItemWidth(); 1947 1948 ImGui::PushItemWidth(80); 1949 ImGui::Text("Lists:"); 1950 static int selection[4] = { 0, 1, 2, 3 }; 1951 for (int i = 0; i < 4; i++) 1952 { 1953 if (i > 0) ImGui::SameLine(); 1954 ImGui::PushID(i); 1955 ImGui::ListBox("", &selection[i], items, IM_ARRAYSIZE(items)); 1956 ImGui::PopID(); 1957 //if (ImGui::IsItemHovered()) ImGui::SetTooltip("ListBox %d hovered", i); 1958 } 1959 ImGui::PopItemWidth(); 1960 1961 // Dummy 1962 ImVec2 button_sz(40, 40); 1963 ImGui::Button("A", button_sz); ImGui::SameLine(); 1964 ImGui::Dummy(button_sz); ImGui::SameLine(); 1965 ImGui::Button("B", button_sz); 1966 1967 // Manually wrapping (we should eventually provide this as an automatic layout feature, but for now you can do it manually) 1968 ImGui::Text("Manually wrapping:"); 1969 ImGuiStyle& style = ImGui::GetStyle(); 1970 int buttons_count = 20; 1971 float window_visible_x2 = ImGui::GetWindowPos().x + ImGui::GetWindowContentRegionMax().x; 1972 for (int n = 0; n < buttons_count; n++) 1973 { 1974 ImGui::PushID(n); 1975 ImGui::Button("Box", button_sz); 1976 float last_button_x2 = ImGui::GetItemRectMax().x; 1977 float next_button_x2 = last_button_x2 + style.ItemSpacing.x + button_sz.x; // Expected position if next button was on same line 1978 if (n + 1 < buttons_count && next_button_x2 < window_visible_x2) 1979 ImGui::SameLine(); 1980 ImGui::PopID(); 1981 } 1982 1983 ImGui::TreePop(); 1984 } 1985 1986 if (ImGui::TreeNode("Tabs")) 1987 { 1988 if (ImGui::TreeNode("Basic")) 1989 { 1990 ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None; 1991 if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) 1992 { 1993 if (ImGui::BeginTabItem("Avocado")) 1994 { 1995 ImGui::Text("This is the Avocado tab!\nblah blah blah blah blah"); 1996 ImGui::EndTabItem(); 1997 } 1998 if (ImGui::BeginTabItem("Broccoli")) 1999 { 2000 ImGui::Text("This is the Broccoli tab!\nblah blah blah blah blah"); 2001 ImGui::EndTabItem(); 2002 } 2003 if (ImGui::BeginTabItem("Cucumber")) 2004 { 2005 ImGui::Text("This is the Cucumber tab!\nblah blah blah blah blah"); 2006 ImGui::EndTabItem(); 2007 } 2008 ImGui::EndTabBar(); 2009 } 2010 ImGui::Separator(); 2011 ImGui::TreePop(); 2012 } 2013 2014 if (ImGui::TreeNode("Advanced & Close Button")) 2015 { 2016 // Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0). 2017 static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable; 2018 ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_Reorderable); 2019 ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs); 2020 ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton); 2021 ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton); 2022 if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0) 2023 tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_; 2024 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown)) 2025 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown); 2026 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll)) 2027 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll); 2028 2029 // Tab Bar 2030 const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" }; 2031 static bool opened[4] = { true, true, true, true }; // Persistent user state 2032 for (int n = 0; n < IM_ARRAYSIZE(opened); n++) 2033 { 2034 if (n > 0) { ImGui::SameLine(); } 2035 ImGui::Checkbox(names[n], &opened[n]); 2036 } 2037 2038 // Passing a bool* to BeginTabItem() is similar to passing one to Begin(): the underlying bool will be set to false when the tab is closed. 2039 if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) 2040 { 2041 for (int n = 0; n < IM_ARRAYSIZE(opened); n++) 2042 if (opened[n] && ImGui::BeginTabItem(names[n], &opened[n], ImGuiTabItemFlags_None)) 2043 { 2044 ImGui::Text("This is the %s tab!", names[n]); 2045 if (n & 1) 2046 ImGui::Text("I am an odd tab."); 2047 ImGui::EndTabItem(); 2048 } 2049 ImGui::EndTabBar(); 2050 } 2051 ImGui::Separator(); 2052 ImGui::TreePop(); 2053 } 2054 ImGui::TreePop(); 2055 } 2056 2057 if (ImGui::TreeNode("Groups")) 2058 { 2059 HelpMarker("BeginGroup() basically locks the horizontal position for new line. EndGroup() bundles the whole group so that you can use \"item\" functions such as IsItemHovered()/IsItemActive() or SameLine() etc. on the whole group."); 2060 ImGui::BeginGroup(); 2061 { 2062 ImGui::BeginGroup(); 2063 ImGui::Button("AAA"); 2064 ImGui::SameLine(); 2065 ImGui::Button("BBB"); 2066 ImGui::SameLine(); 2067 ImGui::BeginGroup(); 2068 ImGui::Button("CCC"); 2069 ImGui::Button("DDD"); 2070 ImGui::EndGroup(); 2071 ImGui::SameLine(); 2072 ImGui::Button("EEE"); 2073 ImGui::EndGroup(); 2074 if (ImGui::IsItemHovered()) 2075 ImGui::SetTooltip("First group hovered"); 2076 } 2077 // Capture the group size and create widgets using the same size 2078 ImVec2 size = ImGui::GetItemRectSize(); 2079 const float values[5] = { 0.5f, 0.20f, 0.80f, 0.60f, 0.25f }; 2080 ImGui::PlotHistogram("##values", values, IM_ARRAYSIZE(values), 0, NULL, 0.0f, 1.0f, size); 2081 2082 ImGui::Button("ACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x)*0.5f, size.y)); 2083 ImGui::SameLine(); 2084 ImGui::Button("REACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x)*0.5f, size.y)); 2085 ImGui::EndGroup(); 2086 ImGui::SameLine(); 2087 2088 ImGui::Button("LEVERAGE\nBUZZWORD", size); 2089 ImGui::SameLine(); 2090 2091 if (ImGui::ListBoxHeader("List", size)) 2092 { 2093 ImGui::Selectable("Selected", true); 2094 ImGui::Selectable("Not Selected", false); 2095 ImGui::ListBoxFooter(); 2096 } 2097 2098 ImGui::TreePop(); 2099 } 2100 2101 if (ImGui::TreeNode("Text Baseline Alignment")) 2102 { 2103 { 2104 ImGui::BulletText("Text baseline:"); 2105 ImGui::SameLine(); 2106 HelpMarker("This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. Lines only composed of text or \"small\" widgets fit in less vertical spaces than lines with normal widgets."); 2107 ImGui::Indent(); 2108 2109 ImGui::Text("KO Blahblah"); ImGui::SameLine(); 2110 ImGui::Button("Some framed item"); ImGui::SameLine(); 2111 HelpMarker("Baseline of button will look misaligned with text.."); 2112 2113 // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets. 2114 // Because we don't know what's coming after the Text() statement, we need to move the text baseline down by FramePadding.y 2115 ImGui::AlignTextToFramePadding(); 2116 ImGui::Text("OK Blahblah"); ImGui::SameLine(); 2117 ImGui::Button("Some framed item"); ImGui::SameLine(); 2118 HelpMarker("We call AlignTextToFramePadding() to vertically align the text baseline by +FramePadding.y"); 2119 2120 // SmallButton() uses the same vertical padding as Text 2121 ImGui::Button("TEST##1"); ImGui::SameLine(); 2122 ImGui::Text("TEST"); ImGui::SameLine(); 2123 ImGui::SmallButton("TEST##2"); 2124 2125 // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets. 2126 ImGui::AlignTextToFramePadding(); 2127 ImGui::Text("Text aligned to framed item"); ImGui::SameLine(); 2128 ImGui::Button("Item##1"); ImGui::SameLine(); 2129 ImGui::Text("Item"); ImGui::SameLine(); 2130 ImGui::SmallButton("Item##2"); ImGui::SameLine(); 2131 ImGui::Button("Item##3"); 2132 2133 ImGui::Unindent(); 2134 } 2135 2136 ImGui::Spacing(); 2137 2138 { 2139 ImGui::BulletText("Multi-line text:"); 2140 ImGui::Indent(); 2141 ImGui::Text("One\nTwo\nThree"); ImGui::SameLine(); 2142 ImGui::Text("Hello\nWorld"); ImGui::SameLine(); 2143 ImGui::Text("Banana"); 2144 2145 ImGui::Text("Banana"); ImGui::SameLine(); 2146 ImGui::Text("Hello\nWorld"); ImGui::SameLine(); 2147 ImGui::Text("One\nTwo\nThree"); 2148 2149 ImGui::Button("HOP##1"); ImGui::SameLine(); 2150 ImGui::Text("Banana"); ImGui::SameLine(); 2151 ImGui::Text("Hello\nWorld"); ImGui::SameLine(); 2152 ImGui::Text("Banana"); 2153 2154 ImGui::Button("HOP##2"); ImGui::SameLine(); 2155 ImGui::Text("Hello\nWorld"); ImGui::SameLine(); 2156 ImGui::Text("Banana"); 2157 ImGui::Unindent(); 2158 } 2159 2160 ImGui::Spacing(); 2161 2162 { 2163 ImGui::BulletText("Misc items:"); 2164 ImGui::Indent(); 2165 2166 // SmallButton() sets FramePadding to zero. Text baseline is aligned to match baseline of previous Button 2167 ImGui::Button("80x80", ImVec2(80, 80)); 2168 ImGui::SameLine(); 2169 ImGui::Button("50x50", ImVec2(50, 50)); 2170 ImGui::SameLine(); 2171 ImGui::Button("Button()"); 2172 ImGui::SameLine(); 2173 ImGui::SmallButton("SmallButton()"); 2174 2175 // Tree 2176 const float spacing = ImGui::GetStyle().ItemInnerSpacing.x; 2177 ImGui::Button("Button##1"); 2178 ImGui::SameLine(0.0f, spacing); 2179 if (ImGui::TreeNode("Node##1")) { for (int i = 0; i < 6; i++) ImGui::BulletText("Item %d..", i); ImGui::TreePop(); } // Dummy tree data 2180 2181 ImGui::AlignTextToFramePadding(); // Vertically align text node a bit lower so it'll be vertically centered with upcoming widget. Otherwise you can use SmallButton (smaller fit). 2182 bool node_open = ImGui::TreeNode("Node##2");// Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add child content. 2183 ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##2"); 2184 if (node_open) { for (int i = 0; i < 6; i++) ImGui::BulletText("Item %d..", i); ImGui::TreePop(); } // Dummy tree data 2185 2186 // Bullet 2187 ImGui::Button("Button##3"); 2188 ImGui::SameLine(0.0f, spacing); 2189 ImGui::BulletText("Bullet text"); 2190 2191 ImGui::AlignTextToFramePadding(); 2192 ImGui::BulletText("Node"); 2193 ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##4"); 2194 ImGui::Unindent(); 2195 } 2196 2197 ImGui::TreePop(); 2198 } 2199 2200 if (ImGui::TreeNode("Scrolling")) 2201 { 2202 // Vertical scroll functions 2203 HelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given vertical position."); 2204 2205 static int track_item = 50; 2206 static bool enable_track = true; 2207 static bool enable_extra_decorations = false; 2208 static float scroll_to_off_px = 0.0f; 2209 static float scroll_to_pos_px = 200.0f; 2210 2211 ImGui::Checkbox("Decoration", &enable_extra_decorations); 2212 ImGui::SameLine(); 2213 HelpMarker("We expose this for testing because scrolling sometimes had issues with window decoration such as menu-bars."); 2214 2215 ImGui::Checkbox("Track", &enable_track); 2216 ImGui::PushItemWidth(100); 2217 ImGui::SameLine(140); enable_track |= ImGui::DragInt("##item", &track_item, 0.25f, 0, 99, "Item = %d"); 2218 2219 bool scroll_to_off = ImGui::Button("Scroll Offset"); 2220 ImGui::SameLine(140); scroll_to_off |= ImGui::DragFloat("##off", &scroll_to_off_px, 1.00f, 0, FLT_MAX, "+%.0f px"); 2221 2222 bool scroll_to_pos = ImGui::Button("Scroll To Pos"); 2223 ImGui::SameLine(140); scroll_to_pos |= ImGui::DragFloat("##pos", &scroll_to_pos_px, 1.00f, -10, FLT_MAX, "X/Y = %.0f px"); 2224 ImGui::PopItemWidth(); 2225 2226 if (scroll_to_off || scroll_to_pos) 2227 enable_track = false; 2228 2229 ImGuiStyle& style = ImGui::GetStyle(); 2230 float child_w = (ImGui::GetContentRegionAvail().x - 4 * style.ItemSpacing.x) / 5; 2231 if (child_w < 1.0f) 2232 child_w = 1.0f; 2233 ImGui::PushID("##VerticalScrolling"); 2234 for (int i = 0; i < 5; i++) 2235 { 2236 if (i > 0) ImGui::SameLine(); 2237 ImGui::BeginGroup(); 2238 const char* names[] = { "Top", "25%", "Center", "75%", "Bottom" }; 2239 ImGui::TextUnformatted(names[i]); 2240 2241 ImGuiWindowFlags child_flags = enable_extra_decorations ? ImGuiWindowFlags_MenuBar : 0; 2242 bool window_visible = ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(child_w, 200.0f), true, child_flags); 2243 if (ImGui::BeginMenuBar()) 2244 { 2245 ImGui::TextUnformatted("abc"); 2246 ImGui::EndMenuBar(); 2247 } 2248 if (scroll_to_off) 2249 ImGui::SetScrollY(scroll_to_off_px); 2250 if (scroll_to_pos) 2251 ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_pos_px, i * 0.25f); 2252 if (window_visible) // Avoid calling SetScrollHereY when running with culled items 2253 { 2254 for (int item = 0; item < 100; item++) 2255 { 2256 if (enable_track && item == track_item) 2257 { 2258 ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item); 2259 ImGui::SetScrollHereY(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom 2260 } 2261 else 2262 { 2263 ImGui::Text("Item %d", item); 2264 } 2265 } 2266 } 2267 float scroll_y = ImGui::GetScrollY(); 2268 float scroll_max_y = ImGui::GetScrollMaxY(); 2269 ImGui::EndChild(); 2270 ImGui::Text("%.0f/%.0f", scroll_y, scroll_max_y); 2271 ImGui::EndGroup(); 2272 } 2273 ImGui::PopID(); 2274 2275 // Horizontal scroll functions 2276 ImGui::Spacing(); 2277 HelpMarker("Use SetScrollHereX() or SetScrollFromPosX() to scroll to a given horizontal position.\n\nUsing the \"Scroll To Pos\" button above will make the discontinuity at edges visible: scrolling to the top/bottom/left/right-most item will add an additional WindowPadding to reflect on reaching the edge of the list.\n\nBecause the clipping rectangle of most window hides half worth of WindowPadding on the left/right, using SetScrollFromPosX(+1) will usually result in clipped text whereas the equivalent SetScrollFromPosY(+1) wouldn't."); 2278 ImGui::PushID("##HorizontalScrolling"); 2279 for (int i = 0; i < 5; i++) 2280 { 2281 float child_height = ImGui::GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0f; 2282 ImGuiWindowFlags child_flags = ImGuiWindowFlags_HorizontalScrollbar | (enable_extra_decorations ? ImGuiWindowFlags_AlwaysVerticalScrollbar : 0); 2283 bool window_visible = ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(-100, child_height), true, child_flags); 2284 if (scroll_to_off) 2285 ImGui::SetScrollX(scroll_to_off_px); 2286 if (scroll_to_pos) 2287 ImGui::SetScrollFromPosX(ImGui::GetCursorStartPos().x + scroll_to_pos_px, i * 0.25f); 2288 if (window_visible) // Avoid calling SetScrollHereY when running with culled items 2289 { 2290 for (int item = 0; item < 100; item++) 2291 { 2292 if (enable_track && item == track_item) 2293 { 2294 ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item); 2295 ImGui::SetScrollHereX(i * 0.25f); // 0.0f:left, 0.5f:center, 1.0f:right 2296 } 2297 else 2298 { 2299 ImGui::Text("Item %d", item); 2300 } 2301 ImGui::SameLine(); 2302 } 2303 } 2304 float scroll_x = ImGui::GetScrollX(); 2305 float scroll_max_x = ImGui::GetScrollMaxX(); 2306 ImGui::EndChild(); 2307 ImGui::SameLine(); 2308 const char* names[] = { "Left", "25%", "Center", "75%", "Right" }; 2309 ImGui::Text("%s\n%.0f/%.0f", names[i], scroll_x, scroll_max_x); 2310 ImGui::Spacing(); 2311 } 2312 ImGui::PopID(); 2313 2314 // Miscellaneous Horizontal Scrolling Demo 2315 HelpMarker("Horizontal scrolling for a window has to be enabled explicitly via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\nYou may want to explicitly specify content width by calling SetNextWindowContentWidth() before Begin()."); 2316 static int lines = 7; 2317 ImGui::SliderInt("Lines", &lines, 1, 15); 2318 ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); 2319 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f)); 2320 ImGui::BeginChild("scrolling", ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30), true, ImGuiWindowFlags_HorizontalScrollbar); 2321 for (int line = 0; line < lines; line++) 2322 { 2323 // Display random stuff (for the sake of this trivial demo we are using basic Button+SameLine. If you want to create your own time line for a real application you may be better off 2324 // manipulating the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets yourself. You may also want to use the lower-level ImDrawList API) 2325 int num_buttons = 10 + ((line & 1) ? line * 9 : line * 3); 2326 for (int n = 0; n < num_buttons; n++) 2327 { 2328 if (n > 0) ImGui::SameLine(); 2329 ImGui::PushID(n + line * 1000); 2330 char num_buf[16]; 2331 sprintf(num_buf, "%d", n); 2332 const char* label = (!(n%15)) ? "FizzBuzz" : (!(n%3)) ? "Fizz" : (!(n%5)) ? "Buzz" : num_buf; 2333 float hue = n*0.05f; 2334 ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(hue, 0.6f, 0.6f)); 2335 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(hue, 0.7f, 0.7f)); 2336 ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(hue, 0.8f, 0.8f)); 2337 ImGui::Button(label, ImVec2(40.0f + sinf((float)(line + n)) * 20.0f, 0.0f)); 2338 ImGui::PopStyleColor(3); 2339 ImGui::PopID(); 2340 } 2341 } 2342 float scroll_x = ImGui::GetScrollX(); 2343 float scroll_max_x = ImGui::GetScrollMaxX(); 2344 ImGui::EndChild(); 2345 ImGui::PopStyleVar(2); 2346 float scroll_x_delta = 0.0f; 2347 ImGui::SmallButton("<<"); if (ImGui::IsItemActive()) { scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f; } ImGui::SameLine(); 2348 ImGui::Text("Scroll from code"); ImGui::SameLine(); 2349 ImGui::SmallButton(">>"); if (ImGui::IsItemActive()) { scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f; } ImGui::SameLine(); 2350 ImGui::Text("%.0f/%.0f", scroll_x, scroll_max_x); 2351 if (scroll_x_delta != 0.0f) 2352 { 2353 ImGui::BeginChild("scrolling"); // Demonstrate a trick: you can use Begin to set yourself in the context of another window (here we are already out of your child window) 2354 ImGui::SetScrollX(ImGui::GetScrollX() + scroll_x_delta); 2355 ImGui::EndChild(); 2356 } 2357 ImGui::Spacing(); 2358 2359 static bool show_horizontal_contents_size_demo_window = false; 2360 ImGui::Checkbox("Show Horizontal contents size demo window", &show_horizontal_contents_size_demo_window); 2361 2362 if (show_horizontal_contents_size_demo_window) 2363 { 2364 static bool show_h_scrollbar = true; 2365 static bool show_button = true; 2366 static bool show_tree_nodes = true; 2367 static bool show_text_wrapped = false; 2368 static bool show_columns = true; 2369 static bool show_tab_bar = true; 2370 static bool show_child = false; 2371 static bool explicit_content_size = false; 2372 static float contents_size_x = 300.0f; 2373 if (explicit_content_size) 2374 ImGui::SetNextWindowContentSize(ImVec2(contents_size_x, 0.0f)); 2375 ImGui::Begin("Horizontal contents size demo window", &show_horizontal_contents_size_demo_window, show_h_scrollbar ? ImGuiWindowFlags_HorizontalScrollbar : 0); 2376 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 0)); 2377 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 0)); 2378 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."); 2379 ImGui::Checkbox("H-scrollbar", &show_h_scrollbar); 2380 ImGui::Checkbox("Button", &show_button); // Will grow contents size (unless explicitly overwritten) 2381 ImGui::Checkbox("Tree nodes", &show_tree_nodes); // Will grow contents size and display highlight over full width 2382 ImGui::Checkbox("Text wrapped", &show_text_wrapped);// Will grow and use contents size 2383 ImGui::Checkbox("Columns", &show_columns); // Will use contents size 2384 ImGui::Checkbox("Tab bar", &show_tab_bar); // Will use contents size 2385 ImGui::Checkbox("Child", &show_child); // Will grow and use contents size 2386 ImGui::Checkbox("Explicit content size", &explicit_content_size); 2387 ImGui::Text("Scroll %.1f/%.1f %.1f/%.1f", ImGui::GetScrollX(), ImGui::GetScrollMaxX(), ImGui::GetScrollY(), ImGui::GetScrollMaxY()); 2388 if (explicit_content_size) 2389 { 2390 ImGui::SameLine(); 2391 ImGui::SetNextItemWidth(100); 2392 ImGui::DragFloat("##csx", &contents_size_x); 2393 ImVec2 p = ImGui::GetCursorScreenPos(); 2394 ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + 10, p.y + 10), IM_COL32_WHITE); 2395 ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(p.x + contents_size_x - 10, p.y), ImVec2(p.x + contents_size_x, p.y + 10), IM_COL32_WHITE); 2396 ImGui::Dummy(ImVec2(0, 10)); 2397 } 2398 ImGui::PopStyleVar(2); 2399 ImGui::Separator(); 2400 if (show_button) 2401 { 2402 ImGui::Button("this is a 300-wide button", ImVec2(300, 0)); 2403 } 2404 if (show_tree_nodes) 2405 { 2406 bool open = true; 2407 if (ImGui::TreeNode("this is a tree node")) 2408 { 2409 if (ImGui::TreeNode("another one of those tree node...")) 2410 { 2411 ImGui::Text("Some tree contents"); 2412 ImGui::TreePop(); 2413 } 2414 ImGui::TreePop(); 2415 } 2416 ImGui::CollapsingHeader("CollapsingHeader", &open); 2417 } 2418 if (show_text_wrapped) 2419 { 2420 ImGui::TextWrapped("This text should automatically wrap on the edge of the work rectangle."); 2421 } 2422 if (show_columns) 2423 { 2424 ImGui::Columns(4); 2425 for (int n = 0; n < 4; n++) 2426 { 2427 ImGui::Text("Width %.2f", ImGui::GetColumnWidth()); 2428 ImGui::NextColumn(); 2429 } 2430 ImGui::Columns(1); 2431 } 2432 if (show_tab_bar && ImGui::BeginTabBar("Hello")) 2433 { 2434 if (ImGui::BeginTabItem("OneOneOne")) { ImGui::EndTabItem(); } 2435 if (ImGui::BeginTabItem("TwoTwoTwo")) { ImGui::EndTabItem(); } 2436 if (ImGui::BeginTabItem("ThreeThreeThree")) { ImGui::EndTabItem(); } 2437 if (ImGui::BeginTabItem("FourFourFour")) { ImGui::EndTabItem(); } 2438 ImGui::EndTabBar(); 2439 } 2440 if (show_child) 2441 { 2442 ImGui::BeginChild("child", ImVec2(0,0), true); 2443 ImGui::EndChild(); 2444 } 2445 ImGui::End(); 2446 } 2447 2448 ImGui::TreePop(); 2449 } 2450 2451 if (ImGui::TreeNode("Clipping")) 2452 { 2453 static ImVec2 size(100, 100), offset(50, 20); 2454 ImGui::TextWrapped("On a per-widget basis we are occasionally clipping text CPU-side if it won't fit in its frame. Otherwise we are doing coarser clipping + passing a scissor rectangle to the renderer. The system is designed to try minimizing both execution and CPU/GPU rendering cost."); 2455 ImGui::DragFloat2("size", (float*)&size, 0.5f, 1.0f, 200.0f, "%.0f"); 2456 ImGui::TextWrapped("(Click and drag)"); 2457 ImVec2 pos = ImGui::GetCursorScreenPos(); 2458 ImVec4 clip_rect(pos.x, pos.y, pos.x + size.x, pos.y + size.y); 2459 ImGui::InvisibleButton("##dummy", size); 2460 if (ImGui::IsItemActive() && ImGui::IsMouseDragging(0)) { offset.x += ImGui::GetIO().MouseDelta.x; offset.y += ImGui::GetIO().MouseDelta.y; } 2461 ImGui::GetWindowDrawList()->AddRectFilled(pos, ImVec2(pos.x + size.x, pos.y + size.y), IM_COL32(90, 90, 120, 255)); 2462 ImGui::GetWindowDrawList()->AddText(ImGui::GetFont(), ImGui::GetFontSize()*2.0f, ImVec2(pos.x + offset.x, pos.y + offset.y), IM_COL32(255, 255, 255, 255), "Line 1 hello\nLine 2 clip me!", NULL, 0.0f, &clip_rect); 2463 ImGui::TreePop(); 2464 } 2465} 2466 2467static void ShowDemoWindowPopups() 2468{ 2469 if (!ImGui::CollapsingHeader("Popups & Modal windows")) 2470 return; 2471 2472 // The properties of popups windows are: 2473 // - They block normal mouse hovering detection outside them. (*) 2474 // - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE. 2475 // - Their visibility state (~bool) is held internally by Dear ImGui instead of being held by the programmer as we are used to with regular Begin() calls. 2476 // User can manipulate the visibility state by calling OpenPopup(). 2477 // (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even when normally blocked by a popup. 2478 // Those three properties are connected. The library needs to hold their visibility state because it can close popups at any time. 2479 2480 // Typical use for regular windows: 2481 // 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(); 2482 // Typical use for popups: 2483 // if (ImGui::Button("Open")) ImGui::OpenPopup("MyPopup"); if (ImGui::BeginPopup("MyPopup") { [...] EndPopup(); } 2484 2485 // With popups we have to go through a library call (here OpenPopup) to manipulate the visibility state. 2486 // This may be a bit confusing at first but it should quickly make sense. Follow on the examples below. 2487 2488 if (ImGui::TreeNode("Popups")) 2489 { 2490 ImGui::TextWrapped("When a popup is active, it inhibits interacting with windows that are behind the popup. Clicking outside the popup closes it."); 2491 2492 static int selected_fish = -1; 2493 const char* names[] = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" }; 2494 static bool toggles[] = { true, false, false, false, false }; 2495 2496 // Simple selection popup 2497 // (If you want to show the current selection inside the Button itself, you may want to build a string using the "###" operator to preserve a constant ID with a variable label) 2498 if (ImGui::Button("Select..")) 2499 ImGui::OpenPopup("my_select_popup"); 2500 ImGui::SameLine(); 2501 ImGui::TextUnformatted(selected_fish == -1 ? "<None>" : names[selected_fish]); 2502 if (ImGui::BeginPopup("my_select_popup")) 2503 { 2504 ImGui::Text("Aquarium"); 2505 ImGui::Separator(); 2506 for (int i = 0; i < IM_ARRAYSIZE(names); i++) 2507 if (ImGui::Selectable(names[i])) 2508 selected_fish = i; 2509 ImGui::EndPopup(); 2510 } 2511 2512 // Showing a menu with toggles 2513 if (ImGui::Button("Toggle..")) 2514 ImGui::OpenPopup("my_toggle_popup"); 2515 if (ImGui::BeginPopup("my_toggle_popup")) 2516 { 2517 for (int i = 0; i < IM_ARRAYSIZE(names); i++) 2518 ImGui::MenuItem(names[i], "", &toggles[i]); 2519 if (ImGui::BeginMenu("Sub-menu")) 2520 { 2521 ImGui::MenuItem("Click me"); 2522 ImGui::EndMenu(); 2523 } 2524 2525 ImGui::Separator(); 2526 ImGui::Text("Tooltip here"); 2527 if (ImGui::IsItemHovered()) 2528 ImGui::SetTooltip("I am a tooltip over a popup"); 2529 2530 if (ImGui::Button("Stacked Popup")) 2531 ImGui::OpenPopup("another popup"); 2532 if (ImGui::BeginPopup("another popup")) 2533 { 2534 for (int i = 0; i < IM_ARRAYSIZE(names); i++) 2535 ImGui::MenuItem(names[i], "", &toggles[i]); 2536 if (ImGui::BeginMenu("Sub-menu")) 2537 { 2538 ImGui::MenuItem("Click me"); 2539 if (ImGui::Button("Stacked Popup")) 2540 ImGui::OpenPopup("another popup"); 2541 if (ImGui::BeginPopup("another popup")) 2542 { 2543 ImGui::Text("I am the last one here."); 2544 ImGui::EndPopup(); 2545 } 2546 ImGui::EndMenu(); 2547 } 2548 ImGui::EndPopup(); 2549 } 2550 ImGui::EndPopup(); 2551 } 2552 2553 // Call the more complete ShowExampleMenuFile which we use in various places of this demo 2554 if (ImGui::Button("File Menu..")) 2555 ImGui::OpenPopup("my_file_popup"); 2556 if (ImGui::BeginPopup("my_file_popup")) 2557 { 2558 ShowExampleMenuFile(); 2559 ImGui::EndPopup(); 2560 } 2561 2562 ImGui::TreePop(); 2563 } 2564 2565 if (ImGui::TreeNode("Context menus")) 2566 { 2567 // BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing: 2568 // if (IsItemHovered() && IsMouseReleased(0)) 2569 // OpenPopup(id); 2570 // return BeginPopup(id); 2571 // For more advanced uses you may want to replicate and cuztomize this code. This the comments inside BeginPopupContextItem() implementation. 2572 static float value = 0.5f; 2573 ImGui::Text("Value = %.3f (<-- right-click here)", value); 2574 if (ImGui::BeginPopupContextItem("item context menu")) 2575 { 2576 if (ImGui::Selectable("Set to zero")) value = 0.0f; 2577 if (ImGui::Selectable("Set to PI")) value = 3.1415f; 2578 ImGui::SetNextItemWidth(-1); 2579 ImGui::DragFloat("##Value", &value, 0.1f, 0.0f, 0.0f); 2580 ImGui::EndPopup(); 2581 } 2582 2583 // We can also use OpenPopupOnItemClick() which is the same as BeginPopupContextItem() but without the Begin call. 2584 // So here we will make it that clicking on the text field with the right mouse button (1) will toggle the visibility of the popup above. 2585 ImGui::Text("(You can also right-click me to open the same popup as above.)"); 2586 ImGui::OpenPopupOnItemClick("item context menu", 1); 2587 2588 // When used after an item that has an ID (here the Button), we can skip providing an ID to BeginPopupContextItem(). 2589 // BeginPopupContextItem() will use the last item ID as the popup ID. 2590 // In addition here, we want to include your editable label inside the button label. We use the ### operator to override the ID (read FAQ about ID for details) 2591 static char name[32] = "Label1"; 2592 char buf[64]; sprintf(buf, "Button: %s###Button", name); // ### operator override ID ignoring the preceding label 2593 ImGui::Button(buf); 2594 if (ImGui::BeginPopupContextItem()) 2595 { 2596 ImGui::Text("Edit name:"); 2597 ImGui::InputText("##edit", name, IM_ARRAYSIZE(name)); 2598 if (ImGui::Button("Close")) 2599 ImGui::CloseCurrentPopup(); 2600 ImGui::EndPopup(); 2601 } 2602 ImGui::SameLine(); ImGui::Text("(<-- right-click here)"); 2603 2604 ImGui::TreePop(); 2605 } 2606 2607 if (ImGui::TreeNode("Modals")) 2608 { 2609 ImGui::TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside the window."); 2610 2611 if (ImGui::Button("Delete..")) 2612 ImGui::OpenPopup("Delete?"); 2613 2614 if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize)) 2615 { 2616 ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!\n\n"); 2617 ImGui::Separator(); 2618 2619 //static int dummy_i = 0; 2620 //ImGui::Combo("Combo", &dummy_i, "Delete\0Delete harder\0"); 2621 2622 static bool dont_ask_me_next_time = false; 2623 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); 2624 ImGui::Checkbox("Don't ask me next time", &dont_ask_me_next_time); 2625 ImGui::PopStyleVar(); 2626 2627 if (ImGui::Button("OK", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); } 2628 ImGui::SetItemDefaultFocus(); 2629 ImGui::SameLine(); 2630 if (ImGui::Button("Cancel", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); } 2631 ImGui::EndPopup(); 2632 } 2633 2634 if (ImGui::Button("Stacked modals..")) 2635 ImGui::OpenPopup("Stacked 1"); 2636 if (ImGui::BeginPopupModal("Stacked 1", NULL, ImGuiWindowFlags_MenuBar)) 2637 { 2638 if (ImGui::BeginMenuBar()) 2639 { 2640 if (ImGui::BeginMenu("File")) 2641 { 2642 if (ImGui::MenuItem("Dummy menu item")) {} 2643 ImGui::EndMenu(); 2644 } 2645 ImGui::EndMenuBar(); 2646 } 2647 ImGui::Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it."); 2648 2649 // Testing behavior of widgets stacking their own regular popups over the modal. 2650 static int item = 1; 2651 static float color[4] = { 0.4f,0.7f,0.0f,0.5f }; 2652 ImGui::Combo("Combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); 2653 ImGui::ColorEdit4("color", color); 2654 2655 if (ImGui::Button("Add another modal..")) 2656 ImGui::OpenPopup("Stacked 2"); 2657 2658 // Also demonstrate passing a bool* to BeginPopupModal(), this will create a regular close button which will close the popup. 2659 // Note that the visibility state of popups is owned by imgui, so the input value of the bool actually doesn't matter here. 2660 bool dummy_open = true; 2661 if (ImGui::BeginPopupModal("Stacked 2", &dummy_open)) 2662 { 2663 ImGui::Text("Hello from Stacked The Second!"); 2664 if (ImGui::Button("Close")) 2665 ImGui::CloseCurrentPopup(); 2666 ImGui::EndPopup(); 2667 } 2668 2669 if (ImGui::Button("Close")) 2670 ImGui::CloseCurrentPopup(); 2671 ImGui::EndPopup(); 2672 } 2673 2674 ImGui::TreePop(); 2675 } 2676 2677 if (ImGui::TreeNode("Menus inside a regular window")) 2678 { 2679 ImGui::TextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!"); 2680 ImGui::Separator(); 2681 // NB: As a quirk in this very specific example, we want to differentiate the parent of this menu from the parent of the various popup menus above. 2682 // To do so we are encloding the items in a PushID()/PopID() block to make them two different menusets. If we don't, opening any popup above and hovering our menu here 2683 // would open it. This is because once a menu is active, we allow to switch to a sibling menu by just hovering on it, which is the desired behavior for regular menus. 2684 ImGui::PushID("foo"); 2685 ImGui::MenuItem("Menu item", "CTRL+M"); 2686 if (ImGui::BeginMenu("Menu inside a regular window")) 2687 { 2688 ShowExampleMenuFile(); 2689 ImGui::EndMenu(); 2690 } 2691 ImGui::PopID(); 2692 ImGui::Separator(); 2693 ImGui::TreePop(); 2694 } 2695} 2696 2697static void ShowDemoWindowColumns() 2698{ 2699 if (!ImGui::CollapsingHeader("Columns")) 2700 return; 2701 2702 ImGui::PushID("Columns"); 2703 2704 static bool disable_indent = false; 2705 ImGui::Checkbox("Disable tree indentation", &disable_indent); 2706 ImGui::SameLine(); 2707 HelpMarker("Disable the indenting of tree nodes so demo columns can use the full window width."); 2708 if (disable_indent) 2709 ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0.0f); 2710 2711 // Basic columns 2712 if (ImGui::TreeNode("Basic")) 2713 { 2714 ImGui::Text("Without border:"); 2715 ImGui::Columns(3, "mycolumns3", false); // 3-ways, no border 2716 ImGui::Separator(); 2717 for (int n = 0; n < 14; n++) 2718 { 2719 char label[32]; 2720 sprintf(label, "Item %d", n); 2721 if (ImGui::Selectable(label)) {} 2722 //if (ImGui::Button(label, ImVec2(-FLT_MIN,0.0f))) {} 2723 ImGui::NextColumn(); 2724 } 2725 ImGui::Columns(1); 2726 ImGui::Separator(); 2727 2728 ImGui::Text("With border:"); 2729 ImGui::Columns(4, "mycolumns"); // 4-ways, with border 2730 ImGui::Separator(); 2731 ImGui::Text("ID"); ImGui::NextColumn(); 2732 ImGui::Text("Name"); ImGui::NextColumn(); 2733 ImGui::Text("Path"); ImGui::NextColumn(); 2734 ImGui::Text("Hovered"); ImGui::NextColumn(); 2735 ImGui::Separator(); 2736 const char* names[3] = { "One", "Two", "Three" }; 2737 const char* paths[3] = { "/path/one", "/path/two", "/path/three" }; 2738 static int selected = -1; 2739 for (int i = 0; i < 3; i++) 2740 { 2741 char label[32]; 2742 sprintf(label, "%04d", i); 2743 if (ImGui::Selectable(label, selected == i, ImGuiSelectableFlags_SpanAllColumns)) 2744 selected = i; 2745 bool hovered = ImGui::IsItemHovered(); 2746 ImGui::NextColumn(); 2747 ImGui::Text(names[i]); ImGui::NextColumn(); 2748 ImGui::Text(paths[i]); ImGui::NextColumn(); 2749 ImGui::Text("%d", hovered); ImGui::NextColumn(); 2750 } 2751 ImGui::Columns(1); 2752 ImGui::Separator(); 2753 ImGui::TreePop(); 2754 } 2755 2756 if (ImGui::TreeNode("Borders")) 2757 { 2758 // NB: Future columns API should allow automatic horizontal borders. 2759 static bool h_borders = true; 2760 static bool v_borders = true; 2761 static int columns_count = 4; 2762 const int lines_count = 3; 2763 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); 2764 ImGui::DragInt("##columns_count", &columns_count, 0.1f, 2, 10, "%d columns"); 2765 if (columns_count < 2) 2766 columns_count = 2; 2767 ImGui::SameLine(); 2768 ImGui::Checkbox("horizontal", &h_borders); 2769 ImGui::SameLine(); 2770 ImGui::Checkbox("vertical", &v_borders); 2771 ImGui::Columns(columns_count, NULL, v_borders); 2772 for (int i = 0; i < columns_count * lines_count; i++) 2773 { 2774 if (h_borders && ImGui::GetColumnIndex() == 0) 2775 ImGui::Separator(); 2776 ImGui::Text("%c%c%c", 'a' + i, 'a' + i, 'a' + i); 2777 ImGui::Text("Width %.2f", ImGui::GetColumnWidth()); 2778 ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x); 2779 ImGui::Text("Offset %.2f", ImGui::GetColumnOffset()); 2780 ImGui::Text("Long text that is likely to clip"); 2781 ImGui::Button("Button", ImVec2(-FLT_MIN, 0.0f)); 2782 ImGui::NextColumn(); 2783 } 2784 ImGui::Columns(1); 2785 if (h_borders) 2786 ImGui::Separator(); 2787 ImGui::TreePop(); 2788 } 2789 2790 // Create multiple items in a same cell before switching to next column 2791 if (ImGui::TreeNode("Mixed items")) 2792 { 2793 ImGui::Columns(3, "mixed"); 2794 ImGui::Separator(); 2795 2796 ImGui::Text("Hello"); 2797 ImGui::Button("Banana"); 2798 ImGui::NextColumn(); 2799 2800 ImGui::Text("ImGui"); 2801 ImGui::Button("Apple"); 2802 static float foo = 1.0f; 2803 ImGui::InputFloat("red", &foo, 0.05f, 0, "%.3f"); 2804 ImGui::Text("An extra line here."); 2805 ImGui::NextColumn(); 2806 2807 ImGui::Text("Sailor"); 2808 ImGui::Button("Corniflower"); 2809 static float bar = 1.0f; 2810 ImGui::InputFloat("blue", &bar, 0.05f, 0, "%.3f"); 2811 ImGui::NextColumn(); 2812 2813 if (ImGui::CollapsingHeader("Category A")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); 2814 if (ImGui::CollapsingHeader("Category B")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); 2815 if (ImGui::CollapsingHeader("Category C")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); 2816 ImGui::Columns(1); 2817 ImGui::Separator(); 2818 ImGui::TreePop(); 2819 } 2820 2821 // Word wrapping 2822 if (ImGui::TreeNode("Word-wrapping")) 2823 { 2824 ImGui::Columns(2, "word-wrapping"); 2825 ImGui::Separator(); 2826 ImGui::TextWrapped("The quick brown fox jumps over the lazy dog."); 2827 ImGui::TextWrapped("Hello Left"); 2828 ImGui::NextColumn(); 2829 ImGui::TextWrapped("The quick brown fox jumps over the lazy dog."); 2830 ImGui::TextWrapped("Hello Right"); 2831 ImGui::Columns(1); 2832 ImGui::Separator(); 2833 ImGui::TreePop(); 2834 } 2835 2836 // Scrolling columns 2837 /* 2838 if (ImGui::TreeNode("Vertical Scrolling")) 2839 { 2840 ImGui::BeginChild("##header", ImVec2(0, ImGui::GetTextLineHeightWithSpacing()+ImGui::GetStyle().ItemSpacing.y)); 2841 ImGui::Columns(3); 2842 ImGui::Text("ID"); ImGui::NextColumn(); 2843 ImGui::Text("Name"); ImGui::NextColumn(); 2844 ImGui::Text("Path"); ImGui::NextColumn(); 2845 ImGui::Columns(1); 2846 ImGui::Separator(); 2847 ImGui::EndChild(); 2848 ImGui::BeginChild("##scrollingregion", ImVec2(0, 60)); 2849 ImGui::Columns(3); 2850 for (int i = 0; i < 10; i++) 2851 { 2852 ImGui::Text("%04d", i); ImGui::NextColumn(); 2853 ImGui::Text("Foobar"); ImGui::NextColumn(); 2854 ImGui::Text("/path/foobar/%04d/", i); ImGui::NextColumn(); 2855 } 2856 ImGui::Columns(1); 2857 ImGui::EndChild(); 2858 ImGui::TreePop(); 2859 } 2860 */ 2861 2862 if (ImGui::TreeNode("Horizontal Scrolling")) 2863 { 2864 ImGui::SetNextWindowContentSize(ImVec2(1500.0f, 0.0f)); 2865 ImGui::BeginChild("##ScrollingRegion", ImVec2(0, ImGui::GetFontSize() * 20), false, ImGuiWindowFlags_HorizontalScrollbar); 2866 ImGui::Columns(10); 2867 int ITEMS_COUNT = 2000; 2868 ImGuiListClipper clipper(ITEMS_COUNT); // Also demonstrate using the clipper for large list 2869 while (clipper.Step()) 2870 { 2871 for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) 2872 for (int j = 0; j < 10; j++) 2873 { 2874 ImGui::Text("Line %d Column %d...", i, j); 2875 ImGui::NextColumn(); 2876 } 2877 } 2878 ImGui::Columns(1); 2879 ImGui::EndChild(); 2880 ImGui::TreePop(); 2881 } 2882 2883 if (ImGui::TreeNode("Tree")) 2884 { 2885 ImGui::Columns(2, "tree", true); 2886 for (int x = 0; x < 3; x++) 2887 { 2888 bool open1 = ImGui::TreeNode((void*)(intptr_t)x, "Node%d", x); 2889 ImGui::NextColumn(); 2890 ImGui::Text("Node contents"); 2891 ImGui::NextColumn(); 2892 if (open1) 2893 { 2894 for (int y = 0; y < 3; y++) 2895 { 2896 bool open2 = ImGui::TreeNode((void*)(intptr_t)y, "Node%d.%d", x, y); 2897 ImGui::NextColumn(); 2898 ImGui::Text("Node contents"); 2899 if (open2) 2900 { 2901 ImGui::Text("Even more contents"); 2902 if (ImGui::TreeNode("Tree in column")) 2903 { 2904 ImGui::Text("The quick brown fox jumps over the lazy dog"); 2905 ImGui::TreePop(); 2906 } 2907 } 2908 ImGui::NextColumn(); 2909 if (open2) 2910 ImGui::TreePop(); 2911 } 2912 ImGui::TreePop(); 2913 } 2914 } 2915 ImGui::Columns(1); 2916 ImGui::TreePop(); 2917 } 2918 2919 if (disable_indent) 2920 ImGui::PopStyleVar(); 2921 ImGui::PopID(); 2922} 2923 2924static void ShowDemoWindowMisc() 2925{ 2926 if (ImGui::CollapsingHeader("Filtering")) 2927 { 2928 // Helper class to easy setup a text filter. 2929 // You may want to implement a more feature-full filtering scheme in your own application. 2930 static ImGuiTextFilter filter; 2931 ImGui::Text("Filter usage:\n" 2932 " \"\" display all lines\n" 2933 " \"xxx\" display lines containing \"xxx\"\n" 2934 " \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n" 2935 " \"-xxx\" hide lines containing \"xxx\""); 2936 filter.Draw(); 2937 const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" }; 2938 for (int i = 0; i < IM_ARRAYSIZE(lines); i++) 2939 if (filter.PassFilter(lines[i])) 2940 ImGui::BulletText("%s", lines[i]); 2941 } 2942 2943 if (ImGui::CollapsingHeader("Inputs, Navigation & Focus")) 2944 { 2945 ImGuiIO& io = ImGui::GetIO(); 2946 2947 // Display ImGuiIO output flags 2948 ImGui::Text("WantCaptureMouse: %d", io.WantCaptureMouse); 2949 ImGui::Text("WantCaptureKeyboard: %d", io.WantCaptureKeyboard); 2950 ImGui::Text("WantTextInput: %d", io.WantTextInput); 2951 ImGui::Text("WantSetMousePos: %d", io.WantSetMousePos); 2952 ImGui::Text("NavActive: %d, NavVisible: %d", io.NavActive, io.NavVisible); 2953 2954 // Display Keyboard/Mouse state 2955 if (ImGui::TreeNode("Keyboard, Mouse & Navigation State")) 2956 { 2957 if (ImGui::IsMousePosValid()) 2958 ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y); 2959 else 2960 ImGui::Text("Mouse pos: <INVALID>"); 2961 ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y); 2962 ImGui::Text("Mouse down:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (io.MouseDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); } 2963 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); } 2964 ImGui::Text("Mouse dbl-clicked:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDoubleClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } 2965 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); } 2966 ImGui::Text("Mouse wheel: %.1f", io.MouseWheel); 2967 2968 ImGui::Text("Keys down:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (io.KeysDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("%d (0x%X) (%.02f secs)", i, i, io.KeysDownDuration[i]); } 2969 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); } 2970 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); } 2971 ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); 2972 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. 2973 2974 ImGui::Text("NavInputs down:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputs[i] > 0.0f) { ImGui::SameLine(); ImGui::Text("[%d] %.2f", i, io.NavInputs[i]); } 2975 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); } 2976 ImGui::Text("NavInputs duration:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputsDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("[%d] %.2f", i, io.NavInputsDownDuration[i]); } 2977 2978 ImGui::Button("Hovering me sets the\nkeyboard capture flag"); 2979 if (ImGui::IsItemHovered()) 2980 ImGui::CaptureKeyboardFromApp(true); 2981 ImGui::SameLine(); 2982 ImGui::Button("Holding me clears the\nthe keyboard capture flag"); 2983 if (ImGui::IsItemActive()) 2984 ImGui::CaptureKeyboardFromApp(false); 2985 2986 ImGui::TreePop(); 2987 } 2988 2989 if (ImGui::TreeNode("Tabbing")) 2990 { 2991 ImGui::Text("Use TAB/SHIFT+TAB to cycle through keyboard editable fields."); 2992 static char buf[32] = "dummy"; 2993 ImGui::InputText("1", buf, IM_ARRAYSIZE(buf)); 2994 ImGui::InputText("2", buf, IM_ARRAYSIZE(buf)); 2995 ImGui::InputText("3", buf, IM_ARRAYSIZE(buf)); 2996 ImGui::PushAllowKeyboardFocus(false); 2997 ImGui::InputText("4 (tab skip)", buf, IM_ARRAYSIZE(buf)); 2998 //ImGui::SameLine(); HelpMarker("Use ImGui::PushAllowKeyboardFocus(bool)\nto disable tabbing through certain widgets."); 2999 ImGui::PopAllowKeyboardFocus(); 3000 ImGui::InputText("5", buf, IM_ARRAYSIZE(buf)); 3001 ImGui::TreePop(); 3002 } 3003 3004 if (ImGui::TreeNode("Focus from code")) 3005 { 3006 bool focus_1 = ImGui::Button("Focus on 1"); ImGui::SameLine(); 3007 bool focus_2 = ImGui::Button("Focus on 2"); ImGui::SameLine(); 3008 bool focus_3 = ImGui::Button("Focus on 3"); 3009 int has_focus = 0; 3010 static char buf[128] = "click on a button to set focus"; 3011 3012 if (focus_1) ImGui::SetKeyboardFocusHere(); 3013 ImGui::InputText("1", buf, IM_ARRAYSIZE(buf)); 3014 if (ImGui::IsItemActive()) has_focus = 1; 3015 3016 if (focus_2) ImGui::SetKeyboardFocusHere(); 3017 ImGui::InputText("2", buf, IM_ARRAYSIZE(buf)); 3018 if (ImGui::IsItemActive()) has_focus = 2; 3019 3020 ImGui::PushAllowKeyboardFocus(false); 3021 if (focus_3) ImGui::SetKeyboardFocusHere(); 3022 ImGui::InputText("3 (tab skip)", buf, IM_ARRAYSIZE(buf)); 3023 if (ImGui::IsItemActive()) has_focus = 3; 3024 ImGui::PopAllowKeyboardFocus(); 3025 3026 if (has_focus) 3027 ImGui::Text("Item with focus: %d", has_focus); 3028 else 3029 ImGui::Text("Item with focus: <none>"); 3030 3031 // Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item 3032 static float f3[3] = { 0.0f, 0.0f, 0.0f }; 3033 int focus_ahead = -1; 3034 if (ImGui::Button("Focus on X")) { focus_ahead = 0; } ImGui::SameLine(); 3035 if (ImGui::Button("Focus on Y")) { focus_ahead = 1; } ImGui::SameLine(); 3036 if (ImGui::Button("Focus on Z")) { focus_ahead = 2; } 3037 if (focus_ahead != -1) ImGui::SetKeyboardFocusHere(focus_ahead); 3038 ImGui::SliderFloat3("Float3", &f3[0], 0.0f, 1.0f); 3039 3040 ImGui::TextWrapped("NB: Cursor & selection are preserved when refocusing last used item in code."); 3041 ImGui::TreePop(); 3042 } 3043 3044 if (ImGui::TreeNode("Dragging")) 3045 { 3046 ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget."); 3047 for (int button = 0; button < 3; button++) 3048 ImGui::Text("IsMouseDragging(%d):\n w/ default threshold: %d,\n w/ zero threshold: %d\n w/ large threshold: %d", 3049 button, ImGui::IsMouseDragging(button), ImGui::IsMouseDragging(button, 0.0f), ImGui::IsMouseDragging(button, 20.0f)); 3050 3051 ImGui::Button("Drag Me"); 3052 if (ImGui::IsItemActive()) 3053 ImGui::GetForegroundDrawList()->AddLine(io.MouseClickedPos[0], io.MousePos, ImGui::GetColorU32(ImGuiCol_Button), 4.0f); // Draw a line between the button and the mouse cursor 3054 3055 // Drag operations gets "unlocked" when the mouse has moved past a certain threshold (the default threshold is stored in io.MouseDragThreshold) 3056 // You can request a lower or higher threshold using the second parameter of IsMouseDragging() and GetMouseDragDelta() 3057 ImVec2 value_raw = ImGui::GetMouseDragDelta(0, 0.0f); 3058 ImVec2 value_with_lock_threshold = ImGui::GetMouseDragDelta(0); 3059 ImVec2 mouse_delta = io.MouseDelta; 3060 ImGui::Text("GetMouseDragDelta(0):\n w/ default threshold: (%.1f, %.1f),\n w/ zero threshold: (%.1f, %.1f)\nMouseDelta: (%.1f, %.1f)", value_with_lock_threshold.x, value_with_lock_threshold.y, value_raw.x, value_raw.y, mouse_delta.x, mouse_delta.y); 3061 ImGui::TreePop(); 3062 } 3063 3064 if (ImGui::TreeNode("Mouse cursors")) 3065 { 3066 const char* mouse_cursors_names[] = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "NotAllowed" }; 3067 IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT); 3068 3069 ImGui::Text("Current mouse cursor = %d: %s", ImGui::GetMouseCursor(), mouse_cursors_names[ImGui::GetMouseCursor()]); 3070 ImGui::Text("Hover to see mouse cursors:"); 3071 ImGui::SameLine(); HelpMarker("Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, otherwise your backend needs to handle it."); 3072 for (int i = 0; i < ImGuiMouseCursor_COUNT; i++) 3073 { 3074 char label[32]; 3075 sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]); 3076 ImGui::Bullet(); ImGui::Selectable(label, false); 3077 if (ImGui::IsItemHovered() || ImGui::IsItemFocused()) 3078 ImGui::SetMouseCursor(i); 3079 } 3080 ImGui::TreePop(); 3081 } 3082 } 3083} 3084 3085//----------------------------------------------------------------------------- 3086// [SECTION] About Window / ShowAboutWindow() 3087// Access from Dear ImGui Demo -> Tools -> About 3088//----------------------------------------------------------------------------- 3089 3090void ImGui::ShowAboutWindow(bool* p_open) 3091{ 3092 if (!ImGui::Begin("About Dear ImGui", p_open, ImGuiWindowFlags_AlwaysAutoResize)) 3093 { 3094 ImGui::End(); 3095 return; 3096 } 3097 ImGui::Text("Dear ImGui %s", ImGui::GetVersion()); 3098 ImGui::Separator(); 3099 ImGui::Text("By Omar Cornut and all Dear ImGui contributors."); 3100 ImGui::Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information."); 3101 3102 static bool show_config_info = false; 3103 ImGui::Checkbox("Config/Build Information", &show_config_info); 3104 if (show_config_info) 3105 { 3106 ImGuiIO& io = ImGui::GetIO(); 3107 ImGuiStyle& style = ImGui::GetStyle(); 3108 3109 bool copy_to_clipboard = ImGui::Button("Copy to clipboard"); 3110 ImGui::BeginChildFrame(ImGui::GetID("cfginfos"), ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 18), ImGuiWindowFlags_NoMove); 3111 if (copy_to_clipboard) 3112 { 3113 ImGui::LogToClipboard(); 3114 ImGui::LogText("```\n"); // Back quotes will make the text appears without formatting when pasting to GitHub 3115 } 3116 3117 ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM); 3118 ImGui::Separator(); 3119 ImGui::Text("sizeof(size_t): %d, sizeof(ImDrawIdx): %d, sizeof(ImDrawVert): %d", (int)sizeof(size_t), (int)sizeof(ImDrawIdx), (int)sizeof(ImDrawVert)); 3120 ImGui::Text("define: __cplusplus=%d", (int)__cplusplus); 3121#ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS 3122 ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_FUNCTIONS"); 3123#endif 3124#ifdef IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS 3125 ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS"); 3126#endif 3127#ifdef IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS 3128 ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS"); 3129#endif 3130#ifdef IMGUI_DISABLE_WIN32_FUNCTIONS 3131 ImGui::Text("define: IMGUI_DISABLE_WIN32_FUNCTIONS"); 3132#endif 3133#ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS 3134 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS"); 3135#endif 3136#ifdef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS 3137 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS"); 3138#endif 3139#ifdef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS 3140 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS"); 3141#endif 3142#ifdef IMGUI_DISABLE_FILE_FUNCTIONS 3143 ImGui::Text("define: IMGUI_DISABLE_FILE_FUNCTIONS"); 3144#endif 3145#ifdef IMGUI_DISABLE_DEFAULT_ALLOCATORS 3146 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_ALLOCATORS"); 3147#endif 3148#ifdef IMGUI_USE_BGRA_PACKED_COLOR 3149 ImGui::Text("define: IMGUI_USE_BGRA_PACKED_COLOR"); 3150#endif 3151#ifdef _WIN32 3152 ImGui::Text("define: _WIN32"); 3153#endif 3154#ifdef _WIN64 3155 ImGui::Text("define: _WIN64"); 3156#endif 3157#ifdef __linux__ 3158 ImGui::Text("define: __linux__"); 3159#endif 3160#ifdef __APPLE__ 3161 ImGui::Text("define: __APPLE__"); 3162#endif 3163#ifdef _MSC_VER 3164 ImGui::Text("define: _MSC_VER=%d", _MSC_VER); 3165#endif 3166#ifdef __MINGW32__ 3167 ImGui::Text("define: __MINGW32__"); 3168#endif 3169#ifdef __MINGW64__ 3170 ImGui::Text("define: __MINGW64__"); 3171#endif 3172#ifdef __GNUC__ 3173 ImGui::Text("define: __GNUC__=%d", (int)__GNUC__); 3174#endif 3175#ifdef __clang_version__ 3176 ImGui::Text("define: __clang_version__=%s", __clang_version__); 3177#endif 3178 ImGui::Separator(); 3179 ImGui::Text("io.BackendPlatformName: %s", io.BackendPlatformName ? io.BackendPlatformName : "NULL"); 3180 ImGui::Text("io.BackendRendererName: %s", io.BackendRendererName ? io.BackendRendererName : "NULL"); 3181 ImGui::Text("io.ConfigFlags: 0x%08X", io.ConfigFlags); 3182 if (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) ImGui::Text(" NavEnableKeyboard"); 3183 if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) ImGui::Text(" NavEnableGamepad"); 3184 if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) ImGui::Text(" NavEnableSetMousePos"); 3185 if (io.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard) ImGui::Text(" NavNoCaptureKeyboard"); 3186 if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) ImGui::Text(" NoMouse"); 3187 if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) ImGui::Text(" NoMouseCursorChange"); 3188 if (io.MouseDrawCursor) ImGui::Text("io.MouseDrawCursor"); 3189 if (io.ConfigMacOSXBehaviors) ImGui::Text("io.ConfigMacOSXBehaviors"); 3190 if (io.ConfigInputTextCursorBlink) ImGui::Text("io.ConfigInputTextCursorBlink"); 3191 if (io.ConfigWindowsResizeFromEdges) ImGui::Text("io.ConfigWindowsResizeFromEdges"); 3192 if (io.ConfigWindowsMoveFromTitleBarOnly) ImGui::Text("io.ConfigWindowsMoveFromTitleBarOnly"); 3193 if (io.ConfigWindowsMemoryCompactTimer >= 0.0f) ImGui::Text("io.ConfigWindowsMemoryCompactTimer = %.1ff", io.ConfigWindowsMemoryCompactTimer); 3194 ImGui::Text("io.BackendFlags: 0x%08X", io.BackendFlags); 3195 if (io.BackendFlags & ImGuiBackendFlags_HasGamepad) ImGui::Text(" HasGamepad"); 3196 if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) ImGui::Text(" HasMouseCursors"); 3197 if (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos) ImGui::Text(" HasSetMousePos"); 3198 if (io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) ImGui::Text(" RendererHasVtxOffset"); 3199 ImGui::Separator(); 3200 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); 3201 ImGui::Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y); 3202 ImGui::Text("io.DisplayFramebufferScale: %.2f,%.2f", io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y); 3203 ImGui::Separator(); 3204 ImGui::Text("style.WindowPadding: %.2f,%.2f", style.WindowPadding.x, style.WindowPadding.y); 3205 ImGui::Text("style.WindowBorderSize: %.2f", style.WindowBorderSize); 3206 ImGui::Text("style.FramePadding: %.2f,%.2f", style.FramePadding.x, style.FramePadding.y); 3207 ImGui::Text("style.FrameRounding: %.2f", style.FrameRounding); 3208 ImGui::Text("style.FrameBorderSize: %.2f", style.FrameBorderSize); 3209 ImGui::Text("style.ItemSpacing: %.2f,%.2f", style.ItemSpacing.x, style.ItemSpacing.y); 3210 ImGui::Text("style.ItemInnerSpacing: %.2f,%.2f", style.ItemInnerSpacing.x, style.ItemInnerSpacing.y); 3211 3212 if (copy_to_clipboard) 3213 { 3214 ImGui::LogText("\n```\n"); 3215 ImGui::LogFinish(); 3216 } 3217 ImGui::EndChildFrame(); 3218 } 3219 ImGui::End(); 3220} 3221 3222//----------------------------------------------------------------------------- 3223// [SECTION] Style Editor / ShowStyleEditor() 3224//----------------------------------------------------------------------------- 3225// - ShowStyleSelector() 3226// - ShowFontSelector() 3227// - ShowStyleEditor() 3228//----------------------------------------------------------------------------- 3229 3230// Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options. 3231// Here we use the simplified Combo() api that packs items into a single literal string. Useful for quick combo boxes where the choices are known locally. 3232bool ImGui::ShowStyleSelector(const char* label) 3233{ 3234 static int style_idx = -1; 3235 if (ImGui::Combo(label, &style_idx, "Classic\0Dark\0Light\0")) 3236 { 3237 switch (style_idx) 3238 { 3239 case 0: ImGui::StyleColorsClassic(); break; 3240 case 1: ImGui::StyleColorsDark(); break; 3241 case 2: ImGui::StyleColorsLight(); break; 3242 } 3243 return true; 3244 } 3245 return false; 3246} 3247 3248// Demo helper function to select among loaded fonts. 3249// Here we use the regular BeginCombo()/EndCombo() api which is more the more flexible one. 3250void ImGui::ShowFontSelector(const char* label) 3251{ 3252 ImGuiIO& io = ImGui::GetIO(); 3253 ImFont* font_current = ImGui::GetFont(); 3254 if (ImGui::BeginCombo(label, font_current->GetDebugName())) 3255 { 3256 for (int n = 0; n < io.Fonts->Fonts.Size; n++) 3257 { 3258 ImFont* font = io.Fonts->Fonts[n]; 3259 ImGui::PushID((void*)font); 3260 if (ImGui::Selectable(font->GetDebugName(), font == font_current)) 3261 io.FontDefault = font; 3262 ImGui::PopID(); 3263 } 3264 ImGui::EndCombo(); 3265 } 3266 ImGui::SameLine(); 3267 HelpMarker( 3268 "- Load additional fonts with io.Fonts->AddFontFromFileTTF().\n" 3269 "- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n" 3270 "- Read FAQ and docs/FONTS.txt for more details.\n" 3271 "- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame()."); 3272} 3273 3274void ImGui::ShowStyleEditor(ImGuiStyle* ref) 3275{ 3276 // You can pass in a reference ImGuiStyle structure to compare to, revert to and save to (else it compares to an internally stored reference) 3277 ImGuiStyle& style = ImGui::GetStyle(); 3278 static ImGuiStyle ref_saved_style; 3279 3280 // Default to using internal storage as reference 3281 static bool init = true; 3282 if (init && ref == NULL) 3283 ref_saved_style = style; 3284 init = false; 3285 if (ref == NULL) 3286 ref = &ref_saved_style; 3287 3288 ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.50f); 3289 3290 if (ImGui::ShowStyleSelector("Colors##Selector")) 3291 ref_saved_style = style; 3292 ImGui::ShowFontSelector("Fonts##Selector"); 3293 3294 // Simplified Settings 3295 if (ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f")) 3296 style.GrabRounding = style.FrameRounding; // Make GrabRounding always the same value as FrameRounding 3297 { bool window_border = (style.WindowBorderSize > 0.0f); if (ImGui::Checkbox("WindowBorder", &window_border)) style.WindowBorderSize = window_border ? 1.0f : 0.0f; } 3298 ImGui::SameLine(); 3299 { bool frame_border = (style.FrameBorderSize > 0.0f); if (ImGui::Checkbox("FrameBorder", &frame_border)) style.FrameBorderSize = frame_border ? 1.0f : 0.0f; } 3300 ImGui::SameLine(); 3301 { bool popup_border = (style.PopupBorderSize > 0.0f); if (ImGui::Checkbox("PopupBorder", &popup_border)) style.PopupBorderSize = popup_border ? 1.0f : 0.0f; } 3302 3303 // Save/Revert button 3304 if (ImGui::Button("Save Ref")) 3305 *ref = ref_saved_style = style; 3306 ImGui::SameLine(); 3307 if (ImGui::Button("Revert Ref")) 3308 style = *ref; 3309 ImGui::SameLine(); 3310 HelpMarker("Save/Revert in local non-persistent storage. Default Colors definition are not affected. Use \"Export\" below to save them somewhere."); 3311 3312 ImGui::Separator(); 3313 3314 if (ImGui::BeginTabBar("##tabs", ImGuiTabBarFlags_None)) 3315 { 3316 if (ImGui::BeginTabItem("Sizes")) 3317 { 3318 ImGui::Text("Main"); 3319 ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f"); 3320 ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f"); 3321 ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f"); 3322 ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f"); 3323 ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f"); 3324 ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f"); 3325 ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f"); 3326 ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f"); 3327 ImGui::Text("Borders"); 3328 ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f"); 3329 ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f"); 3330 ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f"); 3331 ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f"); 3332 ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f"); 3333 ImGui::Text("Rounding"); 3334 ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f"); 3335 ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f"); 3336 ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"); 3337 ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f, "%.0f"); 3338 ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f"); 3339 ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f"); 3340 ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f"); 3341 ImGui::Text("Alignment"); 3342 ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); 3343 int window_menu_button_position = style.WindowMenuButtonPosition + 1; 3344 if (ImGui::Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0")) 3345 style.WindowMenuButtonPosition = window_menu_button_position - 1; 3346 ImGui::Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, "Left\0Right\0"); 3347 ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content."); 3348 ImGui::SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content."); 3349 ImGui::Text("Safe Area Padding"); ImGui::SameLine(); HelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured)."); 3350 ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); 3351 ImGui::EndTabItem(); 3352 } 3353 3354 if (ImGui::BeginTabItem("Colors")) 3355 { 3356 static int output_dest = 0; 3357 static bool output_only_modified = true; 3358 if (ImGui::Button("Export")) 3359 { 3360 if (output_dest == 0) 3361 ImGui::LogToClipboard(); 3362 else 3363 ImGui::LogToTTY(); 3364 ImGui::LogText("ImVec4* colors = ImGui::GetStyle().Colors;" IM_NEWLINE); 3365 for (int i = 0; i < ImGuiCol_COUNT; i++) 3366 { 3367 const ImVec4& col = style.Colors[i]; 3368 const char* name = ImGui::GetStyleColorName(i); 3369 if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0) 3370 ImGui::LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE, name, 23 - (int)strlen(name), "", col.x, col.y, col.z, col.w); 3371 } 3372 ImGui::LogFinish(); 3373 } 3374 ImGui::SameLine(); ImGui::SetNextItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0"); 3375 ImGui::SameLine(); ImGui::Checkbox("Only Modified Colors", &output_only_modified); 3376 3377 static ImGuiTextFilter filter; 3378 filter.Draw("Filter colors", ImGui::GetFontSize() * 16); 3379 3380 static ImGuiColorEditFlags alpha_flags = 0; 3381 if (ImGui::RadioButton("Opaque", alpha_flags == 0)) { alpha_flags = 0; } ImGui::SameLine(); 3382 if (ImGui::RadioButton("Alpha", alpha_flags == ImGuiColorEditFlags_AlphaPreview)) { alpha_flags = ImGuiColorEditFlags_AlphaPreview; } ImGui::SameLine(); 3383 if (ImGui::RadioButton("Both", alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } ImGui::SameLine(); 3384 HelpMarker("In the color list:\nLeft-click on colored square to open color picker,\nRight-click to open edit options menu."); 3385 3386 ImGui::BeginChild("##colors", ImVec2(0, 0), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened); 3387 ImGui::PushItemWidth(-160); 3388 for (int i = 0; i < ImGuiCol_COUNT; i++) 3389 { 3390 const char* name = ImGui::GetStyleColorName(i); 3391 if (!filter.PassFilter(name)) 3392 continue; 3393 ImGui::PushID(i); 3394 ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags); 3395 if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0) 3396 { 3397 // Tips: in a real user application, you may want to merge and use an icon font into the main font, so instead of "Save"/"Revert" you'd use icons. 3398 // Read the FAQ and docs/FONTS.txt about using icon fonts. It's really easy and super convenient! 3399 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) ref->Colors[i] = style.Colors[i]; 3400 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) style.Colors[i] = ref->Colors[i]; 3401 } 3402 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); 3403 ImGui::TextUnformatted(name); 3404 ImGui::PopID(); 3405 } 3406 ImGui::PopItemWidth(); 3407 ImGui::EndChild(); 3408 3409 ImGui::EndTabItem(); 3410 } 3411 3412 if (ImGui::BeginTabItem("Fonts")) 3413 { 3414 ImGuiIO& io = ImGui::GetIO(); 3415 ImFontAtlas* atlas = io.Fonts; 3416 HelpMarker("Read FAQ and docs/FONTS.txt for details on font loading."); 3417 ImGui::PushItemWidth(120); 3418 for (int i = 0; i < atlas->Fonts.Size; i++) 3419 { 3420 ImFont* font = atlas->Fonts[i]; 3421 ImGui::PushID(font); 3422 bool font_details_opened = ImGui::TreeNode(font, "Font %d: \"%s\"\n%.2f px, %d glyphs, %d file(s)", i, font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size, font->ConfigDataCount); 3423 ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) { io.FontDefault = font; } 3424 if (font_details_opened) 3425 { 3426 ImGui::PushFont(font); 3427 ImGui::Text("The quick brown fox jumps over the lazy dog"); 3428 ImGui::PopFont(); 3429 ImGui::DragFloat("Font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f"); // Scale only this font 3430 ImGui::SameLine(); HelpMarker("Note than the default embedded font is NOT meant to be scaled.\n\nFont are currently rendered into bitmaps at a given size at the time of building the atlas. You may oversample them to get some flexibility with scaling. You can also render at multiple sizes and select which one to use at runtime.\n\n(Glimmer of hope: the atlas system should hopefully be rewritten in the future to make scaling more natural and automatic.)"); 3431 ImGui::InputFloat("Font offset", &font->DisplayOffset.y, 1, 1, "%.0f"); 3432 ImGui::Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent); 3433 ImGui::Text("Fallback character: '%c' (U+%04X)", font->FallbackChar, font->FallbackChar); 3434 ImGui::Text("Ellipsis character: '%c' (U+%04X)", font->EllipsisChar, font->EllipsisChar); 3435 const float surface_sqrt = sqrtf((float)font->MetricsTotalSurface); 3436 ImGui::Text("Texture Area: about %d px ~%dx%d px", font->MetricsTotalSurface, (int)surface_sqrt, (int)surface_sqrt); 3437 for (int config_i = 0; config_i < font->ConfigDataCount; config_i++) 3438 if (font->ConfigData) 3439 if (const ImFontConfig* cfg = &font->ConfigData[config_i]) 3440 ImGui::BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d", config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH); 3441 if (ImGui::TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size)) 3442 { 3443 // Display all glyphs of the fonts in separate pages of 256 characters 3444 for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256) 3445 { 3446 // Skip ahead if a large bunch of glyphs are not present in the font (test in chunks of 4k) 3447 // This is only a small optimization to reduce the number of iterations when IM_UNICODE_MAX_CODEPOINT is large. 3448 // (if ImWchar==ImWchar32 we will do at least about 272 queries here) 3449 if (!(base & 4095) && font->IsGlyphRangeUnused(base, base + 4095)) 3450 { 3451 base += 4096 - 256; 3452 continue; 3453 } 3454 3455 int count = 0; 3456 for (unsigned int n = 0; n < 256; n++) 3457 count += font->FindGlyphNoFallback((ImWchar)(base + n)) ? 1 : 0; 3458 if (count > 0 && ImGui::TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph")) 3459 { 3460 float cell_size = font->FontSize * 1; 3461 float cell_spacing = style.ItemSpacing.y; 3462 ImVec2 base_pos = ImGui::GetCursorScreenPos(); 3463 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 3464 for (unsigned int n = 0; n < 256; n++) 3465 { 3466 ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing)); 3467 ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size); 3468 const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base + n)); 3469 draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50)); 3470 if (glyph) 3471 font->RenderChar(draw_list, cell_size, cell_p1, ImGui::GetColorU32(ImGuiCol_Text), (ImWchar)(base + n)); // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions available to generate a string. 3472 if (glyph && ImGui::IsMouseHoveringRect(cell_p1, cell_p2)) 3473 { 3474 ImGui::BeginTooltip(); 3475 ImGui::Text("Codepoint: U+%04X", base + n); 3476 ImGui::Separator(); 3477 ImGui::Text("Visible: %d", glyph->Visible); 3478 ImGui::Text("AdvanceX: %.1f", glyph->AdvanceX); 3479 ImGui::Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1); 3480 ImGui::Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1); 3481 ImGui::EndTooltip(); 3482 } 3483 } 3484 ImGui::Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16)); 3485 ImGui::TreePop(); 3486 } 3487 } 3488 ImGui::TreePop(); 3489 } 3490 ImGui::TreePop(); 3491 } 3492 ImGui::PopID(); 3493 } 3494 if (ImGui::TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight)) 3495 { 3496 ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); 3497 ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f); 3498 ImGui::Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0, 0), ImVec2(1, 1), tint_col, border_col); 3499 ImGui::TreePop(); 3500 } 3501 3502 HelpMarker("Those are old settings provided for convenience.\nHowever, the _correct_ way of scaling your UI is currently to reload your font at the designed size, rebuild the font atlas, and call style.ScaleAllSizes() on a reference ImGuiStyle structure."); 3503 static float window_scale = 1.0f; 3504 if (ImGui::DragFloat("window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.2f")) // scale only this window 3505 ImGui::SetWindowFontScale(window_scale); 3506 ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, 0.3f, 2.0f, "%.2f"); // scale everything 3507 ImGui::PopItemWidth(); 3508 3509 ImGui::EndTabItem(); 3510 } 3511 3512 if (ImGui::BeginTabItem("Rendering")) 3513 { 3514 ImGui::Checkbox("Anti-aliased lines", &style.AntiAliasedLines); ImGui::SameLine(); HelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well."); 3515 ImGui::Checkbox("Anti-aliased fill", &style.AntiAliasedFill); 3516 ImGui::PushItemWidth(100); 3517 ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, 10.0f, "%.2f"); 3518 if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f; 3519 ImGui::DragFloat("Circle segment Max Error", &style.CircleSegmentMaxError, 0.01f, 0.10f, 10.0f, "%.2f"); 3520 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. 3521 ImGui::PopItemWidth(); 3522 3523 ImGui::EndTabItem(); 3524 } 3525 3526 ImGui::EndTabBar(); 3527 } 3528 3529 ImGui::PopItemWidth(); 3530} 3531 3532//----------------------------------------------------------------------------- 3533// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar() 3534//----------------------------------------------------------------------------- 3535// - ShowExampleAppMainMenuBar() 3536// - ShowExampleMenuFile() 3537//----------------------------------------------------------------------------- 3538 3539// Demonstrate creating a "main" fullscreen menu bar and populating it. 3540// Note the difference between BeginMainMenuBar() and BeginMenuBar(): 3541// - BeginMenuBar() = menu-bar inside current window we Begin()-ed into (the window needs the ImGuiWindowFlags_MenuBar flag) 3542// - BeginMainMenuBar() = helper to create menu-bar-sized window at the top of the main viewport + call BeginMenuBar() into it. 3543static void ShowExampleAppMainMenuBar() 3544{ 3545 if (ImGui::BeginMainMenuBar()) 3546 { 3547 if (ImGui::BeginMenu("File")) 3548 { 3549 ShowExampleMenuFile(); 3550 ImGui::EndMenu(); 3551 } 3552 if (ImGui::BeginMenu("Edit")) 3553 { 3554 if (ImGui::MenuItem("Undo", "CTRL+Z")) {} 3555 if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) {} // Disabled item 3556 ImGui::Separator(); 3557 if (ImGui::MenuItem("Cut", "CTRL+X")) {} 3558 if (ImGui::MenuItem("Copy", "CTRL+C")) {} 3559 if (ImGui::MenuItem("Paste", "CTRL+V")) {} 3560 ImGui::EndMenu(); 3561 } 3562 ImGui::EndMainMenuBar(); 3563 } 3564} 3565 3566// Note that shortcuts are currently provided for display only (future version will add flags to BeginMenu to process shortcuts) 3567static void ShowExampleMenuFile() 3568{ 3569 ImGui::MenuItem("(dummy menu)", NULL, false, false); 3570 if (ImGui::MenuItem("New")) {} 3571 if (ImGui::MenuItem("Open", "Ctrl+O")) {} 3572 if (ImGui::BeginMenu("Open Recent")) 3573 { 3574 ImGui::MenuItem("fish_hat.c"); 3575 ImGui::MenuItem("fish_hat.inl"); 3576 ImGui::MenuItem("fish_hat.h"); 3577 if (ImGui::BeginMenu("More..")) 3578 { 3579 ImGui::MenuItem("Hello"); 3580 ImGui::MenuItem("Sailor"); 3581 if (ImGui::BeginMenu("Recurse..")) 3582 { 3583 ShowExampleMenuFile(); 3584 ImGui::EndMenu(); 3585 } 3586 ImGui::EndMenu(); 3587 } 3588 ImGui::EndMenu(); 3589 } 3590 if (ImGui::MenuItem("Save", "Ctrl+S")) {} 3591 if (ImGui::MenuItem("Save As..")) {} 3592 3593 ImGui::Separator(); 3594 if (ImGui::BeginMenu("Options")) 3595 { 3596 static bool enabled = true; 3597 ImGui::MenuItem("Enabled", "", &enabled); 3598 ImGui::BeginChild("child", ImVec2(0, 60), true); 3599 for (int i = 0; i < 10; i++) 3600 ImGui::Text("Scrolling Text %d", i); 3601 ImGui::EndChild(); 3602 static float f = 0.5f; 3603 static int n = 0; 3604 ImGui::SliderFloat("Value", &f, 0.0f, 1.0f); 3605 ImGui::InputFloat("Input", &f, 0.1f); 3606 ImGui::Combo("Combo", &n, "Yes\0No\0Maybe\0\0"); 3607 ImGui::EndMenu(); 3608 } 3609 3610 if (ImGui::BeginMenu("Colors")) 3611 { 3612 float sz = ImGui::GetTextLineHeight(); 3613 for (int i = 0; i < ImGuiCol_COUNT; i++) 3614 { 3615 const char* name = ImGui::GetStyleColorName((ImGuiCol)i); 3616 ImVec2 p = ImGui::GetCursorScreenPos(); 3617 ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x+sz, p.y+sz), ImGui::GetColorU32((ImGuiCol)i)); 3618 ImGui::Dummy(ImVec2(sz, sz)); 3619 ImGui::SameLine(); 3620 ImGui::MenuItem(name); 3621 } 3622 ImGui::EndMenu(); 3623 } 3624 3625 // Here we demonstrate appending again to the "Options" menu (which we already created above) 3626 // Of course in this demo it is a little bit silly that this function calls BeginMenu("Options") twice. 3627 // In a real code-base using it would make senses to use this feature from very different code locations. 3628 if (ImGui::BeginMenu("Options")) // <-- Append! 3629 { 3630 static bool b = true; 3631 ImGui::Checkbox("SomeOption", &b); 3632 ImGui::EndMenu(); 3633 } 3634 3635 if (ImGui::BeginMenu("Disabled", false)) // Disabled 3636 { 3637 IM_ASSERT(0); 3638 } 3639 if (ImGui::MenuItem("Checked", NULL, true)) {} 3640 if (ImGui::MenuItem("Quit", "Alt+F4")) {} 3641} 3642 3643//----------------------------------------------------------------------------- 3644// [SECTION] Example App: Debug Console / ShowExampleAppConsole() 3645//----------------------------------------------------------------------------- 3646 3647// Demonstrate creating a simple console window, with scrolling, filtering, completion and history. 3648// For the console example, here we are using a more C++ like approach of declaring a class to hold the data and the functions. 3649struct ExampleAppConsole 3650{ 3651 char InputBuf[256]; 3652 ImVector<char*> Items; 3653 ImVector<const char*> Commands; 3654 ImVector<char*> History; 3655 int HistoryPos; // -1: new line, 0..History.Size-1 browsing history. 3656 ImGuiTextFilter Filter; 3657 bool AutoScroll; 3658 bool ScrollToBottom; 3659 3660 ExampleAppConsole() 3661 { 3662 ClearLog(); 3663 memset(InputBuf, 0, sizeof(InputBuf)); 3664 HistoryPos = -1; 3665 Commands.push_back("HELP"); 3666 Commands.push_back("HISTORY"); 3667 Commands.push_back("CLEAR"); 3668 Commands.push_back("CLASSIFY"); // "classify" is only here to provide an example of "C"+[tab] completing to "CL" and displaying matches. 3669 AutoScroll = true; 3670 ScrollToBottom = false; 3671 AddLog("Welcome to Dear ImGui!"); 3672 } 3673 ~ExampleAppConsole() 3674 { 3675 ClearLog(); 3676 for (int i = 0; i < History.Size; i++) 3677 free(History[i]); 3678 } 3679 3680 // Portable helpers 3681 static int Stricmp(const char* str1, const char* str2) { int d; while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; } return d; } 3682 static int Strnicmp(const char* str1, const char* str2, int n) { int d = 0; while (n > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; n--; } return d; } 3683 static char* Strdup(const char *str) { size_t len = strlen(str) + 1; void* buf = malloc(len); IM_ASSERT(buf); return (char*)memcpy(buf, (const void*)str, len); } 3684 static void Strtrim(char* str) { char* str_end = str + strlen(str); while (str_end > str && str_end[-1] == ' ') str_end--; *str_end = 0; } 3685 3686 void ClearLog() 3687 { 3688 for (int i = 0; i < Items.Size; i++) 3689 free(Items[i]); 3690 Items.clear(); 3691 } 3692 3693 void AddLog(const char* fmt, ...) IM_FMTARGS(2) 3694 { 3695 // FIXME-OPT 3696 char buf[1024]; 3697 va_list args; 3698 va_start(args, fmt); 3699 vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args); 3700 buf[IM_ARRAYSIZE(buf)-1] = 0; 3701 va_end(args); 3702 Items.push_back(Strdup(buf)); 3703 } 3704 3705 void Draw(const char* title, bool* p_open) 3706 { 3707 ImGui::SetNextWindowSize(ImVec2(520,600), ImGuiCond_FirstUseEver); 3708 if (!ImGui::Begin(title, p_open)) 3709 { 3710 ImGui::End(); 3711 return; 3712 } 3713 3714 // As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar. So e.g. IsItemHovered() will return true when hovering the title bar. 3715 // Here we create a context menu only available from the title bar. 3716 if (ImGui::BeginPopupContextItem()) 3717 { 3718 if (ImGui::MenuItem("Close Console")) 3719 *p_open = false; 3720 ImGui::EndPopup(); 3721 } 3722 3723 ImGui::TextWrapped("This example implements a console with basic coloring, completion and history. A more elaborate implementation may want to store entries along with extra data such as timestamp, emitter, etc."); 3724 ImGui::TextWrapped("Enter 'HELP' for help, press TAB to use text completion."); 3725 3726 // TODO: display items starting from the bottom 3727 3728 if (ImGui::SmallButton("Add Dummy Text")) { AddLog("%d some text", Items.Size); AddLog("some more text"); AddLog("display very important message here!"); } ImGui::SameLine(); 3729 if (ImGui::SmallButton("Add Dummy Error")) { AddLog("[error] something went wrong"); } ImGui::SameLine(); 3730 if (ImGui::SmallButton("Clear")) { ClearLog(); } ImGui::SameLine(); 3731 bool copy_to_clipboard = ImGui::SmallButton("Copy"); 3732 //static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); } 3733 3734 ImGui::Separator(); 3735 3736 // Options menu 3737 if (ImGui::BeginPopup("Options")) 3738 { 3739 ImGui::Checkbox("Auto-scroll", &AutoScroll); 3740 ImGui::EndPopup(); 3741 } 3742 3743 // Options, Filter 3744 if (ImGui::Button("Options")) 3745 ImGui::OpenPopup("Options"); 3746 ImGui::SameLine(); 3747 Filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180); 3748 ImGui::Separator(); 3749 3750 const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); // 1 separator, 1 input text 3751 ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), false, ImGuiWindowFlags_HorizontalScrollbar); // Leave room for 1 separator + 1 InputText 3752 if (ImGui::BeginPopupContextWindow()) 3753 { 3754 if (ImGui::Selectable("Clear")) ClearLog(); 3755 ImGui::EndPopup(); 3756 } 3757 3758 // Display every line as a separate entry so we can change their color or add custom widgets. If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end()); 3759 // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping to only process visible items. 3760 // You can seek and display only the lines that are visible using the ImGuiListClipper helper, if your elements are evenly spaced and you have cheap random access to the elements. 3761 // To use the clipper we could replace the 'for (int i = 0; i < Items.Size; i++)' loop with: 3762 // ImGuiListClipper clipper(Items.Size); 3763 // while (clipper.Step()) 3764 // for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) 3765 // However, note that you can not use this code as is if a filter is active because it breaks the 'cheap random-access' property. We would need random-access on the post-filtered list. 3766 // A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices that passed the filtering test, recomputing this array when user changes the filter, 3767 // and appending newly elements as they are inserted. This is left as a task to the user until we can manage to improve this example code! 3768 // If your items are of variable size you may want to implement code similar to what ImGuiListClipper does. Or split your data into fixed height items to allow random-seeking into your list. 3769 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4,1)); // Tighten spacing 3770 if (copy_to_clipboard) 3771 ImGui::LogToClipboard(); 3772 for (int i = 0; i < Items.Size; i++) 3773 { 3774 const char* item = Items[i]; 3775 if (!Filter.PassFilter(item)) 3776 continue; 3777 3778 // Normally you would store more information in your item (e.g. make Items[] an array of structure, store color/type etc.) 3779 bool pop_color = false; 3780 if (strstr(item, "[error]")) { ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.4f, 0.4f, 1.0f)); pop_color = true; } 3781 else if (strncmp(item, "# ", 2) == 0) { ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.8f, 0.6f, 1.0f)); pop_color = true; } 3782 ImGui::TextUnformatted(item); 3783 if (pop_color) 3784 ImGui::PopStyleColor(); 3785 } 3786 if (copy_to_clipboard) 3787 ImGui::LogFinish(); 3788 3789 if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())) 3790 ImGui::SetScrollHereY(1.0f); 3791 ScrollToBottom = false; 3792 3793 ImGui::PopStyleVar(); 3794 ImGui::EndChild(); 3795 ImGui::Separator(); 3796 3797 // Command-line 3798 bool reclaim_focus = false; 3799 if (ImGui::InputText("Input", InputBuf, IM_ARRAYSIZE(InputBuf), ImGuiInputTextFlags_EnterReturnsTrue|ImGuiInputTextFlags_CallbackCompletion|ImGuiInputTextFlags_CallbackHistory, &TextEditCallbackStub, (void*)this)) 3800 { 3801 char* s = InputBuf; 3802 Strtrim(s); 3803 if (s[0]) 3804 ExecCommand(s); 3805 strcpy(s, ""); 3806 reclaim_focus = true; 3807 } 3808 3809 // Auto-focus on window apparition 3810 ImGui::SetItemDefaultFocus(); 3811 if (reclaim_focus) 3812 ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget 3813 3814 ImGui::End(); 3815 } 3816 3817 void ExecCommand(const char* command_line) 3818 { 3819 AddLog("# %s\n", command_line); 3820 3821 // Insert into history. First find match and delete it so it can be pushed to the back. This isn't trying to be smart or optimal. 3822 HistoryPos = -1; 3823 for (int i = History.Size-1; i >= 0; i--) 3824 if (Stricmp(History[i], command_line) == 0) 3825 { 3826 free(History[i]); 3827 History.erase(History.begin() + i); 3828 break; 3829 } 3830 History.push_back(Strdup(command_line)); 3831 3832 // Process command 3833 if (Stricmp(command_line, "CLEAR") == 0) 3834 { 3835 ClearLog(); 3836 } 3837 else if (Stricmp(command_line, "HELP") == 0) 3838 { 3839 AddLog("Commands:"); 3840 for (int i = 0; i < Commands.Size; i++) 3841 AddLog("- %s", Commands[i]); 3842 } 3843 else if (Stricmp(command_line, "HISTORY") == 0) 3844 { 3845 int first = History.Size - 10; 3846 for (int i = first > 0 ? first : 0; i < History.Size; i++) 3847 AddLog("%3d: %s\n", i, History[i]); 3848 } 3849 else 3850 { 3851 AddLog("Unknown command: '%s'\n", command_line); 3852 } 3853 3854 // On commad input, we scroll to bottom even if AutoScroll==false 3855 ScrollToBottom = true; 3856 } 3857 3858 static int TextEditCallbackStub(ImGuiInputTextCallbackData* data) // In C++11 you are better off using lambdas for this sort of forwarding callbacks 3859 { 3860 ExampleAppConsole* console = (ExampleAppConsole*)data->UserData; 3861 return console->TextEditCallback(data); 3862 } 3863 3864 int TextEditCallback(ImGuiInputTextCallbackData* data) 3865 { 3866 //AddLog("cursor: %d, selection: %d-%d", data->CursorPos, data->SelectionStart, data->SelectionEnd); 3867 switch (data->EventFlag) 3868 { 3869 case ImGuiInputTextFlags_CallbackCompletion: 3870 { 3871 // Example of TEXT COMPLETION 3872 3873 // Locate beginning of current word 3874 const char* word_end = data->Buf + data->CursorPos; 3875 const char* word_start = word_end; 3876 while (word_start > data->Buf) 3877 { 3878 const char c = word_start[-1]; 3879 if (c == ' ' || c == '\t' || c == ',' || c == ';') 3880 break; 3881 word_start--; 3882 } 3883 3884 // Build a list of candidates 3885 ImVector<const char*> candidates; 3886 for (int i = 0; i < Commands.Size; i++) 3887 if (Strnicmp(Commands[i], word_start, (int)(word_end-word_start)) == 0) 3888 candidates.push_back(Commands[i]); 3889 3890 if (candidates.Size == 0) 3891 { 3892 // No match 3893 AddLog("No match for \"%.*s\"!\n", (int)(word_end-word_start), word_start); 3894 } 3895 else if (candidates.Size == 1) 3896 { 3897 // Single match. Delete the beginning of the word and replace it entirely so we've got nice casing 3898 data->DeleteChars((int)(word_start-data->Buf), (int)(word_end-word_start)); 3899 data->InsertChars(data->CursorPos, candidates[0]); 3900 data->InsertChars(data->CursorPos, " "); 3901 } 3902 else 3903 { 3904 // Multiple matches. Complete as much as we can, so inputing "C" will complete to "CL" and display "CLEAR" and "CLASSIFY" 3905 int match_len = (int)(word_end - word_start); 3906 for (;;) 3907 { 3908 int c = 0; 3909 bool all_candidates_matches = true; 3910 for (int i = 0; i < candidates.Size && all_candidates_matches; i++) 3911 if (i == 0) 3912 c = toupper(candidates[i][match_len]); 3913 else if (c == 0 || c != toupper(candidates[i][match_len])) 3914 all_candidates_matches = false; 3915 if (!all_candidates_matches) 3916 break; 3917 match_len++; 3918 } 3919 3920 if (match_len > 0) 3921 { 3922 data->DeleteChars((int)(word_start - data->Buf), (int)(word_end-word_start)); 3923 data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len); 3924 } 3925 3926 // List matches 3927 AddLog("Possible matches:\n"); 3928 for (int i = 0; i < candidates.Size; i++) 3929 AddLog("- %s\n", candidates[i]); 3930 } 3931 3932 break; 3933 } 3934 case ImGuiInputTextFlags_CallbackHistory: 3935 { 3936 // Example of HISTORY 3937 const int prev_history_pos = HistoryPos; 3938 if (data->EventKey == ImGuiKey_UpArrow) 3939 { 3940 if (HistoryPos == -1) 3941 HistoryPos = History.Size - 1; 3942 else if (HistoryPos > 0) 3943 HistoryPos--; 3944 } 3945 else if (data->EventKey == ImGuiKey_DownArrow) 3946 { 3947 if (HistoryPos != -1) 3948 if (++HistoryPos >= History.Size) 3949 HistoryPos = -1; 3950 } 3951 3952 // A better implementation would preserve the data on the current input line along with cursor position. 3953 if (prev_history_pos != HistoryPos) 3954 { 3955 const char* history_str = (HistoryPos >= 0) ? History[HistoryPos] : ""; 3956 data->DeleteChars(0, data->BufTextLen); 3957 data->InsertChars(0, history_str); 3958 } 3959 } 3960 } 3961 return 0; 3962 } 3963}; 3964 3965static void ShowExampleAppConsole(bool* p_open) 3966{ 3967 static ExampleAppConsole console; 3968 console.Draw("Example: Console", p_open); 3969} 3970 3971//----------------------------------------------------------------------------- 3972// [SECTION] Example App: Debug Log / ShowExampleAppLog() 3973//----------------------------------------------------------------------------- 3974 3975// Usage: 3976// static ExampleAppLog my_log; 3977// my_log.AddLog("Hello %d world\n", 123); 3978// my_log.Draw("title"); 3979struct ExampleAppLog 3980{ 3981 ImGuiTextBuffer Buf; 3982 ImGuiTextFilter Filter; 3983 ImVector<int> LineOffsets; // Index to lines offset. We maintain this with AddLog() calls, allowing us to have a random access on lines 3984 bool AutoScroll; // Keep scrolling if already at the bottom 3985 3986 ExampleAppLog() 3987 { 3988 AutoScroll = true; 3989 Clear(); 3990 } 3991 3992 void Clear() 3993 { 3994 Buf.clear(); 3995 LineOffsets.clear(); 3996 LineOffsets.push_back(0); 3997 } 3998 3999 void AddLog(const char* fmt, ...) IM_FMTARGS(2) 4000 { 4001 int old_size = Buf.size(); 4002 va_list args; 4003 va_start(args, fmt); 4004 Buf.appendfv(fmt, args); 4005 va_end(args); 4006 for (int new_size = Buf.size(); old_size < new_size; old_size++) 4007 if (Buf[old_size] == '\n') 4008 LineOffsets.push_back(old_size + 1); 4009 } 4010 4011 void Draw(const char* title, bool* p_open = NULL) 4012 { 4013 if (!ImGui::Begin(title, p_open)) 4014 { 4015 ImGui::End(); 4016 return; 4017 } 4018 4019 // Options menu 4020 if (ImGui::BeginPopup("Options")) 4021 { 4022 ImGui::Checkbox("Auto-scroll", &AutoScroll); 4023 ImGui::EndPopup(); 4024 } 4025 4026 // Main window 4027 if (ImGui::Button("Options")) 4028 ImGui::OpenPopup("Options"); 4029 ImGui::SameLine(); 4030 bool clear = ImGui::Button("Clear"); 4031 ImGui::SameLine(); 4032 bool copy = ImGui::Button("Copy"); 4033 ImGui::SameLine(); 4034 Filter.Draw("Filter", -100.0f); 4035 4036 ImGui::Separator(); 4037 ImGui::BeginChild("scrolling", ImVec2(0,0), false, ImGuiWindowFlags_HorizontalScrollbar); 4038 4039 if (clear) 4040 Clear(); 4041 if (copy) 4042 ImGui::LogToClipboard(); 4043 4044 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); 4045 const char* buf = Buf.begin(); 4046 const char* buf_end = Buf.end(); 4047 if (Filter.IsActive()) 4048 { 4049 // In this example we don't use the clipper when Filter is enabled. 4050 // This is because we don't have a random access on the result on our filter. 4051 // A real application processing logs with ten of thousands of entries may want to store the result of search/filter. 4052 // especially if the filtering function is not trivial (e.g. reg-exp). 4053 for (int line_no = 0; line_no < LineOffsets.Size; line_no++) 4054 { 4055 const char* line_start = buf + LineOffsets[line_no]; 4056 const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; 4057 if (Filter.PassFilter(line_start, line_end)) 4058 ImGui::TextUnformatted(line_start, line_end); 4059 } 4060 } 4061 else 4062 { 4063 // The simplest and easy way to display the entire buffer: 4064 // ImGui::TextUnformatted(buf_begin, buf_end); 4065 // And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward to skip non-visible lines. 4066 // Here we instead demonstrate using the clipper to only process lines that are within the visible area. 4067 // If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them on your side is recommended. 4068 // Using ImGuiListClipper requires A) random access into your data, and B) items all being the same height, 4069 // both of which we can handle since we an array pointing to the beginning of each line of text. 4070 // When using the filter (in the block of code above) we don't have random access into the data to display anymore, which is why we don't use the clipper. 4071 // Storing or skimming through the search result would make it possible (and would be recommended if you want to search through tens of thousands of entries) 4072 ImGuiListClipper clipper; 4073 clipper.Begin(LineOffsets.Size); 4074 while (clipper.Step()) 4075 { 4076 for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++) 4077 { 4078 const char* line_start = buf + LineOffsets[line_no]; 4079 const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; 4080 ImGui::TextUnformatted(line_start, line_end); 4081 } 4082 } 4083 clipper.End(); 4084 } 4085 ImGui::PopStyleVar(); 4086 4087 if (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) 4088 ImGui::SetScrollHereY(1.0f); 4089 4090 ImGui::EndChild(); 4091 ImGui::End(); 4092 } 4093}; 4094 4095// Demonstrate creating a simple log window with basic filtering. 4096static void ShowExampleAppLog(bool* p_open) 4097{ 4098 static ExampleAppLog log; 4099 4100 // For the demo: add a debug button _BEFORE_ the normal log window contents 4101 // We take advantage of a rarely used feature: multiple calls to Begin()/End() are appending to the _same_ window. 4102 // Most of the contents of the window will be added by the log.Draw() call. 4103 ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver); 4104 ImGui::Begin("Example: Log", p_open); 4105 if (ImGui::SmallButton("[Debug] Add 5 entries")) 4106 { 4107 static int counter = 0; 4108 for (int n = 0; n < 5; n++) 4109 { 4110 const char* categories[3] = { "info", "warn", "error" }; 4111 const char* words[] = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" }; 4112 log.AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n", 4113 ImGui::GetFrameCount(), categories[counter % IM_ARRAYSIZE(categories)], ImGui::GetTime(), words[counter % IM_ARRAYSIZE(words)]); 4114 counter++; 4115 } 4116 } 4117 ImGui::End(); 4118 4119 // Actually call in the regular Log helper (which will Begin() into the same window as we just did) 4120 log.Draw("Example: Log", p_open); 4121} 4122 4123//----------------------------------------------------------------------------- 4124// [SECTION] Example App: Simple Layout / ShowExampleAppLayout() 4125//----------------------------------------------------------------------------- 4126 4127// Demonstrate create a window with multiple child windows. 4128static void ShowExampleAppLayout(bool* p_open) 4129{ 4130 ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiCond_FirstUseEver); 4131 if (ImGui::Begin("Example: Simple layout", p_open, ImGuiWindowFlags_MenuBar)) 4132 { 4133 if (ImGui::BeginMenuBar()) 4134 { 4135 if (ImGui::BeginMenu("File")) 4136 { 4137 if (ImGui::MenuItem("Close")) *p_open = false; 4138 ImGui::EndMenu(); 4139 } 4140 ImGui::EndMenuBar(); 4141 } 4142 4143 // left 4144 static int selected = 0; 4145 ImGui::BeginChild("left pane", ImVec2(150, 0), true); 4146 for (int i = 0; i < 100; i++) 4147 { 4148 char label[128]; 4149 sprintf(label, "MyObject %d", i); 4150 if (ImGui::Selectable(label, selected == i)) 4151 selected = i; 4152 } 4153 ImGui::EndChild(); 4154 ImGui::SameLine(); 4155 4156 // right 4157 ImGui::BeginGroup(); 4158 ImGui::BeginChild("item view", ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us 4159 ImGui::Text("MyObject: %d", selected); 4160 ImGui::Separator(); 4161 if (ImGui::BeginTabBar("##Tabs", ImGuiTabBarFlags_None)) 4162 { 4163 if (ImGui::BeginTabItem("Description")) 4164 { 4165 ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "); 4166 ImGui::EndTabItem(); 4167 } 4168 if (ImGui::BeginTabItem("Details")) 4169 { 4170 ImGui::Text("ID: 0123456789"); 4171 ImGui::EndTabItem(); 4172 } 4173 ImGui::EndTabBar(); 4174 } 4175 ImGui::EndChild(); 4176 if (ImGui::Button("Revert")) {} 4177 ImGui::SameLine(); 4178 if (ImGui::Button("Save")) {} 4179 ImGui::EndGroup(); 4180 } 4181 ImGui::End(); 4182} 4183 4184//----------------------------------------------------------------------------- 4185// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor() 4186//----------------------------------------------------------------------------- 4187 4188// Demonstrate create a simple property editor. 4189static void ShowExampleAppPropertyEditor(bool* p_open) 4190{ 4191 ImGui::SetNextWindowSize(ImVec2(430,450), ImGuiCond_FirstUseEver); 4192 if (!ImGui::Begin("Example: Property editor", p_open)) 4193 { 4194 ImGui::End(); 4195 return; 4196 } 4197 4198 HelpMarker("This example shows how you may implement a property editor using two columns.\nAll objects/fields data are dummies here.\nRemember that in many simple cases, you can use ImGui::SameLine(xxx) to position\nyour cursor horizontally instead of using the Columns() API."); 4199 4200 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2,2)); 4201 ImGui::Columns(2); 4202 ImGui::Separator(); 4203 4204 struct funcs 4205 { 4206 static void ShowDummyObject(const char* prefix, int uid) 4207 { 4208 ImGui::PushID(uid); // Use object uid as identifier. Most commonly you could also use the object pointer as a base ID. 4209 ImGui::AlignTextToFramePadding(); // Text and Tree nodes are less high than regular widgets, here we add vertical spacing to make the tree lines equal high. 4210 bool node_open = ImGui::TreeNode("Object", "%s_%u", prefix, uid); 4211 ImGui::NextColumn(); 4212 ImGui::AlignTextToFramePadding(); 4213 ImGui::Text("my sailor is rich"); 4214 ImGui::NextColumn(); 4215 if (node_open) 4216 { 4217 static float dummy_members[8] = { 0.0f,0.0f,1.0f,3.1416f,100.0f,999.0f }; 4218 for (int i = 0; i < 8; i++) 4219 { 4220 ImGui::PushID(i); // Use field index as identifier. 4221 if (i < 2) 4222 { 4223 ShowDummyObject("Child", 424242); 4224 } 4225 else 4226 { 4227 // Here we use a TreeNode to highlight on hover (we could use e.g. Selectable as well) 4228 ImGui::AlignTextToFramePadding(); 4229 ImGui::TreeNodeEx("Field", ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_Bullet, "Field_%d", i); 4230 ImGui::NextColumn(); 4231 ImGui::SetNextItemWidth(-1); 4232 if (i >= 5) 4233 ImGui::InputFloat("##value", &dummy_members[i], 1.0f); 4234 else 4235 ImGui::DragFloat("##value", &dummy_members[i], 0.01f); 4236 ImGui::NextColumn(); 4237 } 4238 ImGui::PopID(); 4239 } 4240 ImGui::TreePop(); 4241 } 4242 ImGui::PopID(); 4243 } 4244 }; 4245 4246 // Iterate dummy objects with dummy members (all the same data) 4247 for (int obj_i = 0; obj_i < 3; obj_i++) 4248 funcs::ShowDummyObject("Object", obj_i); 4249 4250 ImGui::Columns(1); 4251 ImGui::Separator(); 4252 ImGui::PopStyleVar(); 4253 ImGui::End(); 4254} 4255 4256//----------------------------------------------------------------------------- 4257// [SECTION] Example App: Long Text / ShowExampleAppLongText() 4258//----------------------------------------------------------------------------- 4259 4260// Demonstrate/test rendering huge amount of text, and the incidence of clipping. 4261static void ShowExampleAppLongText(bool* p_open) 4262{ 4263 ImGui::SetNextWindowSize(ImVec2(520,600), ImGuiCond_FirstUseEver); 4264 if (!ImGui::Begin("Example: Long text display", p_open)) 4265 { 4266 ImGui::End(); 4267 return; 4268 } 4269 4270 static int test_type = 0; 4271 static ImGuiTextBuffer log; 4272 static int lines = 0; 4273 ImGui::Text("Printing unusually long amount of text."); 4274 ImGui::Combo("Test type", &test_type, "Single call to TextUnformatted()\0Multiple calls to Text(), clipped\0Multiple calls to Text(), not clipped (slow)\0"); 4275 ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size()); 4276 if (ImGui::Button("Clear")) { log.clear(); lines = 0; } 4277 ImGui::SameLine(); 4278 if (ImGui::Button("Add 1000 lines")) 4279 { 4280 for (int i = 0; i < 1000; i++) 4281 log.appendf("%i The quick brown fox jumps over the lazy dog\n", lines+i); 4282 lines += 1000; 4283 } 4284 ImGui::BeginChild("Log"); 4285 switch (test_type) 4286 { 4287 case 0: 4288 // Single call to TextUnformatted() with a big buffer 4289 ImGui::TextUnformatted(log.begin(), log.end()); 4290 break; 4291 case 1: 4292 { 4293 // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper. 4294 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0)); 4295 ImGuiListClipper clipper(lines); 4296 while (clipper.Step()) 4297 for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) 4298 ImGui::Text("%i The quick brown fox jumps over the lazy dog", i); 4299 ImGui::PopStyleVar(); 4300 break; 4301 } 4302 case 2: 4303 // Multiple calls to Text(), not clipped (slow) 4304 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0)); 4305 for (int i = 0; i < lines; i++) 4306 ImGui::Text("%i The quick brown fox jumps over the lazy dog", i); 4307 ImGui::PopStyleVar(); 4308 break; 4309 } 4310 ImGui::EndChild(); 4311 ImGui::End(); 4312} 4313 4314//----------------------------------------------------------------------------- 4315// [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize() 4316//----------------------------------------------------------------------------- 4317 4318// Demonstrate creating a window which gets auto-resized according to its content. 4319static void ShowExampleAppAutoResize(bool* p_open) 4320{ 4321 if (!ImGui::Begin("Example: Auto-resizing window", p_open, ImGuiWindowFlags_AlwaysAutoResize)) 4322 { 4323 ImGui::End(); 4324 return; 4325 } 4326 4327 static int lines = 10; 4328 ImGui::Text("Window will resize every-frame to the size of its content.\nNote that you probably don't want to query the window size to\noutput your content because that would create a feedback loop."); 4329 ImGui::SliderInt("Number of lines", &lines, 1, 20); 4330 for (int i = 0; i < lines; i++) 4331 ImGui::Text("%*sThis is line %d", i * 4, "", i); // Pad with space to extend size horizontally 4332 ImGui::End(); 4333} 4334 4335//----------------------------------------------------------------------------- 4336// [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize() 4337//----------------------------------------------------------------------------- 4338 4339// Demonstrate creating a window with custom resize constraints. 4340static void ShowExampleAppConstrainedResize(bool* p_open) 4341{ 4342 struct CustomConstraints // Helper functions to demonstrate programmatic constraints 4343 { 4344 static void Square(ImGuiSizeCallbackData* data) { data->DesiredSize.x = data->DesiredSize.y = (data->DesiredSize.x > data->DesiredSize.y ? data->DesiredSize.x : data->DesiredSize.y); } 4345 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); } 4346 }; 4347 4348 static bool auto_resize = false; 4349 static int type = 0; 4350 static int display_lines = 10; 4351 if (type == 0) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, FLT_MAX)); // Vertical only 4352 if (type == 1) ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(FLT_MAX, -1)); // Horizontal only 4353 if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100 4354 if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)); // Width 400-500 4355 if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, 500)); // Height 400-500 4356 if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square 4357 if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)(intptr_t)100); // Fixed Step 4358 4359 ImGuiWindowFlags flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0; 4360 if (ImGui::Begin("Example: Constrained Resize", p_open, flags)) 4361 { 4362 const char* desc[] = 4363 { 4364 "Resize vertical only", 4365 "Resize horizontal only", 4366 "Width > 100, Height > 100", 4367 "Width 400-500", 4368 "Height 400-500", 4369 "Custom: Always Square", 4370 "Custom: Fixed Steps (100)", 4371 }; 4372 if (ImGui::Button("200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine(); 4373 if (ImGui::Button("500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine(); 4374 if (ImGui::Button("800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); } 4375 ImGui::SetNextItemWidth(200); 4376 ImGui::Combo("Constraint", &type, desc, IM_ARRAYSIZE(desc)); 4377 ImGui::SetNextItemWidth(200); 4378 ImGui::DragInt("Lines", &display_lines, 0.2f, 1, 100); 4379 ImGui::Checkbox("Auto-resize", &auto_resize); 4380 for (int i = 0; i < display_lines; i++) 4381 ImGui::Text("%*sHello, sailor! Making this line long enough for the example.", i * 4, ""); 4382 } 4383 ImGui::End(); 4384} 4385 4386//----------------------------------------------------------------------------- 4387// [SECTION] Example App: Simple Overlay / ShowExampleAppSimpleOverlay() 4388//----------------------------------------------------------------------------- 4389 4390// Demonstrate creating a simple static window with no decoration + a context-menu to choose which corner of the screen to use. 4391static void ShowExampleAppSimpleOverlay(bool* p_open) 4392{ 4393 const float DISTANCE = 10.0f; 4394 static int corner = 0; 4395 ImGuiIO& io = ImGui::GetIO(); 4396 if (corner != -1) 4397 { 4398 ImVec2 window_pos = ImVec2((corner & 1) ? io.DisplaySize.x - DISTANCE : DISTANCE, (corner & 2) ? io.DisplaySize.y - DISTANCE : DISTANCE); 4399 ImVec2 window_pos_pivot = ImVec2((corner & 1) ? 1.0f : 0.0f, (corner & 2) ? 1.0f : 0.0f); 4400 ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot); 4401 } 4402 ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background 4403 if (ImGui::Begin("Example: Simple overlay", p_open, (corner != -1 ? ImGuiWindowFlags_NoMove : 0) | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav)) 4404 { 4405 ImGui::Text("Simple overlay\n" "in the corner of the screen.\n" "(right-click to change position)"); 4406 ImGui::Separator(); 4407 if (ImGui::IsMousePosValid()) 4408 ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y); 4409 else 4410 ImGui::Text("Mouse Position: <invalid>"); 4411 if (ImGui::BeginPopupContextWindow()) 4412 { 4413 if (ImGui::MenuItem("Custom", NULL, corner == -1)) corner = -1; 4414 if (ImGui::MenuItem("Top-left", NULL, corner == 0)) corner = 0; 4415 if (ImGui::MenuItem("Top-right", NULL, corner == 1)) corner = 1; 4416 if (ImGui::MenuItem("Bottom-left", NULL, corner == 2)) corner = 2; 4417 if (ImGui::MenuItem("Bottom-right", NULL, corner == 3)) corner = 3; 4418 if (p_open && ImGui::MenuItem("Close")) *p_open = false; 4419 ImGui::EndPopup(); 4420 } 4421 } 4422 ImGui::End(); 4423} 4424 4425//----------------------------------------------------------------------------- 4426// [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles() 4427//----------------------------------------------------------------------------- 4428 4429// Demonstrate using "##" and "###" in identifiers to manipulate ID generation. 4430// This apply to all regular items as well. Read FAQ section "How can I have multiple widgets with the same label? Can I have widget without a label? (Yes). A primer on the purpose of labels/IDs." for details. 4431static void ShowExampleAppWindowTitles(bool*) 4432{ 4433 // By default, Windows are uniquely identified by their title. 4434 // You can use the "##" and "###" markers to manipulate the display/ID. 4435 4436 // Using "##" to display same title but have unique identifier. 4437 ImGui::SetNextWindowPos(ImVec2(100, 100), ImGuiCond_FirstUseEver); 4438 ImGui::Begin("Same title as another window##1"); 4439 ImGui::Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique."); 4440 ImGui::End(); 4441 4442 ImGui::SetNextWindowPos(ImVec2(100, 200), ImGuiCond_FirstUseEver); 4443 ImGui::Begin("Same title as another window##2"); 4444 ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique."); 4445 ImGui::End(); 4446 4447 // Using "###" to display a changing title but keep a static identifier "AnimatedTitle" 4448 char buf[128]; 4449 sprintf(buf, "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime() / 0.25f) & 3], ImGui::GetFrameCount()); 4450 ImGui::SetNextWindowPos(ImVec2(100, 300), ImGuiCond_FirstUseEver); 4451 ImGui::Begin(buf); 4452 ImGui::Text("This window has a changing title."); 4453 ImGui::End(); 4454} 4455 4456//----------------------------------------------------------------------------- 4457// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering() 4458//----------------------------------------------------------------------------- 4459 4460// Demonstrate using the low-level ImDrawList to draw custom shapes. 4461static void ShowExampleAppCustomRendering(bool* p_open) 4462{ 4463 if (!ImGui::Begin("Example: Custom rendering", p_open)) 4464 { 4465 ImGui::End(); 4466 return; 4467 } 4468 4469 // Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of overloaded operators, etc. 4470 // Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your types and ImVec2/ImVec4. 4471 // ImGui defines overloaded operators but they are internal to imgui.cpp and not exposed outside (to avoid messing with your types) 4472 // In this example we are not using the maths operators! 4473 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 4474 4475 if (ImGui::BeginTabBar("##TabBar")) 4476 { 4477 if (ImGui::BeginTabItem("Primitives")) 4478 { 4479 ImGui::PushItemWidth(-ImGui::GetFontSize() * 10); 4480 4481 // Draw gradients 4482 // (note that those are currently exacerbating our sRGB/Linear issues) 4483 ImGui::Text("Gradients"); 4484 ImVec2 gradient_size = ImVec2(ImGui::CalcItemWidth(), ImGui::GetFrameHeight()); 4485 { 4486 ImVec2 p = ImGui::GetCursorScreenPos(); 4487 ImU32 col_a = ImGui::GetColorU32(ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); 4488 ImU32 col_b = ImGui::GetColorU32(ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); 4489 draw_list->AddRectFilledMultiColor(p, ImVec2(p.x + gradient_size.x, p.y + gradient_size.y), col_a, col_b, col_b, col_a); 4490 ImGui::InvisibleButton("##gradient1", gradient_size); 4491 } 4492 { 4493 ImVec2 p = ImGui::GetCursorScreenPos(); 4494 ImU32 col_a = ImGui::GetColorU32(ImVec4(0.0f, 1.0f, 0.0f, 1.0f)); 4495 ImU32 col_b = ImGui::GetColorU32(ImVec4(1.0f, 0.0f, 0.0f, 1.0f)); 4496 draw_list->AddRectFilledMultiColor(p, ImVec2(p.x + gradient_size.x, p.y + gradient_size.y), col_a, col_b, col_b, col_a); 4497 ImGui::InvisibleButton("##gradient2", gradient_size); 4498 } 4499 4500 // Draw a bunch of primitives 4501 ImGui::Text("All primitives"); 4502 static float sz = 36.0f; 4503 static float thickness = 3.0f; 4504 static int ngon_sides = 6; 4505 static bool circle_segments_override = false; 4506 static int circle_segments_override_v = 12; 4507 static ImVec4 colf = ImVec4(1.0f, 1.0f, 0.4f, 1.0f); 4508 ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 72.0f, "%.0f"); 4509 ImGui::DragFloat("Thickness", &thickness, 0.05f, 1.0f, 8.0f, "%.02f"); 4510 ImGui::SliderInt("N-gon sides", &ngon_sides, 3, 12); 4511 ImGui::Checkbox("##circlesegmentoverride", &circle_segments_override); 4512 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); 4513 if (ImGui::SliderInt("Circle segments", &circle_segments_override_v, 3, 40)) 4514 circle_segments_override = true; 4515 ImGui::ColorEdit4("Color", &colf.x); 4516 const ImVec2 p = ImGui::GetCursorScreenPos(); 4517 const ImU32 col = ImColor(colf); 4518 const float spacing = 10.0f; 4519 const ImDrawCornerFlags corners_none = 0; 4520 const ImDrawCornerFlags corners_all = ImDrawCornerFlags_All; 4521 const ImDrawCornerFlags corners_tl_br = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotRight; 4522 const int circle_segments = circle_segments_override ? circle_segments_override_v : 0; 4523 float x = p.x + 4.0f, y = p.y + 4.0f; 4524 for (int n = 0; n < 2; n++) 4525 { 4526 // First line uses a thickness of 1.0f, second line uses the configurable thickness 4527 float th = (n == 0) ? 1.0f : thickness; 4528 draw_list->AddNgon(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, ngon_sides, th); x += sz + spacing; // N-gon 4529 draw_list->AddCircle(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments, th); x += sz + spacing; // Circle 4530 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0f, corners_none, th); x += sz + spacing; // Square 4531 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_all, th); x += sz + spacing; // Square with all rounded corners 4532 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_tl_br, th); x += sz + spacing; // Square with two rounded corners 4533 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 4534 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 4535 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!) 4536 draw_list->AddLine(ImVec2(x, y), ImVec2(x, y + sz), col, th); x += spacing; // Vertical line (note: drawing a filled rectangle will be faster!) 4537 draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y + sz), col, th); x += sz + spacing; // Diagonal line 4538 draw_list->AddBezierCurve(ImVec2(x, y), ImVec2(x + sz*1.3f, y + sz*0.3f), ImVec2(x + sz - sz*1.3f, y + sz - sz*0.3f), ImVec2(x + sz, y + sz), col, th); 4539 x = p.x + 4; 4540 y += sz + spacing; 4541 } 4542 draw_list->AddNgonFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz*0.5f, col, ngon_sides); x += sz + spacing; // N-gon 4543 draw_list->AddCircleFilled(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments);x += sz + spacing; // Circle 4544 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col); x += sz + spacing; // Square 4545 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f); x += sz + spacing; // Square with all rounded corners 4546 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 4547 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 4548 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 4549 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) 4550 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) 4551 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + 1, y + 1), col); x += sz; // Pixel (faster than AddLine) 4552 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)); 4553 ImGui::Dummy(ImVec2((sz + spacing) * 9.8f, (sz + spacing) * 3)); 4554 4555 ImGui::PopItemWidth(); 4556 ImGui::EndTabItem(); 4557 } 4558 4559 if (ImGui::BeginTabItem("Canvas")) 4560 { 4561 static ImVector<ImVec2> points; 4562 static bool adding_line = false; 4563 if (ImGui::Button("Clear")) points.clear(); 4564 if (points.Size >= 2) { ImGui::SameLine(); if (ImGui::Button("Undo")) { points.pop_back(); points.pop_back(); } } 4565 ImGui::Text("Left-click and drag to add lines,\nRight-click to undo"); 4566 4567 // Here we are using InvisibleButton() as a convenience to 1) advance the cursor and 2) allows us to use IsItemHovered() 4568 // But you can also draw directly and poll mouse/keyboard by yourself. You can manipulate the cursor using GetCursorPos() and SetCursorPos(). 4569 // If you only use the ImDrawList API, you can notify the owner window of its extends by using SetCursorPos(max). 4570 ImVec2 canvas_pos = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates! 4571 ImVec2 canvas_size = ImGui::GetContentRegionAvail(); // Resize canvas to what's available 4572 if (canvas_size.x < 50.0f) canvas_size.x = 50.0f; 4573 if (canvas_size.y < 50.0f) canvas_size.y = 50.0f; 4574 draw_list->AddRectFilledMultiColor(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), IM_COL32(50, 50, 50, 255), IM_COL32(50, 50, 60, 255), IM_COL32(60, 60, 70, 255), IM_COL32(50, 50, 60, 255)); 4575 draw_list->AddRect(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), IM_COL32(255, 255, 255, 255)); 4576 4577 bool adding_preview = false; 4578 ImGui::InvisibleButton("canvas", canvas_size); 4579 ImVec2 mouse_pos_in_canvas = ImVec2(ImGui::GetIO().MousePos.x - canvas_pos.x, ImGui::GetIO().MousePos.y - canvas_pos.y); 4580 if (adding_line) 4581 { 4582 adding_preview = true; 4583 points.push_back(mouse_pos_in_canvas); 4584 if (!ImGui::IsMouseDown(0)) 4585 adding_line = adding_preview = false; 4586 } 4587 if (ImGui::IsItemHovered()) 4588 { 4589 if (!adding_line && ImGui::IsMouseClicked(0)) 4590 { 4591 points.push_back(mouse_pos_in_canvas); 4592 adding_line = true; 4593 } 4594 if (ImGui::IsMouseClicked(1) && !points.empty()) 4595 { 4596 adding_line = adding_preview = false; 4597 points.pop_back(); 4598 points.pop_back(); 4599 } 4600 } 4601 draw_list->PushClipRect(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), true); // clip lines within the canvas (if we resize it, etc.) 4602 for (int i = 0; i < points.Size - 1; i += 2) 4603 draw_list->AddLine(ImVec2(canvas_pos.x + points[i].x, canvas_pos.y + points[i].y), ImVec2(canvas_pos.x + points[i + 1].x, canvas_pos.y + points[i + 1].y), IM_COL32(255, 255, 0, 255), 2.0f); 4604 draw_list->PopClipRect(); 4605 if (adding_preview) 4606 points.pop_back(); 4607 ImGui::EndTabItem(); 4608 } 4609 4610 if (ImGui::BeginTabItem("BG/FG draw lists")) 4611 { 4612 static bool draw_bg = true; 4613 static bool draw_fg = true; 4614 ImGui::Checkbox("Draw in Background draw list", &draw_bg); 4615 ImGui::SameLine(); HelpMarker("The Background draw list will be rendered below every Dear ImGui windows."); 4616 ImGui::Checkbox("Draw in Foreground draw list", &draw_fg); 4617 ImGui::SameLine(); HelpMarker("The Foreground draw list will be rendered over every Dear ImGui windows."); 4618 ImVec2 window_pos = ImGui::GetWindowPos(); 4619 ImVec2 window_size = ImGui::GetWindowSize(); 4620 ImVec2 window_center = ImVec2(window_pos.x + window_size.x * 0.5f, window_pos.y + window_size.y * 0.5f); 4621 if (draw_bg) 4622 ImGui::GetBackgroundDrawList()->AddCircle(window_center, window_size.x * 0.6f, IM_COL32(255, 0, 0, 200), 0, 10+4); 4623 if (draw_fg) 4624 ImGui::GetForegroundDrawList()->AddCircle(window_center, window_size.y * 0.6f, IM_COL32(0, 255, 0, 200), 0, 10); 4625 ImGui::EndTabItem(); 4626 } 4627 4628 ImGui::EndTabBar(); 4629 } 4630 4631 ImGui::End(); 4632} 4633 4634//----------------------------------------------------------------------------- 4635// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments() 4636//----------------------------------------------------------------------------- 4637 4638// Simplified structure to mimic a Document model 4639struct MyDocument 4640{ 4641 const char* Name; // Document title 4642 bool Open; // Set when the document is open (in this demo, we keep an array of all available documents to simplify the demo) 4643 bool OpenPrev; // Copy of Open from last update. 4644 bool Dirty; // Set when the document has been modified 4645 bool WantClose; // Set when the document 4646 ImVec4 Color; // An arbitrary variable associated to the document 4647 4648 MyDocument(const char* name, bool open = true, const ImVec4& color = ImVec4(1.0f,1.0f,1.0f,1.0f)) 4649 { 4650 Name = name; 4651 Open = OpenPrev = open; 4652 Dirty = false; 4653 WantClose = false; 4654 Color = color; 4655 } 4656 void DoOpen() { Open = true; } 4657 void DoQueueClose() { WantClose = true; } 4658 void DoForceClose() { Open = false; Dirty = false; } 4659 void DoSave() { Dirty = false; } 4660 4661 // Display dummy contents for the Document 4662 static void DisplayContents(MyDocument* doc) 4663 { 4664 ImGui::PushID(doc); 4665 ImGui::Text("Document \"%s\"", doc->Name); 4666 ImGui::PushStyleColor(ImGuiCol_Text, doc->Color); 4667 ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."); 4668 ImGui::PopStyleColor(); 4669 if (ImGui::Button("Modify", ImVec2(100, 0))) 4670 doc->Dirty = true; 4671 ImGui::SameLine(); 4672 if (ImGui::Button("Save", ImVec2(100, 0))) 4673 doc->DoSave(); 4674 ImGui::ColorEdit3("color", &doc->Color.x); // Useful to test drag and drop and hold-dragged-to-open-tab behavior. 4675 ImGui::PopID(); 4676 } 4677 4678 // Display context menu for the Document 4679 static void DisplayContextMenu(MyDocument* doc) 4680 { 4681 if (!ImGui::BeginPopupContextItem()) 4682 return; 4683 4684 char buf[256]; 4685 sprintf(buf, "Save %s", doc->Name); 4686 if (ImGui::MenuItem(buf, "CTRL+S", false, doc->Open)) 4687 doc->DoSave(); 4688 if (ImGui::MenuItem("Close", "CTRL+W", false, doc->Open)) 4689 doc->DoQueueClose(); 4690 ImGui::EndPopup(); 4691 } 4692}; 4693 4694struct ExampleAppDocuments 4695{ 4696 ImVector<MyDocument> Documents; 4697 4698 ExampleAppDocuments() 4699 { 4700 Documents.push_back(MyDocument("Lettuce", true, ImVec4(0.4f, 0.8f, 0.4f, 1.0f))); 4701 Documents.push_back(MyDocument("Eggplant", true, ImVec4(0.8f, 0.5f, 1.0f, 1.0f))); 4702 Documents.push_back(MyDocument("Carrot", true, ImVec4(1.0f, 0.8f, 0.5f, 1.0f))); 4703 Documents.push_back(MyDocument("Tomato", false, ImVec4(1.0f, 0.3f, 0.4f, 1.0f))); 4704 Documents.push_back(MyDocument("A Rather Long Title", false)); 4705 Documents.push_back(MyDocument("Some Document", false)); 4706 } 4707}; 4708 4709// [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface. 4710// If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo, as opposed 4711// to clicking on the regular tab closing button) and stops being submitted, it will take a frame for the tab bar to notice its absence. 4712// During this frame there will be a gap in the tab bar, and if the tab that has disappeared was the selected one, the tab bar 4713// will report no selected tab during the frame. This will effectively give the impression of a flicker for one frame. 4714// We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch. 4715// Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag. 4716static void NotifyOfDocumentsClosedElsewhere(ExampleAppDocuments& app) 4717{ 4718 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) 4719 { 4720 MyDocument* doc = &app.Documents[doc_n]; 4721 if (!doc->Open && doc->OpenPrev) 4722 ImGui::SetTabItemClosed(doc->Name); 4723 doc->OpenPrev = doc->Open; 4724 } 4725} 4726 4727void ShowExampleAppDocuments(bool* p_open) 4728{ 4729 static ExampleAppDocuments app; 4730 4731 // Options 4732 static bool opt_reorderable = true; 4733 static ImGuiTabBarFlags opt_fitting_flags = ImGuiTabBarFlags_FittingPolicyDefault_; 4734 4735 bool window_contents_visible = ImGui::Begin("Example: Documents", p_open, ImGuiWindowFlags_MenuBar); 4736 if (!window_contents_visible) 4737 { 4738 ImGui::End(); 4739 return; 4740 } 4741 4742 // Menu 4743 if (ImGui::BeginMenuBar()) 4744 { 4745 if (ImGui::BeginMenu("File")) 4746 { 4747 int open_count = 0; 4748 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) 4749 open_count += app.Documents[doc_n].Open ? 1 : 0; 4750 4751 if (ImGui::BeginMenu("Open", open_count < app.Documents.Size)) 4752 { 4753 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) 4754 { 4755 MyDocument* doc = &app.Documents[doc_n]; 4756 if (!doc->Open) 4757 if (ImGui::MenuItem(doc->Name)) 4758 doc->DoOpen(); 4759 } 4760 ImGui::EndMenu(); 4761 } 4762 if (ImGui::MenuItem("Close All Documents", NULL, false, open_count > 0)) 4763 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) 4764 app.Documents[doc_n].DoQueueClose(); 4765 if (ImGui::MenuItem("Exit", "Alt+F4")) {} 4766 ImGui::EndMenu(); 4767 } 4768 ImGui::EndMenuBar(); 4769 } 4770 4771 // [Debug] List documents with one checkbox for each 4772 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) 4773 { 4774 MyDocument* doc = &app.Documents[doc_n]; 4775 if (doc_n > 0) 4776 ImGui::SameLine(); 4777 ImGui::PushID(doc); 4778 if (ImGui::Checkbox(doc->Name, &doc->Open)) 4779 if (!doc->Open) 4780 doc->DoForceClose(); 4781 ImGui::PopID(); 4782 } 4783 4784 ImGui::Separator(); 4785 4786 // Submit Tab Bar and Tabs 4787 { 4788 ImGuiTabBarFlags tab_bar_flags = (opt_fitting_flags) | (opt_reorderable ? ImGuiTabBarFlags_Reorderable : 0); 4789 if (ImGui::BeginTabBar("##tabs", tab_bar_flags)) 4790 { 4791 if (opt_reorderable) 4792 NotifyOfDocumentsClosedElsewhere(app); 4793 4794 // [DEBUG] Stress tests 4795 //if ((ImGui::GetFrameCount() % 30) == 0) docs[1].Open ^= 1; // [DEBUG] Automatically show/hide a tab. Test various interactions e.g. dragging with this on. 4796 //if (ImGui::GetIO().KeyCtrl) ImGui::SetTabItemSelected(docs[1].Name); // [DEBUG] Test SetTabItemSelected(), probably not very useful as-is anyway.. 4797 4798 // Submit Tabs 4799 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) 4800 { 4801 MyDocument* doc = &app.Documents[doc_n]; 4802 if (!doc->Open) 4803 continue; 4804 4805 ImGuiTabItemFlags tab_flags = (doc->Dirty ? ImGuiTabItemFlags_UnsavedDocument : 0); 4806 bool visible = ImGui::BeginTabItem(doc->Name, &doc->Open, tab_flags); 4807 4808 // Cancel attempt to close when unsaved add to save queue so we can display a popup. 4809 if (!doc->Open && doc->Dirty) 4810 { 4811 doc->Open = true; 4812 doc->DoQueueClose(); 4813 } 4814 4815 MyDocument::DisplayContextMenu(doc); 4816 if (visible) 4817 { 4818 MyDocument::DisplayContents(doc); 4819 ImGui::EndTabItem(); 4820 } 4821 } 4822 4823 ImGui::EndTabBar(); 4824 } 4825 } 4826 4827 // Update closing queue 4828 static ImVector<MyDocument*> close_queue; 4829 if (close_queue.empty()) 4830 { 4831 // Close queue is locked once we started a popup 4832 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) 4833 { 4834 MyDocument* doc = &app.Documents[doc_n]; 4835 if (doc->WantClose) 4836 { 4837 doc->WantClose = false; 4838 close_queue.push_back(doc); 4839 } 4840 } 4841 } 4842 4843 // Display closing confirmation UI 4844 if (!close_queue.empty()) 4845 { 4846 int close_queue_unsaved_documents = 0; 4847 for (int n = 0; n < close_queue.Size; n++) 4848 if (close_queue[n]->Dirty) 4849 close_queue_unsaved_documents++; 4850 4851 if (close_queue_unsaved_documents == 0) 4852 { 4853 // Close documents when all are unsaved 4854 for (int n = 0; n < close_queue.Size; n++) 4855 close_queue[n]->DoForceClose(); 4856 close_queue.clear(); 4857 } 4858 else 4859 { 4860 if (!ImGui::IsPopupOpen("Save?")) 4861 ImGui::OpenPopup("Save?"); 4862 if (ImGui::BeginPopupModal("Save?")) 4863 { 4864 ImGui::Text("Save change to the following items?"); 4865 ImGui::SetNextItemWidth(-1.0f); 4866 if (ImGui::ListBoxHeader("##", close_queue_unsaved_documents, 6)) 4867 { 4868 for (int n = 0; n < close_queue.Size; n++) 4869 if (close_queue[n]->Dirty) 4870 ImGui::Text("%s", close_queue[n]->Name); 4871 ImGui::ListBoxFooter(); 4872 } 4873 4874 if (ImGui::Button("Yes", ImVec2(80, 0))) 4875 { 4876 for (int n = 0; n < close_queue.Size; n++) 4877 { 4878 if (close_queue[n]->Dirty) 4879 close_queue[n]->DoSave(); 4880 close_queue[n]->DoForceClose(); 4881 } 4882 close_queue.clear(); 4883 ImGui::CloseCurrentPopup(); 4884 } 4885 ImGui::SameLine(); 4886 if (ImGui::Button("No", ImVec2(80, 0))) 4887 { 4888 for (int n = 0; n < close_queue.Size; n++) 4889 close_queue[n]->DoForceClose(); 4890 close_queue.clear(); 4891 ImGui::CloseCurrentPopup(); 4892 } 4893 ImGui::SameLine(); 4894 if (ImGui::Button("Cancel", ImVec2(80, 0))) 4895 { 4896 close_queue.clear(); 4897 ImGui::CloseCurrentPopup(); 4898 } 4899 ImGui::EndPopup(); 4900 } 4901 } 4902 } 4903 4904 ImGui::End(); 4905} 4906 4907// End of Demo code 4908#else 4909 4910void ImGui::ShowAboutWindow(bool*) {} 4911void ImGui::ShowDemoWindow(bool*) {} 4912void ImGui::ShowUserGuide() {} 4913void ImGui::ShowStyleEditor(ImGuiStyle*) {} 4914 4915#endif 4916 4917#endif // #ifndef IMGUI_DISABLE