blob: 2bc8720ba5ff5730fd6ec7efa2c555d746eff8db [file] [log] [blame]
// dear imgui, v1.90.6 WIP
// (demo code)
// Help:
// - Read FAQ at
// - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that.
// - Need help integrating Dear ImGui in your codebase?
// - Read Getting Started
// - Read 'Programmer guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase.
// Read top of imgui.cpp and imgui.h for many details, documentation, comments, links.
// Get the latest version at
// Message to the person tempted to delete this file when integrating Dear ImGui into their codebase:
// Think again! It is the most useful reference code that you and other coders will want to refer to and call.
// Have the ImGui::ShowDemoWindow() function wired in an always-available debug menu of your game/app!
// Also include Metrics! ItemPicker! DebugLog! and other debug features.
// Removing this file from your project is hindering access to documentation for everyone in your team,
// likely leading you to poorer usage of the library.
// Everything in this file will be stripped out by the linker if you don't call ImGui::ShowDemoWindow().
// If you want to link core Dear ImGui in your shipped builds but want a thorough guarantee that the demo will not be
// linked, you can setup your imconfig.h with #define IMGUI_DISABLE_DEMO_WINDOWS and those functions will be empty.
// In another situation, whenever you have Dear ImGui available you probably want this to be available for reference.
// Thank you,
// -Your beloved friend, imgui_demo.cpp (which you won't delete)
// In this demo code, we frequently use 'static' variables inside functions.
// A static variable persists across calls. It is essentially a global variable but declared inside the scope of the function.
// Think of "static int n = 0;" as "global int n = 0;" !
// We do this IN THE DEMO because we want:
// - to gather code and data in the same place.
// - to make the demo source code faster to read, faster to change, smaller in size.
// - it is also a convenient way of storing simple UI related information as long as your function
// doesn't need to be reentrant or used in multiple threads.
// This might be a pattern you will want to use in your code, but most of the data you would be working
// with in a complex codebase is likely going to be stored outside your functions.
// The Demo code in this file is designed to be easy to copy-and-paste into your application!
// Because of this:
// - We never omit the ImGui:: prefix when calling functions, even though most code here is in the same namespace.
// - We try to declare static variables in the local scope, as close as possible to the code using them.
// - We never use any of the helpers/facilities used internally by Dear ImGui, unless available in the public API.
// - We never use maths operators on ImVec2/ImVec4. For our other sources files we use them, and they are provided
// by imgui.h using the IMGUI_DEFINE_MATH_OPERATORS define. 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.
// Because we can't assume anything about your support of maths operators, we cannot use them in imgui_demo.cpp.
// Navigating this file:
// - In Visual Studio: CTRL+comma ("Edit.GoToAll") can follow symbols inside comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot.
// - In Visual Studio w/ Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols inside comments.
// - In VS Code, CLion, etc.: CTRL+click can follow symbols inside comments.
Index of this file:
// [SECTION] Forward Declarations
// [SECTION] Helpers
// [SECTION] Demo Window / ShowDemoWindow()
// - ShowDemoWindow()
// - sub section: ShowDemoWindowWidgets()
// - sub section: ShowDemoWindowLayout()
// - sub section: ShowDemoWindowPopups()
// - sub section: ShowDemoWindowTables()
// - sub section: ShowDemoWindowInputs()
// [SECTION] About Window / ShowAboutWindow()
// [SECTION] Style Editor / ShowStyleEditor()
// [SECTION] User Guide / ShowUserGuide()
// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar()
// [SECTION] Example App: Debug Console / ShowExampleAppConsole()
// [SECTION] Example App: Debug Log / ShowExampleAppLog()
// [SECTION] Example App: Simple Layout / ShowExampleAppLayout()
// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor()
// [SECTION] Example App: Long Text / ShowExampleAppLongText()
// [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize()
// [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize()
// [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay()
// [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen()
// [SECTION] Example App: Manipulating window titles / ShowExampleAppWindowTitles()
// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering()
// [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace()
// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
#include "imgui.h"
// System includes
#include <ctype.h> // toupper
#include <limits.h> // INT_MIN, INT_MAX
#include <math.h> // sqrtf, powf, cosf, sinf, floorf, ceilf
#include <stdio.h> // vsnprintf, sscanf, printf
#include <stdlib.h> // NULL, malloc, free, atoi
#include <stdint.h> // intptr_t
#if !defined(_MSC_VER) || _MSC_VER >= 1800
#include <inttypes.h> // PRId64/PRIu64, not avail in some MinGW headers.
// Visual Studio warnings
#ifdef _MSC_VER
#pragma warning (disable: 4127) // condition expression is constant
#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
#pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to an 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2).
// Clang/GCC warnings with -Weverything
#if defined(__clang__)
#if __has_warning("-Wunknown-warning-option")
#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great!
#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx'
#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse.
#pragma clang diagnostic ignored "-Wdeprecated-declarations" // warning: 'xx' is deprecated: The POSIX name for this.. // for strdup used in demo code (so user can copy & paste the code)
#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning: cast to 'void *' from smaller integer type
#pragma clang diagnostic ignored "-Wformat-security" // warning: format string is not a string literal
#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.
#pragma clang diagnostic ignored "-Wunused-macros" // warning: macro is not used // we define snprintf/vsnprintf on Windows so they are available, but not always used.
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0
#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.
#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning: macro name is a reserved identifier
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access
#elif defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size
#pragma GCC diagnostic ignored "-Wformat-security" // warning: format string is not a string literal (potentially insecure)
#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value
#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.
// Play it nice with Windows users (Update: May 2018, Notepad now supports Unix-style carriage returns!)
#ifdef _WIN32
#define IM_NEWLINE "\r\n"
#define IM_NEWLINE "\n"
// Helpers
#if defined(_MSC_VER) && !defined(snprintf)
#define snprintf _snprintf
#if defined(_MSC_VER) && !defined(vsnprintf)
#define vsnprintf _vsnprintf
// Format specifiers for 64-bit values (hasn't been decently standardized before VS2013)
#if !defined(PRId64) && defined(_MSC_VER)
#define PRId64 "I64d"
#define PRIu64 "I64u"
#elif !defined(PRId64)
#define PRId64 "lld"
#define PRIu64 "llu"
// Helpers macros
// We normally try to not use many helpers in imgui_demo.cpp in order to make code easier to copy and paste,
// but making an exception here as those are largely simplifying code...
// In other imgui sources we can use nicer internal functions from imgui_internal.h (ImMin/ImMax) but not in the demo.
#define IM_MIN(A, B) (((A) < (B)) ? (A) : (B))
#define IM_MAX(A, B) (((A) >= (B)) ? (A) : (B))
#define IM_CLAMP(V, MN, MX) ((V) < (MN) ? (MN) : (V) > (MX) ? (MX) : (V))
// Enforce cdecl calling convention for functions called by the standard library,
// in case compilation settings changed the default to e.g. __vectorcall
#ifdef _MSC_VER
#define IMGUI_CDECL __cdecl
// [SECTION] Forward Declarations, Helpers
// Forward Declarations
static void ShowExampleAppMainMenuBar();
static void ShowExampleAppConsole(bool* p_open);
static void ShowExampleAppCustomRendering(bool* p_open);
static void ShowExampleAppDockSpace(bool* p_open);
static void ShowExampleAppDocuments(bool* p_open);
static void ShowExampleAppLog(bool* p_open);
static void ShowExampleAppLayout(bool* p_open);
static void ShowExampleAppPropertyEditor(bool* p_open);
static void ShowExampleAppSimpleOverlay(bool* p_open);
static void ShowExampleAppAutoResize(bool* p_open);
static void ShowExampleAppConstrainedResize(bool* p_open);
static void ShowExampleAppFullscreen(bool* p_open);
static void ShowExampleAppLongText(bool* p_open);
static void ShowExampleAppWindowTitles(bool* p_open);
static void ShowExampleMenuFile();
// We split the contents of the big ShowDemoWindow() function into smaller functions
// (because the link time of very large functions grow non-linearly)
static void ShowDemoWindowWidgets();
static void ShowDemoWindowLayout();
static void ShowDemoWindowPopups();
static void ShowDemoWindowTables();
static void ShowDemoWindowColumns();
static void ShowDemoWindowInputs();
// [SECTION] Helpers
// Helper to display a little (?) mark which shows a tooltip when hovered.
// In your own code you may want to display an actual icon if you are using a merged icon fonts (see docs/
static void HelpMarker(const char* desc)
if (ImGui::BeginItemTooltip())
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
static void ShowDockingDisabledMessage()
ImGuiIO& io = ImGui::GetIO();
ImGui::Text("ERROR: Docking is not enabled! See Demo > Configuration.");
ImGui::Text("Set io.ConfigFlags |= ImGuiConfigFlags_DockingEnable in your code, or ");
ImGui::SameLine(0.0f, 0.0f);
if (ImGui::SmallButton("click here"))
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
// Helper to wire demo markers located in code to an interactive browser
typedef void (*ImGuiDemoMarkerCallback)(const char* file, int line, const char* section, void* user_data);
extern ImGuiDemoMarkerCallback GImGuiDemoMarkerCallback;
extern void* GImGuiDemoMarkerCallbackUserData;
ImGuiDemoMarkerCallback GImGuiDemoMarkerCallback = NULL;
void* GImGuiDemoMarkerCallbackUserData = NULL;
#define IMGUI_DEMO_MARKER(section) do { if (GImGuiDemoMarkerCallback != NULL) GImGuiDemoMarkerCallback(__FILE__, __LINE__, section, GImGuiDemoMarkerCallbackUserData); } while (0)
// [SECTION] Demo Window / ShowDemoWindow()
// - ShowDemoWindow()
// - ShowDemoWindowWidgets()
// - ShowDemoWindowLayout()
// - ShowDemoWindowPopups()
// - ShowDemoWindowTables()
// - ShowDemoWindowColumns()
// - ShowDemoWindowInputs()
// Demonstrate most Dear ImGui features (this is big function!)
// 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.
void ImGui::ShowDemoWindow(bool* p_open)
// Exceptionally add an extra assert here for people confused about initial Dear ImGui setup
// Most functions would normally just assert/crash if the context is missing.
IM_ASSERT(ImGui::GetCurrentContext() != NULL && "Missing Dear ImGui context. Refer to examples app!");
// Examples Apps (accessible from the "Examples" menu)
static bool show_app_main_menu_bar = false;
static bool show_app_console = false;
static bool show_app_custom_rendering = false;
static bool show_app_dockspace = false;
static bool show_app_documents = false;
static bool show_app_log = false;
static bool show_app_layout = false;
static bool show_app_property_editor = false;
static bool show_app_simple_overlay = false;
static bool show_app_auto_resize = false;
static bool show_app_constrained_resize = false;
static bool show_app_fullscreen = false;
static bool show_app_long_text = false;
static bool show_app_window_titles = false;
if (show_app_main_menu_bar) ShowExampleAppMainMenuBar();
if (show_app_dockspace) ShowExampleAppDockSpace(&show_app_dockspace); // Process the Docking app first, as explicit DockSpace() nodes needs to be submitted early (read comments near the DockSpace function)
if (show_app_documents) ShowExampleAppDocuments(&show_app_documents); // Process the Document app next, as it may also use a DockSpace()
if (show_app_console) ShowExampleAppConsole(&show_app_console);
if (show_app_custom_rendering) ShowExampleAppCustomRendering(&show_app_custom_rendering);
if (show_app_log) ShowExampleAppLog(&show_app_log);
if (show_app_layout) ShowExampleAppLayout(&show_app_layout);
if (show_app_property_editor) ShowExampleAppPropertyEditor(&show_app_property_editor);
if (show_app_simple_overlay) ShowExampleAppSimpleOverlay(&show_app_simple_overlay);
if (show_app_auto_resize) ShowExampleAppAutoResize(&show_app_auto_resize);
if (show_app_constrained_resize) ShowExampleAppConstrainedResize(&show_app_constrained_resize);
if (show_app_fullscreen) ShowExampleAppFullscreen(&show_app_fullscreen);
if (show_app_long_text) ShowExampleAppLongText(&show_app_long_text);
if (show_app_window_titles) ShowExampleAppWindowTitles(&show_app_window_titles);
// Dear ImGui Tools (accessible from the "Tools" menu)
static bool show_tool_metrics = false;
static bool show_tool_debug_log = false;
static bool show_tool_id_stack_tool = false;
static bool show_tool_style_editor = false;
static bool show_tool_about = false;
if (show_tool_metrics)
if (show_tool_debug_log)
if (show_tool_id_stack_tool)
if (show_tool_style_editor)
ImGui::Begin("Dear ImGui Style Editor", &show_tool_style_editor);
if (show_tool_about)
// Demonstrate the various window flags. Typically you would just use the default!
static bool no_titlebar = false;
static bool no_scrollbar = false;
static bool no_menu = false;
static bool no_move = false;
static bool no_resize = false;
static bool no_collapse = false;
static bool no_close = false;
static bool no_nav = false;
static bool no_background = false;
static bool no_bring_to_front = false;
static bool no_docking = false;
static bool unsaved_document = false;
ImGuiWindowFlags window_flags = 0;
if (no_titlebar) window_flags |= ImGuiWindowFlags_NoTitleBar;
if (no_scrollbar) window_flags |= ImGuiWindowFlags_NoScrollbar;
if (!no_menu) window_flags |= ImGuiWindowFlags_MenuBar;
if (no_move) window_flags |= ImGuiWindowFlags_NoMove;
if (no_resize) window_flags |= ImGuiWindowFlags_NoResize;
if (no_collapse) window_flags |= ImGuiWindowFlags_NoCollapse;
if (no_nav) window_flags |= ImGuiWindowFlags_NoNav;
if (no_background) window_flags |= ImGuiWindowFlags_NoBackground;
if (no_bring_to_front) window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus;
if (no_docking) window_flags |= ImGuiWindowFlags_NoDocking;
if (unsaved_document) window_flags |= ImGuiWindowFlags_UnsavedDocument;
if (no_close) p_open = NULL; // Don't pass our bool* to Begin
// We specify a default position/size in case there's no data in the .ini file.
// We only do it to make the demo applications a little more welcoming, but typically this isn't required.
const ImGuiViewport* main_viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(ImVec2(main_viewport->WorkPos.x + 650, main_viewport->WorkPos.y + 20), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver);
// Main body of the Demo window starts here.
if (!ImGui::Begin("Dear ImGui Demo", p_open, window_flags))
// Early out if the window is collapsed, as an optimization.
// Most "big" widgets share a common width settings by default. See 'Demo->Layout->Widgets Width' for details.
// e.g. Use 2/3 of the space for widgets and 1/3 for labels (right align)
//ImGui::PushItemWidth(-ImGui::GetWindowWidth() * 0.35f);
// e.g. Leave a fixed amount of width for labels (by passing a negative value), the rest goes to widgets.
ImGui::PushItemWidth(ImGui::GetFontSize() * -12);
// Menu Bar
if (ImGui::BeginMenuBar())
if (ImGui::BeginMenu("Menu"))
if (ImGui::BeginMenu("Examples"))
ImGui::MenuItem("Main menu bar", NULL, &show_app_main_menu_bar);
ImGui::SeparatorText("Mini apps");
ImGui::MenuItem("Console", NULL, &show_app_console);
ImGui::MenuItem("Custom rendering", NULL, &show_app_custom_rendering);
ImGui::MenuItem("Dockspace", NULL, &show_app_dockspace);
ImGui::MenuItem("Documents", NULL, &show_app_documents);
ImGui::MenuItem("Log", NULL, &show_app_log);
ImGui::MenuItem("Property editor", NULL, &show_app_property_editor);
ImGui::MenuItem("Simple layout", NULL, &show_app_layout);
ImGui::MenuItem("Simple overlay", NULL, &show_app_simple_overlay);
ImGui::MenuItem("Auto-resizing window", NULL, &show_app_auto_resize);
ImGui::MenuItem("Constrained-resizing window", NULL, &show_app_constrained_resize);
ImGui::MenuItem("Fullscreen window", NULL, &show_app_fullscreen);
ImGui::MenuItem("Long text display", NULL, &show_app_long_text);
ImGui::MenuItem("Manipulating window titles", NULL, &show_app_window_titles);
//if (ImGui::MenuItem("MenuItem")) {} // You can also use MenuItem() inside a menu bar!
if (ImGui::BeginMenu("Tools"))
const bool has_debug_tools = true;
const bool has_debug_tools = false;
ImGui::MenuItem("Metrics/Debugger", NULL, &show_tool_metrics, has_debug_tools);
ImGui::MenuItem("Debug Log", NULL, &show_tool_debug_log, has_debug_tools);
ImGui::MenuItem("ID Stack Tool", NULL, &show_tool_id_stack_tool, has_debug_tools);
ImGui::MenuItem("Style Editor", NULL, &show_tool_style_editor);
bool is_debugger_present = ImGui::GetIO().ConfigDebugIsDebuggerPresent;
if (ImGui::MenuItem("Item Picker", NULL, false, has_debug_tools && is_debugger_present))
if (!is_debugger_present)
ImGui::SetItemTooltip("Requires io.ConfigDebugIsDebuggerPresent=true to be set.\n\nWe otherwise disable the menu option to avoid casual users crashing the application.\n\nYou can however always access the Item Picker in Metrics->Tools.");
ImGui::MenuItem("About Dear ImGui", NULL, &show_tool_about);
ImGui::Text("dear imgui says hello! (%s) (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
if (ImGui::CollapsingHeader("Help"))
ImGui::SeparatorText("ABOUT THIS DEMO:");
ImGui::BulletText("Sections below are demonstrating many aspects of the library.");
ImGui::BulletText("The \"Examples\" menu above leads to more demo contents.");
ImGui::BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n"
"and Metrics/Debugger (general purpose Dear ImGui debugging tool).");
ImGui::SeparatorText("PROGRAMMER GUIDE:");
ImGui::BulletText("See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!");
ImGui::BulletText("See comments in imgui.cpp.");
ImGui::BulletText("See example applications in the examples/ folder.");
ImGui::BulletText("Read the FAQ at");
ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls.");
ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls.");
ImGui::SeparatorText("USER GUIDE:");
if (ImGui::CollapsingHeader("Configuration"))
ImGuiIO& io = ImGui::GetIO();
if (ImGui::TreeNode("Configuration##2"))
ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard);
ImGui::SameLine(); HelpMarker("Enable keyboard controls.");
ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", &io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad);
ImGui::SameLine(); HelpMarker("Enable gamepad controls. Require backend to set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details.");
ImGui::CheckboxFlags("io.ConfigFlags: NavEnableSetMousePos", &io.ConfigFlags, ImGuiConfigFlags_NavEnableSetMousePos);
ImGui::SameLine(); HelpMarker("Instruct navigation to move the mouse cursor. See comment for ImGuiConfigFlags_NavEnableSetMousePos.");
ImGui::CheckboxFlags("io.ConfigFlags: NoMouse", &io.ConfigFlags, ImGuiConfigFlags_NoMouse);
if (io.ConfigFlags & ImGuiConfigFlags_NoMouse)
// The "NoMouse" option can get us stuck with a disabled mouse! Let's provide an alternative way to fix it:
if (fmodf((float)ImGui::GetTime(), 0.40f) < 0.20f)
if (ImGui::IsKeyPressed(ImGuiKey_Space))
io.ConfigFlags &= ~ImGuiConfigFlags_NoMouse;
ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", &io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange);
ImGui::SameLine(); HelpMarker("Instruct backend to not alter mouse cursor shape and visibility.");
ImGui::Checkbox("io.ConfigInputTrickleEventQueue", &io.ConfigInputTrickleEventQueue);
ImGui::SameLine(); HelpMarker("Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates.");
ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor);
ImGui::SameLine(); HelpMarker("Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something).");
ImGui::CheckboxFlags("io.ConfigFlags: DockingEnable", &io.ConfigFlags, ImGuiConfigFlags_DockingEnable);
if (io.ConfigDockingWithShift)
HelpMarker("Drag from window title bar or their tab to dock/undock. Hold SHIFT to enable docking.\n\nDrag from window menu button (upper-left button) to undock an entire node (all windows).");
HelpMarker("Drag from window title bar or their tab to dock/undock. Hold SHIFT to disable docking.\n\nDrag from window menu button (upper-left button) to undock an entire node (all windows).");
if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
ImGui::Checkbox("io.ConfigDockingNoSplit", &io.ConfigDockingNoSplit);
ImGui::SameLine(); HelpMarker("Simplified docking mode: disable window splitting, so docking is limited to merging multiple windows together into tab-bars.");
ImGui::Checkbox("io.ConfigDockingWithShift", &io.ConfigDockingWithShift);
ImGui::SameLine(); HelpMarker("Enable docking when holding Shift only (allow to drop in wider space, reduce visual noise)");
ImGui::Checkbox("io.ConfigDockingAlwaysTabBar", &io.ConfigDockingAlwaysTabBar);
ImGui::SameLine(); HelpMarker("Create a docking node and tab-bar on single floating windows.");
ImGui::Checkbox("io.ConfigDockingTransparentPayload", &io.ConfigDockingTransparentPayload);
ImGui::SameLine(); HelpMarker("Make window or viewport transparent when docking and only display docking boxes on the target viewport. Useful if rendering of multiple viewport cannot be synced. Best used with ConfigViewportsNoAutoMerge.");
ImGui::CheckboxFlags("io.ConfigFlags: ViewportsEnable", &io.ConfigFlags, ImGuiConfigFlags_ViewportsEnable);
ImGui::SameLine(); HelpMarker("[beta] Enable beta multi-viewports support. See ImGuiPlatformIO for details.");
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
ImGui::Checkbox("io.ConfigViewportsNoAutoMerge", &io.ConfigViewportsNoAutoMerge);
ImGui::SameLine(); HelpMarker("Set to make all floating imgui windows always create their own viewport. Otherwise, they are merged into the main host viewports when overlapping it.");
ImGui::Checkbox("io.ConfigViewportsNoTaskBarIcon", &io.ConfigViewportsNoTaskBarIcon);
ImGui::SameLine(); HelpMarker("Toggling this at runtime is normally unsupported (most platform backends won't refresh the task bar icon state right away).");
ImGui::Checkbox("io.ConfigViewportsNoDecoration", &io.ConfigViewportsNoDecoration);
ImGui::SameLine(); HelpMarker("Toggling this at runtime is normally unsupported (most platform backends won't refresh the decoration right away).");
ImGui::Checkbox("io.ConfigViewportsNoDefaultParent", &io.ConfigViewportsNoDefaultParent);
ImGui::SameLine(); HelpMarker("Toggling this at runtime is normally unsupported (most platform backends won't refresh the parenting right away).");
ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink);
ImGui::SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting).");
ImGui::Checkbox("io.ConfigInputTextEnterKeepActive", &io.ConfigInputTextEnterKeepActive);
ImGui::SameLine(); HelpMarker("Pressing Enter will keep item active and select contents (single-line only).");
ImGui::Checkbox("io.ConfigDragClickToInputText", &io.ConfigDragClickToInputText);
ImGui::SameLine(); HelpMarker("Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving).");
ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges);
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.");
ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly);
ImGui::Checkbox("io.ConfigMacOSXBehaviors", &io.ConfigMacOSXBehaviors);
ImGui::Text("Also see Style->Rendering for rendering options.");
ImGui::Checkbox("io.ConfigDebugIsDebuggerPresent", &io.ConfigDebugIsDebuggerPresent);
ImGui::SameLine(); HelpMarker("Enable various tools calling IM_DEBUG_BREAK().\n\nRequires a debugger being attached, otherwise IM_DEBUG_BREAK() options will appear to crash your application.");
ImGui::Checkbox("io.ConfigDebugBeginReturnValueOnce", &io.ConfigDebugBeginReturnValueOnce); // .
ImGui::SameLine(); HelpMarker("First calls to Begin()/BeginChild() will return false.\n\nTHIS OPTION IS DISABLED because it needs to be set at application boot-time to make sense. Showing the disabled option is a way to make this feature easier to discover.");
ImGui::Checkbox("io.ConfigDebugBeginReturnValueLoop", &io.ConfigDebugBeginReturnValueLoop);
ImGui::SameLine(); HelpMarker("Some calls to Begin()/BeginChild() will return false.\n\nWill cycle through window depths then repeat. Windows should be flickering while running.");
ImGui::Checkbox("io.ConfigDebugIgnoreFocusLoss", &io.ConfigDebugIgnoreFocusLoss);
ImGui::SameLine(); HelpMarker("Option to deactivate io.AddFocusEvent(false) handling. May facilitate interactions with a debugger when focus loss leads to clearing inputs data.");
ImGui::Checkbox("io.ConfigDebugIniSettings", &io.ConfigDebugIniSettings);
ImGui::SameLine(); HelpMarker("Option to save .ini data with extra comments (particularly helpful for Docking, but makes saving slower).");
IMGUI_DEMO_MARKER("Configuration/Backend Flags");
if (ImGui::TreeNode("Backend Flags"))
"Those flags are set by the backends (imgui_impl_xxx files) to specify their capabilities.\n"
"Here we expose them as read-only fields to avoid breaking interactions with your backend.");
// Make a local copy to avoid modifying actual backend flags.
// FIXME: Maybe we need a BeginReadonly() equivalent to keep label bright?
ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", &io.BackendFlags, ImGuiBackendFlags_HasGamepad);
ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors);
ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos", &io.BackendFlags, ImGuiBackendFlags_HasSetMousePos);
ImGui::CheckboxFlags("io.BackendFlags: PlatformHasViewports", &io.BackendFlags, ImGuiBackendFlags_PlatformHasViewports);
ImGui::CheckboxFlags("io.BackendFlags: HasMouseHoveredViewport",&io.BackendFlags, ImGuiBackendFlags_HasMouseHoveredViewport);
ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", &io.BackendFlags, ImGuiBackendFlags_RendererHasVtxOffset);
ImGui::CheckboxFlags("io.BackendFlags: RendererHasViewports", &io.BackendFlags, ImGuiBackendFlags_RendererHasViewports);
if (ImGui::TreeNode("Style"))
HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function.");
IMGUI_DEMO_MARKER("Configuration/Capture, Logging");
if (ImGui::TreeNode("Capture/Logging"))
"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.\n"
"Try opening any of the contents below in this window and then click one of the \"Log To\" button.");
HelpMarker("You can also call ImGui::LogText() to output directly to the log without a visual output.");
if (ImGui::Button("Copy \"Hello, world!\" to clipboard"))
ImGui::LogText("Hello, world!");
IMGUI_DEMO_MARKER("Window options");
if (ImGui::CollapsingHeader("Window options"))
if (ImGui::BeginTable("split", 3))
ImGui::TableNextColumn(); ImGui::Checkbox("No titlebar", &no_titlebar);
ImGui::TableNextColumn(); ImGui::Checkbox("No scrollbar", &no_scrollbar);
ImGui::TableNextColumn(); ImGui::Checkbox("No menu", &no_menu);
ImGui::TableNextColumn(); ImGui::Checkbox("No move", &no_move);
ImGui::TableNextColumn(); ImGui::Checkbox("No resize", &no_resize);
ImGui::TableNextColumn(); ImGui::Checkbox("No collapse", &no_collapse);
ImGui::TableNextColumn(); ImGui::Checkbox("No close", &no_close);
ImGui::TableNextColumn(); ImGui::Checkbox("No nav", &no_nav);
ImGui::TableNextColumn(); ImGui::Checkbox("No background", &no_background);
ImGui::TableNextColumn(); ImGui::Checkbox("No bring to front", &no_bring_to_front);
ImGui::TableNextColumn(); ImGui::Checkbox("No docking", &no_docking);
ImGui::TableNextColumn(); ImGui::Checkbox("Unsaved document", &unsaved_document);
// All demo contents
// End of ShowDemoWindow()
static void ShowDemoWindowWidgets()
if (!ImGui::CollapsingHeader("Widgets"))
static bool disable_all = false; // The Checkbox for that is inside the "Disabled" section at the bottom
if (disable_all)
if (ImGui::TreeNode("Basic"))
static int clicked = 0;
if (ImGui::Button("Button"))
if (clicked & 1)
ImGui::Text("Thanks for clicking me!");
static bool check = true;
ImGui::Checkbox("checkbox", &check);
static int e = 0;
ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine();
ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine();
ImGui::RadioButton("radio c", &e, 2);
// Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style.
IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Colored)");
for (int i = 0; i < 7; i++)
if (i > 0)
ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.6f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.7f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.8f, 0.8f));
// Use AlignTextToFramePadding() to align text baseline to the baseline of framed widgets elements
// (otherwise a Text+SameLine+Button sequence will have the text a little too high by default!)
// See 'Demo->Layout->Text Baseline Alignment' for details.
ImGui::Text("Hold to repeat:");
// Arrow buttons with Repeater
IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Repeating)");
static int counter = 0;
float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
if (ImGui::ArrowButton("##left", ImGuiDir_Left)) { counter--; }
ImGui::SameLine(0.0f, spacing);
if (ImGui::ArrowButton("##right", ImGuiDir_Right)) { counter++; }
ImGui::Text("%d", counter);
ImGui::SetItemTooltip("I am a tooltip");
ImGui::LabelText("label", "Value");
// To wire InputText() with std::string or any other custom string type,
// see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file.
static char str0[128] = "Hello, world!";
ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0));
ImGui::SameLine(); HelpMarker(
"Hold SHIFT or use mouse to select text.\n"
"CTRL+Left/Right to word jump.\n"
"CTRL+A or Double-Click to select all.\n"
"CTRL+X,CTRL+C,CTRL+V clipboard.\n"
"CTRL+Z,CTRL+Y undo/redo.\n"
"ESCAPE to revert.\n\n"
"You 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).");
static char str1[128] = "";
ImGui::InputTextWithHint("input text (w/ hint)", "enter text here", str1, IM_ARRAYSIZE(str1));
IMGUI_DEMO_MARKER("Widgets/Basic/InputInt, InputFloat");
static int i0 = 123;
ImGui::InputInt("input int", &i0);
static float f0 = 0.001f;
ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f");
static double d0 = 999999.00000001;
ImGui::InputDouble("input double", &d0, 0.01f, 1.0f, "%.8f");
static float f1 = 1.e10f;
ImGui::InputFloat("input scientific", &f1, 0.0f, 0.0f, "%e");
ImGui::SameLine(); HelpMarker(
"You can input value using the scientific notation,\n"
" e.g. \"1e+8\" becomes \"100000000\".");
static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f };
ImGui::InputFloat3("input float3", vec4a);
IMGUI_DEMO_MARKER("Widgets/Basic/DragInt, DragFloat");
static int i1 = 50, i2 = 42;
ImGui::DragInt("drag int", &i1, 1);
ImGui::SameLine(); HelpMarker(
"Click and drag to edit value.\n"
"Hold SHIFT/ALT for faster/slower edit.\n"
"Double-click or CTRL+click to input value.");
ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp);
static float f1 = 1.00f, f2 = 0.0067f;
ImGui::DragFloat("drag float", &f1, 0.005f);
ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns");
IMGUI_DEMO_MARKER("Widgets/Basic/SliderInt, SliderFloat");
static int i1 = 0;
ImGui::SliderInt("slider int", &i1, -1, 3);
ImGui::SameLine(); HelpMarker("CTRL+click to input value.");
static float f1 = 0.123f, f2 = 0.0f;
ImGui::SliderFloat("slider float", &f1, 0.0f, 1.0f, "ratio = %.3f");
ImGui::SliderFloat("slider float (log)", &f2, -10.0f, 10.0f, "%.4f", ImGuiSliderFlags_Logarithmic);
static float angle = 0.0f;
ImGui::SliderAngle("slider angle", &angle);
// Using the format string to display a name instead of an integer.
// Here we completely omit '%d' from the format string, so it'll only display a name.
// This technique can also be used with DragInt().
IMGUI_DEMO_MARKER("Widgets/Basic/Slider (enum)");
enum Element { Element_Fire, Element_Earth, Element_Air, Element_Water, Element_COUNT };
static int elem = Element_Fire;
const char* elems_names[Element_COUNT] = { "Fire", "Earth", "Air", "Water" };
const char* elem_name = (elem >= 0 && elem < Element_COUNT) ? elems_names[elem] : "Unknown";
ImGui::SliderInt("slider enum", &elem, 0, Element_COUNT - 1, elem_name); // Use ImGuiSliderFlags_NoInput flag to disable CTRL+Click here.
ImGui::SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer.");
IMGUI_DEMO_MARKER("Widgets/Basic/ColorEdit3, ColorEdit4");
static float col1[3] = { 1.0f, 0.0f, 0.2f };
static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
ImGui::ColorEdit3("color 1", col1);
ImGui::SameLine(); HelpMarker(
"Click on the color square to open a color picker.\n"
"Click and hold to use drag and drop.\n"
"Right-click on the color square to show options.\n"
"CTRL+click on individual component to input value.\n");
ImGui::ColorEdit4("color 2", col2);
// Using the _simplified_ one-liner Combo() api here
// See "Combo" section for examples of how to use the more flexible BeginCombo()/EndCombo() api.
const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" };
static int item_current = 0;
ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items));
ImGui::SameLine(); HelpMarker(
"Using the simplified one-liner Combo API here.\n"
"Refer to the \"Combo\" section below for an explanation of how to use the more flexible and general BeginCombo/EndCombo API.");
// Using the _simplified_ one-liner ListBox() api here
// See "List boxes" section for examples of how to use the more flexible BeginListBox()/EndListBox() api.
const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" };
static int item_current = 1;
ImGui::ListBox("listbox", &item_current, items, IM_ARRAYSIZE(items), 4);
ImGui::SameLine(); HelpMarker(
"Using the simplified one-liner ListBox API here.\n"
"Refer to the \"List boxes\" section below for an explanation of how to use the more flexible and general BeginListBox/EndListBox API.");
if (ImGui::TreeNode("Tooltips"))
// Tooltips are windows following the mouse. They do not take focus away.
// Typical use cases:
// - Short-form (text only): SetItemTooltip("Hello");
// - Short-form (any contents): if (BeginItemTooltip()) { Text("Hello"); EndTooltip(); }
// - Full-form (text only): if (IsItemHovered(...)) { SetTooltip("Hello"); }
// - Full-form (any contents): if (IsItemHovered(...) && BeginTooltip()) { Text("Hello"); EndTooltip(); }
"Tooltip are typically created by using a IsItemHovered() + SetTooltip() sequence.\n\n"
"We provide a helper SetItemTooltip() function to perform the two with standards flags.");
ImVec2 sz = ImVec2(-FLT_MIN, 0.0f);
ImGui::Button("Basic", sz);
ImGui::SetItemTooltip("I am a tooltip");
ImGui::Button("Fancy", sz);
if (ImGui::BeginItemTooltip())
ImGui::Text("I am a fancy tooltip");
static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr));
ImGui::Text("Sin(time) = %f", sinf((float)ImGui::GetTime()));
ImGui::SeparatorText("Always On");
// Showcase NOT relying on a IsItemHovered() to emit a tooltip.
// Here the tooltip is always emitted when 'always_on == true'.
static int always_on = 0;
ImGui::RadioButton("Off", &always_on, 0);
ImGui::RadioButton("Always On (Simple)", &always_on, 1);
ImGui::RadioButton("Always On (Advanced)", &always_on, 2);
if (always_on == 1)
ImGui::SetTooltip("I am following you around.");
else if (always_on == 2 && ImGui::BeginTooltip())
ImGui::ProgressBar(sinf((float)ImGui::GetTime()) * 0.5f + 0.5f, ImVec2(ImGui::GetFontSize() * 25, 0.0f));
"Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() is the preferred way to standardize"
"tooltip activation details across your application. You may however decide to use custom"
"flags for a specific tooltip instance.");
// The following examples are passed for documentation purpose but may not be useful to most users.
// Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() will pull ImGuiHoveredFlags flags values from
// 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' depending on whether mouse or gamepad/keyboard is being used.
// With default settings, ImGuiHoveredFlags_ForTooltip is equivalent to ImGuiHoveredFlags_DelayShort + ImGuiHoveredFlags_Stationary.
ImGui::Button("Manual", sz);
if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip))
ImGui::SetTooltip("I am a manually emitted tooltip.");
ImGui::Button("DelayNone", sz);
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNone))
ImGui::SetTooltip("I am a tooltip with no delay.");
ImGui::Button("DelayShort", sz);
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort | ImGuiHoveredFlags_NoSharedDelay))
ImGui::SetTooltip("I am a tooltip with a short delay (%0.2f sec).", ImGui::GetStyle().HoverDelayShort);
ImGui::Button("DelayLong", sz);
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal | ImGuiHoveredFlags_NoSharedDelay))
ImGui::SetTooltip("I am a tooltip with a long delay (%0.2f sec).", ImGui::GetStyle().HoverDelayNormal);
ImGui::Button("Stationary", sz);
if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary))
ImGui::SetTooltip("I am a tooltip requiring mouse to be stationary before activating.");
// Using ImGuiHoveredFlags_ForTooltip will pull flags from 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav',
// which default value include the ImGuiHoveredFlags_AllowWhenDisabled flag.
// As a result, Set
ImGui::Button("Disabled item", sz);
if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip))
ImGui::SetTooltip("I am a a tooltip for a disabled item.");
// Testing ImGuiOnceUponAFrame helper.
//static ImGuiOnceUponAFrame once;
//for (int i = 0; i < 5; i++)
// if (once)
// ImGui::Text("This will be displayed only once.");
IMGUI_DEMO_MARKER("Widgets/Tree Nodes");
if (ImGui::TreeNode("Tree Nodes"))
IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Basic trees");
if (ImGui::TreeNode("Basic trees"))
for (int i = 0; i < 5; i++)
// Use SetNextItemOpen() so set the default state of a node to be open. We could
// also use TreeNodeEx() with the ImGuiTreeNodeFlags_DefaultOpen flag to achieve the same thing!
if (i == 0)
ImGui::SetNextItemOpen(true, ImGuiCond_Once);
if (ImGui::TreeNode((void*)(intptr_t)i, "Child %d", i))
ImGui::Text("blah blah");
if (ImGui::SmallButton("button")) {}
IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Advanced, with Selectable nodes");
if (ImGui::TreeNode("Advanced, with Selectable nodes"))
"This is a more typical looking tree with selectable nodes.\n"
"Click to select, CTRL+Click to toggle, click on arrows or double-click to open.");
static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth;
static bool align_label_with_current_x_position = false;
static bool test_drag_and_drop = false;
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnArrow", &base_flags, ImGuiTreeNodeFlags_OpenOnArrow);
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", &base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick);
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAvailWidth", &base_flags, ImGuiTreeNodeFlags_SpanAvailWidth); ImGui::SameLine(); HelpMarker("Extend hit area to all available width instead of allowing more items to be laid out after the node.");
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &base_flags, ImGuiTreeNodeFlags_SpanFullWidth);
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &base_flags, ImGuiTreeNodeFlags_SpanAllColumns); ImGui::SameLine(); HelpMarker("For use in Tables only.");
ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position);
ImGui::Checkbox("Test tree node as drag source", &test_drag_and_drop);
if (align_label_with_current_x_position)
// 'selection_mask' is dumb representation of what may be user-side selection state.
// You may retain selection state inside or outside your objects in whatever format you see fit.
// 'node_clicked' is 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.
static int selection_mask = (1 << 2);
int node_clicked = -1;
for (int i = 0; i < 6; i++)
// Disable the default "open on single-click behavior" + set Selected flag according to our selection.
// To alter selection we use IsItemClicked() && !IsItemToggledOpen(), so clicking on an arrow doesn't alter selection.
ImGuiTreeNodeFlags node_flags = base_flags;
const bool is_selected = (selection_mask & (1 << i)) != 0;
if (is_selected)
node_flags |= ImGuiTreeNodeFlags_Selected;
if (i < 3)
// Items 0..2 are Tree Node
bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Node %d", i);
if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen())
node_clicked = i;
if (test_drag_and_drop && ImGui::BeginDragDropSource())
ImGui::SetDragDropPayload("_TREENODE", NULL, 0);
ImGui::Text("This is a drag and drop source");
if (node_open)
ImGui::BulletText("Blah blah\nBlah Blah");
// Items 3..5 are Tree Leaves
// The only reason we use TreeNode at all is to allow selection of the leaf. Otherwise we can
// use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text().
node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet
ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i);
if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen())
node_clicked = i;
if (test_drag_and_drop && ImGui::BeginDragDropSource())
ImGui::SetDragDropPayload("_TREENODE", NULL, 0);
ImGui::Text("This is a drag and drop source");
if (node_clicked != -1)
// Update selection state
// (process outside of tree loop to avoid visual inconsistencies during the clicking frame)
if (ImGui::GetIO().KeyCtrl)
selection_mask ^= (1 << node_clicked); // CTRL+click to toggle
else //if (!(selection_mask & (1 << node_clicked))) // Depending on selection behavior you want, may want to preserve selection when clicking on item that is part of the selection
selection_mask = (1 << node_clicked); // Click to single-select
if (align_label_with_current_x_position)
IMGUI_DEMO_MARKER("Widgets/Collapsing Headers");
if (ImGui::TreeNode("Collapsing Headers"))
static bool closable_group = true;
ImGui::Checkbox("Show 2nd header", &closable_group);
if (ImGui::CollapsingHeader("Header", ImGuiTreeNodeFlags_None))
ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
for (int i = 0; i < 5; i++)
ImGui::Text("Some content %d", i);
if (ImGui::CollapsingHeader("Header with a close button", &closable_group))
ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
for (int i = 0; i < 5; i++)
ImGui::Text("More content %d", i);
if (ImGui::CollapsingHeader("Header with a bullet", ImGuiTreeNodeFlags_Bullet))
ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
if (ImGui::TreeNode("Bullets"))
ImGui::BulletText("Bullet point 1");
ImGui::BulletText("Bullet point 2\nOn multiple lines");
if (ImGui::TreeNode("Tree node"))
ImGui::BulletText("Another bullet point");
ImGui::Bullet(); ImGui::Text("Bullet point 3 (two calls)");
ImGui::Bullet(); ImGui::SmallButton("Button");
if (ImGui::TreeNode("Text"))
IMGUI_DEMO_MARKER("Widgets/Text/Colored Text");
if (ImGui::TreeNode("Colorful Text"))
// Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility.
ImGui::TextColored(ImVec4(1.0f, 0.0f, 1.0f, 1.0f), "Pink");
ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Yellow");
ImGui::SameLine(); HelpMarker("The TextDisabled color is stored in ImGuiStyle.");
IMGUI_DEMO_MARKER("Widgets/Text/Word Wrapping");
if (ImGui::TreeNode("Word Wrapping"))
// Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility.
"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.");
static float wrap_width = 200.0f;
ImGui::SliderFloat("Wrap width", &wrap_width, -20, 600, "%.0f");
ImDrawList* draw_list = ImGui::GetWindowDrawList();
for (int n = 0; n < 2; n++)
ImGui::Text("Test paragraph %d:", n);
ImVec2 pos = ImGui::GetCursorScreenPos();
ImVec2 marker_min = ImVec2(pos.x + wrap_width, pos.y);
ImVec2 marker_max = ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight());
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width);
if (n == 0)
ImGui::Text("The lazy dog is a good dog. This paragraph should fit within %.0f pixels. Testing a 1 character word. The quick brown fox jumps over the lazy dog.", wrap_width);
ImGui::Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh");
// Draw actual text bounding box, following by marker of our expected limit (should not overlap!)
draw_list->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 255, 0, 255));
draw_list->AddRectFilled(marker_min, marker_max, IM_COL32(255, 0, 255, 255));
IMGUI_DEMO_MARKER("Widgets/Text/UTF-8 Text");
if (ImGui::TreeNode("UTF-8 Text"))
// UTF-8 test with Japanese characters
// (Needs a suitable font? Try "Google Noto" or "Arial Unicode". See docs/ for details.)
// - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8
// - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. in Visual Studio, you
// can save your source files as 'UTF-8 without signature').
// CHARACTERS IN THIS SOURCE FILE. Instead we are encoding a few strings with hexadecimal constants.
// Don't do this in your application! Please use u8"text in any language" in your application!
// 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.
"CJK text will only appear if the font was loaded with the appropriate CJK character ranges. "
"Call io.Fonts->AddFontFromFileTTF() manually to load extra character ranges. "
"Read docs/ for details.");
ImGui::Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)");
ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)");
static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e";
//static char buf[32] = u8"NIHONGO"; // <- this is how you would write it with C++11, using real kanjis
ImGui::InputText("UTF-8 input", buf, IM_ARRAYSIZE(buf));
if (ImGui::TreeNode("Images"))
ImGuiIO& io = ImGui::GetIO();
"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!");
// Below we are displaying the font texture because it is the only texture we have access to inside the demo!
// Remember that ImTextureID is just storage for whatever you want it to be. It is essentially a value that
// will be passed to the rendering backend via the ImDrawCmd structure.
// If you use one of the default imgui_impl_XXXX.cpp rendering backend, they all have comments at the top
// of their respective source file to specify what they expect to be stored in ImTextureID, 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.
// More:
// - 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.
// - You can use ShowMetricsWindow() to inspect the draw data that are being passed to your renderer,
// it will help you debug issues if you are confused about it.
// - Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage().
// - Read
// - Read
ImTextureID my_tex_id = io.Fonts->TexID;
float my_tex_w = (float)io.Fonts->TexWidth;
float my_tex_h = (float)io.Fonts->TexHeight;
static bool use_text_color_for_tint = false;
ImGui::Checkbox("Use Text Color for Tint", &use_text_color_for_tint);
ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h);
ImVec2 pos = ImGui::GetCursorScreenPos();
ImVec2 uv_min = ImVec2(0.0f, 0.0f); // Top-left
ImVec2 uv_max = ImVec2(1.0f, 1.0f); // Lower-right
ImVec4 tint_col = use_text_color_for_tint ? ImGui::GetStyleColorVec4(ImGuiCol_Text) : ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint
ImVec4 border_col = ImGui::GetStyleColorVec4(ImGuiCol_Border);
ImGui::Image(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, tint_col, border_col);
if (ImGui::BeginItemTooltip())
float region_sz = 32.0f;
float region_x = io.MousePos.x - pos.x - region_sz * 0.5f;
float region_y = io.MousePos.y - pos.y - region_sz * 0.5f;
float zoom = 4.0f;
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; }
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; }
ImGui::Text("Min: (%.2f, %.2f)", region_x, region_y);
ImGui::Text("Max: (%.2f, %.2f)", region_x + region_sz, region_y + region_sz);
ImVec2 uv0 = ImVec2((region_x) / my_tex_w, (region_y) / my_tex_h);
ImVec2 uv1 = ImVec2((region_x + region_sz) / my_tex_w, (region_y + region_sz) / my_tex_h);
ImGui::Image(my_tex_id, ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, tint_col, border_col);
IMGUI_DEMO_MARKER("Widgets/Images/Textured buttons");
ImGui::TextWrapped("And now some textured buttons..");
static int pressed_count = 0;
for (int i = 0; i < 8; i++)
// UV coordinates are often (0.0f, 0.0f) and (1.0f, 1.0f) to display an entire textures.
// Here are trying to display only a 32x32 pixels area of the texture, hence the UV computation.
// Read about UV coordinates here:
if (i > 0)
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(i - 1.0f, i - 1.0f));
ImVec2 size = ImVec2(32.0f, 32.0f); // Size of the image we want to make visible
ImVec2 uv0 = ImVec2(0.0f, 0.0f); // UV coordinates for lower-left
ImVec2 uv1 = ImVec2(32.0f / my_tex_w, 32.0f / my_tex_h); // UV coordinates for (32,32) in our texture
ImVec4 bg_col = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); // Black background
ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint
if (ImGui::ImageButton("", my_tex_id, size, uv0, uv1, bg_col, tint_col))
pressed_count += 1;
if (i > 0)
ImGui::Text("Pressed %d times.", pressed_count);
if (ImGui::TreeNode("Combo"))
// Combo Boxes are also called "Dropdown" in other systems
// Expose flags as checkbox for the demo
static ImGuiComboFlags flags = 0;
ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", &flags, ImGuiComboFlags_PopupAlignLeft);
ImGui::SameLine(); HelpMarker("Only makes a difference if the popup is larger than the combo");
if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", &flags, ImGuiComboFlags_NoArrowButton))
flags &= ~ImGuiComboFlags_NoPreview; // Clear incompatible flags
if (ImGui::CheckboxFlags("ImGuiComboFlags_NoPreview", &flags, ImGuiComboFlags_NoPreview))
flags &= ~(ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_WidthFitPreview); // Clear incompatible flags
if (ImGui::CheckboxFlags("ImGuiComboFlags_WidthFitPreview", &flags, ImGuiComboFlags_WidthFitPreview))
flags &= ~ImGuiComboFlags_NoPreview;
// Override default popup height
if (ImGui::CheckboxFlags("ImGuiComboFlags_HeightSmall", &flags, ImGuiComboFlags_HeightSmall))
flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightSmall);
if (ImGui::CheckboxFlags("ImGuiComboFlags_HeightRegular", &flags, ImGuiComboFlags_HeightRegular))
flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightRegular);
if (ImGui::CheckboxFlags("ImGuiComboFlags_HeightLargest", &flags, ImGuiComboFlags_HeightLargest))
flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightLargest);
// Using the generic BeginCombo() API, you have full control over how to display the combo contents.
// (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
// stored in the object itself, etc.)
const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" };
static int item_current_idx = 0; // Here we store our selection data as an index.
// Pass in the preview value visible before opening the combo (it could technically be different contents or not pulled from items[])
const char* combo_preview_value = items[item_current_idx];
if (ImGui::BeginCombo("combo 1", combo_preview_value, flags))
for (int n = 0; n < IM_ARRAYSIZE(items); n++)
const bool is_selected = (item_current_idx == n);
if (ImGui::Selectable(items[n], is_selected))
item_current_idx = n;
// Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
if (is_selected)
ImGui::SeparatorText("One-liner variants");
HelpMarker("Flags above don't apply to this section.");
// Simplified one-liner Combo() API, using values packed in a single constant string
// This is a convenience for when the selection set is small and known at compile-time.
static int item_current_2 = 0;
ImGui::Combo("combo 2 (one-liner)", &item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
// Simplified one-liner Combo() using an array of const char*
// This is not very useful (may obsolete): prefer using BeginCombo()/EndCombo() for full control.
static int item_current_3 = -1; // If the selection isn't within 0..count, Combo won't display a preview
ImGui::Combo("combo 3 (array)", &item_current_3, items, IM_ARRAYSIZE(items));
// Simplified one-liner Combo() using an accessor function
static int item_current_4 = 0;
ImGui::Combo("combo 4 (function)", &item_current_4, [](void* data, int n) { return ((const char**)data)[n]; }, items, IM_ARRAYSIZE(items));
IMGUI_DEMO_MARKER("Widgets/List Boxes");
if (ImGui::TreeNode("List boxes"))
// BeginListBox() is essentially a thin wrapper to using BeginChild()/EndChild()
// using the ImGuiChildFlags_FrameStyle flag for stylistic changes + displaying a label.
// You may be tempted to simply use BeginChild() directly. However note that BeginChild() requires EndChild()
// to always be called (inconsistent with BeginListBox()/EndListBox()).
// Using the generic BeginListBox() API, you have full control over how to display the combo contents.
// (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
// stored in the object itself, etc.)
const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" };
static int item_current_idx = 0; // Here we store our selection data as an index.
if (ImGui::BeginListBox("listbox 1"))
for (int n = 0; n < IM_ARRAYSIZE(items); n++)
const bool is_selected = (item_current_idx == n);
if (ImGui::Selectable(items[n], is_selected))
item_current_idx = n;
// Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
if (is_selected)
ImGui::SameLine(); HelpMarker("Here we are sharing selection state between both boxes.");
// Custom size: use all width, 5 items tall
if (ImGui::BeginListBox("##listbox 2", ImVec2(-FLT_MIN, 5 * ImGui::GetTextLineHeightWithSpacing())))
for (int n = 0; n < IM_ARRAYSIZE(items); n++)
const bool is_selected = (item_current_idx == n);
if (ImGui::Selectable(items[n], is_selected))
item_current_idx = n;
// Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
if (is_selected)
if (ImGui::TreeNode("Selectables"))
// Selectable() has 2 overloads:
// - The one taking "bool selected" as a read-only selection information.
// When Selectable() has been clicked it returns true and you can alter selection state accordingly.
// - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases)
// The earlier is more flexible, as in real application your selection may be stored in many different ways
// and not necessarily inside a bool value (e.g. in flags within objects, as an external list, etc).
if (ImGui::TreeNode("Basic"))
static bool selection[5] = { false, true, false, false };
ImGui::Selectable("1. I am selectable", &selection[0]);
ImGui::Selectable("2. I am selectable", &selection[1]);
ImGui::Selectable("3. I am selectable", &selection[2]);
if (ImGui::Selectable("4. I am double clickable", selection[3], ImGuiSelectableFlags_AllowDoubleClick))
if (ImGui::IsMouseDoubleClicked(0))
selection[3] = !selection[3];
IMGUI_DEMO_MARKER("Widgets/Selectables/Single Selection");
if (ImGui::TreeNode("Selection State: Single Selection"))
static int selected = -1;
for (int n = 0; n < 5; n++)
char buf[32];
sprintf(buf, "Object %d", n);
if (ImGui::Selectable(buf, selected == n))
selected = n;
IMGUI_DEMO_MARKER("Widgets/Selectables/Multiple Selection");
if (ImGui::TreeNode("Selection State: Multiple Selection"))
HelpMarker("Hold CTRL and click to select multiple items.");
static bool selection[5] = { false, false, false, false, false };
for (int n = 0; n < 5; n++)
char buf[32];
sprintf(buf, "Object %d", n);
if (ImGui::Selectable(buf, selection[n]))
if (!ImGui::GetIO().KeyCtrl) // Clear selection when CTRL is not held
memset(selection, 0, sizeof(selection));
selection[n] ^= 1;
IMGUI_DEMO_MARKER("Widgets/Selectables/Rendering more items on the same line");
if (ImGui::TreeNode("Rendering more items on the same line"))
// (1) Using SetNextItemAllowOverlap()
// (2) Using the Selectable() override that takes "bool* p_selected" parameter, the bool value is toggled automatically.
static bool selected[3] = { false, false, false };
ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("main.c", &selected[0]); ImGui::SameLine(); ImGui::SmallButton("Link 1");
ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("Hello.cpp", &selected[1]); ImGui::SameLine(); ImGui::SmallButton("Link 2");
ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("Hello.h", &selected[2]); ImGui::SameLine(); ImGui::SmallButton("Link 3");
IMGUI_DEMO_MARKER("Widgets/Selectables/In columns");
if (ImGui::TreeNode("In columns"))
static bool selected[10] = {};
if (ImGui::BeginTable("split1", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders))
for (int i = 0; i < 10; i++)
char label[32];
sprintf(label, "Item %d", i);
ImGui::Selectable(label, &selected[i]); // FIXME-TABLE: Selection overlap
if (ImGui::BeginTable("split2", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders))
for (int i = 0; i < 10; i++)
char label[32];
sprintf(label, "Item %d", i);
ImGui::Selectable(label, &selected[i], ImGuiSelectableFlags_SpanAllColumns);
ImGui::Text("Some other contents");
if (ImGui::TreeNode("Grid"))
static char selected[4][4] = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } };
// Add in a bit of silly fun...
const float time = (float)ImGui::GetTime();
const bool winning_state = memchr(selected, 0, sizeof(selected)) == NULL; // If all cells are selected...
if (winning_state)
ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f + 0.5f * cosf(time * 2.0f), 0.5f + 0.5f * sinf(time * 3.0f)));
for (int y = 0; y < 4; y++)
for (int x = 0; x < 4; x++)
if (x > 0)
ImGui::PushID(y * 4 + x);
if (ImGui::Selectable("Sailor", selected[y][x] != 0, 0, ImVec2(50, 50)))
// Toggle clicked cell + toggle neighbors
selected[y][x] ^= 1;
if (x > 0) { selected[y][x - 1] ^= 1; }
if (x < 3) { selected[y][x + 1] ^= 1; }
if (y > 0) { selected[y - 1][x] ^= 1; }
if (y < 3) { selected[y + 1][x] ^= 1; }
if (winning_state)
if (ImGui::TreeNode("Alignment"))
"By default, Selectables uses style.SelectableTextAlign but it can be overridden 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");
static bool selected[3 * 3] = { true, false, true, false, true, false, true, false, true };
for (int y = 0; y < 3; y++)
for (int x = 0; x < 3; x++)
ImVec2 alignment = ImVec2((float)x / 2.0f, (float)y / 2.0f);
char name[32];
sprintf(name, "(%.1f,%.1f)", alignment.x, alignment.y);
if (x > 0) ImGui::SameLine();
ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, alignment);
ImGui::Selectable(name, &selected[3 * y + x], ImGuiSelectableFlags_None, ImVec2(80, 80));
// To wire InputText() with std::string or any other custom string type,
// see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file.
IMGUI_DEMO_MARKER("Widgets/Text Input");
if (ImGui::TreeNode("Text Input"))
IMGUI_DEMO_MARKER("Widgets/Text Input/Multi-line Text Input");
if (ImGui::TreeNode("Multi-line Text Input"))
// Note: we are using a fixed-sized buffer for simplicity here. See ImGuiInputTextFlags_CallbackResize
// and the code in misc/cpp/imgui_stdlib.h for how to setup InputText() for dynamically resizing strings.
static char text[1024 * 16] =
" The Pentium F00F bug, shorthand for F0 0F C7 C8,\n"
" the hexadecimal encoding of one offending instruction,\n"
" more formally, the invalid operand with locked CMPXCHG8B\n"
" instruction bug, is a design flaw in the majority of\n"
" Intel Pentium, Pentium MMX, and Pentium OverDrive\n"
" processors (all in the P5 microarchitecture).\n"
"\tlock cmpxchg8b eax\n";
static ImGuiInputTextFlags flags = ImGuiInputTextFlags_AllowTabInput;
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)");
ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly);
ImGui::CheckboxFlags("ImGuiInputTextFlags_AllowTabInput", &flags, ImGuiInputTextFlags_AllowTabInput);
ImGui::SameLine(); HelpMarker("When _AllowTabInput is set, passing through the widget with Tabbing doesn't automatically activate it, in order to also cycling through subsequent widgets.");
ImGui::CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", &flags, ImGuiInputTextFlags_CtrlEnterForNewLine);
ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16), flags);
IMGUI_DEMO_MARKER("Widgets/Text Input/Filtered Text Input");
if (ImGui::TreeNode("Filtered Text Input"))
struct TextFilters
// Modify character input by altering 'data->Eventchar' (ImGuiInputTextFlags_CallbackCharFilter callback)
static int FilterCasingSwap(ImGuiInputTextCallbackData* data)
if (data->EventChar >= 'a' && data->EventChar <= 'z') { data->EventChar -= 'a' - 'A'; } // Lowercase becomes uppercase
else if (data->EventChar >= 'A' && data->EventChar <= 'Z') { data->EventChar += 'a' - 'A'; } // Uppercase becomes lowercase
return 0;
// Return 0 (pass) if the character is 'i' or 'm' or 'g' or 'u' or 'i', otherwise return 1 (filter out)
static int FilterImGuiLetters(ImGuiInputTextCallbackData* data)
if (data->EventChar < 256 && strchr("imgui", (char)data->EventChar))
return 0;
return 1;
static char buf1[32] = ""; ImGui::InputText("default", buf1, 32);
static char buf2[32] = ""; ImGui::InputText("decimal", buf2, 32, ImGuiInputTextFlags_CharsDecimal);
static char buf3[32] = ""; ImGui::InputText("hexadecimal", buf3, 32, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase);
static char buf4[32] = ""; ImGui::InputText("uppercase", buf4, 32, ImGuiInputTextFlags_CharsUppercase);
static char buf5[32] = ""; ImGui::InputText("no blank", buf5, 32, ImGuiInputTextFlags_CharsNoBlank);
static char buf6[32] = ""; ImGui::InputText("casing swap", buf6, 32, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterCasingSwap); // Use CharFilter callback to replace characters.
static char buf7[32] = ""; ImGui::InputText("\"imgui\"", buf7, 32, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters); // Use CharFilter callback to disable some characters.
IMGUI_DEMO_MARKER("Widgets/Text Input/Password input");
if (ImGui::TreeNode("Password Input"))
static char password[64] = "password123";
ImGui::InputText("password", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password);
ImGui::SameLine(); HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n");
ImGui::InputTextWithHint("password (w/ hint)", "<password>", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password);
ImGui::InputText("password (clear)", password, IM_ARRAYSIZE(password));
IMGUI_DEMO_MARKER("Widgets/Text Input/Completion, History, Edit Callbacks");
if (ImGui::TreeNode("Completion, History, Edit Callbacks"))
struct Funcs
static int MyCallback(ImGuiInputTextCallbackData* data)
if (data->EventFlag == ImGuiInputTextFlags_CallbackCompletion)
data->InsertChars(data->CursorPos, "..");
else if (data->EventFlag == ImGuiInputTextFlags_CallbackHistory)
if (data->EventKey == ImGuiKey_UpArrow)
data->DeleteChars(0, data->BufTextLen);
data->InsertChars(0, "Pressed Up!");
else if (data->EventKey == ImGuiKey_DownArrow)
data->DeleteChars(0, data->BufTextLen);
data->InsertChars(0, "Pressed Down!");
else if (data->EventFlag == ImGuiInputTextFlags_CallbackEdit)
// Toggle casing of first character
char c = data->Buf[0];
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) data->Buf[0] ^= 32;
data->BufDirty = true;
// Increment a counter
int* p_int = (int*)data->UserData;
*p_int = *p_int + 1;
return 0;
static char buf1[64];
ImGui::InputText("Completion", buf1, 64, ImGuiInputTextFlags_CallbackCompletion, Funcs::MyCallback);
ImGui::SameLine(); HelpMarker(
"Here we append \"..\" each time Tab is pressed. "
"See 'Examples>Console' for a more meaningful demonstration of using this callback.");
static char buf2[64];
ImGui::InputText("History", buf2, 64, ImGuiInputTextFlags_CallbackHistory, Funcs::MyCallback);
ImGui::SameLine(); HelpMarker(
"Here we replace and select text each time Up/Down are pressed. "
"See 'Examples>Console' for a more meaningful demonstration of using this callback.");
static char buf3[64];
static int edit_count = 0;
ImGui::InputText("Edit", buf3, 64, ImGuiInputTextFlags_CallbackEdit, Funcs::MyCallback, (void*)&edit_count);
ImGui::SameLine(); HelpMarker(
"Here we toggle the casing of the first character on every edit + count edits.");
ImGui::SameLine(); ImGui::Text("(%d)", edit_count);
IMGUI_DEMO_MARKER("Widgets/Text Input/Resize Callback");
if (ImGui::TreeNode("Resize Callback"))
// To wire InputText() with std::string or any other custom string type,
// you can use the ImGuiInputTextFlags_CallbackResize flag + create a custom ImGui::InputText() wrapper
// using your preferred type. See misc/cpp/imgui_stdlib.h for an implementation of this using std::string.
"Using ImGuiInputTextFlags_CallbackResize to wire your custom string type to InputText().\n\n"
"See misc/cpp/imgui_stdlib.h for an implementation of this for std::string.");
struct Funcs
static int MyResizeCallback(ImGuiInputTextCallbackData* data)
if (data->EventFlag == ImGuiInputTextFlags_CallbackResize)
ImVector<char>* my_str = (ImVector<char>*)data->UserData;
IM_ASSERT(my_str->begin() == data->Buf);
my_str->resize(data->BufSize); // NB: On resizing calls, generally data->BufSize == data->BufTextLen + 1
data->Buf = my_str->begin();
return 0;
// Note: Because ImGui:: is a namespace you would typically add your own function into the namespace.
// For example, you code may declare a function 'ImGui::InputText(const char* label, MyString* my_str)'
static bool MyInputTextMultiline(const char* label, ImVector<char>* my_str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0)
IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
return ImGui::InputTextMultiline(label, my_str->begin(), (size_t)my_str->size(), size, flags | ImGuiInputTextFlags_CallbackResize, Funcs::MyResizeCallback, (void*)my_str);
// For this demo we are using ImVector as a string container.
// 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.
static ImVector<char> my_str;
if (my_str.empty())
Funcs::MyInputTextMultiline("##MyStr", &my_str, ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16));
ImGui::Text("Data: %p\nSize: %d\nCapacity: %d", (void*)my_str.begin(), my_str.size(), my_str.capacity());
IMGUI_DEMO_MARKER("Widgets/Text Input/Miscellaneous");
if (ImGui::TreeNode("Miscellaneous"))
static char buf1[16];
static ImGuiInputTextFlags flags = ImGuiInputTextFlags_EscapeClearsAll;
ImGui::CheckboxFlags("ImGuiInputTextFlags_EscapeClearsAll", &flags, ImGuiInputTextFlags_EscapeClearsAll);
ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly);
ImGui::CheckboxFlags("ImGuiInputTextFlags_NoUndoRedo", &flags, ImGuiInputTextFlags_NoUndoRedo);
ImGui::InputText("Hello", buf1, IM_ARRAYSIZE(buf1), flags);
// Tabs
if (ImGui::TreeNode("Tabs"))
if (ImGui::TreeNode("Basic"))
ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None;
if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
if (ImGui::BeginTabItem("Avocado"))
ImGui::Text("This is the Avocado tab!\nblah blah blah blah blah");
if (ImGui::BeginTabItem("Broccoli"))
ImGui::Text("This is the Broccoli tab!\nblah blah blah blah blah");
if (ImGui::BeginTabItem("Cucumber"))
ImGui::Text("This is the Cucumber tab!\nblah blah blah blah blah");
IMGUI_DEMO_MARKER("Widgets/Tabs/Advanced & Close Button");
if (ImGui::TreeNode("Advanced & Close Button"))
// Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0).
static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable;
ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", &tab_bar_flags, ImGuiTabBarFlags_Reorderable);
ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", &tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs);
ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton);
ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", &tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton);
if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0)
tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_;
if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown))
tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown);
if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll))
tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll);
// Tab Bar
const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" };
static bool opened[4] = { true, true, true, true }; // Persistent user state
for (int n = 0; n < IM_ARRAYSIZE(opened); n++)
if (n > 0) { ImGui::SameLine(); }
ImGui::Checkbox(names[n], &opened[n]);
// 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.
if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
for (int n = 0; n < IM_ARRAYSIZE(opened); n++)
if (opened[n] && ImGui::BeginTabItem(names[n], &opened[n], ImGuiTabItemFlags_None))
ImGui::Text("This is the %s tab!", names[n]);
if (n & 1)
ImGui::Text("I am an odd tab.");
IMGUI_DEMO_MARKER("Widgets/Tabs/TabItemButton & Leading-Trailing flags");
if (ImGui::TreeNode("TabItemButton & Leading/Trailing flags"))
static ImVector<int> active_tabs;
static int next_tab_id = 0;
if (next_tab_id == 0) // Initialize with some default tabs
for (int i = 0; i < 3; i++)
// TabItemButton() and Leading/Trailing flags are distinct features which we will demo together.
// (It is possible to submit regular tabs with Leading/Trailing flags, or TabItemButton tabs without Leading/Trailing flags...
// but they tend to make more sense together)
static bool show_leading_button = true;
static bool show_trailing_button = true;
ImGui::Checkbox("Show Leading TabItemButton()", &show_leading_button);
ImGui::Checkbox("Show Trailing TabItemButton()", &show_trailing_button);
// Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs
static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_FittingPolicyResizeDown;
ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton);
if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown))
tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown);
if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll))
tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll);
if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
// Demo a Leading TabItemButton(): click the "?" button to open a menu
if (show_leading_button)
if (ImGui::TabItemButton("?", ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_NoTooltip))
if (ImGui::BeginPopup("MyHelpMenu"))
// Demo Trailing Tabs: click the "+" button to add a new tab.
// (In your app you may want to use a font icon instead of the "+")
// We submit it before the regular tabs, but thanks to the ImGuiTabItemFlags_Trailing flag it will always appear at the end.
if (show_trailing_button)
if (ImGui::TabItemButton("+", ImGuiTabItemFlags_Trailing | ImGuiTabItemFlags_NoTooltip))
active_tabs.push_back(next_tab_id++); // Add new tab
// Submit our regular tabs
for (int n = 0; n < active_tabs.Size; )
bool open = true;
char name[16];
snprintf(name, IM_ARRAYSIZE(name), "%04d", active_tabs[n]);
if (ImGui::BeginTabItem(name, &open, ImGuiTabItemFlags_None))
ImGui::Text("This is the %s tab!", name);
if (!open)
active_tabs.erase(active_tabs.Data + n);
// Plot/Graph widgets are not very good.
// Consider using a third-party library such as ImPlot:
// (see others
if (ImGui::TreeNode("Plotting"))
static bool animate = true;
ImGui::Checkbox("Animate", &animate);
// Plot as lines and plot as histogram
IMGUI_DEMO_MARKER("Widgets/Plotting/PlotLines, PlotHistogram");
static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr));
ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0, 80.0f));
//ImGui::SameLine(); HelpMarker("Consider using ImPlot instead!");
// Fill an array of contiguous float values to plot
// 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.
static float values[90] = {};
static int values_offset = 0;
static double refresh_time = 0.0;
if (!animate || refresh_time == 0.0)
refresh_time = ImGui::GetTime();
while (refresh_time < ImGui::GetTime()) // Create data at fixed 60 Hz rate for the demo
static float phase = 0.0f;
values[values_offset] = cosf(phase);
values_offset = (values_offset + 1) % IM_ARRAYSIZE(values);
phase += 0.10f * values_offset;
refresh_time += 1.0f / 60.0f;
// Plots can display overlay texts
// (in this example, we will display an average value)
float average = 0.0f;
for (int n = 0; n < IM_ARRAYSIZE(values); n++)
average += values[n];
average /= (float)IM_ARRAYSIZE(values);
char overlay[32];
sprintf(overlay, "avg %f", average);
ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, overlay, -1.0f, 1.0f, ImVec2(0, 80.0f));
// Use functions to generate output
// FIXME: This is actually VERY awkward because current plot API only pass in indices.
// We probably want an API passing floats and user provide sample rate/count.
struct Funcs
static float Sin(void*, int i) { return sinf(i * 0.1f); }
static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; }
static int func_type = 0, display_count = 70;
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
ImGui::Combo("func", &func_type, "Sin\0Saw\0");
ImGui::SliderInt("Sample count", &display_count, 1, 400);
float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw;
ImGui::PlotLines("Lines", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
ImGui::PlotHistogram("Histogram", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
// Animate a simple progress bar
static float progress = 0.0f, progress_dir = 1.0f;
if (animate)
progress += progress_dir * 0.4f * ImGui::GetIO().DeltaTime;
if (progress >= +1.1f) { progress = +1.1f; progress_dir *= -1.0f; }
if (progress <= -0.1f) { progress = -0.1f; progress_dir *= -1.0f; }
// Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width,
// or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth.
ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f));
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
ImGui::Text("Progress Bar");
float progress_saturated = IM_CLAMP(progress, 0.0f, 1.0f);
char buf[32];
sprintf(buf, "%d/%d", (int)(progress_saturated * 1753), 1753);
ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), buf);
if (ImGui::TreeNode("Color/Picker Widgets"))
static ImVec4 color = ImVec4(114.0f / 255.0f, 144.0f / 255.0f, 154.0f / 255.0f, 200.0f / 255.0f);
static bool alpha_preview = true;
static bool alpha_half_preview = false;
static bool drag_and_drop = true;
static bool options_menu = true;
static bool hdr = false;
ImGui::Checkbox("With Alpha Preview", &alpha_preview);
ImGui::Checkbox("With Half Alpha Preview", &alpha_half_preview);
ImGui::Checkbox("With Drag and Drop", &drag_and_drop);
ImGui::Checkbox("With Options Menu", &options_menu); ImGui::SameLine(); HelpMarker("Right-click on the individual color widget to show options.");
ImGui::Checkbox("With HDR", &hdr); ImGui::SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets.");
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);
ImGui::SeparatorText("Inline color editor");
ImGui::Text("Color widget:");
ImGui::SameLine(); HelpMarker(
"Click on the color square to open a color picker.\n"
"CTRL+click on individual component to input value.\n");
ImGui::ColorEdit3("MyColor##1", (float*)&color, misc_flags);
IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (HSV, with Alpha)");
ImGui::Text("Color widget HSV with Alpha:");
ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_DisplayHSV | misc_flags);
IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (float display)");
ImGui::Text("Color widget with Float Display:");
ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | misc_flags);
IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with Picker)");
ImGui::Text("Color button with Picker:");
ImGui::SameLine(); HelpMarker(
"With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\n"
"With the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only "
"be used for the tooltip and picker popup.");
ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | misc_flags);
IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with custom Picker popup)");
ImGui::Text("Color button with Custom Picker Popup:");
// Generate a default palette. The palette will persist and can be edited.
static bool saved_palette_init = true;
static ImVec4 saved_palette[32] = {};
if (saved_palette_init)
for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++)
ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f,
saved_palette[n].x, saved_palette[n].y, saved_palette[n].z);
saved_palette[n].w = 1.0f; // Alpha
saved_palette_init = false;
static ImVec4 backup_color;
bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags);
ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x);
open_popup |= ImGui::Button("Palette");
if (open_popup)
backup_color = color;
if (ImGui::BeginPopup("mypicker"))
ImGui::ColorPicker4("##picker", (float*)&color, misc_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview);
ImGui::BeginGroup(); // Lock X position
ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40));
if (ImGui::ColorButton("##previous", backup_color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40)))
color = backup_color;
for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++)
if ((n % 8) != 0)
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y);
ImGuiColorEditFlags palette_button_flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip;
if (ImGui::ColorButton("##palette", saved_palette[n], palette_button_flags, ImVec2(20, 20)))
color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha!
// Allow user to drop colors into each palette entry. Note that ColorButton() is already a
// drag source by default, unless specifying the ImGuiColorEditFlags_NoDragDrop flag.
if (ImGui::BeginDragDropTarget())
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3);
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F))
memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4);
IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (simple)");
ImGui::Text("Color button only:");
static bool no_border = false;
ImGui::Checkbox("ImGuiColorEditFlags_NoBorder", &no_border);
ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, misc_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80));
ImGui::SeparatorText("Color picker");
static bool alpha = true;
static bool alpha_bar = true;
static bool side_preview = true;
static bool ref_color = false;
static ImVec4 ref_color_v(1.0f, 0.0f, 1.0f, 0.5f);
static int display_mode = 0;
static int picker_mode = 0;
ImGui::Checkbox("With Alpha", &alpha);
ImGui::Checkbox("With Alpha Bar", &alpha_bar);
ImGui::Checkbox("With Side Preview", &side_preview);
if (side_preview)
ImGui::Checkbox("With Ref Color", &ref_color);
if (ref_color)
ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | misc_flags);
ImGui::Combo("Display Mode", &display_mode, "Auto/Current\0None\0RGB Only\0HSV Only\0Hex Only\0");
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 on those inputs.\n\nColorPicker defaults to displaying RGB+HSV+Hex "
"if you don't specify a display mode.\n\nYou can change the defaults using SetColorEditOptions().");
ImGui::SameLine(); HelpMarker("When not specified explicitly (Auto/Current mode), user can right-click the picker to change mode.");
ImGuiColorEditFlags flags = misc_flags;
if (!alpha) flags |= ImGuiColorEditFlags_NoAlpha; // This is by default if you call ColorPicker3() instead of ColorPicker4()
if (alpha_bar) flags |= ImGuiColorEditFlags_AlphaBar;
if (!side_preview) flags |= ImGuiColorEditFlags_NoSidePreview;
if (picker_mode == 1) flags |= ImGuiColorEditFlags_PickerHueBar;
if (picker_mode == 2) flags |= ImGuiColorEditFlags_PickerHueWheel;
if (display_mode == 1) flags |= ImGuiColorEditFlags_NoInputs; // Disable all RGB/HSV/Hex displays
if (display_mode == 2) flags |= ImGuiColorEditFlags_DisplayRGB; // Override display mode
if (display_mode == 3) flags |= ImGuiColorEditFlags_DisplayHSV;
if (display_mode == 4) flags |= ImGuiColorEditFlags_DisplayHex;
ImGui::ColorPicker4("MyColor##4", (float*)&color, flags, ref_color ? &ref_color_v.x : NULL);
ImGui::Text("Set defaults in code:");
ImGui::SameLine(); HelpMarker(
"SetColorEditOptions() is designed to allow you to set boot-time default.\n"
"We 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.");
if (ImGui::Button("Default: Uint8 + HSV + Hue Bar"))
ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_PickerHueBar);
if (ImGui::Button("Default: Float + HDR + Hue Wheel"))
ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel);
// Always display a small version of both types of pickers
// (that's in order to make it more visible in the demo to people who are skimming quickly through it)
ImGui::Text("Both types:");
float w = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.y) * 0.40f;
ImGui::ColorPicker3("##MyColor##5", (float*)&color, ImGuiColorEditFlags_PickerHueBar | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha);
ImGui::ColorPicker3("##MyColor##6", (float*)&color, ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha);
// HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0)
static ImVec4 color_hsv(0.23f, 1.0f, 1.0f, 1.0f); // Stored as HSV!
ImGui::Text("HSV encoded colors");
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.");
ImGui::Text("Color widget with InputHSV:");
ImGui::ColorEdit4("HSV shown as RGB##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float);
ImGui::ColorEdit4("HSV shown as HSV##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float);
ImGui::DragFloat4("Raw HSV values", (float*)&color_hsv, 0.01f, 0.0f, 1.0f);
IMGUI_DEMO_MARKER("Widgets/Drag and Slider Flags");
if (ImGui::TreeNode("Drag/Slider Flags"))
// Demonstrate using advanced flags for DragXXX and SliderXXX functions. Note that the flags are the same!
static ImGuiSliderFlags flags = ImGuiSliderFlags_None;
ImGui::CheckboxFlags("ImGuiSliderFlags_AlwaysClamp", &flags, ImGuiSliderFlags_AlwaysClamp);
ImGui::SameLine(); HelpMarker("Always clamp value to min/max bounds (if any) when input manually with CTRL+Click.");
ImGui::CheckboxFlags("ImGuiSliderFlags_Logarithmic", &flags, ImGuiSliderFlags_Logarithmic);
ImGui::SameLine(); HelpMarker("Enable logarithmic editing (more precision for small values).");
ImGui::CheckboxFlags("ImGuiSliderFlags_NoRoundToFormat", &flags, ImGuiSliderFlags_NoRoundToFormat);
ImGui::SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits).");
ImGui::CheckboxFlags("ImGuiSliderFlags_NoInput", &flags, ImGuiSliderFlags_NoInput);
ImGui::SameLine(); HelpMarker("Disable CTRL+Click or Enter key allowing to input text directly into the widget.");
// Drags
static float drag_f = 0.5f;
static int drag_i = 50;
ImGui::Text("Underlying float value: %f", drag_f);
ImGui::DragFloat("DragFloat (0 -> 1)", &drag_f, 0.005f, 0.0f, 1.0f, "%.3f", flags);
ImGui::DragFloat("DragFloat (0 -> +inf)", &drag_f, 0.005f, 0.0f, FLT_MAX, "%.3f", flags);
ImGui::DragFloat("DragFloat (-inf -> 1)", &drag_f, 0.005f, -FLT_MAX, 1.0f, "%.3f", flags);
ImGui::DragFloat("DragFloat (-inf -> +inf)", &drag_f, 0.005f, -FLT_MAX, +FLT_MAX, "%.3f", flags);
ImGui::DragInt("DragInt (0 -> 100)", &drag_i, 0.5f, 0, 100, "%d", flags);
// Sliders
static float slider_f = 0.5f;
static int slider_i = 50;
ImGui::Text("Underlying float value: %f", slider_f);
ImGui::SliderFloat("SliderFloat (0 -> 1)", &slider_f, 0.0f, 1.0f, "%.3f", flags);
ImGui::SliderInt("SliderInt (0 -> 100)", &slider_i, 0, 100, "%d", flags);
IMGUI_DEMO_MARKER("Widgets/Range Widgets");
if (ImGui::TreeNode("Range Widgets"))
static float begin = 10, end = 90;
static int begin_i = 100, end_i = 1000;
ImGui::DragFloatRange2("range float", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%", ImGuiSliderFlags_AlwaysClamp);
ImGui::DragIntRange2("range int", &begin_i, &end_i, 5, 0, 1000, "Min: %d units", "Max: %d units");
ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %d units", "Max: %d units");
IMGUI_DEMO_MARKER("Widgets/Data Types");
if (ImGui::TreeNode("Data Types"))
// DragScalar/InputScalar/SliderScalar functions allow various data types
// - signed/unsigned
// - 8/16/32/64-bits
// - integer/float/double
// To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum
// to pass the type, and passing all arguments by pointer.
// This is the reason the test code below creates local variables to hold "zero" "one" etc. for each type.
// In practice, if you frequently use a given type that is not covered by the normal API entry points,
// you can wrap it yourself inside a 1 line function which can take typed argument as value instead of void*,
// and then pass their address to the generic function. For example:
// bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld")
// {
// return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format);
// }
// Setup limits (as helper variables so we can take their address, as explained above)
// Note: SliderScalar() functions have a maximum usable range of half the natural type maximum, hence the /2.
#ifndef LLONG_MIN
ImS64 LLONG_MIN = -9223372036854775807LL - 1;
ImS64 LLONG_MAX = 9223372036854775807LL;
ImU64 ULLONG_MAX = (2ULL * 9223372036854775807LL + 1);
const char s8_zero = 0, s8_one = 1, s8_fifty = 50, s8_min = -128, s8_max = 127;
const ImU8 u8_zero = 0, u8_one = 1, u8_fifty = 50, u8_min = 0, u8_max = 255;
const short s16_zero = 0, s16_one = 1, s16_fifty = 50, s16_min = -32768, s16_max = 32767;
const ImU16 u16_zero = 0, u16_one = 1, u16_fifty = 50, u16_min = 0, u16_max = 65535;
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;
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;
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;
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;
const float f32_zero = 0.f, f32_one = 1.f, f32_lo_a = -10000000000.0f, f32_hi_a = +10000000000.0f;
const double f64_zero = 0., f64_one = 1., f64_lo_a = -1000000000000000.0, f64_hi_a = +1000000000000000.0;
// State
static char s8_v = 127;
static ImU8 u8_v = 255;
static short s16_v = 32767;
static ImU16 u16_v = 65535;
static ImS32 s32_v = -1;
static ImU32 u32_v = (ImU32)-1;
static ImS64 s64_v = -1;
static ImU64 u64_v = (ImU64)-1;
static float f32_v = 0.123f;
static double f64_v = 90000.01234567890123456789;
const float drag_speed = 0.2f;
static bool drag_clamp = false;
IMGUI_DEMO_MARKER("Widgets/Data Types/Drags");
ImGui::Checkbox("Clamp integers to 0..50", &drag_clamp);
ImGui::SameLine(); HelpMarker(
"As with every widget in dear imgui, we never modify values unless there is a user interaction.\n"
"You can override the clamping limits by using CTRL+Click to input a value.");
ImGui::DragScalar("drag s8", ImGuiDataType_S8, &s8_v, drag_speed, drag_clamp ? &s8_zero : NULL, drag_clamp ? &s8_fifty : NULL);
ImGui::DragScalar("drag u8", ImGuiDataType_U8, &u8_v, drag_speed, drag_clamp ? &u8_zero : NULL, drag_clamp ? &u8_fifty : NULL, "%u ms");
ImGui::DragScalar("drag s16", ImGuiDataType_S16, &s16_v, drag_speed, drag_clamp ? &s16_zero : NULL, drag_clamp ? &s16_fifty : NULL);
ImGui::DragScalar("drag u16", ImGuiDataType_U16, &u16_v, drag_speed, drag_clamp ? &u16_zero : NULL, drag_clamp ? &u16_fifty : NULL, "%u ms");
ImGui::DragScalar("drag s32", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL);
ImGui::DragScalar("drag s32 hex", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL, "0x%08X");
ImGui::DragScalar("drag u32", ImGuiDataType_U32, &u32_v, drag_speed, drag_clamp ? &u32_zero : NULL, drag_clamp ? &u32_fifty : NULL, "%u ms");
ImGui::DragScalar("drag s64", ImGuiDataType_S64, &s64_v, drag_speed, drag_clamp ? &s64_zero : NULL, drag_clamp ? &s64_fifty : NULL);
ImGui::DragScalar("drag u64", ImGuiDataType_U64, &u64_v, drag_speed, drag_clamp ? &u64_zero : NULL, drag_clamp ? &u64_fifty : NULL);
ImGui::DragScalar("drag float", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f");
ImGui::DragScalar("drag float log", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f", ImGuiSliderFlags_Logarithmic);
ImGui::DragScalar("drag double", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, NULL, "%.10f grams");
ImGui::DragScalar("drag double log",ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", ImGuiSliderFlags_Logarithmic);
IMGUI_DEMO_MARKER("Widgets/Data Types/Sliders");
ImGui::SliderScalar("slider s8 full", ImGuiDataType_S8, &s8_v, &s8_min, &s8_max, "%d");
ImGui::SliderScalar("slider u8 full", ImGuiDataType_U8, &u8_v, &u8_min, &u8_max, "%u");
ImGui::SliderScalar("slider s16 full", ImGuiDataType_S16, &s16_v, &s16_min, &s16_max, "%d");
ImGui::SliderScalar("slider u16 full", ImGuiDataType_U16, &u16_v, &u16_min, &u16_max, "%u");
ImGui::SliderScalar("slider s32 low", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty,"%d");
ImGui::SliderScalar("slider s32 high", ImGuiDataType_S32, &s32_v, &s32_hi_a, &s32_hi_b, "%d");
ImGui::SliderScalar("slider s32 full", ImGuiDataType_S32, &s32_v, &s32_min, &s32_max, "%d");
ImGui::SliderScalar("slider s32 hex", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty, "0x%04X");
ImGui::SliderScalar("slider u32 low", ImGuiDataType_U32, &u32_v, &u32_zero, &u32_fifty,"%u");
ImGui::SliderScalar("slider u32 high", ImGuiDataType_U32, &u32_v, &u32_hi_a, &u32_hi_b, "%u");
ImGui::SliderScalar("slider u32 full", ImGuiDataType_U32, &u32_v, &u32_min, &u32_max, "%u");
ImGui::SliderScalar("slider s64 low", ImGuiDataType_S64, &s64_v, &s64_zero, &s64_fifty,"%" PRId64);
ImGui::SliderScalar("slider s64 high", ImGuiDataType_S64, &s64_v, &s64_hi_a, &s64_hi_b, "%" PRId64);
ImGui::SliderScalar("slider s64 full", ImGuiDataType_S64, &s64_v, &s64_min, &s64_max, "%" PRId64);
ImGui::SliderScalar("slider u64 low", ImGuiDataType_U64, &u64_v, &u64_zero, &u64_fifty,"%" PRIu64 " ms");
ImGui::SliderScalar("slider u64 high", ImGuiDataType_U64, &u64_v, &u64_hi_a, &u64_hi_b, "%" PRIu64 " ms");
ImGui::SliderScalar("slider u64 full", ImGuiDataType_U64, &u64_v, &u64_min, &u64_max, "%" PRIu64 " ms");
ImGui::SliderScalar("slider float low", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one);
ImGui::SliderScalar("slider float low log", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one, "%.10f", ImGuiSliderFlags_Logarithmic);
ImGui::SliderScalar("slider float high", ImGuiDataType_Float, &f32_v, &f32_lo_a, &f32_hi_a, "%e");
ImGui::SliderScalar("slider double low", ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f grams");
ImGui::SliderScalar("slider double low log",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f", ImGuiSliderFlags_Logarithmic);
ImGui::SliderScalar("slider double high", ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams");
ImGui::SeparatorText("Sliders (reverse)");
ImGui::SliderScalar("slider s8 reverse", ImGuiDataType_S8, &s8_v, &s8_max, &s8_min, "%d");
ImGui::SliderScalar("slider u8 reverse", ImGuiDataType_U8, &u8_v, &u8_max, &u8_min, "%u");
ImGui::SliderScalar("slider s32 reverse", ImGuiDataType_S32, &s32_v, &s32_fifty, &s32_zero, "%d");
ImGui::SliderScalar("slider u32 reverse", ImGuiDataType_U32, &u32_v, &u32_fifty, &u32_zero, "%u");
ImGui::SliderScalar("slider s64 reverse", ImGuiDataType_S64, &s64_v, &s64_fifty, &s64_zero, "%" PRId64);
ImGui::SliderScalar("slider u64 reverse", ImGuiDataType_U64, &u64_v, &u64_fifty, &u64_zero, "%" PRIu64 " ms");
IMGUI_DEMO_MARKER("Widgets/Data Types/Inputs");
static bool inputs_step = true;
ImGui::Checkbox("Show step buttons", &inputs_step);
ImGui::InputScalar("input s8", ImGuiDataType_S8, &s8_v, inputs_step ? &s8_one : NULL, NULL, "%d");
ImGui::InputScalar("input u8", ImGuiDataType_U8, &u8_v, inputs_step ? &u8_one : NULL, NULL, "%u");
ImGui::InputScalar("input s16", ImGuiDataType_S16, &s16_v, inputs_step ? &s16_one : NULL, NULL, "%d");
ImGui::InputScalar("input u16", ImGuiDataType_U16, &u16_v, inputs_step ? &u16_one : NULL, NULL, "%u");
ImGui::InputScalar("input s32", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%d");
ImGui::InputScalar("input s32 hex", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%04X");
ImGui::InputScalar("input u32", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%u");
ImGui::InputScalar("input u32 hex", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%08X");
ImGui::InputScalar("input s64", ImGuiDataType_S64, &s64_v, inputs_step ? &s64_one : NULL);
ImGui::InputScalar("input u64", ImGuiDataType_U64, &u64_v, inputs_step ? &u64_one : NULL);
ImGui::InputScalar("input float", ImGuiDataType_Float, &f32_v, inputs_step ? &f32_one : NULL);
ImGui::InputScalar("input double", ImGuiDataType_Double, &f64_v, inputs_step ? &f64_one : NULL);
IMGUI_DEMO_MARKER("Widgets/Multi-component Widgets");
if (ImGui::TreeNode("Multi-component Widgets"))
static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f };
static int vec4i[4] = { 1, 5, 100, 255 };
ImGui::InputFloat2("input float2", vec4f);
ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f);
ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f);
ImGui::InputInt2("input int2", vec4i);
ImGui::DragInt2("drag int2", vec4i, 1, 0, 255);
ImGui::SliderInt2("slider int2", vec4i, 0, 255);
ImGui::InputFloat3("input float3", vec4f);
ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f);
ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f);
ImGui::InputInt3("input int3", vec4i);
ImGui::DragInt3("drag int3", vec4i, 1, 0, 255);
ImGui::SliderInt3("slider int3", vec4i, 0, 255);
ImGui::InputFloat4("input float4", vec4f);
ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f);
ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f);
ImGui::InputInt4("input int4", vec4i);
ImGui::DragInt4("drag int4", vec4i, 1, 0, 255);
ImGui::SliderInt4("slider int4", vec4i, 0, 255);
IMGUI_DEMO_MARKER("Widgets/Vertical Sliders");
if (ImGui::TreeNode("Vertical Sliders"))
const float spacing = 4;
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
static int int_value = 0;
ImGui::VSliderInt("##int", ImVec2(18, 160), &int_value, 0, 5);
static float values[7] = { 0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f };
for (int i = 0; i < 7; i++)
if (i > 0) ImGui::SameLine();