openMSX
imgui_demo.cc
Go to the documentation of this file.
1// dear imgui, v1.91.5 WIP
2// (demo code)
3
4// Help:
5// - Read FAQ at http://dearimgui.com/faq
6// - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that.
7// - Need help integrating Dear ImGui in your codebase?
8// - Read Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started
9// - Read 'Programmer guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase.
10// Read top of imgui.cpp and imgui.h for many details, documentation, comments, links.
11// Get the latest version at https://github.com/ocornut/imgui
12
13// How to easily locate code?
14// - Use Tools->Item Picker to debug break in code by clicking any widgets: https://github.com/ocornut/imgui/wiki/Debug-Tools
15// - Browse an online version the demo with code linked to hovered widgets: https://pthom.github.io/imgui_manual_online/manual/imgui_manual.html
16// - Find a visible string and search for it in the code!
17
18//---------------------------------------------------
19// PLEASE DO NOT REMOVE THIS FILE FROM YOUR PROJECT!
20//---------------------------------------------------
21// Message to the person tempted to delete this file when integrating Dear ImGui into their codebase:
22// Think again! It is the most useful reference code that you and other coders will want to refer to and call.
23// Have the ImGui::ShowDemoWindow() function wired in an always-available debug menu of your game/app!
24// Also include Metrics! ItemPicker! DebugLog! and other debug features.
25// Removing this file from your project is hindering access to documentation for everyone in your team,
26// likely leading you to poorer usage of the library.
27// Everything in this file will be stripped out by the linker if you don't call ImGui::ShowDemoWindow().
28// If you want to link core Dear ImGui in your shipped builds but want a thorough guarantee that the demo will not be
29// linked, you can setup your imconfig.h with #define IMGUI_DISABLE_DEMO_WINDOWS and those functions will be empty.
30// In another situation, whenever you have Dear ImGui available you probably want this to be available for reference.
31// Thank you,
32// -Your beloved friend, imgui_demo.cpp (which you won't delete)
33
34//--------------------------------------------
35// ABOUT THE MEANING OF THE 'static' KEYWORD:
36//--------------------------------------------
37// In this demo code, we frequently use 'static' variables inside functions.
38// A static variable persists across calls. It is essentially a global variable but declared inside the scope of the function.
39// Think of "static int n = 0;" as "global int n = 0;" !
40// We do this IN THE DEMO because we want:
41// - to gather code and data in the same place.
42// - to make the demo source code faster to read, faster to change, smaller in size.
43// - it is also a convenient way of storing simple UI related information as long as your function
44// doesn't need to be reentrant or used in multiple threads.
45// This might be a pattern you will want to use in your code, but most of the data you would be working
46// with in a complex codebase is likely going to be stored outside your functions.
47
48//-----------------------------------------
49// ABOUT THE CODING STYLE OF OUR DEMO CODE
50//-----------------------------------------
51// The Demo code in this file is designed to be easy to copy-and-paste into your application!
52// Because of this:
53// - We never omit the ImGui:: prefix when calling functions, even though most code here is in the same namespace.
54// - We try to declare static variables in the local scope, as close as possible to the code using them.
55// - We never use any of the helpers/facilities used internally by Dear ImGui, unless available in the public API.
56// - We never use maths operators on ImVec2/ImVec4. For our other sources files we use them, and they are provided
57// by imgui.h using the IMGUI_DEFINE_MATH_OPERATORS define. For your own sources file they are optional
58// and require you either enable those, either provide your own via IM_VEC2_CLASS_EXTRA in imconfig.h.
59// Because we can't assume anything about your support of maths operators, we cannot use them in imgui_demo.cpp.
60
61// Navigating this file:
62// - In Visual Studio: CTRL+comma ("Edit.GoToAll") can follow symbols inside comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot.
63// - In Visual Studio w/ Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols inside comments.
64// - In VS Code, CLion, etc.: CTRL+click can follow symbols inside comments.
65// - You can search/grep for all sections listed in the index to find the section.
66
67/*
68
69Index of this file:
70
71// [SECTION] Forward Declarations
72// [SECTION] Helpers
73// [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor & Multi-Select demos)
74// [SECTION] Demo Window / ShowDemoWindow()
75// [SECTION] ShowDemoWindowMenuBar()
76// [SECTION] ShowDemoWindowWidgets()
77// [SECTION] ShowDemoWindowMultiSelect()
78// [SECTION] ShowDemoWindowLayout()
79// [SECTION] ShowDemoWindowPopups()
80// [SECTION] ShowDemoWindowTables()
81// [SECTION] ShowDemoWindowInputs()
82// [SECTION] About Window / ShowAboutWindow()
83// [SECTION] Style Editor / ShowStyleEditor()
84// [SECTION] User Guide / ShowUserGuide()
85// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar()
86// [SECTION] Example App: Debug Console / ShowExampleAppConsole()
87// [SECTION] Example App: Debug Log / ShowExampleAppLog()
88// [SECTION] Example App: Simple Layout / ShowExampleAppLayout()
89// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor()
90// [SECTION] Example App: Long Text / ShowExampleAppLongText()
91// [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize()
92// [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize()
93// [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay()
94// [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen()
95// [SECTION] Example App: Manipulating window titles / ShowExampleAppWindowTitles()
96// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering()
97// [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace()
98// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
99// [SECTION] Example App: Assets Browser / ShowExampleAppAssetsBrowser()
100
101*/
102
103#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
104#define _CRT_SECURE_NO_WARNINGS
105#endif
106
107#include "imgui.h"
108#ifndef IMGUI_DISABLE
109
110// System includes
111#include <ctype.h> // toupper
112#include <limits.h> // INT_MIN, INT_MAX
113#include <math.h> // sqrtf, powf, cosf, sinf, floorf, ceilf
114#include <stdio.h> // vsnprintf, sscanf, printf
115#include <stdlib.h> // NULL, malloc, free, atoi
116#include <stdint.h> // intptr_t
117#if !defined(_MSC_VER) || _MSC_VER >= 1800
118#include <inttypes.h> // PRId64/PRIu64, not avail in some MinGW headers.
119#endif
120#ifdef __EMSCRIPTEN__
121#include <emscripten/version.h> // __EMSCRIPTEN_major__ etc.
122#endif
123
124// Visual Studio warnings
125#ifdef _MSC_VER
126#pragma warning (disable: 4127) // condition expression is constant
127#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
128#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).
129#endif
130
131// Clang/GCC warnings with -Weverything
132#if defined(__clang__)
133#if __has_warning("-Wunknown-warning-option")
134#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!
135#endif
136#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx'
137#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse.
138#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)
139#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning: cast to 'void *' from smaller integer type
140#pragma clang diagnostic ignored "-Wformat-security" // warning: format string is not a string literal
141#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.
142#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.
143#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0
144#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.
145#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning: macro name is a reserved identifier
146#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
147#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access
148#elif defined(__GNUC__)
149#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
150#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size
151#pragma GCC diagnostic ignored "-Wformat-security" // warning: format string is not a string literal (potentially insecure)
152#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
153#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value
154#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.
155#endif
156
157// Play it nice with Windows users (Update: May 2018, Notepad now supports Unix-style carriage returns!)
158#ifdef _WIN32
159#define IM_NEWLINE "\r\n"
160#else
161#define IM_NEWLINE "\n"
162#endif
163
164// Helpers
165#if defined(_MSC_VER) && !defined(snprintf)
166#define snprintf _snprintf
167#endif
168#if defined(_MSC_VER) && !defined(vsnprintf)
169#define vsnprintf _vsnprintf
170#endif
171
172// Format specifiers for 64-bit values (hasn't been decently standardized before VS2013)
173#if !defined(PRId64) && defined(_MSC_VER)
174#define PRId64 "I64d"
175#define PRIu64 "I64u"
176#elif !defined(PRId64)
177#define PRId64 "lld"
178#define PRIu64 "llu"
179#endif
180
181// Helpers macros
182// We normally try to not use many helpers in imgui_demo.cpp in order to make code easier to copy and paste,
183// but making an exception here as those are largely simplifying code...
184// In other imgui sources we can use nicer internal functions from imgui_internal.h (ImMin/ImMax) but not in the demo.
185#define IM_MIN(A, B) (((A) < (B)) ? (A) : (B))
186#define IM_MAX(A, B) (((A) >= (B)) ? (A) : (B))
187#define IM_CLAMP(V, MN, MX) ((V) < (MN) ? (MN) : (V) > (MX) ? (MX) : (V))
188
189// Enforce cdecl calling convention for functions called by the standard library,
190// in case compilation settings changed the default to e.g. __vectorcall
191#ifndef IMGUI_CDECL
192#ifdef _MSC_VER
193#define IMGUI_CDECL __cdecl
194#else
195#define IMGUI_CDECL
196#endif
197#endif
198
199//-----------------------------------------------------------------------------
200// [SECTION] Forward Declarations
201//-----------------------------------------------------------------------------
202
203#if !defined(IMGUI_DISABLE_DEMO_WINDOWS)
204
205// Forward Declarations
207static void ShowExampleAppMainMenuBar();
208static void ShowExampleAppAssetsBrowser(bool* p_open);
209static void ShowExampleAppConsole(bool* p_open);
210static void ShowExampleAppCustomRendering(bool* p_open);
211static void ShowExampleAppDockSpace(bool* p_open);
212static void ShowExampleAppDocuments(bool* p_open);
213static void ShowExampleAppLog(bool* p_open);
214static void ShowExampleAppLayout(bool* p_open);
215static void ShowExampleAppPropertyEditor(bool* p_open, ImGuiDemoWindowData* demo_data);
216static void ShowExampleAppSimpleOverlay(bool* p_open);
217static void ShowExampleAppAutoResize(bool* p_open);
218static void ShowExampleAppConstrainedResize(bool* p_open);
219static void ShowExampleAppFullscreen(bool* p_open);
220static void ShowExampleAppLongText(bool* p_open);
221static void ShowExampleAppWindowTitles(bool* p_open);
222static void ShowExampleMenuFile();
223
224// We split the contents of the big ShowDemoWindow() function into smaller functions
225// (because the link time of very large functions tends to grow non-linearly)
226static void ShowDemoWindowMenuBar(ImGuiDemoWindowData* demo_data);
227static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data);
228static void ShowDemoWindowMultiSelect(ImGuiDemoWindowData* demo_data);
229static void ShowDemoWindowLayout();
230static void ShowDemoWindowPopups();
231static void ShowDemoWindowTables();
232static void ShowDemoWindowColumns();
233static void ShowDemoWindowInputs();
234
235//-----------------------------------------------------------------------------
236// [SECTION] Helpers
237//-----------------------------------------------------------------------------
238
239// Helper to display a little (?) mark which shows a tooltip when hovered.
240// In your own code you may want to display an actual icon if you are using a merged icon fonts (see docs/FONTS.md)
241static void HelpMarker(const char* desc)
242{
243 ImGui::TextDisabled("(?)");
244 if (ImGui::BeginItemTooltip())
245 {
246 ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
248 ImGui::PopTextWrapPos();
249 ImGui::EndTooltip();
250 }
251}
252
253static void ShowDockingDisabledMessage()
254{
255 ImGuiIO& io = ImGui::GetIO();
256 ImGui::Text("ERROR: Docking is not enabled! See Demo > Configuration.");
257 ImGui::Text("Set io.ConfigFlags |= ImGuiConfigFlags_DockingEnable in your code, or ");
258 ImGui::SameLine(0.0f, 0.0f);
259 if (ImGui::SmallButton("click here"))
260 io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
261}
262
263// Helper to wire demo markers located in code to an interactive browser
264typedef void (*ImGuiDemoMarkerCallback)(const char* file, int line, const char* section, void* user_data);
269#define IMGUI_DEMO_MARKER(section) do { if (GImGuiDemoMarkerCallback != NULL) GImGuiDemoMarkerCallback(__FILE__, __LINE__, section, GImGuiDemoMarkerCallbackUserData); } while (0)
270
271//-----------------------------------------------------------------------------
272// [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor etc.)
273//-----------------------------------------------------------------------------
274
275// Simple representation for a tree
276// (this is designed to be simple to understand for our demos, not to be fancy or efficient etc.)
278{
279 // Tree structure
280 char Name[28] = "";
281 int UID = 0;
283 ImVector<ExampleTreeNode*> Childs;
284 unsigned short IndexInParent = 0; // Maintaining this allows us to implement linear traversal more easily
285
286 // Leaf Data
287 bool HasData = false; // All leaves have data
288 bool DataMyBool = true;
289 int DataMyInt = 128;
290 ImVec2 DataMyVec2 = ImVec2(0.0f, 3.141592f);
291};
292
293// Simple representation of struct metadata/serialization data.
294// (this is a minimal version of what a typical advanced application may provide)
296{
297 const char* Name; // Member name
298 ImGuiDataType DataType; // Member type
299 int DataCount; // Member count (1 when scalar)
300 int Offset; // Offset inside parent structure
301};
302
303// Metadata description of ExampleTreeNode struct.
304static const ExampleMemberInfo ExampleTreeNodeMemberInfos[]
305{
306 { "MyBool", ImGuiDataType_Bool, 1, offsetof(ExampleTreeNode, DataMyBool) },
307 { "MyInt", ImGuiDataType_S32, 1, offsetof(ExampleTreeNode, DataMyInt) },
308 { "MyVec2", ImGuiDataType_Float, 2, offsetof(ExampleTreeNode, DataMyVec2) },
309};
310
311static ExampleTreeNode* ExampleTree_CreateNode(const char* name, int uid, ExampleTreeNode* parent)
312{
313 ExampleTreeNode* node = IM_NEW(ExampleTreeNode);
314 snprintf(node->Name, IM_ARRAYSIZE(node->Name), "%s", name);
315 node->UID = uid;
316 node->Parent = parent;
317 node->IndexInParent = parent ? (unsigned short)parent->Childs.Size : 0;
318 if (parent)
319 parent->Childs.push_back(node);
320 return node;
321}
322
323// Create example tree data
324// (this allocates _many_ more times than most other code in either Dear ImGui or others demo)
325static ExampleTreeNode* ExampleTree_CreateDemoTree()
326{
327 static const char* root_names[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pear", "Pineapple", "Strawberry", "Watermelon" };
328 const size_t NAME_MAX_LEN = sizeof(ExampleTreeNode::Name);
329 char name_buf[NAME_MAX_LEN];
330 int uid = 0;
331 ExampleTreeNode* node_L0 = ExampleTree_CreateNode("<ROOT>", ++uid, NULL);
332 const int root_items_multiplier = 2;
333 for (int idx_L0 = 0; idx_L0 < IM_ARRAYSIZE(root_names) * root_items_multiplier; idx_L0++)
334 {
335 snprintf(name_buf, IM_ARRAYSIZE(name_buf), "%s %d", root_names[idx_L0 / root_items_multiplier], idx_L0 % root_items_multiplier);
336 ExampleTreeNode* node_L1 = ExampleTree_CreateNode(name_buf, ++uid, node_L0);
337 const int number_of_childs = (int)strlen(node_L1->Name);
338 for (int idx_L1 = 0; idx_L1 < number_of_childs; idx_L1++)
339 {
340 snprintf(name_buf, IM_ARRAYSIZE(name_buf), "Child %d", idx_L1);
341 ExampleTreeNode* node_L2 = ExampleTree_CreateNode(name_buf, ++uid, node_L1);
342 node_L2->HasData = true;
343 if (idx_L1 == 0)
344 {
345 snprintf(name_buf, IM_ARRAYSIZE(name_buf), "Sub-child %d", 0);
346 ExampleTreeNode* node_L3 = ExampleTree_CreateNode(name_buf, ++uid, node_L2);
347 node_L3->HasData = true;
348 }
349 }
350 }
351 return node_L0;
352}
353
354//-----------------------------------------------------------------------------
355// [SECTION] Demo Window / ShowDemoWindow()
356//-----------------------------------------------------------------------------
357
358// Data to be shared accross different functions of the demo.
360{
361 // Examples Apps (accessible from the "Examples" menu)
362 bool ShowMainMenuBar = false;
364 bool ShowAppConsole = false;
366 bool ShowAppDocuments = false;
367 bool ShowAppDockSpace = false;
368 bool ShowAppLog = false;
369 bool ShowAppLayout = false;
372 bool ShowAppAutoResize = false;
374 bool ShowAppFullscreen = false;
375 bool ShowAppLongText = false;
377
378 // Dear ImGui Tools (accessible from the "Tools" menu)
379 bool ShowMetrics = false;
380 bool ShowDebugLog = false;
381 bool ShowIDStackTool = false;
382 bool ShowStyleEditor = false;
383 bool ShowAbout = false;
384
385 // Other data
387};
388
389// Demonstrate most Dear ImGui features (this is big function!)
390// You may execute this function to experiment with the UI and understand what it does.
391// You may then search for keywords in the code when you are interested by a specific feature.
392void ImGui::ShowDemoWindow(bool* p_open)
393{
394 // Exceptionally add an extra assert here for people confused about initial Dear ImGui setup
395 // Most functions would normally just assert/crash if the context is missing.
396 IM_ASSERT(ImGui::GetCurrentContext() != NULL && "Missing Dear ImGui context. Refer to examples app!");
397
398 // Verify ABI compatibility between caller code and compiled version of Dear ImGui. This helps detects some build issues.
399 IMGUI_CHECKVERSION();
400
401 // Stored data
402 static ImGuiDemoWindowData demo_data;
403
404 // Examples Apps (accessible from the "Examples" menu)
405 if (demo_data.ShowMainMenuBar) { ShowExampleAppMainMenuBar(); }
406 if (demo_data.ShowAppDockSpace) { ShowExampleAppDockSpace(&demo_data.ShowAppDockSpace); } // Important: Process the Docking app first, as explicit DockSpace() nodes needs to be submitted early (read comments near the DockSpace function)
407 if (demo_data.ShowAppDocuments) { ShowExampleAppDocuments(&demo_data.ShowAppDocuments); } // ...process the Document app next, as it may also use a DockSpace()
408 if (demo_data.ShowAppAssetsBrowser) { ShowExampleAppAssetsBrowser(&demo_data.ShowAppAssetsBrowser); }
409 if (demo_data.ShowAppConsole) { ShowExampleAppConsole(&demo_data.ShowAppConsole); }
410 if (demo_data.ShowAppCustomRendering) { ShowExampleAppCustomRendering(&demo_data.ShowAppCustomRendering); }
411 if (demo_data.ShowAppLog) { ShowExampleAppLog(&demo_data.ShowAppLog); }
412 if (demo_data.ShowAppLayout) { ShowExampleAppLayout(&demo_data.ShowAppLayout); }
413 if (demo_data.ShowAppPropertyEditor) { ShowExampleAppPropertyEditor(&demo_data.ShowAppPropertyEditor, &demo_data); }
414 if (demo_data.ShowAppSimpleOverlay) { ShowExampleAppSimpleOverlay(&demo_data.ShowAppSimpleOverlay); }
415 if (demo_data.ShowAppAutoResize) { ShowExampleAppAutoResize(&demo_data.ShowAppAutoResize); }
416 if (demo_data.ShowAppConstrainedResize) { ShowExampleAppConstrainedResize(&demo_data.ShowAppConstrainedResize); }
417 if (demo_data.ShowAppFullscreen) { ShowExampleAppFullscreen(&demo_data.ShowAppFullscreen); }
418 if (demo_data.ShowAppLongText) { ShowExampleAppLongText(&demo_data.ShowAppLongText); }
419 if (demo_data.ShowAppWindowTitles) { ShowExampleAppWindowTitles(&demo_data.ShowAppWindowTitles); }
420
421 // Dear ImGui Tools (accessible from the "Tools" menu)
422 if (demo_data.ShowMetrics) { ImGui::ShowMetricsWindow(&demo_data.ShowMetrics); }
423 if (demo_data.ShowDebugLog) { ImGui::ShowDebugLogWindow(&demo_data.ShowDebugLog); }
424 if (demo_data.ShowIDStackTool) { ImGui::ShowIDStackToolWindow(&demo_data.ShowIDStackTool); }
425 if (demo_data.ShowAbout) { ImGui::ShowAboutWindow(&demo_data.ShowAbout); }
426 if (demo_data.ShowStyleEditor)
427 {
428 ImGui::Begin("Dear ImGui Style Editor", &demo_data.ShowStyleEditor);
429 ImGui::ShowStyleEditor();
430 ImGui::End();
431 }
432
433 // Demonstrate the various window flags. Typically you would just use the default!
434 static bool no_titlebar = false;
435 static bool no_scrollbar = false;
436 static bool no_menu = false;
437 static bool no_move = false;
438 static bool no_resize = false;
439 static bool no_collapse = false;
440 static bool no_close = false;
441 static bool no_nav = false;
442 static bool no_background = false;
443 static bool no_bring_to_front = false;
444 static bool no_docking = false;
445 static bool unsaved_document = false;
446
447 ImGuiWindowFlags window_flags = 0;
448 if (no_titlebar) window_flags |= ImGuiWindowFlags_NoTitleBar;
449 if (no_scrollbar) window_flags |= ImGuiWindowFlags_NoScrollbar;
450 if (!no_menu) window_flags |= ImGuiWindowFlags_MenuBar;
451 if (no_move) window_flags |= ImGuiWindowFlags_NoMove;
452 if (no_resize) window_flags |= ImGuiWindowFlags_NoResize;
453 if (no_collapse) window_flags |= ImGuiWindowFlags_NoCollapse;
454 if (no_nav) window_flags |= ImGuiWindowFlags_NoNav;
455 if (no_background) window_flags |= ImGuiWindowFlags_NoBackground;
456 if (no_bring_to_front) window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus;
457 if (no_docking) window_flags |= ImGuiWindowFlags_NoDocking;
458 if (unsaved_document) window_flags |= ImGuiWindowFlags_UnsavedDocument;
459 if (no_close) p_open = NULL; // Don't pass our bool* to Begin
460
461 // We specify a default position/size in case there's no data in the .ini file.
462 // We only do it to make the demo applications a little more welcoming, but typically this isn't required.
463 const ImGuiViewport* main_viewport = ImGui::GetMainViewport();
464 ImGui::SetNextWindowPos(ImVec2(main_viewport->WorkPos.x + 650, main_viewport->WorkPos.y + 20), ImGuiCond_FirstUseEver);
465 ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver);
466
467 // Main body of the Demo window starts here.
468 if (!ImGui::Begin("Dear ImGui Demo", p_open, window_flags))
469 {
470 // Early out if the window is collapsed, as an optimization.
471 ImGui::End();
472 return;
473 }
474
475 // Most "big" widgets share a common width settings by default. See 'Demo->Layout->Widgets Width' for details.
476 ImGui::PushItemWidth(ImGui::GetFontSize() * -12); // e.g. Leave a fixed amount of width for labels (by passing a negative value), the rest goes to widgets.
477 //ImGui::PushItemWidth(-ImGui::GetWindowWidth() * 0.35f); // e.g. Use 2/3 of the space for widgets and 1/3 for labels (right align)
478
479 // Menu Bar
480 ShowDemoWindowMenuBar(&demo_data);
481
482 ImGui::Text("dear imgui says hello! (%s) (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
483 ImGui::Spacing();
484
485 IMGUI_DEMO_MARKER("Help");
486 if (ImGui::CollapsingHeader("Help"))
487 {
488 ImGui::SeparatorText("ABOUT THIS DEMO:");
489 ImGui::BulletText("Sections below are demonstrating many aspects of the library.");
490 ImGui::BulletText("The \"Examples\" menu above leads to more demo contents.");
491 ImGui::BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n"
492 "and Metrics/Debugger (general purpose Dear ImGui debugging tool).");
493
494 ImGui::SeparatorText("PROGRAMMER GUIDE:");
495 ImGui::BulletText("See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!");
496 ImGui::BulletText("See comments in imgui.cpp.");
497 ImGui::BulletText("See example applications in the examples/ folder.");
498 ImGui::BulletText("Read the FAQ at ");
499 ImGui::SameLine(0, 0);
500 ImGui::TextLinkOpenURL("https://www.dearimgui.com/faq/");
501 ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls.");
502 ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls.");
503
504 ImGui::SeparatorText("USER GUIDE:");
505 ImGui::ShowUserGuide();
506 }
507
508 IMGUI_DEMO_MARKER("Configuration");
509 if (ImGui::CollapsingHeader("Configuration"))
510 {
511 ImGuiIO& io = ImGui::GetIO();
512
513 if (ImGui::TreeNode("Configuration##2"))
514 {
515 ImGui::SeparatorText("General");
516 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard);
517 ImGui::SameLine(); HelpMarker("Enable keyboard controls.");
518 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", &io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad);
519 ImGui::SameLine(); HelpMarker("Enable gamepad controls. Require backend to set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details.");
520 ImGui::CheckboxFlags("io.ConfigFlags: NoMouse", &io.ConfigFlags, ImGuiConfigFlags_NoMouse);
521 ImGui::SameLine(); HelpMarker("Instruct dear imgui to disable mouse inputs and interactions.");
522
523 // The "NoMouse" option can get us stuck with a disabled mouse! Let's provide an alternative way to fix it:
524 if (io.ConfigFlags & ImGuiConfigFlags_NoMouse)
525 {
526 if (fmodf((float)ImGui::GetTime(), 0.40f) < 0.20f)
527 {
528 ImGui::SameLine();
529 ImGui::Text("<<PRESS SPACE TO DISABLE>>");
530 }
531 // Prevent both being checked
532 if (ImGui::IsKeyPressed(ImGuiKey_Space) || (io.ConfigFlags & ImGuiConfigFlags_NoKeyboard))
533 io.ConfigFlags &= ~ImGuiConfigFlags_NoMouse;
534 }
535
536 ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", &io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange);
537 ImGui::SameLine(); HelpMarker("Instruct backend to not alter mouse cursor shape and visibility.");
538 ImGui::CheckboxFlags("io.ConfigFlags: NoKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NoKeyboard);
539 ImGui::SameLine(); HelpMarker("Instruct dear imgui to disable keyboard inputs and interactions.");
540
541 ImGui::Checkbox("io.ConfigInputTrickleEventQueue", &io.ConfigInputTrickleEventQueue);
542 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.");
543 ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor);
544 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).");
545
546 ImGui::SeparatorText("Keyboard/Gamepad Navigation");
547 ImGui::Checkbox("io.ConfigNavSwapGamepadButtons", &io.ConfigNavSwapGamepadButtons);
548 ImGui::Checkbox("io.ConfigNavMoveSetMousePos", &io.ConfigNavMoveSetMousePos);
549 ImGui::SameLine(); HelpMarker("Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is difficult");
550 ImGui::Checkbox("io.ConfigNavCaptureKeyboard", &io.ConfigNavCaptureKeyboard);
551 ImGui::Checkbox("io.ConfigNavEscapeClearFocusItem", &io.ConfigNavEscapeClearFocusItem);
552 ImGui::SameLine(); HelpMarker("Pressing Escape clears focused item.");
553 ImGui::Checkbox("io.ConfigNavEscapeClearFocusWindow", &io.ConfigNavEscapeClearFocusWindow);
554 ImGui::SameLine(); HelpMarker("Pressing Escape clears focused window.");
555 ImGui::Checkbox("io.ConfigNavCursorVisibleAuto", &io.ConfigNavCursorVisibleAuto);
556 ImGui::SameLine(); HelpMarker("Using directional navigation key makes the cursor visible. Mouse click hides the cursor.");
557 ImGui::Checkbox("io.ConfigNavCursorVisibleAlways", &io.ConfigNavCursorVisibleAlways);
558 ImGui::SameLine(); HelpMarker("Navigation cursor is always visible.");
559
560 ImGui::SeparatorText("Docking");
561 ImGui::CheckboxFlags("io.ConfigFlags: DockingEnable", &io.ConfigFlags, ImGuiConfigFlags_DockingEnable);
562 ImGui::SameLine();
563 if (io.ConfigDockingWithShift)
564 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).");
565 else
566 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).");
567 if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
568 {
569 ImGui::Indent();
570 ImGui::Checkbox("io.ConfigDockingNoSplit", &io.ConfigDockingNoSplit);
571 ImGui::SameLine(); HelpMarker("Simplified docking mode: disable window splitting, so docking is limited to merging multiple windows together into tab-bars.");
572 ImGui::Checkbox("io.ConfigDockingWithShift", &io.ConfigDockingWithShift);
573 ImGui::SameLine(); HelpMarker("Enable docking when holding Shift only (allow to drop in wider space, reduce visual noise)");
574 ImGui::Checkbox("io.ConfigDockingAlwaysTabBar", &io.ConfigDockingAlwaysTabBar);
575 ImGui::SameLine(); HelpMarker("Create a docking node and tab-bar on single floating windows.");
576 ImGui::Checkbox("io.ConfigDockingTransparentPayload", &io.ConfigDockingTransparentPayload);
577 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.");
578 ImGui::Unindent();
579 }
580
581 ImGui::SeparatorText("Multi-viewports");
582 ImGui::CheckboxFlags("io.ConfigFlags: ViewportsEnable", &io.ConfigFlags, ImGuiConfigFlags_ViewportsEnable);
583 ImGui::SameLine(); HelpMarker("[beta] Enable beta multi-viewports support. See ImGuiPlatformIO for details.");
584 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
585 {
586 ImGui::Indent();
587 ImGui::Checkbox("io.ConfigViewportsNoAutoMerge", &io.ConfigViewportsNoAutoMerge);
588 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.");
589 ImGui::Checkbox("io.ConfigViewportsNoTaskBarIcon", &io.ConfigViewportsNoTaskBarIcon);
590 ImGui::SameLine(); HelpMarker("Toggling this at runtime is normally unsupported (most platform backends won't refresh the task bar icon state right away).");
591 ImGui::Checkbox("io.ConfigViewportsNoDecoration", &io.ConfigViewportsNoDecoration);
592 ImGui::SameLine(); HelpMarker("Toggling this at runtime is normally unsupported (most platform backends won't refresh the decoration right away).");
593 ImGui::Checkbox("io.ConfigViewportsNoDefaultParent", &io.ConfigViewportsNoDefaultParent);
594 ImGui::SameLine(); HelpMarker("Toggling this at runtime is normally unsupported (most platform backends won't refresh the parenting right away).");
595 ImGui::Unindent();
596 }
597
598 ImGui::SeparatorText("Widgets");
599 ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink);
600 ImGui::SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting).");
601 ImGui::Checkbox("io.ConfigInputTextEnterKeepActive", &io.ConfigInputTextEnterKeepActive);
602 ImGui::SameLine(); HelpMarker("Pressing Enter will keep item active and select contents (single-line only).");
603 ImGui::Checkbox("io.ConfigDragClickToInputText", &io.ConfigDragClickToInputText);
604 ImGui::SameLine(); HelpMarker("Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving).");
605 ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges);
606 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.");
607 ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly);
608 ImGui::Checkbox("io.ConfigScrollbarScrollByPage", &io.ConfigScrollbarScrollByPage);
609 ImGui::SameLine(); HelpMarker("Enable scrolling page by page when clicking outside the scrollbar grab.\nWhen disabled, always scroll to clicked location.\nWhen enabled, Shift+Click scrolls to clicked location.");
610 ImGui::Checkbox("io.ConfigMacOSXBehaviors", &io.ConfigMacOSXBehaviors);
611 ImGui::SameLine(); HelpMarker("Swap Cmd<>Ctrl keys, enable various MacOS style behaviors.");
612 ImGui::Text("Also see Style->Rendering for rendering options.");
613
614 // Also read: https://github.com/ocornut/imgui/wiki/Error-Handling
615 ImGui::SeparatorText("Error Handling");
616
617 ImGui::Checkbox("io.ConfigErrorRecovery", &io.ConfigErrorRecovery);
618 ImGui::SameLine(); HelpMarker(
619 "Options to configure how we handle recoverable errors.\n"
620 "- Error recovery is not perfect nor guaranteed! It is a feature to ease development.\n"
621 "- You not are not supposed to rely on it in the course of a normal application run.\n"
622 "- Possible usage: facilitate recovery from errors triggered from a scripting language or after specific exceptions handlers.\n"
623 "- Always ensure that on programmers seat you have at minimum Asserts or Tooltips enabled when making direct imgui API call!"
624 "Otherwise it would severely hinder your ability to catch and correct mistakes!");
625 ImGui::Checkbox("io.ConfigErrorRecoveryEnableAssert", &io.ConfigErrorRecoveryEnableAssert);
626 ImGui::Checkbox("io.ConfigErrorRecoveryEnableDebugLog", &io.ConfigErrorRecoveryEnableDebugLog);
627 ImGui::Checkbox("io.ConfigErrorRecoveryEnableTooltip", &io.ConfigErrorRecoveryEnableTooltip);
628 if (!io.ConfigErrorRecoveryEnableAssert && !io.ConfigErrorRecoveryEnableDebugLog && !io.ConfigErrorRecoveryEnableTooltip)
629 io.ConfigErrorRecoveryEnableAssert = io.ConfigErrorRecoveryEnableDebugLog = io.ConfigErrorRecoveryEnableTooltip = true;
630
631 // Also read: https://github.com/ocornut/imgui/wiki/Debug-Tools
632 ImGui::SeparatorText("Debug");
633 ImGui::Checkbox("io.ConfigDebugIsDebuggerPresent", &io.ConfigDebugIsDebuggerPresent);
634 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.");
635 ImGui::Checkbox("io.ConfigDebugHighlightIdConflicts", &io.ConfigDebugHighlightIdConflicts);
636 ImGui::SameLine(); HelpMarker("Highlight and show an error message when multiple items have conflicting identifiers.");
637 ImGui::BeginDisabled();
638 ImGui::Checkbox("io.ConfigDebugBeginReturnValueOnce", &io.ConfigDebugBeginReturnValueOnce);
639 ImGui::EndDisabled();
640 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.");
641 ImGui::Checkbox("io.ConfigDebugBeginReturnValueLoop", &io.ConfigDebugBeginReturnValueLoop);
642 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.");
643 ImGui::Checkbox("io.ConfigDebugIgnoreFocusLoss", &io.ConfigDebugIgnoreFocusLoss);
644 ImGui::SameLine(); HelpMarker("Option to deactivate io.AddFocusEvent(false) handling. May facilitate interactions with a debugger when focus loss leads to clearing inputs data.");
645 ImGui::Checkbox("io.ConfigDebugIniSettings", &io.ConfigDebugIniSettings);
646 ImGui::SameLine(); HelpMarker("Option to save .ini data with extra comments (particularly helpful for Docking, but makes saving slower).");
647
648 ImGui::TreePop();
649 ImGui::Spacing();
650 }
651
652 IMGUI_DEMO_MARKER("Configuration/Backend Flags");
653 if (ImGui::TreeNode("Backend Flags"))
654 {
655 HelpMarker(
656 "Those flags are set by the backends (imgui_impl_xxx files) to specify their capabilities.\n"
657 "Here we expose them as read-only fields to avoid breaking interactions with your backend.");
658
659 // Make a local copy to avoid modifying actual backend flags.
660 // FIXME: Maybe we need a BeginReadonly() equivalent to keep label bright?
661 ImGui::BeginDisabled();
662 ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", &io.BackendFlags, ImGuiBackendFlags_HasGamepad);
663 ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors);
664 ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos", &io.BackendFlags, ImGuiBackendFlags_HasSetMousePos);
665 ImGui::CheckboxFlags("io.BackendFlags: PlatformHasViewports", &io.BackendFlags, ImGuiBackendFlags_PlatformHasViewports);
666 ImGui::CheckboxFlags("io.BackendFlags: HasMouseHoveredViewport",&io.BackendFlags, ImGuiBackendFlags_HasMouseHoveredViewport);
667 ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", &io.BackendFlags, ImGuiBackendFlags_RendererHasVtxOffset);
668 ImGui::CheckboxFlags("io.BackendFlags: RendererHasViewports", &io.BackendFlags, ImGuiBackendFlags_RendererHasViewports);
669 ImGui::EndDisabled();
670
671 ImGui::TreePop();
672 ImGui::Spacing();
673 }
674
675 IMGUI_DEMO_MARKER("Configuration/Style");
676 if (ImGui::TreeNode("Style"))
677 {
678 ImGui::Checkbox("Style Editor", &demo_data.ShowStyleEditor);
679 ImGui::SameLine();
680 HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function.");
681 ImGui::TreePop();
682 ImGui::Spacing();
683 }
684
685 IMGUI_DEMO_MARKER("Configuration/Capture, Logging");
686 if (ImGui::TreeNode("Capture/Logging"))
687 {
688 HelpMarker(
689 "The logging API redirects all text output so you can easily capture the content of "
690 "a window or a block. Tree nodes can be automatically expanded.\n"
691 "Try opening any of the contents below in this window and then click one of the \"Log To\" button.");
692 ImGui::LogButtons();
693
694 HelpMarker("You can also call ImGui::LogText() to output directly to the log without a visual output.");
695 if (ImGui::Button("Copy \"Hello, world!\" to clipboard"))
696 {
697 ImGui::LogToClipboard();
698 ImGui::LogText("Hello, world!");
699 ImGui::LogFinish();
700 }
701 ImGui::TreePop();
702 }
703 }
704
705 IMGUI_DEMO_MARKER("Window options");
706 if (ImGui::CollapsingHeader("Window options"))
707 {
708 if (ImGui::BeginTable("split", 3))
709 {
710 ImGui::TableNextColumn(); ImGui::Checkbox("No titlebar", &no_titlebar);
711 ImGui::TableNextColumn(); ImGui::Checkbox("No scrollbar", &no_scrollbar);
712 ImGui::TableNextColumn(); ImGui::Checkbox("No menu", &no_menu);
713 ImGui::TableNextColumn(); ImGui::Checkbox("No move", &no_move);
714 ImGui::TableNextColumn(); ImGui::Checkbox("No resize", &no_resize);
715 ImGui::TableNextColumn(); ImGui::Checkbox("No collapse", &no_collapse);
716 ImGui::TableNextColumn(); ImGui::Checkbox("No close", &no_close);
717 ImGui::TableNextColumn(); ImGui::Checkbox("No nav", &no_nav);
718 ImGui::TableNextColumn(); ImGui::Checkbox("No background", &no_background);
719 ImGui::TableNextColumn(); ImGui::Checkbox("No bring to front", &no_bring_to_front);
720 ImGui::TableNextColumn(); ImGui::Checkbox("No docking", &no_docking);
721 ImGui::TableNextColumn(); ImGui::Checkbox("Unsaved document", &unsaved_document);
722 ImGui::EndTable();
723 }
724 }
725
726 // All demo contents
727 ShowDemoWindowWidgets(&demo_data);
728 ShowDemoWindowLayout();
729 ShowDemoWindowPopups();
730 ShowDemoWindowTables();
731 ShowDemoWindowInputs();
732
733 // End of ShowDemoWindow()
734 ImGui::PopItemWidth();
735 ImGui::End();
736}
737
738//-----------------------------------------------------------------------------
739// [SECTION] ShowDemoWindowMenuBar()
740//-----------------------------------------------------------------------------
741
742static void ShowDemoWindowMenuBar(ImGuiDemoWindowData* demo_data)
743{
744 IMGUI_DEMO_MARKER("Menu");
745 if (ImGui::BeginMenuBar())
746 {
747 if (ImGui::BeginMenu("Menu"))
748 {
749 IMGUI_DEMO_MARKER("Menu/File");
750 ShowExampleMenuFile();
751 ImGui::EndMenu();
752 }
753 if (ImGui::BeginMenu("Examples"))
754 {
755 IMGUI_DEMO_MARKER("Menu/Examples");
756 ImGui::MenuItem("Main menu bar", NULL, &demo_data->ShowMainMenuBar);
757
758 ImGui::SeparatorText("Mini apps");
759 ImGui::MenuItem("Assets Browser", NULL, &demo_data->ShowAppAssetsBrowser);
760 ImGui::MenuItem("Console", NULL, &demo_data->ShowAppConsole);
761 ImGui::MenuItem("Custom rendering", NULL, &demo_data->ShowAppCustomRendering);
762 ImGui::MenuItem("Documents", NULL, &demo_data->ShowAppDocuments);
763 ImGui::MenuItem("Dockspace", NULL, &demo_data->ShowAppDockSpace);
764 ImGui::MenuItem("Log", NULL, &demo_data->ShowAppLog);
765 ImGui::MenuItem("Property editor", NULL, &demo_data->ShowAppPropertyEditor);
766 ImGui::MenuItem("Simple layout", NULL, &demo_data->ShowAppLayout);
767 ImGui::MenuItem("Simple overlay", NULL, &demo_data->ShowAppSimpleOverlay);
768
769 ImGui::SeparatorText("Concepts");
770 ImGui::MenuItem("Auto-resizing window", NULL, &demo_data->ShowAppAutoResize);
771 ImGui::MenuItem("Constrained-resizing window", NULL, &demo_data->ShowAppConstrainedResize);
772 ImGui::MenuItem("Fullscreen window", NULL, &demo_data->ShowAppFullscreen);
773 ImGui::MenuItem("Long text display", NULL, &demo_data->ShowAppLongText);
774 ImGui::MenuItem("Manipulating window titles", NULL, &demo_data->ShowAppWindowTitles);
775
776 ImGui::EndMenu();
777 }
778 //if (ImGui::MenuItem("MenuItem")) {} // You can also use MenuItem() inside a menu bar!
779 if (ImGui::BeginMenu("Tools"))
780 {
781 IMGUI_DEMO_MARKER("Menu/Tools");
782 ImGuiIO& io = ImGui::GetIO();
783#ifndef IMGUI_DISABLE_DEBUG_TOOLS
784 const bool has_debug_tools = true;
785#else
786 const bool has_debug_tools = false;
787#endif
788 ImGui::MenuItem("Metrics/Debugger", NULL, &demo_data->ShowMetrics, has_debug_tools);
789 ImGui::MenuItem("Debug Log", NULL, &demo_data->ShowDebugLog, has_debug_tools);
790 ImGui::MenuItem("ID Stack Tool", NULL, &demo_data->ShowIDStackTool, has_debug_tools);
791 bool is_debugger_present = io.ConfigDebugIsDebuggerPresent;
792 if (ImGui::MenuItem("Item Picker", NULL, false, has_debug_tools && is_debugger_present))
793 ImGui::DebugStartItemPicker();
794 if (!is_debugger_present)
795 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.");
796 ImGui::MenuItem("Style Editor", NULL, &demo_data->ShowStyleEditor);
797 ImGui::MenuItem("About Dear ImGui", NULL, &demo_data->ShowAbout);
798
799 ImGui::SeparatorText("Debug Options");
800 ImGui::MenuItem("Highlight ID Conflicts", NULL, &io.ConfigDebugHighlightIdConflicts, has_debug_tools);
801 ImGui::EndMenu();
802 }
803 ImGui::EndMenuBar();
804 }
805}
806
807//-----------------------------------------------------------------------------
808// [SECTION] ShowDemoWindowWidgets()
809//-----------------------------------------------------------------------------
810
811static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data)
812{
813 IMGUI_DEMO_MARKER("Widgets");
814 //ImGui::SetNextItemOpen(true, ImGuiCond_Once);
815 if (!ImGui::CollapsingHeader("Widgets"))
816 return;
817
818 static bool disable_all = false; // The Checkbox for that is inside the "Disabled" section at the bottom
819 if (disable_all)
820 ImGui::BeginDisabled();
821
822 IMGUI_DEMO_MARKER("Widgets/Basic");
823 if (ImGui::TreeNode("Basic"))
824 {
825 ImGui::SeparatorText("General");
826
827 IMGUI_DEMO_MARKER("Widgets/Basic/Button");
828 static int clicked = 0;
829 if (ImGui::Button("Button"))
830 clicked++;
831 if (clicked & 1)
832 {
833 ImGui::SameLine();
834 ImGui::Text("Thanks for clicking me!");
835 }
836
837 IMGUI_DEMO_MARKER("Widgets/Basic/Checkbox");
838 static bool check = true;
839 ImGui::Checkbox("checkbox", &check);
840
841 IMGUI_DEMO_MARKER("Widgets/Basic/RadioButton");
842 static int e = 0;
843 ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine();
844 ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine();
845 ImGui::RadioButton("radio c", &e, 2);
846
847 // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style.
848 IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Colored)");
849 for (int i = 0; i < 7; i++)
850 {
851 if (i > 0)
852 ImGui::SameLine();
853 ImGui::PushID(i);
854 ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.6f));
855 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.7f));
856 ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.8f, 0.8f));
857 ImGui::Button("Click");
858 ImGui::PopStyleColor(3);
859 ImGui::PopID();
860 }
861
862 // Use AlignTextToFramePadding() to align text baseline to the baseline of framed widgets elements
863 // (otherwise a Text+SameLine+Button sequence will have the text a little too high by default!)
864 // See 'Demo->Layout->Text Baseline Alignment' for details.
865 ImGui::AlignTextToFramePadding();
866 ImGui::Text("Hold to repeat:");
867 ImGui::SameLine();
868
869 // Arrow buttons with Repeater
870 IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Repeating)");
871 static int counter = 0;
872 float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
873 ImGui::PushItemFlag(ImGuiItemFlags_ButtonRepeat, true);
874 if (ImGui::ArrowButton("##left", ImGuiDir_Left)) { counter--; }
875 ImGui::SameLine(0.0f, spacing);
876 if (ImGui::ArrowButton("##right", ImGuiDir_Right)) { counter++; }
877 ImGui::PopItemFlag();
878 ImGui::SameLine();
879 ImGui::Text("%d", counter);
880
881 ImGui::Button("Tooltip");
882 ImGui::SetItemTooltip("I am a tooltip");
883
884 ImGui::LabelText("label", "Value");
885
886 ImGui::SeparatorText("Inputs");
887
888 {
889 // To wire InputText() with std::string or any other custom string type,
890 // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file.
891 IMGUI_DEMO_MARKER("Widgets/Basic/InputText");
892 static char str0[128] = "Hello, world!";
893 ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0));
894 ImGui::SameLine(); HelpMarker(
895 "USER:\n"
896 "Hold SHIFT or use mouse to select text.\n"
897 "CTRL+Left/Right to word jump.\n"
898 "CTRL+A or Double-Click to select all.\n"
899 "CTRL+X,CTRL+C,CTRL+V clipboard.\n"
900 "CTRL+Z,CTRL+Y undo/redo.\n"
901 "ESCAPE to revert.\n\n"
902 "PROGRAMMER:\n"
903 "You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() "
904 "to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example (this is not demonstrated "
905 "in imgui_demo.cpp).");
906
907 static char str1[128] = "";
908 ImGui::InputTextWithHint("input text (w/ hint)", "enter text here", str1, IM_ARRAYSIZE(str1));
909
910 IMGUI_DEMO_MARKER("Widgets/Basic/InputInt, InputFloat");
911 static int i0 = 123;
912 ImGui::InputInt("input int", &i0);
913
914 static float f0 = 0.001f;
915 ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f");
916
917 static double d0 = 999999.00000001;
918 ImGui::InputDouble("input double", &d0, 0.01f, 1.0f, "%.8f");
919
920 static float f1 = 1.e10f;
921 ImGui::InputFloat("input scientific", &f1, 0.0f, 0.0f, "%e");
922 ImGui::SameLine(); HelpMarker(
923 "You can input value using the scientific notation,\n"
924 " e.g. \"1e+8\" becomes \"100000000\".");
925
926 static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f };
927 ImGui::InputFloat3("input float3", vec4a);
928 }
929
930 ImGui::SeparatorText("Drags");
931
932 {
933 IMGUI_DEMO_MARKER("Widgets/Basic/DragInt, DragFloat");
934 static int i1 = 50, i2 = 42, i3 = 128;
935 ImGui::DragInt("drag int", &i1, 1);
936 ImGui::SameLine(); HelpMarker(
937 "Click and drag to edit value.\n"
938 "Hold SHIFT/ALT for faster/slower edit.\n"
939 "Double-click or CTRL+click to input value.");
940 ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp);
941 ImGui::DragInt("drag int wrap 100..200", &i3, 1, 100, 200, "%d", ImGuiSliderFlags_WrapAround);
942
943 static float f1 = 1.00f, f2 = 0.0067f;
944 ImGui::DragFloat("drag float", &f1, 0.005f);
945 ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns");
946 //ImGui::DragFloat("drag wrap -1..1", &f3, 0.005f, -1.0f, 1.0f, NULL, ImGuiSliderFlags_WrapAround);
947 }
948
949 ImGui::SeparatorText("Sliders");
950
951 {
952 IMGUI_DEMO_MARKER("Widgets/Basic/SliderInt, SliderFloat");
953 static int i1 = 0;
954 ImGui::SliderInt("slider int", &i1, -1, 3);
955 ImGui::SameLine(); HelpMarker("CTRL+click to input value.");
956
957 static float f1 = 0.123f, f2 = 0.0f;
958 ImGui::SliderFloat("slider float", &f1, 0.0f, 1.0f, "ratio = %.3f");
959 ImGui::SliderFloat("slider float (log)", &f2, -10.0f, 10.0f, "%.4f", ImGuiSliderFlags_Logarithmic);
960
961 IMGUI_DEMO_MARKER("Widgets/Basic/SliderAngle");
962 static float angle = 0.0f;
963 ImGui::SliderAngle("slider angle", &angle);
964
965 // Using the format string to display a name instead of an integer.
966 // Here we completely omit '%d' from the format string, so it'll only display a name.
967 // This technique can also be used with DragInt().
968 IMGUI_DEMO_MARKER("Widgets/Basic/Slider (enum)");
969 enum Element { Element_Fire, Element_Earth, Element_Air, Element_Water, Element_COUNT };
970 static int elem = Element_Fire;
971 const char* elems_names[Element_COUNT] = { "Fire", "Earth", "Air", "Water" };
972 const char* elem_name = (elem >= 0 && elem < Element_COUNT) ? elems_names[elem] : "Unknown";
973 ImGui::SliderInt("slider enum", &elem, 0, Element_COUNT - 1, elem_name); // Use ImGuiSliderFlags_NoInput flag to disable CTRL+Click here.
974 ImGui::SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer.");
975 }
976
977 ImGui::SeparatorText("Selectors/Pickers");
978
979 {
980 IMGUI_DEMO_MARKER("Widgets/Basic/ColorEdit3, ColorEdit4");
981 static float col1[3] = { 1.0f, 0.0f, 0.2f };
982 static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
983 ImGui::ColorEdit3("color 1", col1);
984 ImGui::SameLine(); HelpMarker(
985 "Click on the color square to open a color picker.\n"
986 "Click and hold to use drag and drop.\n"
987 "Right-click on the color square to show options.\n"
988 "CTRL+click on individual component to input value.\n");
989
990 ImGui::ColorEdit4("color 2", col2);
991 }
992
993 {
994 // Using the _simplified_ one-liner Combo() api here
995 // See "Combo" section for examples of how to use the more flexible BeginCombo()/EndCombo() api.
996 IMGUI_DEMO_MARKER("Widgets/Basic/Combo");
997 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" };
998 static int item_current = 0;
999 ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items));
1000 ImGui::SameLine(); HelpMarker(
1001 "Using the simplified one-liner Combo API here.\n"
1002 "Refer to the \"Combo\" section below for an explanation of how to use the more flexible and general BeginCombo/EndCombo API.");
1003 }
1004
1005 {
1006 // Using the _simplified_ one-liner ListBox() api here
1007 // See "List boxes" section for examples of how to use the more flexible BeginListBox()/EndListBox() api.
1008 IMGUI_DEMO_MARKER("Widgets/Basic/ListBox");
1009 const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" };
1010 static int item_current = 1;
1011 ImGui::ListBox("listbox", &item_current, items, IM_ARRAYSIZE(items), 4);
1012 ImGui::SameLine(); HelpMarker(
1013 "Using the simplified one-liner ListBox API here.\n"
1014 "Refer to the \"List boxes\" section below for an explanation of how to use the more flexible and general BeginListBox/EndListBox API.");
1015 }
1016
1017 ImGui::TreePop();
1018 }
1019
1020 IMGUI_DEMO_MARKER("Widgets/Tooltips");
1021 if (ImGui::TreeNode("Tooltips"))
1022 {
1023 // Tooltips are windows following the mouse. They do not take focus away.
1024 ImGui::SeparatorText("General");
1025
1026 // Typical use cases:
1027 // - Short-form (text only): SetItemTooltip("Hello");
1028 // - Short-form (any contents): if (BeginItemTooltip()) { Text("Hello"); EndTooltip(); }
1029
1030 // - Full-form (text only): if (IsItemHovered(...)) { SetTooltip("Hello"); }
1031 // - Full-form (any contents): if (IsItemHovered(...) && BeginTooltip()) { Text("Hello"); EndTooltip(); }
1032
1033 HelpMarker(
1034 "Tooltip are typically created by using a IsItemHovered() + SetTooltip() sequence.\n\n"
1035 "We provide a helper SetItemTooltip() function to perform the two with standards flags.");
1036
1037 ImVec2 sz = ImVec2(-FLT_MIN, 0.0f);
1038
1039 ImGui::Button("Basic", sz);
1040 ImGui::SetItemTooltip("I am a tooltip");
1041
1042 ImGui::Button("Fancy", sz);
1043 if (ImGui::BeginItemTooltip())
1044 {
1045 ImGui::Text("I am a fancy tooltip");
1046 static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
1047 ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr));
1048 ImGui::Text("Sin(time) = %f", sinf((float)ImGui::GetTime()));
1049 ImGui::EndTooltip();
1050 }
1051
1052 ImGui::SeparatorText("Always On");
1053
1054 // Showcase NOT relying on a IsItemHovered() to emit a tooltip.
1055 // Here the tooltip is always emitted when 'always_on == true'.
1056 static int always_on = 0;
1057 ImGui::RadioButton("Off", &always_on, 0);
1058 ImGui::SameLine();
1059 ImGui::RadioButton("Always On (Simple)", &always_on, 1);
1060 ImGui::SameLine();
1061 ImGui::RadioButton("Always On (Advanced)", &always_on, 2);
1062 if (always_on == 1)
1063 ImGui::SetTooltip("I am following you around.");
1064 else if (always_on == 2 && ImGui::BeginTooltip())
1065 {
1066 ImGui::ProgressBar(sinf((float)ImGui::GetTime()) * 0.5f + 0.5f, ImVec2(ImGui::GetFontSize() * 25, 0.0f));
1067 ImGui::EndTooltip();
1068 }
1069
1070 ImGui::SeparatorText("Custom");
1071
1072 HelpMarker(
1073 "Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() is the preferred way to standardize"
1074 "tooltip activation details across your application. You may however decide to use custom"
1075 "flags for a specific tooltip instance.");
1076
1077 // The following examples are passed for documentation purpose but may not be useful to most users.
1078 // Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() will pull ImGuiHoveredFlags flags values from
1079 // 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' depending on whether mouse or keyboard/gamepad is being used.
1080 // With default settings, ImGuiHoveredFlags_ForTooltip is equivalent to ImGuiHoveredFlags_DelayShort + ImGuiHoveredFlags_Stationary.
1081 ImGui::Button("Manual", sz);
1082 if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip))
1083 ImGui::SetTooltip("I am a manually emitted tooltip.");
1084
1085 ImGui::Button("DelayNone", sz);
1086 if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNone))
1087 ImGui::SetTooltip("I am a tooltip with no delay.");
1088
1089 ImGui::Button("DelayShort", sz);
1090 if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort | ImGuiHoveredFlags_NoSharedDelay))
1091 ImGui::SetTooltip("I am a tooltip with a short delay (%0.2f sec).", ImGui::GetStyle().HoverDelayShort);
1092
1093 ImGui::Button("DelayLong", sz);
1094 if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal | ImGuiHoveredFlags_NoSharedDelay))
1095 ImGui::SetTooltip("I am a tooltip with a long delay (%0.2f sec).", ImGui::GetStyle().HoverDelayNormal);
1096
1097 ImGui::Button("Stationary", sz);
1098 if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary))
1099 ImGui::SetTooltip("I am a tooltip requiring mouse to be stationary before activating.");
1100
1101 // Using ImGuiHoveredFlags_ForTooltip will pull flags from 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav',
1102 // which default value include the ImGuiHoveredFlags_AllowWhenDisabled flag.
1103 ImGui::BeginDisabled();
1104 ImGui::Button("Disabled item", sz);
1105 if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip))
1106 ImGui::SetTooltip("I am a a tooltip for a disabled item.");
1107 ImGui::EndDisabled();
1108
1109 ImGui::TreePop();
1110 }
1111
1112 // Testing ImGuiOnceUponAFrame helper.
1113 //static ImGuiOnceUponAFrame once;
1114 //for (int i = 0; i < 5; i++)
1115 // if (once)
1116 // ImGui::Text("This will be displayed only once.");
1117
1118 IMGUI_DEMO_MARKER("Widgets/Tree Nodes");
1119 if (ImGui::TreeNode("Tree Nodes"))
1120 {
1121 IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Basic trees");
1122 if (ImGui::TreeNode("Basic trees"))
1123 {
1124 for (int i = 0; i < 5; i++)
1125 {
1126 // Use SetNextItemOpen() so set the default state of a node to be open. We could
1127 // also use TreeNodeEx() with the ImGuiTreeNodeFlags_DefaultOpen flag to achieve the same thing!
1128 if (i == 0)
1129 ImGui::SetNextItemOpen(true, ImGuiCond_Once);
1130
1131 // Here we use PushID() to generate a unique base ID, and then the "" used as TreeNode id won't conflict.
1132 // An alternative to using 'PushID() + TreeNode("", ...)' to generate a unique ID is to use 'TreeNode((void*)(intptr_t)i, ...)',
1133 // aka generate a dummy pointer-sized value to be hashed. The demo below uses that technique. Both are fine.
1134 ImGui::PushID(i);
1135 if (ImGui::TreeNode("", "Child %d", i))
1136 {
1137 ImGui::Text("blah blah");
1138 ImGui::SameLine();
1139 if (ImGui::SmallButton("button")) {}
1140 ImGui::TreePop();
1141 }
1142 ImGui::PopID();
1143 }
1144 ImGui::TreePop();
1145 }
1146
1147 IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Advanced, with Selectable nodes");
1148 if (ImGui::TreeNode("Advanced, with Selectable nodes"))
1149 {
1150 HelpMarker(
1151 "This is a more typical looking tree with selectable nodes.\n"
1152 "Click to select, CTRL+Click to toggle, click on arrows or double-click to open.");
1153 static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth;
1154 static bool align_label_with_current_x_position = false;
1155 static bool test_drag_and_drop = false;
1156 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnArrow", &base_flags, ImGuiTreeNodeFlags_OpenOnArrow);
1157 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", &base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick);
1158 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.");
1159 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &base_flags, ImGuiTreeNodeFlags_SpanFullWidth);
1160 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanTextWidth", &base_flags, ImGuiTreeNodeFlags_SpanTextWidth); ImGui::SameLine(); HelpMarker("Reduce hit area to the text label and a bit of margin.");
1161 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &base_flags, ImGuiTreeNodeFlags_SpanAllColumns); ImGui::SameLine(); HelpMarker("For use in Tables only.");
1162 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_AllowOverlap", &base_flags, ImGuiTreeNodeFlags_AllowOverlap);
1163 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_Framed", &base_flags, ImGuiTreeNodeFlags_Framed); ImGui::SameLine(); HelpMarker("Draw frame with background (e.g. for CollapsingHeader)");
1164 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_NavLeftJumpsBackHere", &base_flags, ImGuiTreeNodeFlags_NavLeftJumpsBackHere);
1165 ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position);
1166 ImGui::Checkbox("Test tree node as drag source", &test_drag_and_drop);
1167 ImGui::Text("Hello!");
1168 if (align_label_with_current_x_position)
1169 ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing());
1170
1171 // 'selection_mask' is dumb representation of what may be user-side selection state.
1172 // You may retain selection state inside or outside your objects in whatever format you see fit.
1173 // 'node_clicked' is temporary storage of what node we have clicked to process selection at the end
1175 static int selection_mask = (1 << 2);
1176 int node_clicked = -1;
1177 for (int i = 0; i < 6; i++)
1178 {
1179 // Disable the default "open on single-click behavior" + set Selected flag according to our selection.
1180 // To alter selection we use IsItemClicked() && !IsItemToggledOpen(), so clicking on an arrow doesn't alter selection.
1181 ImGuiTreeNodeFlags node_flags = base_flags;
1182 const bool is_selected = (selection_mask & (1 << i)) != 0;
1183 if (is_selected)
1184 node_flags |= ImGuiTreeNodeFlags_Selected;
1185 if (i < 3)
1186 {
1187 // Items 0..2 are Tree Node
1188 bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Node %d", i);
1189 if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen())
1190 node_clicked = i;
1191 if (test_drag_and_drop && ImGui::BeginDragDropSource())
1192 {
1193 ImGui::SetDragDropPayload("_TREENODE", NULL, 0);
1194 ImGui::Text("This is a drag and drop source");
1195 ImGui::EndDragDropSource();
1196 }
1197 if (i == 2 && (base_flags & ImGuiTreeNodeFlags_SpanTextWidth))
1198 {
1199 // Item 2 has an additional inline button to help demonstrate SpanTextWidth.
1200 ImGui::SameLine();
1201 if (ImGui::SmallButton("button")) {}
1202 }
1203 if (node_open)
1204 {
1205 ImGui::BulletText("Blah blah\nBlah Blah");
1206 ImGui::SameLine();
1207 ImGui::SmallButton("Button");
1208 ImGui::TreePop();
1209 }
1210 }
1211 else
1212 {
1213 // Items 3..5 are Tree Leaves
1214 // The only reason we use TreeNode at all is to allow selection of the leaf. Otherwise we can
1215 // use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text().
1216 node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet
1217 ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i);
1218 if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen())
1219 node_clicked = i;
1220 if (test_drag_and_drop && ImGui::BeginDragDropSource())
1221 {
1222 ImGui::SetDragDropPayload("_TREENODE", NULL, 0);
1223 ImGui::Text("This is a drag and drop source");
1224 ImGui::EndDragDropSource();
1225 }
1226 }
1227 }
1228 if (node_clicked != -1)
1229 {
1230 // Update selection state
1231 // (process outside of tree loop to avoid visual inconsistencies during the clicking frame)
1232 if (ImGui::GetIO().KeyCtrl)
1233 selection_mask ^= (1 << node_clicked); // CTRL+click to toggle
1234 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
1235 selection_mask = (1 << node_clicked); // Click to single-select
1236 }
1237 if (align_label_with_current_x_position)
1238 ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing());
1239 ImGui::TreePop();
1240 }
1241 ImGui::TreePop();
1242 }
1243
1244 IMGUI_DEMO_MARKER("Widgets/Collapsing Headers");
1245 if (ImGui::TreeNode("Collapsing Headers"))
1246 {
1247 static bool closable_group = true;
1248 ImGui::Checkbox("Show 2nd header", &closable_group);
1249 if (ImGui::CollapsingHeader("Header", ImGuiTreeNodeFlags_None))
1250 {
1251 ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
1252 for (int i = 0; i < 5; i++)
1253 ImGui::Text("Some content %d", i);
1254 }
1255 if (ImGui::CollapsingHeader("Header with a close button", &closable_group))
1256 {
1257 ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
1258 for (int i = 0; i < 5; i++)
1259 ImGui::Text("More content %d", i);
1260 }
1261 /*
1262 if (ImGui::CollapsingHeader("Header with a bullet", ImGuiTreeNodeFlags_Bullet))
1263 ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
1264 */
1265 ImGui::TreePop();
1266 }
1267
1268 IMGUI_DEMO_MARKER("Widgets/Bullets");
1269 if (ImGui::TreeNode("Bullets"))
1270 {
1271 ImGui::BulletText("Bullet point 1");
1272 ImGui::BulletText("Bullet point 2\nOn multiple lines");
1273 if (ImGui::TreeNode("Tree node"))
1274 {
1275 ImGui::BulletText("Another bullet point");
1276 ImGui::TreePop();
1277 }
1278 ImGui::Bullet(); ImGui::Text("Bullet point 3 (two calls)");
1279 ImGui::Bullet(); ImGui::SmallButton("Button");
1280 ImGui::TreePop();
1281 }
1282
1283 IMGUI_DEMO_MARKER("Widgets/Text");
1284 if (ImGui::TreeNode("Text"))
1285 {
1286 IMGUI_DEMO_MARKER("Widgets/Text/Colored Text");
1287 if (ImGui::TreeNode("Colorful Text"))
1288 {
1289 // Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility.
1290 ImGui::TextColored(ImVec4(1.0f, 0.0f, 1.0f, 1.0f), "Pink");
1291 ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Yellow");
1292 ImGui::TextDisabled("Disabled");
1293 ImGui::SameLine(); HelpMarker("The TextDisabled color is stored in ImGuiStyle.");
1294 ImGui::TreePop();
1295 }
1296
1297 IMGUI_DEMO_MARKER("Widgets/Text/Word Wrapping");
1298 if (ImGui::TreeNode("Word Wrapping"))
1299 {
1300 // Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility.
1301 ImGui::TextWrapped(
1302 "This text should automatically wrap on the edge of the window. The current implementation "
1303 "for text wrapping follows simple rules suitable for English and possibly other languages.");
1304 ImGui::Spacing();
1305
1306 static float wrap_width = 200.0f;
1307 ImGui::SliderFloat("Wrap width", &wrap_width, -20, 600, "%.0f");
1308
1309 ImDrawList* draw_list = ImGui::GetWindowDrawList();
1310 for (int n = 0; n < 2; n++)
1311 {
1312 ImGui::Text("Test paragraph %d:", n);
1313 ImVec2 pos = ImGui::GetCursorScreenPos();
1314 ImVec2 marker_min = ImVec2(pos.x + wrap_width, pos.y);
1315 ImVec2 marker_max = ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight());
1316 ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width);
1317 if (n == 0)
1318 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);
1319 else
1320 ImGui::Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh");
1321
1322 // Draw actual text bounding box, following by marker of our expected limit (should not overlap!)
1323 draw_list->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 255, 0, 255));
1324 draw_list->AddRectFilled(marker_min, marker_max, IM_COL32(255, 0, 255, 255));
1325 ImGui::PopTextWrapPos();
1326 }
1327
1328 ImGui::TreePop();
1329 }
1330
1331 IMGUI_DEMO_MARKER("Widgets/Text/UTF-8 Text");
1332 if (ImGui::TreeNode("UTF-8 Text"))
1333 {
1334 // UTF-8 test with Japanese characters
1335 // (Needs a suitable font? Try "Google Noto" or "Arial Unicode". See docs/FONTS.md for details.)
1336 // - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8
1337 // - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. in Visual Studio, you
1338 // can save your source files as 'UTF-8 without signature').
1339 // - FOR THIS DEMO FILE ONLY, BECAUSE WE WANT TO SUPPORT OLD COMPILERS, WE ARE *NOT* INCLUDING RAW UTF-8
1340 // CHARACTERS IN THIS SOURCE FILE. Instead we are encoding a few strings with hexadecimal constants.
1341 // Don't do this in your application! Please use u8"text in any language" in your application!
1342 // Note that characters values are preserved even by InputText() if the font cannot be displayed,
1343 // so you can safely copy & paste garbled characters into another application.
1344 ImGui::TextWrapped(
1345 "CJK text will only appear if the font was loaded with the appropriate CJK character ranges. "
1346 "Call io.Fonts->AddFontFromFileTTF() manually to load extra character ranges. "
1347 "Read docs/FONTS.md for details.");
1348 ImGui::Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)");
1349 ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)");
1350 static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e";
1351 //static char buf[32] = u8"NIHONGO"; // <- this is how you would write it with C++11, using real kanjis
1352 ImGui::InputText("UTF-8 input", buf, IM_ARRAYSIZE(buf));
1353 ImGui::TreePop();
1354 }
1355 ImGui::TreePop();
1356 }
1357
1358 IMGUI_DEMO_MARKER("Widgets/Images");
1359 if (ImGui::TreeNode("Images"))
1360 {
1361 ImGuiIO& io = ImGui::GetIO();
1362 ImGui::TextWrapped(
1363 "Below we are displaying the font texture (which is the only texture we have access to in this demo). "
1364 "Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. "
1365 "Hover the texture for a zoomed view!");
1366
1367 // Below we are displaying the font texture because it is the only texture we have access to inside the demo!
1368 // Remember that ImTextureID is just storage for whatever you want it to be. It is essentially a value that
1369 // will be passed to the rendering backend via the ImDrawCmd structure.
1370 // If you use one of the default imgui_impl_XXXX.cpp rendering backend, they all have comments at the top
1371 // of their respective source file to specify what they expect to be stored in ImTextureID, for example:
1372 // - The imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer
1373 // - The imgui_impl_opengl3.cpp renderer expect a GLuint OpenGL texture identifier, etc.
1374 // More:
1375 // - If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers
1376 // to ImGui::Image(), and gather width/height through your own functions, etc.
1377 // - You can use ShowMetricsWindow() to inspect the draw data that are being passed to your renderer,
1378 // it will help you debug issues if you are confused about it.
1379 // - Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage().
1380 // - Read https://github.com/ocornut/imgui/blob/master/docs/FAQ.md
1381 // - Read https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
1382 ImTextureID my_tex_id = io.Fonts->TexID;
1383 float my_tex_w = (float)io.Fonts->TexWidth;
1384 float my_tex_h = (float)io.Fonts->TexHeight;
1385 {
1386 static bool use_text_color_for_tint = false;
1387 ImGui::Checkbox("Use Text Color for Tint", &use_text_color_for_tint);
1388 ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h);
1389 ImVec2 pos = ImGui::GetCursorScreenPos();
1390 ImVec2 uv_min = ImVec2(0.0f, 0.0f); // Top-left
1391 ImVec2 uv_max = ImVec2(1.0f, 1.0f); // Lower-right
1392 ImVec4 tint_col = use_text_color_for_tint ? ImGui::GetStyleColorVec4(ImGuiCol_Text) : ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint
1393 ImVec4 border_col = ImGui::GetStyleColorVec4(ImGuiCol_Border);
1394 ImGui::Image(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, tint_col, border_col);
1395 if (ImGui::BeginItemTooltip())
1396 {
1397 float region_sz = 32.0f;
1398 float region_x = io.MousePos.x - pos.x - region_sz * 0.5f;
1399 float region_y = io.MousePos.y - pos.y - region_sz * 0.5f;
1400 float zoom = 4.0f;
1401 if (region_x < 0.0f) { region_x = 0.0f; }
1402 else if (region_x > my_tex_w - region_sz) { region_x = my_tex_w - region_sz; }
1403 if (region_y < 0.0f) { region_y = 0.0f; }
1404 else if (region_y > my_tex_h - region_sz) { region_y = my_tex_h - region_sz; }
1405 ImGui::Text("Min: (%.2f, %.2f)", region_x, region_y);
1406 ImGui::Text("Max: (%.2f, %.2f)", region_x + region_sz, region_y + region_sz);
1407 ImVec2 uv0 = ImVec2((region_x) / my_tex_w, (region_y) / my_tex_h);
1408 ImVec2 uv1 = ImVec2((region_x + region_sz) / my_tex_w, (region_y + region_sz) / my_tex_h);
1409 ImGui::Image(my_tex_id, ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, tint_col, border_col);
1410 ImGui::EndTooltip();
1411 }
1412 }
1413
1414 IMGUI_DEMO_MARKER("Widgets/Images/Textured buttons");
1415 ImGui::TextWrapped("And now some textured buttons..");
1416 static int pressed_count = 0;
1417 for (int i = 0; i < 8; i++)
1418 {
1419 // UV coordinates are often (0.0f, 0.0f) and (1.0f, 1.0f) to display an entire textures.
1420 // Here are trying to display only a 32x32 pixels area of the texture, hence the UV computation.
1421 // Read about UV coordinates here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
1422 ImGui::PushID(i);
1423 if (i > 0)
1424 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(i - 1.0f, i - 1.0f));
1425 ImVec2 size = ImVec2(32.0f, 32.0f); // Size of the image we want to make visible
1426 ImVec2 uv0 = ImVec2(0.0f, 0.0f); // UV coordinates for lower-left
1427 ImVec2 uv1 = ImVec2(32.0f / my_tex_w, 32.0f / my_tex_h); // UV coordinates for (32,32) in our texture
1428 ImVec4 bg_col = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); // Black background
1429 ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint
1430 if (ImGui::ImageButton("", my_tex_id, size, uv0, uv1, bg_col, tint_col))
1431 pressed_count += 1;
1432 if (i > 0)
1433 ImGui::PopStyleVar();
1434 ImGui::PopID();
1435 ImGui::SameLine();
1436 }
1437 ImGui::NewLine();
1438 ImGui::Text("Pressed %d times.", pressed_count);
1439 ImGui::TreePop();
1440 }
1441
1442 IMGUI_DEMO_MARKER("Widgets/Combo");
1443 if (ImGui::TreeNode("Combo"))
1444 {
1445 // Combo Boxes are also called "Dropdown" in other systems
1446 // Expose flags as checkbox for the demo
1447 static ImGuiComboFlags flags = 0;
1448 ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", &flags, ImGuiComboFlags_PopupAlignLeft);
1449 ImGui::SameLine(); HelpMarker("Only makes a difference if the popup is larger than the combo");
1450 if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", &flags, ImGuiComboFlags_NoArrowButton))
1451 flags &= ~ImGuiComboFlags_NoPreview; // Clear incompatible flags
1452 if (ImGui::CheckboxFlags("ImGuiComboFlags_NoPreview", &flags, ImGuiComboFlags_NoPreview))
1453 flags &= ~(ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_WidthFitPreview); // Clear incompatible flags
1454 if (ImGui::CheckboxFlags("ImGuiComboFlags_WidthFitPreview", &flags, ImGuiComboFlags_WidthFitPreview))
1455 flags &= ~ImGuiComboFlags_NoPreview;
1456
1457 // Override default popup height
1458 if (ImGui::CheckboxFlags("ImGuiComboFlags_HeightSmall", &flags, ImGuiComboFlags_HeightSmall))
1459 flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightSmall);
1460 if (ImGui::CheckboxFlags("ImGuiComboFlags_HeightRegular", &flags, ImGuiComboFlags_HeightRegular))
1461 flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightRegular);
1462 if (ImGui::CheckboxFlags("ImGuiComboFlags_HeightLargest", &flags, ImGuiComboFlags_HeightLargest))
1463 flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightLargest);
1464
1465 // Using the generic BeginCombo() API, you have full control over how to display the combo contents.
1466 // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
1467 // stored in the object itself, etc.)
1468 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" };
1469 static int item_selected_idx = 0; // Here we store our selection data as an index.
1470
1471 // Pass in the preview value visible before opening the combo (it could technically be different contents or not pulled from items[])
1472 const char* combo_preview_value = items[item_selected_idx];
1473
1474 if (ImGui::BeginCombo("combo 1", combo_preview_value, flags))
1475 {
1476 for (int n = 0; n < IM_ARRAYSIZE(items); n++)
1477 {
1478 const bool is_selected = (item_selected_idx == n);
1479 if (ImGui::Selectable(items[n], is_selected))
1480 item_selected_idx = n;
1481
1482 // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
1483 if (is_selected)
1484 ImGui::SetItemDefaultFocus();
1485 }
1486 ImGui::EndCombo();
1487 }
1488
1489 ImGui::Spacing();
1490 ImGui::SeparatorText("One-liner variants");
1491 HelpMarker("Flags above don't apply to this section.");
1492
1493 // Simplified one-liner Combo() API, using values packed in a single constant string
1494 // This is a convenience for when the selection set is small and known at compile-time.
1495 static int item_current_2 = 0;
1496 ImGui::Combo("combo 2 (one-liner)", &item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
1497
1498 // Simplified one-liner Combo() using an array of const char*
1499 // This is not very useful (may obsolete): prefer using BeginCombo()/EndCombo() for full control.
1500 static int item_current_3 = -1; // If the selection isn't within 0..count, Combo won't display a preview
1501 ImGui::Combo("combo 3 (array)", &item_current_3, items, IM_ARRAYSIZE(items));
1502
1503 // Simplified one-liner Combo() using an accessor function
1504 static int item_current_4 = 0;
1505 ImGui::Combo("combo 4 (function)", &item_current_4, [](void* data, int n) { return ((const char**)data)[n]; }, items, IM_ARRAYSIZE(items));
1506
1507 ImGui::TreePop();
1508 }
1509
1510 IMGUI_DEMO_MARKER("Widgets/List Boxes");
1511 if (ImGui::TreeNode("List boxes"))
1512 {
1513 // BeginListBox() is essentially a thin wrapper to using BeginChild()/EndChild()
1514 // using the ImGuiChildFlags_FrameStyle flag for stylistic changes + displaying a label.
1515 // You may be tempted to simply use BeginChild() directly. However note that BeginChild() requires EndChild()
1516 // to always be called (inconsistent with BeginListBox()/EndListBox()).
1517
1518 // Using the generic BeginListBox() API, you have full control over how to display the combo contents.
1519 // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
1520 // stored in the object itself, etc.)
1521 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" };
1522 static int item_selected_idx = 0; // Here we store our selected data as an index.
1523
1524 static bool item_highlight = false;
1525 int item_highlighted_idx = -1; // Here we store our highlighted data as an index.
1526 ImGui::Checkbox("Highlight hovered item in second listbox", &item_highlight);
1527
1528 if (ImGui::BeginListBox("listbox 1"))
1529 {
1530 for (int n = 0; n < IM_ARRAYSIZE(items); n++)
1531 {
1532 const bool is_selected = (item_selected_idx == n);
1533 if (ImGui::Selectable(items[n], is_selected))
1534 item_selected_idx = n;
1535
1536 if (item_highlight && ImGui::IsItemHovered())
1537 item_highlighted_idx = n;
1538
1539 // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
1540 if (is_selected)
1541 ImGui::SetItemDefaultFocus();
1542 }
1543 ImGui::EndListBox();
1544 }
1545 ImGui::SameLine(); HelpMarker("Here we are sharing selection state between both boxes.");
1546
1547 // Custom size: use all width, 5 items tall
1548 ImGui::Text("Full-width:");
1549 if (ImGui::BeginListBox("##listbox 2", ImVec2(-FLT_MIN, 5 * ImGui::GetTextLineHeightWithSpacing())))
1550 {
1551 for (int n = 0; n < IM_ARRAYSIZE(items); n++)
1552 {
1553 bool is_selected = (item_selected_idx == n);
1554 ImGuiSelectableFlags flags = (item_highlighted_idx == n) ? ImGuiSelectableFlags_Highlight : 0;
1555 if (ImGui::Selectable(items[n], is_selected, flags))
1556 item_selected_idx = n;
1557
1558 // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
1559 if (is_selected)
1560 ImGui::SetItemDefaultFocus();
1561 }
1562 ImGui::EndListBox();
1563 }
1564
1565 ImGui::TreePop();
1566 }
1567
1568 IMGUI_DEMO_MARKER("Widgets/Selectables");
1569 //ImGui::SetNextItemOpen(true, ImGuiCond_Once);
1570 if (ImGui::TreeNode("Selectables"))
1571 {
1572 // Selectable() has 2 overloads:
1573 // - The one taking "bool selected" as a read-only selection information.
1574 // When Selectable() has been clicked it returns true and you can alter selection state accordingly.
1575 // - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases)
1576 // The earlier is more flexible, as in real application your selection may be stored in many different ways
1577 // and not necessarily inside a bool value (e.g. in flags within objects, as an external list, etc).
1578 IMGUI_DEMO_MARKER("Widgets/Selectables/Basic");
1579 if (ImGui::TreeNode("Basic"))
1580 {
1581 static bool selection[5] = { false, true, false, false };
1582 ImGui::Selectable("1. I am selectable", &selection[0]);
1583 ImGui::Selectable("2. I am selectable", &selection[1]);
1584 ImGui::Selectable("3. I am selectable", &selection[2]);
1585 if (ImGui::Selectable("4. I am double clickable", selection[3], ImGuiSelectableFlags_AllowDoubleClick))
1586 if (ImGui::IsMouseDoubleClicked(0))
1587 selection[3] = !selection[3];
1588 ImGui::TreePop();
1589 }
1590
1591 IMGUI_DEMO_MARKER("Widgets/Selectables/Rendering more items on the same line");
1592 if (ImGui::TreeNode("Rendering more items on the same line"))
1593 {
1594 // (1) Using SetNextItemAllowOverlap()
1595 // (2) Using the Selectable() override that takes "bool* p_selected" parameter, the bool value is toggled automatically.
1596 static bool selected[3] = { false, false, false };
1597 ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("main.c", &selected[0]); ImGui::SameLine(); ImGui::SmallButton("Link 1");
1598 ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("Hello.cpp", &selected[1]); ImGui::SameLine(); ImGui::SmallButton("Link 2");
1599 ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("Hello.h", &selected[2]); ImGui::SameLine(); ImGui::SmallButton("Link 3");
1600 ImGui::TreePop();
1601 }
1602
1603 IMGUI_DEMO_MARKER("Widgets/Selectables/In Tables");
1604 if (ImGui::TreeNode("In Tables"))
1605 {
1606 static bool selected[10] = {};
1607
1608 if (ImGui::BeginTable("split1", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders))
1609 {
1610 for (int i = 0; i < 10; i++)
1611 {
1612 char label[32];
1613 sprintf(label, "Item %d", i);
1614 ImGui::TableNextColumn();
1615 ImGui::Selectable(label, &selected[i]); // FIXME-TABLE: Selection overlap
1616 }
1617 ImGui::EndTable();
1618 }
1619 ImGui::Spacing();
1620 if (ImGui::BeginTable("split2", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders))
1621 {
1622 for (int i = 0; i < 10; i++)
1623 {
1624 char label[32];
1625 sprintf(label, "Item %d", i);
1626 ImGui::TableNextRow();
1627 ImGui::TableNextColumn();
1628 ImGui::Selectable(label, &selected[i], ImGuiSelectableFlags_SpanAllColumns);
1629 ImGui::TableNextColumn();
1630 ImGui::Text("Some other contents");
1631 ImGui::TableNextColumn();
1632 ImGui::Text("123456");
1633 }
1634 ImGui::EndTable();
1635 }
1636 ImGui::TreePop();
1637 }
1638
1639 IMGUI_DEMO_MARKER("Widgets/Selectables/Grid");
1640 if (ImGui::TreeNode("Grid"))
1641 {
1642 static char selected[4][4] = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } };
1643
1644 // Add in a bit of silly fun...
1645 const float time = (float)ImGui::GetTime();
1646 const bool winning_state = memchr(selected, 0, sizeof(selected)) == NULL; // If all cells are selected...
1647 if (winning_state)
1648 ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f + 0.5f * cosf(time * 2.0f), 0.5f + 0.5f * sinf(time * 3.0f)));
1649
1650 for (int y = 0; y < 4; y++)
1651 for (int x = 0; x < 4; x++)
1652 {
1653 if (x > 0)
1654 ImGui::SameLine();
1655 ImGui::PushID(y * 4 + x);
1656 if (ImGui::Selectable("Sailor", selected[y][x] != 0, 0, ImVec2(50, 50)))
1657 {
1658 // Toggle clicked cell + toggle neighbors
1659 selected[y][x] ^= 1;
1660 if (x > 0) { selected[y][x - 1] ^= 1; }
1661 if (x < 3) { selected[y][x + 1] ^= 1; }
1662 if (y > 0) { selected[y - 1][x] ^= 1; }
1663 if (y < 3) { selected[y + 1][x] ^= 1; }
1664 }
1665 ImGui::PopID();
1666 }
1667
1668 if (winning_state)
1669 ImGui::PopStyleVar();
1670 ImGui::TreePop();
1671 }
1672 IMGUI_DEMO_MARKER("Widgets/Selectables/Alignment");
1673 if (ImGui::TreeNode("Alignment"))
1674 {
1675 HelpMarker(
1676 "By default, Selectables uses style.SelectableTextAlign but it can be overridden on a per-item "
1677 "basis using PushStyleVar(). You'll probably want to always keep your default situation to "
1678 "left-align otherwise it becomes difficult to layout multiple items on a same line");
1679 static bool selected[3 * 3] = { true, false, true, false, true, false, true, false, true };
1680 for (int y = 0; y < 3; y++)
1681 {
1682 for (int x = 0; x < 3; x++)
1683 {
1684 ImVec2 alignment = ImVec2((float)x / 2.0f, (float)y / 2.0f);
1685 char name[32];
1686 sprintf(name, "(%.1f,%.1f)", alignment.x, alignment.y);
1687 if (x > 0) ImGui::SameLine();
1688 ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, alignment);
1689 ImGui::Selectable(name, &selected[3 * y + x], ImGuiSelectableFlags_None, ImVec2(80, 80));
1690 ImGui::PopStyleVar();
1691 }
1692 }
1693 ImGui::TreePop();
1694 }
1695 ImGui::TreePop();
1696 }
1697
1698 ShowDemoWindowMultiSelect(demo_data);
1699
1700 // To wire InputText() with std::string or any other custom string type,
1701 // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file.
1702 IMGUI_DEMO_MARKER("Widgets/Text Input");
1703 if (ImGui::TreeNode("Text Input"))
1704 {
1705 IMGUI_DEMO_MARKER("Widgets/Text Input/Multi-line Text Input");
1706 if (ImGui::TreeNode("Multi-line Text Input"))
1707 {
1708 // Note: we are using a fixed-sized buffer for simplicity here. See ImGuiInputTextFlags_CallbackResize
1709 // and the code in misc/cpp/imgui_stdlib.h for how to setup InputText() for dynamically resizing strings.
1710 static char text[1024 * 16] =
1711 "/*\n"
1712 " The Pentium F00F bug, shorthand for F0 0F C7 C8,\n"
1713 " the hexadecimal encoding of one offending instruction,\n"
1714 " more formally, the invalid operand with locked CMPXCHG8B\n"
1715 " instruction bug, is a design flaw in the majority of\n"
1716 " Intel Pentium, Pentium MMX, and Pentium OverDrive\n"
1717 " processors (all in the P5 microarchitecture).\n"
1718 "*/\n\n"
1719 "label:\n"
1720 "\tlock cmpxchg8b eax\n";
1721
1722 static ImGuiInputTextFlags flags = ImGuiInputTextFlags_AllowTabInput;
1723 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)");
1724 ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly);
1725 ImGui::CheckboxFlags("ImGuiInputTextFlags_AllowTabInput", &flags, ImGuiInputTextFlags_AllowTabInput);
1726 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.");
1727 ImGui::CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", &flags, ImGuiInputTextFlags_CtrlEnterForNewLine);
1728 ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16), flags);
1729 ImGui::TreePop();
1730 }
1731
1732 IMGUI_DEMO_MARKER("Widgets/Text Input/Filtered Text Input");
1733 if (ImGui::TreeNode("Filtered Text Input"))
1734 {
1735 struct TextFilters
1736 {
1737 // Modify character input by altering 'data->Eventchar' (ImGuiInputTextFlags_CallbackCharFilter callback)
1738 static int FilterCasingSwap(ImGuiInputTextCallbackData* data)
1739 {
1740 if (data->EventChar >= 'a' && data->EventChar <= 'z') { data->EventChar -= 'a' - 'A'; } // Lowercase becomes uppercase
1741 else if (data->EventChar >= 'A' && data->EventChar <= 'Z') { data->EventChar += 'a' - 'A'; } // Uppercase becomes lowercase
1742 return 0;
1743 }
1744
1745 // Return 0 (pass) if the character is 'i' or 'm' or 'g' or 'u' or 'i', otherwise return 1 (filter out)
1746 static int FilterImGuiLetters(ImGuiInputTextCallbackData* data)
1747 {
1748 if (data->EventChar < 256 && strchr("imgui", (char)data->EventChar))
1749 return 0;
1750 return 1;
1751 }
1752 };
1753
1754 static char buf1[32] = ""; ImGui::InputText("default", buf1, 32);
1755 static char buf2[32] = ""; ImGui::InputText("decimal", buf2, 32, ImGuiInputTextFlags_CharsDecimal);
1756 static char buf3[32] = ""; ImGui::InputText("hexadecimal", buf3, 32, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase);
1757 static char buf4[32] = ""; ImGui::InputText("uppercase", buf4, 32, ImGuiInputTextFlags_CharsUppercase);
1758 static char buf5[32] = ""; ImGui::InputText("no blank", buf5, 32, ImGuiInputTextFlags_CharsNoBlank);
1759 static char buf6[32] = ""; ImGui::InputText("casing swap", buf6, 32, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterCasingSwap); // Use CharFilter callback to replace characters.
1760 static char buf7[32] = ""; ImGui::InputText("\"imgui\"", buf7, 32, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters); // Use CharFilter callback to disable some characters.
1761 ImGui::TreePop();
1762 }
1763
1764 IMGUI_DEMO_MARKER("Widgets/Text Input/Password input");
1765 if (ImGui::TreeNode("Password Input"))
1766 {
1767 static char password[64] = "password123";
1768 ImGui::InputText("password", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password);
1769 ImGui::SameLine(); HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n");
1770 ImGui::InputTextWithHint("password (w/ hint)", "<password>", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password);
1771 ImGui::InputText("password (clear)", password, IM_ARRAYSIZE(password));
1772 ImGui::TreePop();
1773 }
1774
1775 IMGUI_DEMO_MARKER("Widgets/Text Input/Completion, History, Edit Callbacks");
1776 if (ImGui::TreeNode("Completion, History, Edit Callbacks"))
1777 {
1778 struct Funcs
1779 {
1780 static int MyCallback(ImGuiInputTextCallbackData* data)
1781 {
1782 if (data->EventFlag == ImGuiInputTextFlags_CallbackCompletion)
1783 {
1784 data->InsertChars(data->CursorPos, "..");
1785 }
1786 else if (data->EventFlag == ImGuiInputTextFlags_CallbackHistory)
1787 {
1788 if (data->EventKey == ImGuiKey_UpArrow)
1789 {
1790 data->DeleteChars(0, data->BufTextLen);
1791 data->InsertChars(0, "Pressed Up!");
1792 data->SelectAll();
1793 }
1794 else if (data->EventKey == ImGuiKey_DownArrow)
1795 {
1796 data->DeleteChars(0, data->BufTextLen);
1797 data->InsertChars(0, "Pressed Down!");
1798 data->SelectAll();
1799 }
1800 }
1801 else if (data->EventFlag == ImGuiInputTextFlags_CallbackEdit)
1802 {
1803 // Toggle casing of first character
1804 char c = data->Buf[0];
1805 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) data->Buf[0] ^= 32;
1806 data->BufDirty = true;
1807
1808 // Increment a counter
1809 int* p_int = (int*)data->UserData;
1810 *p_int = *p_int + 1;
1811 }
1812 return 0;
1813 }
1814 };
1815 static char buf1[64];
1816 ImGui::InputText("Completion", buf1, 64, ImGuiInputTextFlags_CallbackCompletion, Funcs::MyCallback);
1817 ImGui::SameLine(); HelpMarker(
1818 "Here we append \"..\" each time Tab is pressed. "
1819 "See 'Examples>Console' for a more meaningful demonstration of using this callback.");
1820
1821 static char buf2[64];
1822 ImGui::InputText("History", buf2, 64, ImGuiInputTextFlags_CallbackHistory, Funcs::MyCallback);
1823 ImGui::SameLine(); HelpMarker(
1824 "Here we replace and select text each time Up/Down are pressed. "
1825 "See 'Examples>Console' for a more meaningful demonstration of using this callback.");
1826
1827 static char buf3[64];
1828 static int edit_count = 0;
1829 ImGui::InputText("Edit", buf3, 64, ImGuiInputTextFlags_CallbackEdit, Funcs::MyCallback, (void*)&edit_count);
1830 ImGui::SameLine(); HelpMarker(
1831 "Here we toggle the casing of the first character on every edit + count edits.");
1832 ImGui::SameLine(); ImGui::Text("(%d)", edit_count);
1833
1834 ImGui::TreePop();
1835 }
1836
1837 IMGUI_DEMO_MARKER("Widgets/Text Input/Resize Callback");
1838 if (ImGui::TreeNode("Resize Callback"))
1839 {
1840 // To wire InputText() with std::string or any other custom string type,
1841 // you can use the ImGuiInputTextFlags_CallbackResize flag + create a custom ImGui::InputText() wrapper
1842 // using your preferred type. See misc/cpp/imgui_stdlib.h for an implementation of this using std::string.
1843 HelpMarker(
1844 "Using ImGuiInputTextFlags_CallbackResize to wire your custom string type to InputText().\n\n"
1845 "See misc/cpp/imgui_stdlib.h for an implementation of this for std::string.");
1846 struct Funcs
1847 {
1848 static int MyResizeCallback(ImGuiInputTextCallbackData* data)
1849 {
1850 if (data->EventFlag == ImGuiInputTextFlags_CallbackResize)
1851 {
1852 ImVector<char>* my_str = (ImVector<char>*)data->UserData;
1853 IM_ASSERT(my_str->begin() == data->Buf);
1854 my_str->resize(data->BufSize); // NB: On resizing calls, generally data->BufSize == data->BufTextLen + 1
1855 data->Buf = my_str->begin();
1856 }
1857 return 0;
1858 }
1859
1860 // Note: Because ImGui:: is a namespace you would typically add your own function into the namespace.
1861 // For example, you code may declare a function 'ImGui::InputText(const char* label, MyString* my_str)'
1862 static bool MyInputTextMultiline(const char* label, ImVector<char>* my_str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0)
1863 {
1864 IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
1865 return ImGui::InputTextMultiline(label, my_str->begin(), (size_t)my_str->size(), size, flags | ImGuiInputTextFlags_CallbackResize, Funcs::MyResizeCallback, (void*)my_str);
1866 }
1867 };
1868
1869 // For this demo we are using ImVector as a string container.
1870 // Note that because we need to store a terminating zero character, our size/capacity are 1 more
1871 // than usually reported by a typical string class.
1872 static ImVector<char> my_str;
1873 if (my_str.empty())
1874 my_str.push_back(0);
1875 Funcs::MyInputTextMultiline("##MyStr", &my_str, ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16));
1876 ImGui::Text("Data: %p\nSize: %d\nCapacity: %d", (void*)my_str.begin(), my_str.size(), my_str.capacity());
1877 ImGui::TreePop();
1878 }
1879
1880 IMGUI_DEMO_MARKER("Widgets/Text Input/Miscellaneous");
1881 if (ImGui::TreeNode("Miscellaneous"))
1882 {
1883 static char buf1[16];
1884 static ImGuiInputTextFlags flags = ImGuiInputTextFlags_EscapeClearsAll;
1885 ImGui::CheckboxFlags("ImGuiInputTextFlags_EscapeClearsAll", &flags, ImGuiInputTextFlags_EscapeClearsAll);
1886 ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly);
1887 ImGui::CheckboxFlags("ImGuiInputTextFlags_NoUndoRedo", &flags, ImGuiInputTextFlags_NoUndoRedo);
1888 ImGui::InputText("Hello", buf1, IM_ARRAYSIZE(buf1), flags);
1889 ImGui::TreePop();
1890 }
1891
1892 ImGui::TreePop();
1893 }
1894
1895 // Tabs
1896 IMGUI_DEMO_MARKER("Widgets/Tabs");
1897 if (ImGui::TreeNode("Tabs"))
1898 {
1899 IMGUI_DEMO_MARKER("Widgets/Tabs/Basic");
1900 if (ImGui::TreeNode("Basic"))
1901 {
1902 ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None;
1903 if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
1904 {
1905 if (ImGui::BeginTabItem("Avocado"))
1906 {
1907 ImGui::Text("This is the Avocado tab!\nblah blah blah blah blah");
1908 ImGui::EndTabItem();
1909 }
1910 if (ImGui::BeginTabItem("Broccoli"))
1911 {
1912 ImGui::Text("This is the Broccoli tab!\nblah blah blah blah blah");
1913 ImGui::EndTabItem();
1914 }
1915 if (ImGui::BeginTabItem("Cucumber"))
1916 {
1917 ImGui::Text("This is the Cucumber tab!\nblah blah blah blah blah");
1918 ImGui::EndTabItem();
1919 }
1920 ImGui::EndTabBar();
1921 }
1922 ImGui::Separator();
1923 ImGui::TreePop();
1924 }
1925
1926 IMGUI_DEMO_MARKER("Widgets/Tabs/Advanced & Close Button");
1927 if (ImGui::TreeNode("Advanced & Close Button"))
1928 {
1929 // Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0).
1930 static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable;
1931 ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", &tab_bar_flags, ImGuiTabBarFlags_Reorderable);
1932 ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", &tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs);
1933 ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton);
1934 ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", &tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton);
1935 ImGui::CheckboxFlags("ImGuiTabBarFlags_DrawSelectedOverline", &tab_bar_flags, ImGuiTabBarFlags_DrawSelectedOverline);
1936 if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0)
1937 tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_;
1938 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown))
1939 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown);
1940 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll))
1941 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll);
1942
1943 // Tab Bar
1944 ImGui::AlignTextToFramePadding();
1945 ImGui::Text("Opened:");
1946 const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" };
1947 static bool opened[4] = { true, true, true, true }; // Persistent user state
1948 for (int n = 0; n < IM_ARRAYSIZE(opened); n++)
1949 {
1950 ImGui::SameLine();
1951 ImGui::Checkbox(names[n], &opened[n]);
1952 }
1953
1954 // Passing a bool* to BeginTabItem() is similar to passing one to Begin():
1955 // the underlying bool will be set to false when the tab is closed.
1956 if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
1957 {
1958 for (int n = 0; n < IM_ARRAYSIZE(opened); n++)
1959 if (opened[n] && ImGui::BeginTabItem(names[n], &opened[n], ImGuiTabItemFlags_None))
1960 {
1961 ImGui::Text("This is the %s tab!", names[n]);
1962 if (n & 1)
1963 ImGui::Text("I am an odd tab.");
1964 ImGui::EndTabItem();
1965 }
1966 ImGui::EndTabBar();
1967 }
1968 ImGui::Separator();
1969 ImGui::TreePop();
1970 }
1971
1972 IMGUI_DEMO_MARKER("Widgets/Tabs/TabItemButton & Leading-Trailing flags");
1973 if (ImGui::TreeNode("TabItemButton & Leading/Trailing flags"))
1974 {
1975 static ImVector<int> active_tabs;
1976 static int next_tab_id = 0;
1977 if (next_tab_id == 0) // Initialize with some default tabs
1978 for (int i = 0; i < 3; i++)
1979 active_tabs.push_back(next_tab_id++);
1980
1981 // TabItemButton() and Leading/Trailing flags are distinct features which we will demo together.
1982 // (It is possible to submit regular tabs with Leading/Trailing flags, or TabItemButton tabs without Leading/Trailing flags...
1983 // but they tend to make more sense together)
1984 static bool show_leading_button = true;
1985 static bool show_trailing_button = true;
1986 ImGui::Checkbox("Show Leading TabItemButton()", &show_leading_button);
1987 ImGui::Checkbox("Show Trailing TabItemButton()", &show_trailing_button);
1988
1989 // Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs
1990 static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_FittingPolicyResizeDown;
1991 ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton);
1992 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown))
1993 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown);
1994 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll))
1995 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll);
1996
1997 if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
1998 {
1999 // Demo a Leading TabItemButton(): click the "?" button to open a menu
2000 if (show_leading_button)
2001 if (ImGui::TabItemButton("?", ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_NoTooltip))
2002 ImGui::OpenPopup("MyHelpMenu");
2003 if (ImGui::BeginPopup("MyHelpMenu"))
2004 {
2005 ImGui::Selectable("Hello!");
2006 ImGui::EndPopup();
2007 }
2008
2009 // Demo Trailing Tabs: click the "+" button to add a new tab.
2010 // (In your app you may want to use a font icon instead of the "+")
2011 // We submit it before the regular tabs, but thanks to the ImGuiTabItemFlags_Trailing flag it will always appear at the end.
2012 if (show_trailing_button)
2013 if (ImGui::TabItemButton("+", ImGuiTabItemFlags_Trailing | ImGuiTabItemFlags_NoTooltip))
2014 active_tabs.push_back(next_tab_id++); // Add new tab
2015
2016 // Submit our regular tabs
2017 for (int n = 0; n < active_tabs.Size; )
2018 {
2019 bool open = true;
2020 char name[16];
2021 snprintf(name, IM_ARRAYSIZE(name), "%04d", active_tabs[n]);
2022 if (ImGui::BeginTabItem(name, &open, ImGuiTabItemFlags_None))
2023 {
2024 ImGui::Text("This is the %s tab!", name);
2025 ImGui::EndTabItem();
2026 }
2027
2028 if (!open)
2029 active_tabs.erase(active_tabs.Data + n);
2030 else
2031 n++;
2032 }
2033
2034 ImGui::EndTabBar();
2035 }
2036 ImGui::Separator();
2037 ImGui::TreePop();
2038 }
2039 ImGui::TreePop();
2040 }
2041
2042 // Plot/Graph widgets are not very good.
2043 // Consider using a third-party library such as ImPlot: https://github.com/epezent/implot
2044 // (see others https://github.com/ocornut/imgui/wiki/Useful-Extensions)
2045 IMGUI_DEMO_MARKER("Widgets/Plotting");
2046 if (ImGui::TreeNode("Plotting"))
2047 {
2048 static bool animate = true;
2049 ImGui::Checkbox("Animate", &animate);
2050
2051 // Plot as lines and plot as histogram
2052 static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
2053 ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr));
2054 ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0, 80.0f));
2055 //ImGui::SameLine(); HelpMarker("Consider using ImPlot instead!");
2056
2057 // Fill an array of contiguous float values to plot
2058 // Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float
2059 // and the sizeof() of your structure in the "stride" parameter.
2060 static float values[90] = {};
2061 static int values_offset = 0;
2062 static double refresh_time = 0.0;
2063 if (!animate || refresh_time == 0.0)
2064 refresh_time = ImGui::GetTime();
2065 while (refresh_time < ImGui::GetTime()) // Create data at fixed 60 Hz rate for the demo
2066 {
2067 static float phase = 0.0f;
2068 values[values_offset] = cosf(phase);
2069 values_offset = (values_offset + 1) % IM_ARRAYSIZE(values);
2070 phase += 0.10f * values_offset;
2071 refresh_time += 1.0f / 60.0f;
2072 }
2073
2074 // Plots can display overlay texts
2075 // (in this example, we will display an average value)
2076 {
2077 float average = 0.0f;
2078 for (int n = 0; n < IM_ARRAYSIZE(values); n++)
2079 average += values[n];
2080 average /= (float)IM_ARRAYSIZE(values);
2081 char overlay[32];
2082 sprintf(overlay, "avg %f", average);
2083 ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, overlay, -1.0f, 1.0f, ImVec2(0, 80.0f));
2084 }
2085
2086 // Use functions to generate output
2087 // FIXME: This is actually VERY awkward because current plot API only pass in indices.
2088 // We probably want an API passing floats and user provide sample rate/count.
2089 struct Funcs
2090 {
2091 static float Sin(void*, int i) { return sinf(i * 0.1f); }
2092 static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; }
2093 };
2094 static int func_type = 0, display_count = 70;
2095 ImGui::SeparatorText("Functions");
2096 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
2097 ImGui::Combo("func", &func_type, "Sin\0Saw\0");
2098 ImGui::SameLine();
2099 ImGui::SliderInt("Sample count", &display_count, 1, 400);
2100 float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw;
2101 ImGui::PlotLines("Lines##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
2102 ImGui::PlotHistogram("Histogram##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
2103 ImGui::Separator();
2104
2105 ImGui::Text("Need better plotting and graphing? Consider using ImPlot:");
2106 ImGui::TextLinkOpenURL("https://github.com/epezent/implot");
2107 ImGui::Separator();
2108
2109 ImGui::TreePop();
2110 }
2111
2112 IMGUI_DEMO_MARKER("Widgets/Progress Bars");
2113 if (ImGui::TreeNode("Progress Bars"))
2114 {
2115 // Animate a simple progress bar
2116 static float progress = 0.0f, progress_dir = 1.0f;
2117 progress += progress_dir * 0.4f * ImGui::GetIO().DeltaTime;
2118 if (progress >= +1.1f) { progress = +1.1f; progress_dir *= -1.0f; }
2119 if (progress <= -0.1f) { progress = -0.1f; progress_dir *= -1.0f; }
2120
2121 // Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width,
2122 // or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth.
2123 ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f));
2124 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
2125 ImGui::Text("Progress Bar");
2126
2127 float progress_saturated = IM_CLAMP(progress, 0.0f, 1.0f);
2128 char buf[32];
2129 sprintf(buf, "%d/%d", (int)(progress_saturated * 1753), 1753);
2130 ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), buf);
2131
2132 // Pass an animated negative value, e.g. -1.0f * (float)ImGui::GetTime() is the recommended value.
2133 // Adjust the factor if you want to adjust the animation speed.
2134 ImGui::ProgressBar(-1.0f * (float)ImGui::GetTime(), ImVec2(0.0f, 0.0f), "Searching..");
2135 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
2136 ImGui::Text("Indeterminate");
2137
2138 ImGui::TreePop();
2139 }
2140
2141 IMGUI_DEMO_MARKER("Widgets/Color");
2142 if (ImGui::TreeNode("Color/Picker Widgets"))
2143 {
2144 static ImVec4 color = ImVec4(114.0f / 255.0f, 144.0f / 255.0f, 154.0f / 255.0f, 200.0f / 255.0f);
2145
2146 static bool alpha_preview = true;
2147 static bool alpha_half_preview = false;
2148 static bool drag_and_drop = true;
2149 static bool options_menu = true;
2150 static bool hdr = false;
2151 ImGui::SeparatorText("Options");
2152 ImGui::Checkbox("With Alpha Preview", &alpha_preview);
2153 ImGui::Checkbox("With Half Alpha Preview", &alpha_half_preview);
2154 ImGui::Checkbox("With Drag and Drop", &drag_and_drop);
2155 ImGui::Checkbox("With Options Menu", &options_menu); ImGui::SameLine(); HelpMarker("Right-click on the individual color widget to show options.");
2156 ImGui::Checkbox("With HDR", &hdr); ImGui::SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets.");
2157 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);
2158
2159 IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit");
2160 ImGui::SeparatorText("Inline color editor");
2161 ImGui::Text("Color widget:");
2162 ImGui::SameLine(); HelpMarker(
2163 "Click on the color square to open a color picker.\n"
2164 "CTRL+click on individual component to input value.\n");
2165 ImGui::ColorEdit3("MyColor##1", (float*)&color, misc_flags);
2166
2167 IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (HSV, with Alpha)");
2168 ImGui::Text("Color widget HSV with Alpha:");
2169 ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_DisplayHSV | misc_flags);
2170
2171 IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (float display)");
2172 ImGui::Text("Color widget with Float Display:");
2173 ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | misc_flags);
2174
2175 IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with Picker)");
2176 ImGui::Text("Color button with Picker:");
2177 ImGui::SameLine(); HelpMarker(
2178 "With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\n"
2179 "With the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only "
2180 "be used for the tooltip and picker popup.");
2181 ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | misc_flags);
2182
2183 IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with custom Picker popup)");
2184 ImGui::Text("Color button with Custom Picker Popup:");
2185
2186 // Generate a default palette. The palette will persist and can be edited.
2187 static bool saved_palette_init = true;
2188 static ImVec4 saved_palette[32] = {};
2189 if (saved_palette_init)
2190 {
2191 for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++)
2192 {
2193 ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f,
2194 saved_palette[n].x, saved_palette[n].y, saved_palette[n].z);
2195 saved_palette[n].w = 1.0f; // Alpha
2196 }
2197 saved_palette_init = false;
2198 }
2199
2200 static ImVec4 backup_color;
2201 bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags);
2202 ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x);
2203 open_popup |= ImGui::Button("Palette");
2204 if (open_popup)
2205 {
2206 ImGui::OpenPopup("mypicker");
2207 backup_color = color;
2208 }
2209 if (ImGui::BeginPopup("mypicker"))
2210 {
2211 ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!");
2212 ImGui::Separator();
2213 ImGui::ColorPicker4("##picker", (float*)&color, misc_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview);
2214 ImGui::SameLine();
2215
2216 ImGui::BeginGroup(); // Lock X position
2217 ImGui::Text("Current");
2218 ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40));
2219 ImGui::Text("Previous");
2220 if (ImGui::ColorButton("##previous", backup_color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40)))
2221 color = backup_color;
2222 ImGui::Separator();
2223 ImGui::Text("Palette");
2224 for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++)
2225 {
2226 ImGui::PushID(n);
2227 if ((n % 8) != 0)
2228 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y);
2229
2230 ImGuiColorEditFlags palette_button_flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip;
2231 if (ImGui::ColorButton("##palette", saved_palette[n], palette_button_flags, ImVec2(20, 20)))
2232 color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha!
2233
2234 // Allow user to drop colors into each palette entry. Note that ColorButton() is already a
2235 // drag source by default, unless specifying the ImGuiColorEditFlags_NoDragDrop flag.
2236 if (ImGui::BeginDragDropTarget())
2237 {
2238 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
2239 memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3);
2240 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F))
2241 memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4);
2242 ImGui::EndDragDropTarget();
2243 }
2244
2245 ImGui::PopID();
2246 }
2247 ImGui::EndGroup();
2248 ImGui::EndPopup();
2249 }
2250
2251 IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (simple)");
2252 ImGui::Text("Color button only:");
2253 static bool no_border = false;
2254 ImGui::Checkbox("ImGuiColorEditFlags_NoBorder", &no_border);
2255 ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, misc_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80));
2256
2257 IMGUI_DEMO_MARKER("Widgets/Color/ColorPicker");
2258 ImGui::SeparatorText("Color picker");
2259 static bool alpha = true;
2260 static bool alpha_bar = true;
2261 static bool side_preview = true;
2262 static bool ref_color = false;
2263 static ImVec4 ref_color_v(1.0f, 0.0f, 1.0f, 0.5f);
2264 static int display_mode = 0;
2265 static int picker_mode = 0;
2266 ImGui::Checkbox("With Alpha", &alpha);
2267 ImGui::Checkbox("With Alpha Bar", &alpha_bar);
2268 ImGui::Checkbox("With Side Preview", &side_preview);
2269 if (side_preview)
2270 {
2271 ImGui::SameLine();
2272 ImGui::Checkbox("With Ref Color", &ref_color);
2273 if (ref_color)
2274 {
2275 ImGui::SameLine();
2276 ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | misc_flags);
2277 }
2278 }
2279 ImGui::Combo("Display Mode", &display_mode, "Auto/Current\0None\0RGB Only\0HSV Only\0Hex Only\0");
2280 ImGui::SameLine(); HelpMarker(
2281 "ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, "
2282 "but the user can change it with a right-click on those inputs.\n\nColorPicker defaults to displaying RGB+HSV+Hex "
2283 "if you don't specify a display mode.\n\nYou can change the defaults using SetColorEditOptions().");
2284 ImGui::SameLine(); HelpMarker("When not specified explicitly (Auto/Current mode), user can right-click the picker to change mode.");
2285 ImGuiColorEditFlags flags = misc_flags;
2286 if (!alpha) flags |= ImGuiColorEditFlags_NoAlpha; // This is by default if you call ColorPicker3() instead of ColorPicker4()
2287 if (alpha_bar) flags |= ImGuiColorEditFlags_AlphaBar;
2288 if (!side_preview) flags |= ImGuiColorEditFlags_NoSidePreview;
2289 if (picker_mode == 1) flags |= ImGuiColorEditFlags_PickerHueBar;
2290 if (picker_mode == 2) flags |= ImGuiColorEditFlags_PickerHueWheel;
2291 if (display_mode == 1) flags |= ImGuiColorEditFlags_NoInputs; // Disable all RGB/HSV/Hex displays
2292 if (display_mode == 2) flags |= ImGuiColorEditFlags_DisplayRGB; // Override display mode
2293 if (display_mode == 3) flags |= ImGuiColorEditFlags_DisplayHSV;
2294 if (display_mode == 4) flags |= ImGuiColorEditFlags_DisplayHex;
2295 ImGui::ColorPicker4("MyColor##4", (float*)&color, flags, ref_color ? &ref_color_v.x : NULL);
2296
2297 ImGui::Text("Set defaults in code:");
2298 ImGui::SameLine(); HelpMarker(
2299 "SetColorEditOptions() is designed to allow you to set boot-time default.\n"
2300 "We don't have Push/Pop functions because you can force options on a per-widget basis if needed,"
2301 "and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid"
2302 "encouraging you to persistently save values that aren't forward-compatible.");
2303 if (ImGui::Button("Default: Uint8 + HSV + Hue Bar"))
2304 ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_PickerHueBar);
2305 if (ImGui::Button("Default: Float + HDR + Hue Wheel"))
2306 ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel);
2307
2308 // Always display a small version of both types of pickers
2309 // (that's in order to make it more visible in the demo to people who are skimming quickly through it)
2310 ImGui::Text("Both types:");
2311 float w = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.y) * 0.40f;
2312 ImGui::SetNextItemWidth(w);
2313 ImGui::ColorPicker3("##MyColor##5", (float*)&color, ImGuiColorEditFlags_PickerHueBar | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha);
2314 ImGui::SameLine();
2315 ImGui::SetNextItemWidth(w);
2316 ImGui::ColorPicker3("##MyColor##6", (float*)&color, ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha);
2317
2318 // HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0)
2319 static ImVec4 color_hsv(0.23f, 1.0f, 1.0f, 1.0f); // Stored as HSV!
2320 ImGui::Spacing();
2321 ImGui::Text("HSV encoded colors");
2322 ImGui::SameLine(); HelpMarker(
2323 "By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV"
2324 "allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV. This comes with the"
2325 "added benefit that you can manipulate hue values with the picker even when saturation or value are zero.");
2326 ImGui::Text("Color widget with InputHSV:");
2327 ImGui::ColorEdit4("HSV shown as RGB##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float);
2328 ImGui::ColorEdit4("HSV shown as HSV##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float);
2329 ImGui::DragFloat4("Raw HSV values", (float*)&color_hsv, 0.01f, 0.0f, 1.0f);
2330
2331 ImGui::TreePop();
2332 }
2333
2334 IMGUI_DEMO_MARKER("Widgets/Drag and Slider Flags");
2335 if (ImGui::TreeNode("Drag/Slider Flags"))
2336 {
2337 // Demonstrate using advanced flags for DragXXX and SliderXXX functions. Note that the flags are the same!
2338 static ImGuiSliderFlags flags = ImGuiSliderFlags_None;
2339 ImGui::CheckboxFlags("ImGuiSliderFlags_AlwaysClamp", &flags, ImGuiSliderFlags_AlwaysClamp);
2340 ImGui::CheckboxFlags("ImGuiSliderFlags_ClampOnInput", &flags, ImGuiSliderFlags_ClampOnInput);
2341 ImGui::SameLine(); HelpMarker("Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds.");
2342 ImGui::CheckboxFlags("ImGuiSliderFlags_ClampZeroRange", &flags, ImGuiSliderFlags_ClampZeroRange);
2343 ImGui::SameLine(); HelpMarker("Clamp even if min==max==0.0f. Otherwise DragXXX functions don't clamp.");
2344 ImGui::CheckboxFlags("ImGuiSliderFlags_Logarithmic", &flags, ImGuiSliderFlags_Logarithmic);
2345 ImGui::SameLine(); HelpMarker("Enable logarithmic editing (more precision for small values).");
2346 ImGui::CheckboxFlags("ImGuiSliderFlags_NoRoundToFormat", &flags, ImGuiSliderFlags_NoRoundToFormat);
2347 ImGui::SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits).");
2348 ImGui::CheckboxFlags("ImGuiSliderFlags_NoInput", &flags, ImGuiSliderFlags_NoInput);
2349 ImGui::SameLine(); HelpMarker("Disable CTRL+Click or Enter key allowing to input text directly into the widget.");
2350 ImGui::CheckboxFlags("ImGuiSliderFlags_WrapAround", &flags, ImGuiSliderFlags_WrapAround);
2351 ImGui::SameLine(); HelpMarker("Enable wrapping around from max to min and from min to max (only supported by DragXXX() functions)");
2352
2353 // Drags
2354 static float drag_f = 0.5f;
2355 static int drag_i = 50;
2356 ImGui::Text("Underlying float value: %f", drag_f);
2357 ImGui::DragFloat("DragFloat (0 -> 1)", &drag_f, 0.005f, 0.0f, 1.0f, "%.3f", flags);
2358 ImGui::DragFloat("DragFloat (0 -> +inf)", &drag_f, 0.005f, 0.0f, FLT_MAX, "%.3f", flags);
2359 ImGui::DragFloat("DragFloat (-inf -> 1)", &drag_f, 0.005f, -FLT_MAX, 1.0f, "%.3f", flags);
2360 ImGui::DragFloat("DragFloat (-inf -> +inf)", &drag_f, 0.005f, -FLT_MAX, +FLT_MAX, "%.3f", flags);
2361 //ImGui::DragFloat("DragFloat (0 -> 0)", &drag_f, 0.005f, 0.0f, 0.0f, "%.3f", flags); // To test ClampZeroRange
2362 //ImGui::DragFloat("DragFloat (100 -> 100)", &drag_f, 0.005f, 100.0f, 100.0f, "%.3f", flags);
2363 ImGui::DragInt("DragInt (0 -> 100)", &drag_i, 0.5f, 0, 100, "%d", flags);
2364
2365 // Sliders
2366 static float slider_f = 0.5f;
2367 static int slider_i = 50;
2368 const ImGuiSliderFlags flags_for_sliders = flags & ~ImGuiSliderFlags_WrapAround;
2369 ImGui::Text("Underlying float value: %f", slider_f);
2370 ImGui::SliderFloat("SliderFloat (0 -> 1)", &slider_f, 0.0f, 1.0f, "%.3f", flags_for_sliders);
2371 ImGui::SliderInt("SliderInt (0 -> 100)", &slider_i, 0, 100, "%d", flags_for_sliders);
2372
2373 ImGui::TreePop();
2374 }
2375
2376 IMGUI_DEMO_MARKER("Widgets/Range Widgets");
2377 if (ImGui::TreeNode("Range Widgets"))
2378 {
2379 static float begin = 10, end = 90;
2380 static int begin_i = 100, end_i = 1000;
2381 ImGui::DragFloatRange2("range float", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%", ImGuiSliderFlags_AlwaysClamp);
2382 ImGui::DragIntRange2("range int", &begin_i, &end_i, 5, 0, 1000, "Min: %d units", "Max: %d units");
2383 ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %d units", "Max: %d units");
2384 ImGui::TreePop();
2385 }
2386
2387 IMGUI_DEMO_MARKER("Widgets/Data Types");
2388 if (ImGui::TreeNode("Data Types"))
2389 {
2390 // DragScalar/InputScalar/SliderScalar functions allow various data types
2391 // - signed/unsigned
2392 // - 8/16/32/64-bits
2393 // - integer/float/double
2394 // To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum
2395 // to pass the type, and passing all arguments by pointer.
2396 // This is the reason the test code below creates local variables to hold "zero" "one" etc. for each type.
2397 // In practice, if you frequently use a given type that is not covered by the normal API entry points,
2398 // you can wrap it yourself inside a 1 line function which can take typed argument as value instead of void*,
2399 // and then pass their address to the generic function. For example:
2400 // bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld")
2401 // {
2402 // return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format);
2403 // }
2404
2405 // Setup limits (as helper variables so we can take their address, as explained above)
2406 // Note: SliderScalar() functions have a maximum usable range of half the natural type maximum, hence the /2.
2407 #ifndef LLONG_MIN
2408 ImS64 LLONG_MIN = -9223372036854775807LL - 1;
2409 ImS64 LLONG_MAX = 9223372036854775807LL;
2410 ImU64 ULLONG_MAX = (2ULL * 9223372036854775807LL + 1);
2411 #endif
2412 const char s8_zero = 0, s8_one = 1, s8_fifty = 50, s8_min = -128, s8_max = 127;
2413 const ImU8 u8_zero = 0, u8_one = 1, u8_fifty = 50, u8_min = 0, u8_max = 255;
2414 const short s16_zero = 0, s16_one = 1, s16_fifty = 50, s16_min = -32768, s16_max = 32767;
2415 const ImU16 u16_zero = 0, u16_one = 1, u16_fifty = 50, u16_min = 0, u16_max = 65535;
2416 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;
2417 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;
2418 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;
2419 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;
2420 const float f32_zero = 0.f, f32_one = 1.f, f32_lo_a = -10000000000.0f, f32_hi_a = +10000000000.0f;
2421 const double f64_zero = 0., f64_one = 1., f64_lo_a = -1000000000000000.0, f64_hi_a = +1000000000000000.0;
2422
2423 // State
2424 static char s8_v = 127;
2425 static ImU8 u8_v = 255;
2426 static short s16_v = 32767;
2427 static ImU16 u16_v = 65535;
2428 static ImS32 s32_v = -1;
2429 static ImU32 u32_v = (ImU32)-1;
2430 static ImS64 s64_v = -1;
2431 static ImU64 u64_v = (ImU64)-1;
2432 static float f32_v = 0.123f;
2433 static double f64_v = 90000.01234567890123456789;
2434
2435 const float drag_speed = 0.2f;
2436 static bool drag_clamp = false;
2437 IMGUI_DEMO_MARKER("Widgets/Data Types/Drags");
2438 ImGui::SeparatorText("Drags");
2439 ImGui::Checkbox("Clamp integers to 0..50", &drag_clamp);
2440 ImGui::SameLine(); HelpMarker(
2441 "As with every widget in dear imgui, we never modify values unless there is a user interaction.\n"
2442 "You can override the clamping limits by using CTRL+Click to input a value.");
2443 ImGui::DragScalar("drag s8", ImGuiDataType_S8, &s8_v, drag_speed, drag_clamp ? &s8_zero : NULL, drag_clamp ? &s8_fifty : NULL);
2444 ImGui::DragScalar("drag u8", ImGuiDataType_U8, &u8_v, drag_speed, drag_clamp ? &u8_zero : NULL, drag_clamp ? &u8_fifty : NULL, "%u ms");
2445 ImGui::DragScalar("drag s16", ImGuiDataType_S16, &s16_v, drag_speed, drag_clamp ? &s16_zero : NULL, drag_clamp ? &s16_fifty : NULL);
2446 ImGui::DragScalar("drag u16", ImGuiDataType_U16, &u16_v, drag_speed, drag_clamp ? &u16_zero : NULL, drag_clamp ? &u16_fifty : NULL, "%u ms");
2447 ImGui::DragScalar("drag s32", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL);
2448 ImGui::DragScalar("drag s32 hex", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL, "0x%08X");
2449 ImGui::DragScalar("drag u32", ImGuiDataType_U32, &u32_v, drag_speed, drag_clamp ? &u32_zero : NULL, drag_clamp ? &u32_fifty : NULL, "%u ms");
2450 ImGui::DragScalar("drag s64", ImGuiDataType_S64, &s64_v, drag_speed, drag_clamp ? &s64_zero : NULL, drag_clamp ? &s64_fifty : NULL);
2451 ImGui::DragScalar("drag u64", ImGuiDataType_U64, &u64_v, drag_speed, drag_clamp ? &u64_zero : NULL, drag_clamp ? &u64_fifty : NULL);
2452 ImGui::DragScalar("drag float", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f");
2453 ImGui::DragScalar("drag float log", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f", ImGuiSliderFlags_Logarithmic);
2454 ImGui::DragScalar("drag double", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, NULL, "%.10f grams");
2455 ImGui::DragScalar("drag double log",ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", ImGuiSliderFlags_Logarithmic);
2456
2457 IMGUI_DEMO_MARKER("Widgets/Data Types/Sliders");
2458 ImGui::SeparatorText("Sliders");
2459 ImGui::SliderScalar("slider s8 full", ImGuiDataType_S8, &s8_v, &s8_min, &s8_max, "%d");
2460 ImGui::SliderScalar("slider u8 full", ImGuiDataType_U8, &u8_v, &u8_min, &u8_max, "%u");
2461 ImGui::SliderScalar("slider s16 full", ImGuiDataType_S16, &s16_v, &s16_min, &s16_max, "%d");
2462 ImGui::SliderScalar("slider u16 full", ImGuiDataType_U16, &u16_v, &u16_min, &u16_max, "%u");
2463 ImGui::SliderScalar("slider s32 low", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty,"%d");
2464 ImGui::SliderScalar("slider s32 high", ImGuiDataType_S32, &s32_v, &s32_hi_a, &s32_hi_b, "%d");
2465 ImGui::SliderScalar("slider s32 full", ImGuiDataType_S32, &s32_v, &s32_min, &s32_max, "%d");
2466 ImGui::SliderScalar("slider s32 hex", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty, "0x%04X");
2467 ImGui::SliderScalar("slider u32 low", ImGuiDataType_U32, &u32_v, &u32_zero, &u32_fifty,"%u");
2468 ImGui::SliderScalar("slider u32 high", ImGuiDataType_U32, &u32_v, &u32_hi_a, &u32_hi_b, "%u");
2469 ImGui::SliderScalar("slider u32 full", ImGuiDataType_U32, &u32_v, &u32_min, &u32_max, "%u");
2470 ImGui::SliderScalar("slider s64 low", ImGuiDataType_S64, &s64_v, &s64_zero, &s64_fifty,"%" PRId64);
2471 ImGui::SliderScalar("slider s64 high", ImGuiDataType_S64, &s64_v, &s64_hi_a, &s64_hi_b, "%" PRId64);
2472 ImGui::SliderScalar("slider s64 full", ImGuiDataType_S64, &s64_v, &s64_min, &s64_max, "%" PRId64);
2473 ImGui::SliderScalar("slider u64 low", ImGuiDataType_U64, &u64_v, &u64_zero, &u64_fifty,"%" PRIu64 " ms");
2474 ImGui::SliderScalar("slider u64 high", ImGuiDataType_U64, &u64_v, &u64_hi_a, &u64_hi_b, "%" PRIu64 " ms");
2475 ImGui::SliderScalar("slider u64 full", ImGuiDataType_U64, &u64_v, &u64_min, &u64_max, "%" PRIu64 " ms");
2476 ImGui::SliderScalar("slider float low", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one);
2477 ImGui::SliderScalar("slider float low log", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one, "%.10f", ImGuiSliderFlags_Logarithmic);
2478 ImGui::SliderScalar("slider float high", ImGuiDataType_Float, &f32_v, &f32_lo_a, &f32_hi_a, "%e");
2479 ImGui::SliderScalar("slider double low", ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f grams");
2480 ImGui::SliderScalar("slider double low log",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f", ImGuiSliderFlags_Logarithmic);
2481 ImGui::SliderScalar("slider double high", ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams");
2482
2483 ImGui::SeparatorText("Sliders (reverse)");
2484 ImGui::SliderScalar("slider s8 reverse", ImGuiDataType_S8, &s8_v, &s8_max, &s8_min, "%d");
2485 ImGui::SliderScalar("slider u8 reverse", ImGuiDataType_U8, &u8_v, &u8_max, &u8_min, "%u");
2486 ImGui::SliderScalar("slider s32 reverse", ImGuiDataType_S32, &s32_v, &s32_fifty, &s32_zero, "%d");
2487 ImGui::SliderScalar("slider u32 reverse", ImGuiDataType_U32, &u32_v, &u32_fifty, &u32_zero, "%u");
2488 ImGui::SliderScalar("slider s64 reverse", ImGuiDataType_S64, &s64_v, &s64_fifty, &s64_zero, "%" PRId64);
2489 ImGui::SliderScalar("slider u64 reverse", ImGuiDataType_U64, &u64_v, &u64_fifty, &u64_zero, "%" PRIu64 " ms");
2490
2491 IMGUI_DEMO_MARKER("Widgets/Data Types/Inputs");
2492 static bool inputs_step = true;
2493 static ImGuiInputTextFlags flags = ImGuiInputTextFlags_None;
2494 ImGui::SeparatorText("Inputs");
2495 ImGui::Checkbox("Show step buttons", &inputs_step);
2496 ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly);
2497 ImGui::CheckboxFlags("ImGuiInputTextFlags_ParseEmptyRefVal", &flags, ImGuiInputTextFlags_ParseEmptyRefVal);
2498 ImGui::CheckboxFlags("ImGuiInputTextFlags_DisplayEmptyRefVal", &flags, ImGuiInputTextFlags_DisplayEmptyRefVal);
2499 ImGui::InputScalar("input s8", ImGuiDataType_S8, &s8_v, inputs_step ? &s8_one : NULL, NULL, "%d", flags);
2500 ImGui::InputScalar("input u8", ImGuiDataType_U8, &u8_v, inputs_step ? &u8_one : NULL, NULL, "%u", flags);
2501 ImGui::InputScalar("input s16", ImGuiDataType_S16, &s16_v, inputs_step ? &s16_one : NULL, NULL, "%d", flags);
2502 ImGui::InputScalar("input u16", ImGuiDataType_U16, &u16_v, inputs_step ? &u16_one : NULL, NULL, "%u", flags);
2503 ImGui::InputScalar("input s32", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%d", flags);
2504 ImGui::InputScalar("input s32 hex", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%04X", flags);
2505 ImGui::InputScalar("input u32", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%u", flags);
2506 ImGui::InputScalar("input u32 hex", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%08X", flags);
2507 ImGui::InputScalar("input s64", ImGuiDataType_S64, &s64_v, inputs_step ? &s64_one : NULL, NULL, NULL, flags);
2508 ImGui::InputScalar("input u64", ImGuiDataType_U64, &u64_v, inputs_step ? &u64_one : NULL, NULL, NULL, flags);
2509 ImGui::InputScalar("input float", ImGuiDataType_Float, &f32_v, inputs_step ? &f32_one : NULL, NULL, NULL, flags);
2510 ImGui::InputScalar("input double", ImGuiDataType_Double, &f64_v, inputs_step ? &f64_one : NULL, NULL, NULL, flags);
2511
2512 ImGui::TreePop();
2513 }
2514
2515 IMGUI_DEMO_MARKER("Widgets/Multi-component Widgets");
2516 if (ImGui::TreeNode("Multi-component Widgets"))
2517 {
2518 static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f };
2519 static int vec4i[4] = { 1, 5, 100, 255 };
2520
2521 ImGui::SeparatorText("2-wide");
2522 ImGui::InputFloat2("input float2", vec4f);
2523 ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f);
2524 ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f);
2525 ImGui::InputInt2("input int2", vec4i);
2526 ImGui::DragInt2("drag int2", vec4i, 1, 0, 255);
2527 ImGui::SliderInt2("slider int2", vec4i, 0, 255);
2528
2529 ImGui::SeparatorText("3-wide");
2530 ImGui::InputFloat3("input float3", vec4f);
2531 ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f);
2532 ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f);
2533 ImGui::InputInt3("input int3", vec4i);
2534 ImGui::DragInt3("drag int3", vec4i, 1, 0, 255);
2535 ImGui::SliderInt3("slider int3", vec4i, 0, 255);
2536
2537 ImGui::SeparatorText("4-wide");
2538 ImGui::InputFloat4("input float4", vec4f);
2539 ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f);
2540 ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f);
2541 ImGui::InputInt4("input int4", vec4i);
2542 ImGui::DragInt4("drag int4", vec4i, 1, 0, 255);
2543 ImGui::SliderInt4("slider int4", vec4i, 0, 255);
2544
2545 ImGui::TreePop();
2546 }
2547
2548 IMGUI_DEMO_MARKER("Widgets/Vertical Sliders");
2549 if (ImGui::TreeNode("Vertical Sliders"))
2550 {
2551 const float spacing = 4;
2552 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
2553
2554 static int int_value = 0;
2555 ImGui::VSliderInt("##int", ImVec2(18, 160), &int_value, 0, 5);
2556 ImGui::SameLine();
2557
2558 static float values[7] = { 0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f };
2559 ImGui::PushID("set1");
2560 for (int i = 0; i < 7; i++)
2561 {
2562 if (i > 0) ImGui::SameLine();
2563 ImGui::PushID(i);
2564 ImGui::PushStyleColor(ImGuiCol_FrameBg, (ImVec4)ImColor::HSV(i / 7.0f, 0.5f, 0.5f));
2565 ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.5f));
2566 ImGui::PushStyleColor(ImGuiCol_FrameBgActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.5f));
2567 ImGui::PushStyleColor(ImGuiCol_SliderGrab, (ImVec4)ImColor::HSV(i / 7.0f, 0.9f, 0.9f));
2568 ImGui::VSliderFloat("##v", ImVec2(18, 160), &values[i], 0.0f, 1.0f, "");
2569 if (ImGui::IsItemActive() || ImGui::IsItemHovered())
2570 ImGui::SetTooltip("%.3f", values[i]);
2571 ImGui::PopStyleColor(4);
2572 ImGui::PopID();
2573 }
2574 ImGui::PopID();
2575
2576 ImGui::SameLine();
2577 ImGui::PushID("set2");
2578 static float values2[4] = { 0.20f, 0.80f, 0.40f, 0.25f };
2579 const int rows = 3;
2580 const ImVec2 small_slider_size(18, (float)(int)((160.0f - (rows - 1) * spacing) / rows));
2581 for (int nx = 0; nx < 4; nx++)
2582 {
2583 if (nx > 0) ImGui::SameLine();
2584 ImGui::BeginGroup();
2585 for (int ny = 0; ny < rows; ny++)
2586 {
2587 ImGui::PushID(nx * rows + ny);
2588 ImGui::VSliderFloat("##v", small_slider_size, &values2[nx], 0.0f, 1.0f, "");
2589 if (ImGui::IsItemActive() || ImGui::IsItemHovered())
2590 ImGui::SetTooltip("%.3f", values2[nx]);
2591 ImGui::PopID();
2592 }
2593 ImGui::EndGroup();
2594 }
2595 ImGui::PopID();
2596
2597 ImGui::SameLine();
2598 ImGui::PushID("set3");
2599 for (int i = 0; i < 4; i++)
2600 {
2601 if (i > 0) ImGui::SameLine();
2602 ImGui::PushID(i);
2603 ImGui::PushStyleVar(ImGuiStyleVar_GrabMinSize, 40);
2604 ImGui::VSliderFloat("##v", ImVec2(40, 160), &values[i], 0.0f, 1.0f, "%.2f\nsec");
2605 ImGui::PopStyleVar();
2606 ImGui::PopID();
2607 }
2608 ImGui::PopID();
2609 ImGui::PopStyleVar();
2610 ImGui::TreePop();
2611 }
2612
2613 IMGUI_DEMO_MARKER("Widgets/Drag and drop");
2614 if (ImGui::TreeNode("Drag and Drop"))
2615 {
2616 IMGUI_DEMO_MARKER("Widgets/Drag and drop/Standard widgets");
2617 if (ImGui::TreeNode("Drag and drop in standard widgets"))
2618 {
2619 // ColorEdit widgets automatically act as drag source and drag target.
2620 // They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F
2621 // to allow your own widgets to use colors in their drag and drop interaction.
2622 // Also see 'Demo->Widgets->Color/Picker Widgets->Palette' demo.
2623 HelpMarker("You can drag from the color squares.");
2624 static float col1[3] = { 1.0f, 0.0f, 0.2f };
2625 static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
2626 ImGui::ColorEdit3("color 1", col1);
2627 ImGui::ColorEdit4("color 2", col2);
2628 ImGui::TreePop();
2629 }
2630
2631 IMGUI_DEMO_MARKER("Widgets/Drag and drop/Copy-swap items");
2632 if (ImGui::TreeNode("Drag and drop to copy/swap items"))
2633 {
2634 enum Mode
2635 {
2636 Mode_Copy,
2637 Mode_Move,
2638 Mode_Swap
2639 };
2640 static int mode = 0;
2641 if (ImGui::RadioButton("Copy", mode == Mode_Copy)) { mode = Mode_Copy; } ImGui::SameLine();
2642 if (ImGui::RadioButton("Move", mode == Mode_Move)) { mode = Mode_Move; } ImGui::SameLine();
2643 if (ImGui::RadioButton("Swap", mode == Mode_Swap)) { mode = Mode_Swap; }
2644 static const char* names[9] =
2645 {
2646 "Bobby", "Beatrice", "Betty",
2647 "Brianna", "Barry", "Bernard",
2648 "Bibi", "Blaine", "Bryn"
2649 };
2650 for (int n = 0; n < IM_ARRAYSIZE(names); n++)
2651 {
2652 ImGui::PushID(n);
2653 if ((n % 3) != 0)
2654 ImGui::SameLine();
2655 ImGui::Button(names[n], ImVec2(60, 60));
2656
2657 // Our buttons are both drag sources and drag targets here!
2658 if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None))
2659 {
2660 // Set payload to carry the index of our item (could be anything)
2661 ImGui::SetDragDropPayload("DND_DEMO_CELL", &n, sizeof(int));
2662
2663 // Display preview (could be anything, e.g. when dragging an image we could decide to display
2664 // the filename and a small preview of the image, etc.)
2665 if (mode == Mode_Copy) { ImGui::Text("Copy %s", names[n]); }
2666 if (mode == Mode_Move) { ImGui::Text("Move %s", names[n]); }
2667 if (mode == Mode_Swap) { ImGui::Text("Swap %s", names[n]); }
2668 ImGui::EndDragDropSource();
2669 }
2670 if (ImGui::BeginDragDropTarget())
2671 {
2672 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DND_DEMO_CELL"))
2673 {
2674 IM_ASSERT(payload->DataSize == sizeof(int));
2675 int payload_n = *(const int*)payload->Data;
2676 if (mode == Mode_Copy)
2677 {
2678 names[n] = names[payload_n];
2679 }
2680 if (mode == Mode_Move)
2681 {
2682 names[n] = names[payload_n];
2683 names[payload_n] = "";
2684 }
2685 if (mode == Mode_Swap)
2686 {
2687 const char* tmp = names[n];
2688 names[n] = names[payload_n];
2689 names[payload_n] = tmp;
2690 }
2691 }
2692 ImGui::EndDragDropTarget();
2693 }
2694 ImGui::PopID();
2695 }
2696 ImGui::TreePop();
2697 }
2698
2699 IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Drag to reorder items (simple)");
2700 if (ImGui::TreeNode("Drag to reorder items (simple)"))
2701 {
2702 // FIXME: there is temporary (usually single-frame) ID Conflict during reordering as a same item may be submitting twice.
2703 // This code was always slightly faulty but in a way which was not easily noticeable.
2704 // Until we fix this, enable ImGuiItemFlags_AllowDuplicateId to disable detecting the issue.
2705 ImGui::PushItemFlag(ImGuiItemFlags_AllowDuplicateId, true);
2706
2707 // Simple reordering
2708 HelpMarker(
2709 "We don't use the drag and drop api at all here! "
2710 "Instead we query when the item is held but not hovered, and order items accordingly.");
2711 static const char* item_names[] = { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" };
2712 for (int n = 0; n < IM_ARRAYSIZE(item_names); n++)
2713 {
2714 const char* item = item_names[n];
2715 ImGui::Selectable(item);
2716
2717 if (ImGui::IsItemActive() && !ImGui::IsItemHovered())
2718 {
2719 int n_next = n + (ImGui::GetMouseDragDelta(0).y < 0.f ? -1 : 1);
2720 if (n_next >= 0 && n_next < IM_ARRAYSIZE(item_names))
2721 {
2722 item_names[n] = item_names[n_next];
2723 item_names[n_next] = item;
2724 ImGui::ResetMouseDragDelta();
2725 }
2726 }
2727 }
2728
2729 ImGui::PopItemFlag();
2730 ImGui::TreePop();
2731 }
2732
2733 IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Tooltip at target location");
2734 if (ImGui::TreeNode("Tooltip at target location"))
2735 {
2736 for (int n = 0; n < 2; n++)
2737 {
2738 // Drop targets
2739 ImGui::Button(n ? "drop here##1" : "drop here##0");
2740 if (ImGui::BeginDragDropTarget())
2741 {
2742 ImGuiDragDropFlags drop_target_flags = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoPreviewTooltip;
2743 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, drop_target_flags))
2744 {
2745 IM_UNUSED(payload);
2746 ImGui::SetMouseCursor(ImGuiMouseCursor_NotAllowed);
2747 ImGui::SetTooltip("Cannot drop here!");
2748 }
2749 ImGui::EndDragDropTarget();
2750 }
2751
2752 // Drop source
2753 static ImVec4 col4 = { 1.0f, 0.0f, 0.2f, 1.0f };
2754 if (n == 0)
2755 ImGui::ColorButton("drag me", col4);
2756
2757 }
2758 ImGui::TreePop();
2759 }
2760
2761 ImGui::TreePop();
2762 }
2763
2764 IMGUI_DEMO_MARKER("Widgets/Querying Item Status (Edited,Active,Hovered etc.)");
2765 if (ImGui::TreeNode("Querying Item Status (Edited/Active/Hovered etc.)"))
2766 {
2767 // Select an item type
2768 const char* item_names[] =
2769 {
2770 "Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputTextMultiline", "InputFloat",
2771 "InputFloat3", "ColorEdit4", "Selectable", "MenuItem", "TreeNode", "TreeNode (w/ double-click)", "Combo", "ListBox"
2772 };
2773 static int item_type = 4;
2774 static bool item_disabled = false;
2775 ImGui::Combo("Item Type", &item_type, item_names, IM_ARRAYSIZE(item_names), IM_ARRAYSIZE(item_names));
2776 ImGui::SameLine();
2777 HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions. Note that the bool return value of most ImGui function is generally equivalent to calling ImGui::IsItemHovered().");
2778 ImGui::Checkbox("Item Disabled", &item_disabled);
2779
2780 // Submit selected items so we can query their status in the code following it.
2781 bool ret = false;
2782 static bool b = false;
2783 static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f };
2784 static char str[16] = {};
2785 if (item_disabled)
2786 ImGui::BeginDisabled(true);
2787 if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction
2788 if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); } // Testing button
2789 if (item_type == 2) { ImGui::PushItemFlag(ImGuiItemFlags_ButtonRepeat, true); ret = ImGui::Button("ITEM: Button"); ImGui::PopItemFlag(); } // Testing button (with repeater)
2790 if (item_type == 3) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); } // Testing checkbox
2791 if (item_type == 4) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item
2792 if (item_type == 5) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which handles tabbing)
2793 if (item_type == 6) { ret = ImGui::InputTextMultiline("ITEM: InputTextMultiline", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which uses a child window)
2794 if (item_type == 7) { ret = ImGui::InputFloat("ITEM: InputFloat", col4f, 1.0f); } // Testing +/- buttons on scalar input
2795 if (item_type == 8) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
2796 if (item_type == 9) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
2797 if (item_type == 10){ ret = ImGui::Selectable("ITEM: Selectable"); } // Testing selectable item
2798 if (item_type == 11){ ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy)
2799 if (item_type == 12){ ret = ImGui::TreeNode("ITEM: TreeNode"); if (ret) ImGui::TreePop(); } // Testing tree node
2800 if (item_type == 13){ ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy.
2801 if (item_type == 14){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::Combo("ITEM: Combo", &current, items, IM_ARRAYSIZE(items)); }
2802 if (item_type == 15){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", &current, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); }
2803
2804 bool hovered_delay_none = ImGui::IsItemHovered();
2805 bool hovered_delay_stationary = ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary);
2806 bool hovered_delay_short = ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort);
2807 bool hovered_delay_normal = ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal);
2808 bool hovered_delay_tooltip = ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip); // = Normal + Stationary
2809
2810 // Display the values of IsItemHovered() and other common item state functions.
2811 // Note that the ImGuiHoveredFlags_XXX flags can be combined.
2812 // Because BulletText is an item itself and that would affect the output of IsItemXXX functions,
2813 // we query every state in a single call to avoid storing them and to simplify the code.
2814 ImGui::BulletText(
2815 "Return value = %d\n"
2816 "IsItemFocused() = %d\n"
2817 "IsItemHovered() = %d\n"
2818 "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n"
2819 "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n"
2820 "IsItemHovered(_AllowWhenOverlappedByItem) = %d\n"
2821 "IsItemHovered(_AllowWhenOverlappedByWindow) = %d\n"
2822 "IsItemHovered(_AllowWhenDisabled) = %d\n"
2823 "IsItemHovered(_RectOnly) = %d\n"
2824 "IsItemActive() = %d\n"
2825 "IsItemEdited() = %d\n"
2826 "IsItemActivated() = %d\n"
2827 "IsItemDeactivated() = %d\n"
2828 "IsItemDeactivatedAfterEdit() = %d\n"
2829 "IsItemVisible() = %d\n"
2830 "IsItemClicked() = %d\n"
2831 "IsItemToggledOpen() = %d\n"
2832 "GetItemRectMin() = (%.1f, %.1f)\n"
2833 "GetItemRectMax() = (%.1f, %.1f)\n"
2834 "GetItemRectSize() = (%.1f, %.1f)",
2835 ret,
2836 ImGui::IsItemFocused(),
2837 ImGui::IsItemHovered(),
2838 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2839 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
2840 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlappedByItem),
2841 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlappedByWindow),
2842 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled),
2843 ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly),
2844 ImGui::IsItemActive(),
2845 ImGui::IsItemEdited(),
2846 ImGui::IsItemActivated(),
2847 ImGui::IsItemDeactivated(),
2848 ImGui::IsItemDeactivatedAfterEdit(),
2849 ImGui::IsItemVisible(),
2850 ImGui::IsItemClicked(),
2851 ImGui::IsItemToggledOpen(),
2852 ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y,
2853 ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y,
2854 ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y
2855 );
2856 ImGui::BulletText(
2857 "with Hovering Delay or Stationary test:\n"
2858 "IsItemHovered() = = %d\n"
2859 "IsItemHovered(_Stationary) = %d\n"
2860 "IsItemHovered(_DelayShort) = %d\n"
2861 "IsItemHovered(_DelayNormal) = %d\n"
2862 "IsItemHovered(_Tooltip) = %d",
2863 hovered_delay_none, hovered_delay_stationary, hovered_delay_short, hovered_delay_normal, hovered_delay_tooltip);
2864
2865 if (item_disabled)
2866 ImGui::EndDisabled();
2867
2868 char buf[1] = "";
2869 ImGui::InputText("unused", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_ReadOnly);
2870 ImGui::SameLine();
2871 HelpMarker("This widget is only here to be able to tab-out of the widgets above and see e.g. Deactivated() status.");
2872
2873 ImGui::TreePop();
2874 }
2875
2876 IMGUI_DEMO_MARKER("Widgets/Querying Window Status (Focused,Hovered etc.)");
2877 if (ImGui::TreeNode("Querying Window Status (Focused/Hovered etc.)"))
2878 {
2879 static bool embed_all_inside_a_child_window = false;
2880 ImGui::Checkbox("Embed everything inside a child window for testing _RootWindow flag.", &embed_all_inside_a_child_window);
2881 if (embed_all_inside_a_child_window)
2882 ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20.0f), ImGuiChildFlags_Borders);
2883
2884 // Testing IsWindowFocused() function with its various flags.
2885 ImGui::BulletText(
2886 "IsWindowFocused() = %d\n"
2887 "IsWindowFocused(_ChildWindows) = %d\n"
2888 "IsWindowFocused(_ChildWindows|_NoPopupHierarchy) = %d\n"
2889 "IsWindowFocused(_ChildWindows|_DockHierarchy) = %d\n"
2890 "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n"
2891 "IsWindowFocused(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n"
2892 "IsWindowFocused(_ChildWindows|_RootWindow|_DockHierarchy) = %d\n"
2893 "IsWindowFocused(_RootWindow) = %d\n"
2894 "IsWindowFocused(_RootWindow|_NoPopupHierarchy) = %d\n"
2895 "IsWindowFocused(_RootWindow|_DockHierarchy) = %d\n"
2896 "IsWindowFocused(_AnyWindow) = %d\n",
2897 ImGui::IsWindowFocused(),
2898 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows),
2899 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_NoPopupHierarchy),
2900 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_DockHierarchy),
2901 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow),
2902 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy),
2903 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_DockHierarchy),
2904 ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow),
2905 ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy),
2906 ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_DockHierarchy),
2907 ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow));
2908
2909 // Testing IsWindowHovered() function with its various flags.
2910 ImGui::BulletText(
2911 "IsWindowHovered() = %d\n"
2912 "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n"
2913 "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n"
2914 "IsWindowHovered(_ChildWindows) = %d\n"
2915 "IsWindowHovered(_ChildWindows|_NoPopupHierarchy) = %d\n"
2916 "IsWindowHovered(_ChildWindows|_DockHierarchy) = %d\n"
2917 "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n"
2918 "IsWindowHovered(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n"
2919 "IsWindowHovered(_ChildWindows|_RootWindow|_DockHierarchy) = %d\n"
2920 "IsWindowHovered(_RootWindow) = %d\n"
2921 "IsWindowHovered(_RootWindow|_NoPopupHierarchy) = %d\n"
2922 "IsWindowHovered(_RootWindow|_DockHierarchy) = %d\n"
2923 "IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n"
2924 "IsWindowHovered(_AnyWindow) = %d\n"
2925 "IsWindowHovered(_Stationary) = %d\n",
2926 ImGui::IsWindowHovered(),
2927 ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2928 ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
2929 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows),
2930 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy),
2931 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_DockHierarchy),
2932 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow),
2933 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy),
2934 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_DockHierarchy),
2935 ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow),
2936 ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy),
2937 ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_DockHierarchy),
2938 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2939 ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow),
2940 ImGui::IsWindowHovered(ImGuiHoveredFlags_Stationary));
2941
2942 ImGui::BeginChild("child", ImVec2(0, 50), ImGuiChildFlags_Borders);
2943 ImGui::Text("This is another child window for testing the _ChildWindows flag.");
2944 ImGui::EndChild();
2945 if (embed_all_inside_a_child_window)
2946 ImGui::EndChild();
2947
2948 // Calling IsItemHovered() after begin returns the hovered status of the title bar.
2949 // This is useful in particular if you want to create a context menu associated to the title bar of a window.
2950 // This will also work when docked into a Tab (the Tab replace the Title Bar and guarantee the same properties).
2951 static bool test_window = false;
2952 ImGui::Checkbox("Hovered/Active tests after Begin() for title bar testing", &test_window);
2953 if (test_window)
2954 {
2955 // FIXME-DOCK: This window cannot be docked within the ImGui Demo window, this will cause a feedback loop and get them stuck.
2956 // Could we fix this through an ImGuiWindowClass feature? Or an API call to tag our parent as "don't skip items"?
2957 ImGui::Begin("Title bar Hovered/Active tests", &test_window);
2958 if (ImGui::BeginPopupContextItem()) // <-- This is using IsItemHovered()
2959 {
2960 if (ImGui::MenuItem("Close")) { test_window = false; }
2961 ImGui::EndPopup();
2962 }
2963 ImGui::Text(
2964 "IsItemHovered() after begin = %d (== is title bar hovered)\n"
2965 "IsItemActive() after begin = %d (== is window being clicked/moved)\n",
2966 ImGui::IsItemHovered(), ImGui::IsItemActive());
2967 ImGui::End();
2968 }
2969
2970 ImGui::TreePop();
2971 }
2972
2973 // Demonstrate BeginDisabled/EndDisabled using a checkbox located at the bottom of the section (which is a bit odd:
2974 // logically we'd have this checkbox at the top of the section, but we don't want this feature to steal that space)
2975 if (disable_all)
2976 ImGui::EndDisabled();
2977
2978 IMGUI_DEMO_MARKER("Widgets/Disable Block");
2979 if (ImGui::TreeNode("Disable block"))
2980 {
2981 ImGui::Checkbox("Disable entire section above", &disable_all);
2982 ImGui::SameLine(); HelpMarker("Demonstrate using BeginDisabled()/EndDisabled() across this section.");
2983 ImGui::TreePop();
2984 }
2985
2986 IMGUI_DEMO_MARKER("Widgets/Text Filter");
2987 if (ImGui::TreeNode("Text Filter"))
2988 {
2989 // Helper class to easy setup a text filter.
2990 // You may want to implement a more feature-full filtering scheme in your own application.
2991 HelpMarker("Not a widget per-se, but ImGuiTextFilter is a helper to perform simple filtering on text strings.");
2992 static ImGuiTextFilter filter;
2993 ImGui::Text("Filter usage:\n"
2994 " \"\" display all lines\n"
2995 " \"xxx\" display lines containing \"xxx\"\n"
2996 " \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n"
2997 " \"-xxx\" hide lines containing \"xxx\"");
2998 filter.Draw();
2999 const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" };
3000 for (int i = 0; i < IM_ARRAYSIZE(lines); i++)
3001 if (filter.PassFilter(lines[i]))
3002 ImGui::BulletText("%s", lines[i]);
3003 ImGui::TreePop();
3004 }
3005}
3006
3007static const char* ExampleNames[] =
3008{
3009 "Artichoke", "Arugula", "Asparagus", "Avocado", "Bamboo Shoots", "Bean Sprouts", "Beans", "Beet", "Belgian Endive", "Bell Pepper",
3010 "Bitter Gourd", "Bok Choy", "Broccoli", "Brussels Sprouts", "Burdock Root", "Cabbage", "Calabash", "Capers", "Carrot", "Cassava",
3011 "Cauliflower", "Celery", "Celery Root", "Celcuce", "Chayote", "Chinese Broccoli", "Corn", "Cucumber"
3012};
3013
3014// Extra functions to add deletion support to ImGuiSelectionBasicStorage
3015struct ExampleSelectionWithDeletion : ImGuiSelectionBasicStorage
3016{
3017 // Find which item should be Focused after deletion.
3018 // Call _before_ item submission. Retunr an index in the before-deletion item list, your item loop should call SetKeyboardFocusHere() on it.
3019 // The subsequent ApplyDeletionPostLoop() code will use it to apply Selection.
3020 // - We cannot provide this logic in core Dear ImGui because we don't have access to selection data.
3021 // - We don't actually manipulate the ImVector<> here, only in ApplyDeletionPostLoop(), but using similar API for consistency and flexibility.
3022 // - Important: Deletion only works if the underlying ImGuiID for your items are stable: aka not depend on their index, but on e.g. item id/ptr.
3023 // FIXME-MULTISELECT: Doesn't take account of the possibility focus target will be moved during deletion. Need refocus or scroll offset.
3024 int ApplyDeletionPreLoop(ImGuiMultiSelectIO* ms_io, int items_count)
3025 {
3026 if (Size == 0)
3027 return -1;
3028
3029 // If focused item is not selected...
3030 const int focused_idx = (int)ms_io->NavIdItem; // Index of currently focused item
3031 if (ms_io->NavIdSelected == false) // This is merely a shortcut, == Contains(adapter->IndexToStorage(items, focused_idx))
3032 {
3033 ms_io->RangeSrcReset = true; // Request to recover RangeSrc from NavId next frame. Would be ok to reset even when NavIdSelected==true, but it would take an extra frame to recover RangeSrc when deleting a selected item.
3034 return focused_idx; // Request to focus same item after deletion.
3035 }
3036
3037 // If focused item is selected: land on first unselected item after focused item.
3038 for (int idx = focused_idx + 1; idx < items_count; idx++)
3039 if (!Contains(GetStorageIdFromIndex(idx)))
3040 return idx;
3041
3042 // If focused item is selected: otherwise return last unselected item before focused item.
3043 for (int idx = IM_MIN(focused_idx, items_count) - 1; idx >= 0; idx--)
3044 if (!Contains(GetStorageIdFromIndex(idx)))
3045 return idx;
3046
3047 return -1;
3048 }
3049
3050 // Rewrite item list (delete items) + update selection.
3051 // - Call after EndMultiSelect()
3052 // - We cannot provide this logic in core Dear ImGui because we don't have access to your items, nor to selection data.
3053 template<typename ITEM_TYPE>
3054 void ApplyDeletionPostLoop(ImGuiMultiSelectIO* ms_io, ImVector<ITEM_TYPE>& items, int item_curr_idx_to_select)
3055 {
3056 // Rewrite item list (delete items) + convert old selection index (before deletion) to new selection index (after selection).
3057 // If NavId was not part of selection, we will stay on same item.
3058 ImVector<ITEM_TYPE> new_items;
3059 new_items.reserve(items.Size - Size);
3060 int item_next_idx_to_select = -1;
3061 for (int idx = 0; idx < items.Size; idx++)
3062 {
3063 if (!Contains(GetStorageIdFromIndex(idx)))
3064 new_items.push_back(items[idx]);
3065 if (item_curr_idx_to_select == idx)
3066 item_next_idx_to_select = new_items.Size - 1;
3067 }
3068 items.swap(new_items);
3069
3070 // Update selection
3071 Clear();
3072 if (item_next_idx_to_select != -1 && ms_io->NavIdSelected)
3073 SetItemSelected(GetStorageIdFromIndex(item_next_idx_to_select), true);
3074 }
3075};
3076
3077// Example: Implement dual list box storage and interface
3079{
3080 ImVector<ImGuiID> Items[2]; // ID is index into ExampleName[]
3081 ImGuiSelectionBasicStorage Selections[2]; // Store ExampleItemId into selection
3082 bool OptKeepSorted = true;
3083
3084 void MoveAll(int src, int dst)
3085 {
3086 IM_ASSERT((src == 0 && dst == 1) || (src == 1 && dst == 0));
3087 for (ImGuiID item_id : Items[src])
3088 Items[dst].push_back(item_id);
3089 Items[src].clear();
3090 SortItems(dst);
3091 Selections[src].Swap(Selections[dst]);
3092 Selections[src].Clear();
3093 }
3094 void MoveSelected(int src, int dst)
3095 {
3096 for (int src_n = 0; src_n < Items[src].Size; src_n++)
3097 {
3098 ImGuiID item_id = Items[src][src_n];
3099 if (!Selections[src].Contains(item_id))
3100 continue;
3101 Items[src].erase(&Items[src][src_n]); // FIXME-OPT: Could be implemented more optimally (rebuild src items and swap)
3102 Items[dst].push_back(item_id);
3103 src_n--;
3104 }
3105 if (OptKeepSorted)
3106 SortItems(dst);
3107 Selections[src].Swap(Selections[dst]);
3108 Selections[src].Clear();
3109 }
3110 void ApplySelectionRequests(ImGuiMultiSelectIO* ms_io, int side)
3111 {
3112 // In this example we store item id in selection (instead of item index)
3113 Selections[side].UserData = Items[side].Data;
3114 Selections[side].AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { ImGuiID* items = (ImGuiID*)self->UserData; return items[idx]; };
3115 Selections[side].ApplyRequests(ms_io);
3116 }
3117 static int IMGUI_CDECL CompareItemsByValue(const void* lhs, const void* rhs)
3118 {
3119 const int* a = (const int*)lhs;
3120 const int* b = (const int*)rhs;
3121 return (*a - *b) > 0 ? +1 : -1;
3122 }
3123 void SortItems(int n)
3124 {
3125 qsort(Items[n].Data, (size_t)Items[n].Size, sizeof(Items[n][0]), CompareItemsByValue);
3126 }
3127 void Show()
3128 {
3129 //ImGui::Checkbox("Sorted", &OptKeepSorted);
3130 if (ImGui::BeginTable("split", 3, ImGuiTableFlags_None))
3131 {
3132 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch); // Left side
3133 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed); // Buttons
3134 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch); // Right side
3135 ImGui::TableNextRow();
3136
3137 int request_move_selected = -1;
3138 int request_move_all = -1;
3139 float child_height_0 = 0.0f;
3140 for (int side = 0; side < 2; side++)
3141 {
3142 // FIXME-MULTISELECT: Dual List Box: Add context menus
3143 // FIXME-NAV: Using ImGuiWindowFlags_NavFlattened exhibit many issues.
3144 ImVector<ImGuiID>& items = Items[side];
3145 ImGuiSelectionBasicStorage& selection = Selections[side];
3146
3147 ImGui::TableSetColumnIndex((side == 0) ? 0 : 2);
3148 ImGui::Text("%s (%d)", (side == 0) ? "Available" : "Basket", items.Size);
3149
3150 // Submit scrolling range to avoid glitches on moving/deletion
3151 const float items_height = ImGui::GetTextLineHeightWithSpacing();
3152 ImGui::SetNextWindowContentSize(ImVec2(0.0f, items.Size * items_height));
3153
3154 bool child_visible;
3155 if (side == 0)
3156 {
3157 // Left child is resizable
3158 ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetFrameHeightWithSpacing() * 4), ImVec2(FLT_MAX, FLT_MAX));
3159 child_visible = ImGui::BeginChild("0", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY);
3160 child_height_0 = ImGui::GetWindowSize().y;
3161 }
3162 else
3163 {
3164 // Right child use same height as left one
3165 child_visible = ImGui::BeginChild("1", ImVec2(-FLT_MIN, child_height_0), ImGuiChildFlags_FrameStyle);
3166 }
3167 if (child_visible)
3168 {
3169 ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_None;
3170 ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size);
3171 ApplySelectionRequests(ms_io, side);
3172
3173 for (int item_n = 0; item_n < items.Size; item_n++)
3174 {
3175 ImGuiID item_id = items[item_n];
3176 bool item_is_selected = selection.Contains(item_id);
3177 ImGui::SetNextItemSelectionUserData(item_n);
3178 ImGui::Selectable(ExampleNames[item_id], item_is_selected, ImGuiSelectableFlags_AllowDoubleClick);
3179 if (ImGui::IsItemFocused())
3180 {
3181 // FIXME-MULTISELECT: Dual List Box: Transfer focus
3182 if (ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_KeypadEnter))
3183 request_move_selected = side;
3184 if (ImGui::IsMouseDoubleClicked(0)) // FIXME-MULTISELECT: Double-click on multi-selection?
3185 request_move_selected = side;
3186 }
3187 }
3188
3189 ms_io = ImGui::EndMultiSelect();
3190 ApplySelectionRequests(ms_io, side);
3191 }
3192 ImGui::EndChild();
3193 }
3194
3195 // Buttons columns
3196 ImGui::TableSetColumnIndex(1);
3197 ImGui::NewLine();
3198 //ImVec2 button_sz = { ImGui::CalcTextSize(">>").x + ImGui::GetStyle().FramePadding.x * 2.0f, ImGui::GetFrameHeight() + padding.y * 2.0f };
3199 ImVec2 button_sz = { ImGui::GetFrameHeight(), ImGui::GetFrameHeight() };
3200
3201 // (Using BeginDisabled()/EndDisabled() works but feels distracting given how it is currently visualized)
3202 if (ImGui::Button(">>", button_sz))
3203 request_move_all = 0;
3204 if (ImGui::Button(">", button_sz))
3205 request_move_selected = 0;
3206 if (ImGui::Button("<", button_sz))
3207 request_move_selected = 1;
3208 if (ImGui::Button("<<", button_sz))
3209 request_move_all = 1;
3210
3211 // Process requests
3212 if (request_move_all != -1)
3213 MoveAll(request_move_all, request_move_all ^ 1);
3214 if (request_move_selected != -1)
3215 MoveSelected(request_move_selected, request_move_selected ^ 1);
3216
3217 // FIXME-MULTISELECT: Support action from outside
3218 /*
3219 if (OptKeepSorted == false)
3220 {
3221 ImGui::NewLine();
3222 if (ImGui::ArrowButton("MoveUp", ImGuiDir_Up)) {}
3223 if (ImGui::ArrowButton("MoveDown", ImGuiDir_Down)) {}
3224 }
3225 */
3226
3227 ImGui::EndTable();
3228 }
3229 }
3230};
3231
3232//-----------------------------------------------------------------------------
3233// [SECTION] ShowDemoWindowMultiSelect()
3234//-----------------------------------------------------------------------------
3235// Multi-selection demos
3236// Also read: https://github.com/ocornut/imgui/wiki/Multi-Select
3237//-----------------------------------------------------------------------------
3238
3239static void ShowDemoWindowMultiSelect(ImGuiDemoWindowData* demo_data)
3240{
3241 IMGUI_DEMO_MARKER("Widgets/Selection State & Multi-Select");
3242 if (ImGui::TreeNode("Selection State & Multi-Select"))
3243 {
3244 HelpMarker("Selections can be built using Selectable(), TreeNode() or other widgets. Selection state is owned by application code/data.");
3245
3246 // Without any fancy API: manage single-selection yourself.
3247 IMGUI_DEMO_MARKER("Widgets/Selection State/Single-Select");
3248 if (ImGui::TreeNode("Single-Select"))
3249 {
3250 static int selected = -1;
3251 for (int n = 0; n < 5; n++)
3252 {
3253 char buf[32];
3254 sprintf(buf, "Object %d", n);
3255 if (ImGui::Selectable(buf, selected == n))
3256 selected = n;
3257 }
3258 ImGui::TreePop();
3259 }
3260
3261 // Demonstrate implementation a most-basic form of multi-selection manually
3262 // This doesn't support the SHIFT modifier which requires BeginMultiSelect()!
3263 IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (manual/simplified, without BeginMultiSelect)");
3264 if (ImGui::TreeNode("Multi-Select (manual/simplified, without BeginMultiSelect)"))
3265 {
3266 HelpMarker("Hold CTRL and click to select multiple items.");
3267 static bool selection[5] = { false, false, false, false, false };
3268 for (int n = 0; n < 5; n++)
3269 {
3270 char buf[32];
3271 sprintf(buf, "Object %d", n);
3272 if (ImGui::Selectable(buf, selection[n]))
3273 {
3274 if (!ImGui::GetIO().KeyCtrl) // Clear selection when CTRL is not held
3275 memset(selection, 0, sizeof(selection));
3276 selection[n] ^= 1; // Toggle current item
3277 }
3278 }
3279 ImGui::TreePop();
3280 }
3281
3282 // Demonstrate handling proper multi-selection using the BeginMultiSelect/EndMultiSelect API.
3283 // SHIFT+Click w/ CTRL and other standard features are supported.
3284 // We use the ImGuiSelectionBasicStorage helper which you may freely reimplement.
3285 IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select");
3286 if (ImGui::TreeNode("Multi-Select"))
3287 {
3288 ImGui::Text("Supported features:");
3289 ImGui::BulletText("Keyboard navigation (arrows, page up/down, home/end, space).");
3290 ImGui::BulletText("Ctrl modifier to preserve and toggle selection.");
3291 ImGui::BulletText("Shift modifier for range selection.");
3292 ImGui::BulletText("CTRL+A to select all.");
3293 ImGui::BulletText("Escape to clear selection.");
3294 ImGui::BulletText("Click and drag to box-select.");
3295 ImGui::Text("Tip: Use 'Demo->Tools->Debug Log->Selection' to see selection requests as they happen.");
3296
3297 // Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection
3298 const int ITEMS_COUNT = 50;
3299 static ImGuiSelectionBasicStorage selection;
3300 ImGui::Text("Selection: %d/%d", selection.Size, ITEMS_COUNT);
3301
3302 // The BeginChild() has no purpose for selection logic, other that offering a scrolling region.
3303 if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
3304 {
3305 ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
3306 ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT);
3307 selection.ApplyRequests(ms_io);
3308
3309 for (int n = 0; n < ITEMS_COUNT; n++)
3310 {
3311 char label[64];
3312 sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_ARRAYSIZE(ExampleNames)]);
3313 bool item_is_selected = selection.Contains((ImGuiID)n);
3314 ImGui::SetNextItemSelectionUserData(n);
3315 ImGui::Selectable(label, item_is_selected);
3316 }
3317
3318 ms_io = ImGui::EndMultiSelect();
3319 selection.ApplyRequests(ms_io);
3320 }
3321 ImGui::EndChild();
3322 ImGui::TreePop();
3323 }
3324
3325 // Demonstrate using the clipper with BeginMultiSelect()/EndMultiSelect()
3326 IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (with clipper)");
3327 if (ImGui::TreeNode("Multi-Select (with clipper)"))
3328 {
3329 // Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection
3330 static ImGuiSelectionBasicStorage selection;
3331
3332 ImGui::Text("Added features:");
3333 ImGui::BulletText("Using ImGuiListClipper.");
3334
3335 const int ITEMS_COUNT = 10000;
3336 ImGui::Text("Selection: %d/%d", selection.Size, ITEMS_COUNT);
3337 if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
3338 {
3339 ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
3340 ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT);
3341 selection.ApplyRequests(ms_io);
3342
3343 ImGuiListClipper clipper;
3344 clipper.Begin(ITEMS_COUNT);
3345 if (ms_io->RangeSrcItem != -1)
3346 clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped.
3347 while (clipper.Step())
3348 {
3349 for (int n = clipper.DisplayStart; n < clipper.DisplayEnd; n++)
3350 {
3351 char label[64];
3352 sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_ARRAYSIZE(ExampleNames)]);
3353 bool item_is_selected = selection.Contains((ImGuiID)n);
3354 ImGui::SetNextItemSelectionUserData(n);
3355 ImGui::Selectable(label, item_is_selected);
3356 }
3357 }
3358
3359 ms_io = ImGui::EndMultiSelect();
3360 selection.ApplyRequests(ms_io);
3361 }
3362 ImGui::EndChild();
3363 ImGui::TreePop();
3364 }
3365
3366 // Demonstrate dynamic item list + deletion support using the BeginMultiSelect/EndMultiSelect API.
3367 // In order to support Deletion without any glitches you need to:
3368 // - (1) If items are submitted in their own scrolling area, submit contents size SetNextWindowContentSize() ahead of time to prevent one-frame readjustment of scrolling.
3369 // - (2) Items needs to have persistent ID Stack identifier = ID needs to not depends on their index. PushID(index) = KO. PushID(item_id) = OK. This is in order to focus items reliably after a selection.
3370 // - (3) BeginXXXX process
3371 // - (4) Focus process
3372 // - (5) EndXXXX process
3373 IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (with deletion)");
3374 if (ImGui::TreeNode("Multi-Select (with deletion)"))
3375 {
3376 // Storing items data separately from selection data.
3377 // (you may decide to store selection data inside your item (aka intrusive storage) if you don't need multiple views over same items)
3378 // Use a custom selection.Adapter: store item identifier in Selection (instead of index)
3379 static ImVector<ImGuiID> items;
3380 static ExampleSelectionWithDeletion selection;
3381 selection.UserData = (void*)&items;
3382 selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { ImVector<ImGuiID>* p_items = (ImVector<ImGuiID>*)self->UserData; return (*p_items)[idx]; }; // Index -> ID
3383
3384 ImGui::Text("Added features:");
3385 ImGui::BulletText("Dynamic list with Delete key support.");
3386 ImGui::Text("Selection size: %d/%d", selection.Size, items.Size);
3387
3388 // Initialize default list with 50 items + button to add/remove items.
3389 static ImGuiID items_next_id = 0;
3390 if (items_next_id == 0)
3391 for (ImGuiID n = 0; n < 50; n++)
3392 items.push_back(items_next_id++);
3393 if (ImGui::SmallButton("Add 20 items")) { for (int n = 0; n < 20; n++) { items.push_back(items_next_id++); } }
3394 ImGui::SameLine();
3395 if (ImGui::SmallButton("Remove 20 items")) { for (int n = IM_MIN(20, items.Size); n > 0; n--) { selection.SetItemSelected(items.back(), false); items.pop_back(); } }
3396
3397 // (1) Extra to support deletion: Submit scrolling range to avoid glitches on deletion
3398 const float items_height = ImGui::GetTextLineHeightWithSpacing();
3399 ImGui::SetNextWindowContentSize(ImVec2(0.0f, items.Size * items_height));
3400
3401 if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
3402 {
3403 ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
3404 ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size);
3405 selection.ApplyRequests(ms_io);
3406
3407 const bool want_delete = ImGui::Shortcut(ImGuiKey_Delete, ImGuiInputFlags_Repeat) && (selection.Size > 0);
3408 const int item_curr_idx_to_focus = want_delete ? selection.ApplyDeletionPreLoop(ms_io, items.Size) : -1;
3409
3410 for (int n = 0; n < items.Size; n++)
3411 {
3412 const ImGuiID item_id = items[n];
3413 char label[64];
3414 sprintf(label, "Object %05u: %s", item_id, ExampleNames[item_id % IM_ARRAYSIZE(ExampleNames)]);
3415
3416 bool item_is_selected = selection.Contains(item_id);
3417 ImGui::SetNextItemSelectionUserData(n);
3418 ImGui::Selectable(label, item_is_selected);
3419 if (item_curr_idx_to_focus == n)
3420 ImGui::SetKeyboardFocusHere(-1);
3421 }
3422
3423 // Apply multi-select requests
3424 ms_io = ImGui::EndMultiSelect();
3425 selection.ApplyRequests(ms_io);
3426 if (want_delete)
3427 selection.ApplyDeletionPostLoop(ms_io, items, item_curr_idx_to_focus);
3428 }
3429 ImGui::EndChild();
3430 ImGui::TreePop();
3431 }
3432
3433 // Implement a Dual List Box (#6648)
3434 IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (dual list box)");
3435 if (ImGui::TreeNode("Multi-Select (dual list box)"))
3436 {
3437 // Init default state
3438 static ExampleDualListBox dlb;
3439 if (dlb.Items[0].Size == 0 && dlb.Items[1].Size == 0)
3440 for (int item_id = 0; item_id < IM_ARRAYSIZE(ExampleNames); item_id++)
3441 dlb.Items[0].push_back((ImGuiID)item_id);
3442
3443 // Show
3444 dlb.Show();
3445
3446 ImGui::TreePop();
3447 }
3448
3449 // Demonstrate using the clipper with BeginMultiSelect()/EndMultiSelect()
3450 IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (in a table)");
3451 if (ImGui::TreeNode("Multi-Select (in a table)"))
3452 {
3453 static ImGuiSelectionBasicStorage selection;
3454
3455 const int ITEMS_COUNT = 10000;
3456 ImGui::Text("Selection: %d/%d", selection.Size, ITEMS_COUNT);
3457 if (ImGui::BeginTable("##Basket", 2, ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter))
3458 {
3459 ImGui::TableSetupColumn("Object");
3460 ImGui::TableSetupColumn("Action");
3461 ImGui::TableSetupScrollFreeze(0, 1);
3462 ImGui::TableHeadersRow();
3463
3464 ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
3465 ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT);
3466 selection.ApplyRequests(ms_io);
3467
3468 ImGuiListClipper clipper;
3469 clipper.Begin(ITEMS_COUNT);
3470 if (ms_io->RangeSrcItem != -1)
3471 clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped.
3472 while (clipper.Step())
3473 {
3474 for (int n = clipper.DisplayStart; n < clipper.DisplayEnd; n++)
3475 {
3476 ImGui::TableNextRow();
3477 ImGui::TableNextColumn();
3478 char label[64];
3479 sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_ARRAYSIZE(ExampleNames)]);
3480 bool item_is_selected = selection.Contains((ImGuiID)n);
3481 ImGui::SetNextItemSelectionUserData(n);
3482 ImGui::Selectable(label, item_is_selected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap);
3483 ImGui::TableNextColumn();
3484 ImGui::SmallButton("hello");
3485 }
3486 }
3487
3488 ms_io = ImGui::EndMultiSelect();
3489 selection.ApplyRequests(ms_io);
3490 ImGui::EndTable();
3491 }
3492 ImGui::TreePop();
3493 }
3494
3495 IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (checkboxes)");
3496 if (ImGui::TreeNode("Multi-Select (checkboxes)"))
3497 {
3498 ImGui::Text("In a list of checkboxes (not selectable):");
3499 ImGui::BulletText("Using _NoAutoSelect + _NoAutoClear flags.");
3500 ImGui::BulletText("Shift+Click to check multiple boxes.");
3501 ImGui::BulletText("Shift+Keyboard to copy current value to other boxes.");
3502
3503 // If you have an array of checkboxes, you may want to use NoAutoSelect + NoAutoClear and the ImGuiSelectionExternalStorage helper.
3504 static bool items[20] = {};
3505 static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_NoAutoSelect | ImGuiMultiSelectFlags_NoAutoClear | ImGuiMultiSelectFlags_ClearOnEscape;
3506 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoSelect", &flags, ImGuiMultiSelectFlags_NoAutoSelect);
3507 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoClear", &flags, ImGuiMultiSelectFlags_NoAutoClear);
3508 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect2d", &flags, ImGuiMultiSelectFlags_BoxSelect2d); // Cannot use ImGuiMultiSelectFlags_BoxSelect1d as checkboxes are varying width.
3509
3510 if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeY))
3511 {
3512 ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, -1, IM_ARRAYSIZE(items));
3513 ImGuiSelectionExternalStorage storage_wrapper;
3514 storage_wrapper.UserData = (void*)items;
3515 storage_wrapper.AdapterSetItemSelected = [](ImGuiSelectionExternalStorage* self, int n, bool selected) { bool* array = (bool*)self->UserData; array[n] = selected; };
3516 storage_wrapper.ApplyRequests(ms_io);
3517 for (int n = 0; n < 20; n++)
3518 {
3519 char label[32];
3520 sprintf(label, "Item %d", n);
3521 ImGui::SetNextItemSelectionUserData(n);
3522 ImGui::Checkbox(label, &items[n]);
3523 }
3524 ms_io = ImGui::EndMultiSelect();
3525 storage_wrapper.ApplyRequests(ms_io);
3526 }
3527 ImGui::EndChild();
3528
3529 ImGui::TreePop();
3530 }
3531
3532 // Demonstrate individual selection scopes in same window
3533 IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (multiple scopes)");
3534 if (ImGui::TreeNode("Multi-Select (multiple scopes)"))
3535 {
3536 // Use default select: Pass index to SetNextItemSelectionUserData(), store index in Selection
3537 const int SCOPES_COUNT = 3;
3538 const int ITEMS_COUNT = 8; // Per scope
3539 static ImGuiSelectionBasicStorage selections_data[SCOPES_COUNT];
3540
3541 // Use ImGuiMultiSelectFlags_ScopeRect to not affect other selections in same window.
3542 static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ScopeRect | ImGuiMultiSelectFlags_ClearOnEscape;// | ImGuiMultiSelectFlags_ClearOnClickVoid;
3543 if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeWindow", &flags, ImGuiMultiSelectFlags_ScopeWindow) && (flags & ImGuiMultiSelectFlags_ScopeWindow))
3544 flags &= ~ImGuiMultiSelectFlags_ScopeRect;
3545 if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeRect", &flags, ImGuiMultiSelectFlags_ScopeRect) && (flags & ImGuiMultiSelectFlags_ScopeRect))
3546 flags &= ~ImGuiMultiSelectFlags_ScopeWindow;
3547 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnClickVoid", &flags, ImGuiMultiSelectFlags_ClearOnClickVoid);
3548 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect1d", &flags, ImGuiMultiSelectFlags_BoxSelect1d);
3549
3550 for (int selection_scope_n = 0; selection_scope_n < SCOPES_COUNT; selection_scope_n++)
3551 {
3552 ImGui::PushID(selection_scope_n);
3553 ImGuiSelectionBasicStorage* selection = &selections_data[selection_scope_n];
3554 ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection->Size, ITEMS_COUNT);
3555 selection->ApplyRequests(ms_io);
3556
3557 ImGui::SeparatorText("Selection scope");
3558 ImGui::Text("Selection size: %d/%d", selection->Size, ITEMS_COUNT);
3559
3560 for (int n = 0; n < ITEMS_COUNT; n++)
3561 {
3562 char label[64];
3563 sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_ARRAYSIZE(ExampleNames)]);
3564 bool item_is_selected = selection->Contains((ImGuiID)n);
3565 ImGui::SetNextItemSelectionUserData(n);
3566 ImGui::Selectable(label, item_is_selected);
3567 }
3568
3569 // Apply multi-select requests
3570 ms_io = ImGui::EndMultiSelect();
3571 selection->ApplyRequests(ms_io);
3572 ImGui::PopID();
3573 }
3574 ImGui::TreePop();
3575 }
3576
3577 // See ShowExampleAppAssetsBrowser()
3578 if (ImGui::TreeNode("Multi-Select (tiled assets browser)"))
3579 {
3580 ImGui::Checkbox("Assets Browser", &demo_data->ShowAppAssetsBrowser);
3581 ImGui::Text("(also access from 'Examples->Assets Browser' in menu)");
3582 ImGui::TreePop();
3583 }
3584
3585 // Demonstrate supporting multiple-selection in a tree.
3586 // - We don't use linear indices for selection user data, but our ExampleTreeNode* pointer directly!
3587 // This showcase how SetNextItemSelectionUserData() never assume indices!
3588 // - The difficulty here is to "interpolate" from RangeSrcItem to RangeDstItem in the SetAll/SetRange request.
3589 // We want this interpolation to match what the user sees: in visible order, skipping closed nodes.
3590 // This is implemented by our TreeGetNextNodeInVisibleOrder() user-space helper.
3591 // - Important: In a real codebase aiming to implement full-featured selectable tree with custom filtering, you
3592 // are more likely to build an array mapping sequential indices to visible tree nodes, since your
3593 // filtering/search + clipping process will benefit from it. Having this will make this interpolation much easier.
3594 // - Consider this a prototype: we are working toward simplifying some of it.
3595 IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (trees)");
3596 if (ImGui::TreeNode("Multi-Select (trees)"))
3597 {
3598 HelpMarker(
3599 "This is rather advanced and experimental. If you are getting started with multi-select,"
3600 "please don't start by looking at how to use it for a tree!\n\n"
3601 "Future versions will try to simplify and formalize some of this.");
3602
3603 struct ExampleTreeFuncs
3604 {
3605 static void DrawNode(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection)
3606 {
3607 ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;
3608 tree_node_flags |= ImGuiTreeNodeFlags_NavLeftJumpsBackHere; // Enable pressing left to jump to parent
3609 if (node->Childs.Size == 0)
3610 tree_node_flags |= ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_Leaf;
3611 if (selection->Contains((ImGuiID)node->UID))
3612 tree_node_flags |= ImGuiTreeNodeFlags_Selected;
3613
3614 // Using SetNextItemStorageID() to specify storage id, so we can easily peek into
3615 // the storage holding open/close stage, using our TreeNodeGetOpen/TreeNodeSetOpen() functions.
3616 ImGui::SetNextItemSelectionUserData((ImGuiSelectionUserData)(intptr_t)node);
3617 ImGui::SetNextItemStorageID((ImGuiID)node->UID);
3618 if (ImGui::TreeNodeEx(node->Name, tree_node_flags))
3619 {
3620 for (ExampleTreeNode* child : node->Childs)
3621 DrawNode(child, selection);
3622 ImGui::TreePop();
3623 }
3624 else if (ImGui::IsItemToggledOpen())
3625 {
3626 TreeCloseAndUnselectChildNodes(node, selection);
3627 }
3628 }
3629
3630 static bool TreeNodeGetOpen(ExampleTreeNode* node)
3631 {
3632 return ImGui::GetStateStorage()->GetBool((ImGuiID)node->UID);
3633 }
3634
3635 static void TreeNodeSetOpen(ExampleTreeNode* node, bool open)
3636 {
3637 ImGui::GetStateStorage()->SetBool((ImGuiID)node->UID, open);
3638 }
3639
3640 // When closing a node: 1) close and unselect all child nodes, 2) select parent if any child was selected.
3641 // FIXME: This is currently handled by user logic but I'm hoping to eventually provide tree node
3642 // features to do this automatically, e.g. a ImGuiTreeNodeFlags_AutoCloseChildNodes etc.
3643 static int TreeCloseAndUnselectChildNodes(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection, int depth = 0)
3644 {
3645 // Recursive close (the test for depth == 0 is because we call this on a node that was just closed!)
3646 int unselected_count = selection->Contains((ImGuiID)node->UID) ? 1 : 0;
3647 if (depth == 0 || TreeNodeGetOpen(node))
3648 {
3649 for (ExampleTreeNode* child : node->Childs)
3650 unselected_count += TreeCloseAndUnselectChildNodes(child, selection, depth + 1);
3651 TreeNodeSetOpen(node, false);
3652 }
3653
3654 // Select root node if any of its child was selected, otherwise unselect
3655 selection->SetItemSelected((ImGuiID)node->UID, (depth == 0 && unselected_count > 0));
3656 return unselected_count;
3657 }
3658
3659 // Apply multi-selection requests
3660 static void ApplySelectionRequests(ImGuiMultiSelectIO* ms_io, ExampleTreeNode* tree, ImGuiSelectionBasicStorage* selection)
3661 {
3662 for (ImGuiSelectionRequest& req : ms_io->Requests)
3663 {
3664 if (req.Type == ImGuiSelectionRequestType_SetAll)
3665 {
3666 if (req.Selected)
3667 TreeSetAllInOpenNodes(tree, selection, req.Selected);
3668 else
3669 selection->Clear();
3670 }
3671 else if (req.Type == ImGuiSelectionRequestType_SetRange)
3672 {
3673 ExampleTreeNode* first_node = (ExampleTreeNode*)(intptr_t)req.RangeFirstItem;
3674 ExampleTreeNode* last_node = (ExampleTreeNode*)(intptr_t)req.RangeLastItem;
3675 for (ExampleTreeNode* node = first_node; node != NULL; node = TreeGetNextNodeInVisibleOrder(node, last_node))
3676 selection->SetItemSelected((ImGuiID)node->UID, req.Selected);
3677 }
3678 }
3679 }
3680
3681 static void TreeSetAllInOpenNodes(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection, bool selected)
3682 {
3683 if (node->Parent != NULL) // Root node isn't visible nor selectable in our scheme
3684 selection->SetItemSelected((ImGuiID)node->UID, selected);
3685 if (node->Parent == NULL || TreeNodeGetOpen(node))
3686 for (ExampleTreeNode* child : node->Childs)
3687 TreeSetAllInOpenNodes(child, selection, selected);
3688 }
3689
3690 // Interpolate in *user-visible order* AND only *over opened nodes*.
3691 // If you have a sequential mapping tables (e.g. generated after a filter/search pass) this would be simpler.
3692 // Here the tricks are that:
3693 // - we store/maintain ExampleTreeNode::IndexInParent which allows implementing a linear iterator easily, without searches, without recursion.
3694 // this could be replaced by a search in parent, aka 'int index_in_parent = curr_node->Parent->Childs.find_index(curr_node)'
3695 // which would only be called when crossing from child to a parent, aka not too much.
3696 // - we call SetNextItemStorageID() before our TreeNode() calls with an ID which doesn't relate to UI stack,
3697 // making it easier to call TreeNodeGetOpen()/TreeNodeSetOpen() from any location.
3698 static ExampleTreeNode* TreeGetNextNodeInVisibleOrder(ExampleTreeNode* curr_node, ExampleTreeNode* last_node)
3699 {
3700 // Reached last node
3701 if (curr_node == last_node)
3702 return NULL;
3703
3704 // Recurse into childs. Query storage to tell if the node is open.
3705 if (curr_node->Childs.Size > 0 && TreeNodeGetOpen(curr_node))
3706 return curr_node->Childs[0];
3707
3708 // Next sibling, then into our own parent
3709 while (curr_node->Parent != NULL)
3710 {
3711 if (curr_node->IndexInParent + 1 < curr_node->Parent->Childs.Size)
3712 return curr_node->Parent->Childs[curr_node->IndexInParent + 1];
3713 curr_node = curr_node->Parent;
3714 }
3715 return NULL;
3716 }
3717
3718 }; // ExampleTreeFuncs
3719
3720 static ImGuiSelectionBasicStorage selection;
3721 if (demo_data->DemoTree == NULL)
3722 demo_data->DemoTree = ExampleTree_CreateDemoTree(); // Create tree once
3723 ImGui::Text("Selection size: %d", selection.Size);
3724
3725 if (ImGui::BeginChild("##Tree", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
3726 {
3727 ExampleTreeNode* tree = demo_data->DemoTree;
3728 ImGuiMultiSelectFlags ms_flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect2d;
3729 ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(ms_flags, selection.Size, -1);
3730 ExampleTreeFuncs::ApplySelectionRequests(ms_io, tree, &selection);
3731 for (ExampleTreeNode* node : tree->Childs)
3732 ExampleTreeFuncs::DrawNode(node, &selection);
3733 ms_io = ImGui::EndMultiSelect();
3734 ExampleTreeFuncs::ApplySelectionRequests(ms_io, tree, &selection);
3735 }
3736 ImGui::EndChild();
3737
3738 ImGui::TreePop();
3739 }
3740
3741 // Advanced demonstration of BeginMultiSelect()
3742 // - Showcase clipping.
3743 // - Showcase deletion.
3744 // - Showcase basic drag and drop.
3745 // - Showcase TreeNode variant (note that tree node don't expand in the demo: supporting expanding tree nodes + clipping a separate thing).
3746 // - Showcase using inside a table.
3747 IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (advanced)");
3748 //ImGui::SetNextItemOpen(true, ImGuiCond_Once);
3749 if (ImGui::TreeNode("Multi-Select (advanced)"))
3750 {
3751 // Options
3752 enum WidgetType { WidgetType_Selectable, WidgetType_TreeNode };
3753 static bool use_clipper = true;
3754 static bool use_deletion = true;
3755 static bool use_drag_drop = true;
3756 static bool show_in_table = false;
3757 static bool show_color_button = true;
3758 static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
3759 static WidgetType widget_type = WidgetType_Selectable;
3760
3761 if (ImGui::TreeNode("Options"))
3762 {
3763 if (ImGui::RadioButton("Selectables", widget_type == WidgetType_Selectable)) { widget_type = WidgetType_Selectable; }
3764 ImGui::SameLine();
3765 if (ImGui::RadioButton("Tree nodes", widget_type == WidgetType_TreeNode)) { widget_type = WidgetType_TreeNode; }
3766 ImGui::SameLine();
3767 HelpMarker("TreeNode() is technically supported but... using this correctly is more complicated (you need some sort of linear/random access to your tree, which is suited to advanced trees setups already implementing filters and clipper. We will work toward simplifying and demoing this.\n\nFor now the tree demo is actually a little bit meaningless because it is an empty tree with only root nodes.");
3768 ImGui::Checkbox("Enable clipper", &use_clipper);
3769 ImGui::Checkbox("Enable deletion", &use_deletion);
3770 ImGui::Checkbox("Enable drag & drop", &use_drag_drop);
3771 ImGui::Checkbox("Show in a table", &show_in_table);
3772 ImGui::Checkbox("Show color button", &show_color_button);
3773 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SingleSelect", &flags, ImGuiMultiSelectFlags_SingleSelect);
3774 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoSelectAll", &flags, ImGuiMultiSelectFlags_NoSelectAll);
3775 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoRangeSelect", &flags, ImGuiMultiSelectFlags_NoRangeSelect);
3776 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoSelect", &flags, ImGuiMultiSelectFlags_NoAutoSelect);
3777 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoClear", &flags, ImGuiMultiSelectFlags_NoAutoClear);
3778 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoClearOnReselect", &flags, ImGuiMultiSelectFlags_NoAutoClearOnReselect);
3779 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect1d", &flags, ImGuiMultiSelectFlags_BoxSelect1d);
3780 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect2d", &flags, ImGuiMultiSelectFlags_BoxSelect2d);
3781 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelectNoScroll", &flags, ImGuiMultiSelectFlags_BoxSelectNoScroll);
3782 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnEscape", &flags, ImGuiMultiSelectFlags_ClearOnEscape);
3783 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnClickVoid", &flags, ImGuiMultiSelectFlags_ClearOnClickVoid);
3784 if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeWindow", &flags, ImGuiMultiSelectFlags_ScopeWindow) && (flags & ImGuiMultiSelectFlags_ScopeWindow))
3785 flags &= ~ImGuiMultiSelectFlags_ScopeRect;
3786 if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeRect", &flags, ImGuiMultiSelectFlags_ScopeRect) && (flags & ImGuiMultiSelectFlags_ScopeRect))
3787 flags &= ~ImGuiMultiSelectFlags_ScopeWindow;
3788 if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SelectOnClick", &flags, ImGuiMultiSelectFlags_SelectOnClick) && (flags & ImGuiMultiSelectFlags_SelectOnClick))
3789 flags &= ~ImGuiMultiSelectFlags_SelectOnClickRelease;
3790 if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SelectOnClickRelease", &flags, ImGuiMultiSelectFlags_SelectOnClickRelease) && (flags & ImGuiMultiSelectFlags_SelectOnClickRelease))
3791 flags &= ~ImGuiMultiSelectFlags_SelectOnClick;
3792 ImGui::SameLine(); HelpMarker("Allow dragging an unselected item without altering selection.");
3793 ImGui::TreePop();
3794 }
3795
3796 // Initialize default list with 1000 items.
3797 // Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection
3798 static ImVector<int> items;
3799 static int items_next_id = 0;
3800 if (items_next_id == 0) { for (int n = 0; n < 1000; n++) { items.push_back(items_next_id++); } }
3801 static ExampleSelectionWithDeletion selection;
3802 static bool request_deletion_from_menu = false; // Queue deletion triggered from context menu
3803
3804 ImGui::Text("Selection size: %d/%d", selection.Size, items.Size);
3805
3806 const float items_height = (widget_type == WidgetType_TreeNode) ? ImGui::GetTextLineHeight() : ImGui::GetTextLineHeightWithSpacing();
3807 ImGui::SetNextWindowContentSize(ImVec2(0.0f, items.Size * items_height));
3808 if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
3809 {
3810 ImVec2 color_button_sz(ImGui::GetFontSize(), ImGui::GetFontSize());
3811 if (widget_type == WidgetType_TreeNode)
3812 ImGui::PushStyleVarY(ImGuiStyleVar_ItemSpacing, 0.0f);
3813
3814 ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size);
3815 selection.ApplyRequests(ms_io);
3816
3817 const bool want_delete = (ImGui::Shortcut(ImGuiKey_Delete, ImGuiInputFlags_Repeat) && (selection.Size > 0)) || request_deletion_from_menu;
3818 const int item_curr_idx_to_focus = want_delete ? selection.ApplyDeletionPreLoop(ms_io, items.Size) : -1;
3819 request_deletion_from_menu = false;
3820
3821 if (show_in_table)
3822 {
3823 if (widget_type == WidgetType_TreeNode)
3824 ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(0.0f, 0.0f));
3825 ImGui::BeginTable("##Split", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_NoPadOuterX);
3826 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 0.70f);
3827 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 0.30f);
3828 //ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacingY, 0.0f);
3829 }
3830
3831 ImGuiListClipper clipper;
3832 if (use_clipper)
3833 {
3834 clipper.Begin(items.Size);
3835 if (item_curr_idx_to_focus != -1)
3836 clipper.IncludeItemByIndex(item_curr_idx_to_focus); // Ensure focused item is not clipped.
3837 if (ms_io->RangeSrcItem != -1)
3838 clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped.
3839 }
3840
3841 while (!use_clipper || clipper.Step())
3842 {
3843 const int item_begin = use_clipper ? clipper.DisplayStart : 0;
3844 const int item_end = use_clipper ? clipper.DisplayEnd : items.Size;
3845 for (int n = item_begin; n < item_end; n++)
3846 {
3847 if (show_in_table)
3848 ImGui::TableNextColumn();
3849
3850 const int item_id = items[n];
3851 const char* item_category = ExampleNames[item_id % IM_ARRAYSIZE(ExampleNames)];
3852 char label[64];
3853 sprintf(label, "Object %05d: %s", item_id, item_category);
3854
3855 // IMPORTANT: for deletion refocus to work we need object ID to be stable,
3856 // aka not depend on their index in the list. Here we use our persistent item_id
3857 // instead of index to build a unique ID that will persist.
3858 // (If we used PushID(index) instead, focus wouldn't be restored correctly after deletion).
3859 ImGui::PushID(item_id);
3860
3861 // Emit a color button, to test that Shift+LeftArrow landing on an item that is not part
3862 // of the selection scope doesn't erroneously alter our selection.
3863 if (show_color_button)
3864 {
3865 ImU32 dummy_col = (ImU32)((unsigned int)n * 0xC250B74B) | IM_COL32_A_MASK;
3866 ImGui::ColorButton("##", ImColor(dummy_col), ImGuiColorEditFlags_NoTooltip, color_button_sz);
3867 ImGui::SameLine();
3868 }
3869
3870 // Submit item
3871 bool item_is_selected = selection.Contains((ImGuiID)n);
3872 bool item_is_open = false;
3873 ImGui::SetNextItemSelectionUserData(n);
3874 if (widget_type == WidgetType_Selectable)
3875 {
3876 ImGui::Selectable(label, item_is_selected, ImGuiSelectableFlags_None);
3877 }
3878 else if (widget_type == WidgetType_TreeNode)
3879 {
3880 ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;
3881 if (item_is_selected)
3882 tree_node_flags |= ImGuiTreeNodeFlags_Selected;
3883 item_is_open = ImGui::TreeNodeEx(label, tree_node_flags);
3884 }
3885
3886 // Focus (for after deletion)
3887 if (item_curr_idx_to_focus == n)
3888 ImGui::SetKeyboardFocusHere(-1);
3889
3890 // Drag and Drop
3891 if (use_drag_drop && ImGui::BeginDragDropSource())
3892 {
3893 // Create payload with full selection OR single unselected item.
3894 // (the later is only possible when using ImGuiMultiSelectFlags_SelectOnClickRelease)
3895 if (ImGui::GetDragDropPayload() == NULL)
3896 {
3897 ImVector<int> payload_items;
3898 void* it = NULL;
3899 ImGuiID id = 0;
3900 if (!item_is_selected)
3901 payload_items.push_back(item_id);
3902 else
3903 while (selection.GetNextSelectedItem(&it, &id))
3904 payload_items.push_back((int)id);
3905 ImGui::SetDragDropPayload("MULTISELECT_DEMO_ITEMS", payload_items.Data, (size_t)payload_items.size_in_bytes());
3906 }
3907
3908 // Display payload content in tooltip
3909 const ImGuiPayload* payload = ImGui::GetDragDropPayload();
3910 const int* payload_items = (int*)payload->Data;
3911 const int payload_count = (int)payload->DataSize / (int)sizeof(int);
3912 if (payload_count == 1)
3913 ImGui::Text("Object %05d: %s", payload_items[0], ExampleNames[payload_items[0] % IM_ARRAYSIZE(ExampleNames)]);
3914 else
3915 ImGui::Text("Dragging %d objects", payload_count);
3916
3917 ImGui::EndDragDropSource();
3918 }
3919
3920 if (widget_type == WidgetType_TreeNode && item_is_open)
3921 ImGui::TreePop();
3922
3923 // Right-click: context menu
3924 if (ImGui::BeginPopupContextItem())
3925 {
3926 ImGui::BeginDisabled(!use_deletion || selection.Size == 0);
3927 sprintf(label, "Delete %d item(s)###DeleteSelected", selection.Size);
3928 if (ImGui::Selectable(label))
3929 request_deletion_from_menu = true;
3930 ImGui::EndDisabled();
3931 ImGui::Selectable("Close");
3932 ImGui::EndPopup();
3933 }
3934
3935 // Demo content within a table
3936 if (show_in_table)
3937 {
3938 ImGui::TableNextColumn();
3939 ImGui::SetNextItemWidth(-FLT_MIN);
3940 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
3941 ImGui::InputText("###NoLabel", (char*)(void*)item_category, strlen(item_category), ImGuiInputTextFlags_ReadOnly);
3942 ImGui::PopStyleVar();
3943 }
3944
3945 ImGui::PopID();
3946 }
3947 if (!use_clipper)
3948 break;
3949 }
3950
3951 if (show_in_table)
3952 {
3953 ImGui::EndTable();
3954 if (widget_type == WidgetType_TreeNode)
3955 ImGui::PopStyleVar();
3956 }
3957
3958 // Apply multi-select requests
3959 ms_io = ImGui::EndMultiSelect();
3960 selection.ApplyRequests(ms_io);
3961 if (want_delete)
3962 selection.ApplyDeletionPostLoop(ms_io, items, item_curr_idx_to_focus);
3963
3964 if (widget_type == WidgetType_TreeNode)
3965 ImGui::PopStyleVar();
3966 }
3967 ImGui::EndChild();
3968 ImGui::TreePop();
3969 }
3970 ImGui::TreePop();
3971 }
3972}
3973
3974//-----------------------------------------------------------------------------
3975// [SECTION] ShowDemoWindowLayout()
3976//-----------------------------------------------------------------------------
3977
3978static void ShowDemoWindowLayout()
3979{
3980 IMGUI_DEMO_MARKER("Layout");
3981 if (!ImGui::CollapsingHeader("Layout & Scrolling"))
3982 return;
3983
3984 IMGUI_DEMO_MARKER("Layout/Child windows");
3985 if (ImGui::TreeNode("Child windows"))
3986 {
3987 ImGui::SeparatorText("Child windows");
3988
3989 HelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window.");
3990 static bool disable_mouse_wheel = false;
3991 static bool disable_menu = false;
3992 ImGui::Checkbox("Disable Mouse Wheel", &disable_mouse_wheel);
3993 ImGui::Checkbox("Disable Menu", &disable_menu);
3994
3995 // Child 1: no border, enable horizontal scrollbar
3996 {
3997 ImGuiWindowFlags window_flags = ImGuiWindowFlags_HorizontalScrollbar;
3998 if (disable_mouse_wheel)
3999 window_flags |= ImGuiWindowFlags_NoScrollWithMouse;
4000 ImGui::BeginChild("ChildL", ImVec2(ImGui::GetContentRegionAvail().x * 0.5f, 260), ImGuiChildFlags_None, window_flags);
4001 for (int i = 0; i < 100; i++)
4002 ImGui::Text("%04d: scrollable region", i);
4003 ImGui::EndChild();
4004 }
4005
4006 ImGui::SameLine();
4007
4008 // Child 2: rounded border
4009 {
4010 ImGuiWindowFlags window_flags = ImGuiWindowFlags_None;
4011 if (disable_mouse_wheel)
4012 window_flags |= ImGuiWindowFlags_NoScrollWithMouse;
4013 if (!disable_menu)
4014 window_flags |= ImGuiWindowFlags_MenuBar;
4015 ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f);
4016 ImGui::BeginChild("ChildR", ImVec2(0, 260), ImGuiChildFlags_Borders, window_flags);
4017 if (!disable_menu && ImGui::BeginMenuBar())
4018 {
4019 if (ImGui::BeginMenu("Menu"))
4020 {
4021 ShowExampleMenuFile();
4022 ImGui::EndMenu();
4023 }
4024 ImGui::EndMenuBar();
4025 }
4026 if (ImGui::BeginTable("split", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings))
4027 {
4028 for (int i = 0; i < 100; i++)
4029 {
4030 char buf[32];
4031 sprintf(buf, "%03d", i);
4032 ImGui::TableNextColumn();
4033 ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f));
4034 }
4035 ImGui::EndTable();
4036 }
4037 ImGui::EndChild();
4038 ImGui::PopStyleVar();
4039 }
4040
4041 // Child 3: manual-resize
4042 ImGui::SeparatorText("Manual-resize");
4043 {
4044 HelpMarker("Drag bottom border to resize. Double-click bottom border to auto-fit to vertical contents.");
4045 //if (ImGui::Button("Set Height to 200"))
4046 // ImGui::SetNextWindowSize(ImVec2(-FLT_MIN, 200.0f));
4047
4048 ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyleColorVec4(ImGuiCol_FrameBg));
4049 if (ImGui::BeginChild("ResizableChild", ImVec2(-FLT_MIN, ImGui::GetTextLineHeightWithSpacing() * 8), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeY))
4050 for (int n = 0; n < 10; n++)
4051 ImGui::Text("Line %04d", n);
4052 ImGui::PopStyleColor();
4053 ImGui::EndChild();
4054 }
4055
4056 // Child 4: auto-resizing height with a limit
4057 ImGui::SeparatorText("Auto-resize with constraints");
4058 {
4059 static int draw_lines = 3;
4060 static int max_height_in_lines = 10;
4061 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
4062 ImGui::DragInt("Lines Count", &draw_lines, 0.2f);
4063 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
4064 ImGui::DragInt("Max Height (in Lines)", &max_height_in_lines, 0.2f);
4065
4066 ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 1), ImVec2(FLT_MAX, ImGui::GetTextLineHeightWithSpacing() * max_height_in_lines));
4067 if (ImGui::BeginChild("ConstrainedChild", ImVec2(-FLT_MIN, 0.0f), ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeY))
4068 for (int n = 0; n < draw_lines; n++)
4069 ImGui::Text("Line %04d", n);
4070 ImGui::EndChild();
4071 }
4072
4073 ImGui::SeparatorText("Misc/Advanced");
4074
4075 // Demonstrate a few extra things
4076 // - Changing ImGuiCol_ChildBg (which is transparent black in default styles)
4077 // - Using SetCursorPos() to position child window (the child window is an item from the POV of parent window)
4078 // You can also call SetNextWindowPos() to position the child window. The parent window will effectively
4079 // layout from this position.
4080 // - Using ImGui::GetItemRectMin/Max() to query the "item" state (because the child window is an item from
4081 // the POV of the parent window). See 'Demo->Querying Status (Edited/Active/Hovered etc.)' for details.
4082 {
4083 static int offset_x = 0;
4084 static bool override_bg_color = true;
4085 static ImGuiChildFlags child_flags = ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY;
4086 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
4087 ImGui::DragInt("Offset X", &offset_x, 1.0f, -1000, 1000);
4088 ImGui::Checkbox("Override ChildBg color", &override_bg_color);
4089 ImGui::CheckboxFlags("ImGuiChildFlags_Borders", &child_flags, ImGuiChildFlags_Borders);
4090 ImGui::CheckboxFlags("ImGuiChildFlags_AlwaysUseWindowPadding", &child_flags, ImGuiChildFlags_AlwaysUseWindowPadding);
4091 ImGui::CheckboxFlags("ImGuiChildFlags_ResizeX", &child_flags, ImGuiChildFlags_ResizeX);
4092 ImGui::CheckboxFlags("ImGuiChildFlags_ResizeY", &child_flags, ImGuiChildFlags_ResizeY);
4093 ImGui::CheckboxFlags("ImGuiChildFlags_FrameStyle", &child_flags, ImGuiChildFlags_FrameStyle);
4094 ImGui::SameLine(); HelpMarker("Style the child window like a framed item: use FrameBg, FrameRounding, FrameBorderSize, FramePadding instead of ChildBg, ChildRounding, ChildBorderSize, WindowPadding.");
4095 if (child_flags & ImGuiChildFlags_FrameStyle)
4096 override_bg_color = false;
4097
4098 ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (float)offset_x);
4099 if (override_bg_color)
4100 ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(255, 0, 0, 100));
4101 ImGui::BeginChild("Red", ImVec2(200, 100), child_flags, ImGuiWindowFlags_None);
4102 if (override_bg_color)
4103 ImGui::PopStyleColor();
4104
4105 for (int n = 0; n < 50; n++)
4106 ImGui::Text("Some test %d", n);
4107 ImGui::EndChild();
4108 bool child_is_hovered = ImGui::IsItemHovered();
4109 ImVec2 child_rect_min = ImGui::GetItemRectMin();
4110 ImVec2 child_rect_max = ImGui::GetItemRectMax();
4111 ImGui::Text("Hovered: %d", child_is_hovered);
4112 ImGui::Text("Rect of child window is: (%.0f,%.0f) (%.0f,%.0f)", child_rect_min.x, child_rect_min.y, child_rect_max.x, child_rect_max.y);
4113 }
4114
4115 ImGui::TreePop();
4116 }
4117
4118 IMGUI_DEMO_MARKER("Layout/Widgets Width");
4119 if (ImGui::TreeNode("Widgets Width"))
4120 {
4121 static float f = 0.0f;
4122 static bool show_indented_items = true;
4123 ImGui::Checkbox("Show indented items", &show_indented_items);
4124
4125 // Use SetNextItemWidth() to set the width of a single upcoming item.
4126 // Use PushItemWidth()/PopItemWidth() to set the width of a group of items.
4127 // In real code use you'll probably want to choose width values that are proportional to your font size
4128 // e.g. Using '20.0f * GetFontSize()' as width instead of '200.0f', etc.
4129
4130 ImGui::Text("SetNextItemWidth/PushItemWidth(100)");
4131 ImGui::SameLine(); HelpMarker("Fixed width.");
4132 ImGui::PushItemWidth(100);
4133 ImGui::DragFloat("float##1b", &f);
4134 if (show_indented_items)
4135 {
4136 ImGui::Indent();
4137 ImGui::DragFloat("float (indented)##1b", &f);
4138 ImGui::Unindent();
4139 }
4140 ImGui::PopItemWidth();
4141
4142 ImGui::Text("SetNextItemWidth/PushItemWidth(-100)");
4143 ImGui::SameLine(); HelpMarker("Align to right edge minus 100");
4144 ImGui::PushItemWidth(-100);
4145 ImGui::DragFloat("float##2a", &f);
4146 if (show_indented_items)
4147 {
4148 ImGui::Indent();
4149 ImGui::DragFloat("float (indented)##2b", &f);
4150 ImGui::Unindent();
4151 }
4152 ImGui::PopItemWidth();
4153
4154 ImGui::Text("SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)");
4155 ImGui::SameLine(); HelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)");
4156 ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * 0.5f);
4157 ImGui::DragFloat("float##3a", &f);
4158 if (show_indented_items)
4159 {
4160 ImGui::Indent();
4161 ImGui::DragFloat("float (indented)##3b", &f);
4162 ImGui::Unindent();
4163 }
4164 ImGui::PopItemWidth();
4165
4166 ImGui::Text("SetNextItemWidth/PushItemWidth(-GetContentRegionAvail().x * 0.5f)");
4167 ImGui::SameLine(); HelpMarker("Align to right edge minus half");
4168 ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.5f);
4169 ImGui::DragFloat("float##4a", &f);
4170 if (show_indented_items)
4171 {
4172 ImGui::Indent();
4173 ImGui::DragFloat("float (indented)##4b", &f);
4174 ImGui::Unindent();
4175 }
4176 ImGui::PopItemWidth();
4177
4178 // Demonstrate using PushItemWidth to surround three items.
4179 // Calling SetNextItemWidth() before each of them would have the same effect.
4180 ImGui::Text("SetNextItemWidth/PushItemWidth(-FLT_MIN)");
4181 ImGui::SameLine(); HelpMarker("Align to right edge");
4182 ImGui::PushItemWidth(-FLT_MIN);
4183 ImGui::DragFloat("##float5a", &f);
4184 if (show_indented_items)
4185 {
4186 ImGui::Indent();
4187 ImGui::DragFloat("float (indented)##5b", &f);
4188 ImGui::Unindent();
4189 }
4190 ImGui::PopItemWidth();
4191
4192 ImGui::TreePop();
4193 }
4194
4195 IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout");
4196 if (ImGui::TreeNode("Basic Horizontal Layout"))
4197 {
4198 ImGui::TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)");
4199
4200 // Text
4201 IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine");
4202 ImGui::Text("Two items: Hello"); ImGui::SameLine();
4203 ImGui::TextColored(ImVec4(1, 1, 0, 1), "Sailor");
4204
4205 // Adjust spacing
4206 ImGui::Text("More spacing: Hello"); ImGui::SameLine(0, 20);
4207 ImGui::TextColored(ImVec4(1, 1, 0, 1), "Sailor");
4208
4209 // Button
4210 ImGui::AlignTextToFramePadding();
4211 ImGui::Text("Normal buttons"); ImGui::SameLine();
4212 ImGui::Button("Banana"); ImGui::SameLine();
4213 ImGui::Button("Apple"); ImGui::SameLine();
4214 ImGui::Button("Corniflower");
4215
4216 // Button
4217 ImGui::Text("Small buttons"); ImGui::SameLine();
4218 ImGui::SmallButton("Like this one"); ImGui::SameLine();
4219 ImGui::Text("can fit within a text block.");
4220
4221 // Aligned to arbitrary position. Easy/cheap column.
4222 IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (with offset)");
4223 ImGui::Text("Aligned");
4224 ImGui::SameLine(150); ImGui::Text("x=150");
4225 ImGui::SameLine(300); ImGui::Text("x=300");
4226 ImGui::Text("Aligned");
4227 ImGui::SameLine(150); ImGui::SmallButton("x=150");
4228 ImGui::SameLine(300); ImGui::SmallButton("x=300");
4229
4230 // Checkbox
4231 IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (more)");
4232 static bool c1 = false, c2 = false, c3 = false, c4 = false;
4233 ImGui::Checkbox("My", &c1); ImGui::SameLine();
4234 ImGui::Checkbox("Tailor", &c2); ImGui::SameLine();
4235 ImGui::Checkbox("Is", &c3); ImGui::SameLine();
4236 ImGui::Checkbox("Rich", &c4);
4237
4238 // Various
4239 static float f0 = 1.0f, f1 = 2.0f, f2 = 3.0f;
4240 ImGui::PushItemWidth(80);
4241 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD" };
4242 static int item = -1;
4243 ImGui::Combo("Combo", &item, items, IM_ARRAYSIZE(items)); ImGui::SameLine();
4244 ImGui::SliderFloat("X", &f0, 0.0f, 5.0f); ImGui::SameLine();
4245 ImGui::SliderFloat("Y", &f1, 0.0f, 5.0f); ImGui::SameLine();
4246 ImGui::SliderFloat("Z", &f2, 0.0f, 5.0f);
4247 ImGui::PopItemWidth();
4248
4249 ImGui::PushItemWidth(80);
4250 ImGui::Text("Lists:");
4251 static int selection[4] = { 0, 1, 2, 3 };
4252 for (int i = 0; i < 4; i++)
4253 {
4254 if (i > 0) ImGui::SameLine();
4255 ImGui::PushID(i);
4256 ImGui::ListBox("", &selection[i], items, IM_ARRAYSIZE(items));
4257 ImGui::PopID();
4258 //ImGui::SetItemTooltip("ListBox %d hovered", i);
4259 }
4260 ImGui::PopItemWidth();
4261
4262 // Dummy
4263 IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Dummy");
4264 ImVec2 button_sz(40, 40);
4265 ImGui::Button("A", button_sz); ImGui::SameLine();
4266 ImGui::Dummy(button_sz); ImGui::SameLine();
4267 ImGui::Button("B", button_sz);
4268
4269 // Manually wrapping
4270 // (we should eventually provide this as an automatic layout feature, but for now you can do it manually)
4271 IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Manual wrapping");
4272 ImGui::Text("Manual wrapping:");
4273 ImGuiStyle& style = ImGui::GetStyle();
4274 int buttons_count = 20;
4275 float window_visible_x2 = ImGui::GetCursorScreenPos().x + ImGui::GetContentRegionAvail().x;
4276 for (int n = 0; n < buttons_count; n++)
4277 {
4278 ImGui::PushID(n);
4279 ImGui::Button("Box", button_sz);
4280 float last_button_x2 = ImGui::GetItemRectMax().x;
4281 float next_button_x2 = last_button_x2 + style.ItemSpacing.x + button_sz.x; // Expected position if next button was on same line
4282 if (n + 1 < buttons_count && next_button_x2 < window_visible_x2)
4283 ImGui::SameLine();
4284 ImGui::PopID();
4285 }
4286
4287 ImGui::TreePop();
4288 }
4289
4290 IMGUI_DEMO_MARKER("Layout/Groups");
4291 if (ImGui::TreeNode("Groups"))
4292 {
4293 HelpMarker(
4294 "BeginGroup() basically locks the horizontal position for new line. "
4295 "EndGroup() bundles the whole group so that you can use \"item\" functions such as "
4296 "IsItemHovered()/IsItemActive() or SameLine() etc. on the whole group.");
4297 ImGui::BeginGroup();
4298 {
4299 ImGui::BeginGroup();
4300 ImGui::Button("AAA");
4301 ImGui::SameLine();
4302 ImGui::Button("BBB");
4303 ImGui::SameLine();
4304 ImGui::BeginGroup();
4305 ImGui::Button("CCC");
4306 ImGui::Button("DDD");
4307 ImGui::EndGroup();
4308 ImGui::SameLine();
4309 ImGui::Button("EEE");
4310 ImGui::EndGroup();
4311 ImGui::SetItemTooltip("First group hovered");
4312 }
4313 // Capture the group size and create widgets using the same size
4314 ImVec2 size = ImGui::GetItemRectSize();
4315 const float values[5] = { 0.5f, 0.20f, 0.80f, 0.60f, 0.25f };
4316 ImGui::PlotHistogram("##values", values, IM_ARRAYSIZE(values), 0, NULL, 0.0f, 1.0f, size);
4317
4318 ImGui::Button("ACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y));
4319 ImGui::SameLine();
4320 ImGui::Button("REACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y));
4321 ImGui::EndGroup();
4322 ImGui::SameLine();
4323
4324 ImGui::Button("LEVERAGE\nBUZZWORD", size);
4325 ImGui::SameLine();
4326
4327 if (ImGui::BeginListBox("List", size))
4328 {
4329 ImGui::Selectable("Selected", true);
4330 ImGui::Selectable("Not Selected", false);
4331 ImGui::EndListBox();
4332 }
4333
4334 ImGui::TreePop();
4335 }
4336
4337 IMGUI_DEMO_MARKER("Layout/Text Baseline Alignment");
4338 if (ImGui::TreeNode("Text Baseline Alignment"))
4339 {
4340 {
4341 ImGui::BulletText("Text baseline:");
4342 ImGui::SameLine(); HelpMarker(
4343 "This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. "
4344 "Lines only composed of text or \"small\" widgets use less vertical space than lines with framed widgets.");
4345 ImGui::Indent();
4346
4347 ImGui::Text("KO Blahblah"); ImGui::SameLine();
4348 ImGui::Button("Some framed item"); ImGui::SameLine();
4349 HelpMarker("Baseline of button will look misaligned with text..");
4350
4351 // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets.
4352 // (because we don't know what's coming after the Text() statement, we need to move the text baseline
4353 // down by FramePadding.y ahead of time)
4354 ImGui::AlignTextToFramePadding();
4355 ImGui::Text("OK Blahblah"); ImGui::SameLine();
4356 ImGui::Button("Some framed item##2"); ImGui::SameLine();
4357 HelpMarker("We call AlignTextToFramePadding() to vertically align the text baseline by +FramePadding.y");
4358
4359 // SmallButton() uses the same vertical padding as Text
4360 ImGui::Button("TEST##1"); ImGui::SameLine();
4361 ImGui::Text("TEST"); ImGui::SameLine();
4362 ImGui::SmallButton("TEST##2");
4363
4364 // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets.
4365 ImGui::AlignTextToFramePadding();
4366 ImGui::Text("Text aligned to framed item"); ImGui::SameLine();
4367 ImGui::Button("Item##1"); ImGui::SameLine();
4368 ImGui::Text("Item"); ImGui::SameLine();
4369 ImGui::SmallButton("Item##2"); ImGui::SameLine();
4370 ImGui::Button("Item##3");
4371
4372 ImGui::Unindent();
4373 }
4374
4375 ImGui::Spacing();
4376
4377 {
4378 ImGui::BulletText("Multi-line text:");
4379 ImGui::Indent();
4380 ImGui::Text("One\nTwo\nThree"); ImGui::SameLine();
4381 ImGui::Text("Hello\nWorld"); ImGui::SameLine();
4382 ImGui::Text("Banana");
4383
4384 ImGui::Text("Banana"); ImGui::SameLine();
4385 ImGui::Text("Hello\nWorld"); ImGui::SameLine();
4386 ImGui::Text("One\nTwo\nThree");
4387
4388 ImGui::Button("HOP##1"); ImGui::SameLine();
4389 ImGui::Text("Banana"); ImGui::SameLine();
4390 ImGui::Text("Hello\nWorld"); ImGui::SameLine();
4391 ImGui::Text("Banana");
4392
4393 ImGui::Button("HOP##2"); ImGui::SameLine();
4394 ImGui::Text("Hello\nWorld"); ImGui::SameLine();
4395 ImGui::Text("Banana");
4396 ImGui::Unindent();
4397 }
4398
4399 ImGui::Spacing();
4400
4401 {
4402 ImGui::BulletText("Misc items:");
4403 ImGui::Indent();
4404
4405 // SmallButton() sets FramePadding to zero. Text baseline is aligned to match baseline of previous Button.
4406 ImGui::Button("80x80", ImVec2(80, 80));
4407 ImGui::SameLine();
4408 ImGui::Button("50x50", ImVec2(50, 50));
4409 ImGui::SameLine();
4410 ImGui::Button("Button()");
4411 ImGui::SameLine();
4412 ImGui::SmallButton("SmallButton()");
4413
4414 // Tree
4415 const float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
4416 ImGui::Button("Button##1");
4417 ImGui::SameLine(0.0f, spacing);
4418 if (ImGui::TreeNode("Node##1"))
4419 {
4420 // Placeholder tree data
4421 for (int i = 0; i < 6; i++)
4422 ImGui::BulletText("Item %d..", i);
4423 ImGui::TreePop();
4424 }
4425
4426 // Vertically align text node a bit lower so it'll be vertically centered with upcoming widget.
4427 // Otherwise you can use SmallButton() (smaller fit).
4428 ImGui::AlignTextToFramePadding();
4429
4430 // Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add
4431 // other contents below the node.
4432 bool node_open = ImGui::TreeNode("Node##2");
4433 ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##2");
4434 if (node_open)
4435 {
4436 // Placeholder tree data
4437 for (int i = 0; i < 6; i++)
4438 ImGui::BulletText("Item %d..", i);
4439 ImGui::TreePop();
4440 }
4441
4442 // Bullet
4443 ImGui::Button("Button##3");
4444 ImGui::SameLine(0.0f, spacing);
4445 ImGui::BulletText("Bullet text");
4446
4447 ImGui::AlignTextToFramePadding();
4448 ImGui::BulletText("Node");
4449 ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##4");
4450 ImGui::Unindent();
4451 }
4452
4453 ImGui::TreePop();
4454 }
4455
4456 IMGUI_DEMO_MARKER("Layout/Scrolling");
4457 if (ImGui::TreeNode("Scrolling"))
4458 {
4459 // Vertical scroll functions
4460 IMGUI_DEMO_MARKER("Layout/Scrolling/Vertical");
4461 HelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given vertical position.");
4462
4463 static int track_item = 50;
4464 static bool enable_track = true;
4465 static bool enable_extra_decorations = false;
4466 static float scroll_to_off_px = 0.0f;
4467 static float scroll_to_pos_px = 200.0f;
4468
4469 ImGui::Checkbox("Decoration", &enable_extra_decorations);
4470
4471 ImGui::Checkbox("Track", &enable_track);
4472 ImGui::PushItemWidth(100);
4473 ImGui::SameLine(140); enable_track |= ImGui::DragInt("##item", &track_item, 0.25f, 0, 99, "Item = %d");
4474
4475 bool scroll_to_off = ImGui::Button("Scroll Offset");
4476 ImGui::SameLine(140); scroll_to_off |= ImGui::DragFloat("##off", &scroll_to_off_px, 1.00f, 0, FLT_MAX, "+%.0f px");
4477
4478 bool scroll_to_pos = ImGui::Button("Scroll To Pos");
4479 ImGui::SameLine(140); scroll_to_pos |= ImGui::DragFloat("##pos", &scroll_to_pos_px, 1.00f, -10, FLT_MAX, "X/Y = %.0f px");
4480 ImGui::PopItemWidth();
4481
4482 if (scroll_to_off || scroll_to_pos)
4483 enable_track = false;
4484
4485 ImGuiStyle& style = ImGui::GetStyle();
4486 float child_w = (ImGui::GetContentRegionAvail().x - 4 * style.ItemSpacing.x) / 5;
4487 if (child_w < 1.0f)
4488 child_w = 1.0f;
4489 ImGui::PushID("##VerticalScrolling");
4490 for (int i = 0; i < 5; i++)
4491 {
4492 if (i > 0) ImGui::SameLine();
4493 ImGui::BeginGroup();
4494 const char* names[] = { "Top", "25%", "Center", "75%", "Bottom" };
4495 ImGui::TextUnformatted(names[i]);
4496
4497 const ImGuiWindowFlags child_flags = enable_extra_decorations ? ImGuiWindowFlags_MenuBar : 0;
4498 const ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i);
4499 const bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(child_w, 200.0f), ImGuiChildFlags_Borders, child_flags);
4500 if (ImGui::BeginMenuBar())
4501 {
4503 ImGui::EndMenuBar();
4504 }
4505 if (scroll_to_off)
4506 ImGui::SetScrollY(scroll_to_off_px);
4507 if (scroll_to_pos)
4508 ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_pos_px, i * 0.25f);
4509 if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items
4510 {
4511 for (int item = 0; item < 100; item++)
4512 {
4513 if (enable_track && item == track_item)
4514 {
4515 ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item);
4516 ImGui::SetScrollHereY(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom
4517 }
4518 else
4519 {
4520 ImGui::Text("Item %d", item);
4521 }
4522 }
4523 }
4524 float scroll_y = ImGui::GetScrollY();
4525 float scroll_max_y = ImGui::GetScrollMaxY();
4526 ImGui::EndChild();
4527 ImGui::Text("%.0f/%.0f", scroll_y, scroll_max_y);
4528 ImGui::EndGroup();
4529 }
4530 ImGui::PopID();
4531
4532 // Horizontal scroll functions
4533 IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal");
4534 ImGui::Spacing();
4535 HelpMarker(
4536 "Use SetScrollHereX() or SetScrollFromPosX() to scroll to a given horizontal position.\n\n"
4537 "Because the clipping rectangle of most window hides half worth of WindowPadding on the "
4538 "left/right, using SetScrollFromPosX(+1) will usually result in clipped text whereas the "
4539 "equivalent SetScrollFromPosY(+1) wouldn't.");
4540 ImGui::PushID("##HorizontalScrolling");
4541 for (int i = 0; i < 5; i++)
4542 {
4543 float child_height = ImGui::GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0f;
4544 ImGuiWindowFlags child_flags = ImGuiWindowFlags_HorizontalScrollbar | (enable_extra_decorations ? ImGuiWindowFlags_AlwaysVerticalScrollbar : 0);
4545 ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i);
4546 bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(-100, child_height), ImGuiChildFlags_Borders, child_flags);
4547 if (scroll_to_off)
4548 ImGui::SetScrollX(scroll_to_off_px);
4549 if (scroll_to_pos)
4550 ImGui::SetScrollFromPosX(ImGui::GetCursorStartPos().x + scroll_to_pos_px, i * 0.25f);
4551 if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items
4552 {
4553 for (int item = 0; item < 100; item++)
4554 {
4555 if (item > 0)
4556 ImGui::SameLine();
4557 if (enable_track && item == track_item)
4558 {
4559 ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item);
4560 ImGui::SetScrollHereX(i * 0.25f); // 0.0f:left, 0.5f:center, 1.0f:right
4561 }
4562 else
4563 {
4564 ImGui::Text("Item %d", item);
4565 }
4566 }
4567 }
4568 float scroll_x = ImGui::GetScrollX();
4569 float scroll_max_x = ImGui::GetScrollMaxX();
4570 ImGui::EndChild();
4571 ImGui::SameLine();
4572 const char* names[] = { "Left", "25%", "Center", "75%", "Right" };
4573 ImGui::Text("%s\n%.0f/%.0f", names[i], scroll_x, scroll_max_x);
4574 ImGui::Spacing();
4575 }
4576 ImGui::PopID();
4577
4578 // Miscellaneous Horizontal Scrolling Demo
4579 IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal (more)");
4580 HelpMarker(
4581 "Horizontal scrolling for a window is enabled via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\n"
4582 "You may want to also explicitly specify content width by using SetNextWindowContentWidth() before Begin().");
4583 static int lines = 7;
4584 ImGui::SliderInt("Lines", &lines, 1, 15);
4585 ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
4586 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f));
4587 ImVec2 scrolling_child_size = ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30);
4588 ImGui::BeginChild("scrolling", scrolling_child_size, ImGuiChildFlags_Borders, ImGuiWindowFlags_HorizontalScrollbar);
4589 for (int line = 0; line < lines; line++)
4590 {
4591 // Display random stuff. For the sake of this trivial demo we are using basic Button() + SameLine()
4592 // If you want to create your own time line for a real application you may be better off manipulating
4593 // the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets
4594 // yourself. You may also want to use the lower-level ImDrawList API.
4595 int num_buttons = 10 + ((line & 1) ? line * 9 : line * 3);
4596 for (int n = 0; n < num_buttons; n++)
4597 {
4598 if (n > 0) ImGui::SameLine();
4599 ImGui::PushID(n + line * 1000);
4600 char num_buf[16];
4601 sprintf(num_buf, "%d", n);
4602 const char* label = (!(n % 15)) ? "FizzBuzz" : (!(n % 3)) ? "Fizz" : (!(n % 5)) ? "Buzz" : num_buf;
4603 float hue = n * 0.05f;
4604 ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(hue, 0.6f, 0.6f));
4605 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(hue, 0.7f, 0.7f));
4606 ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(hue, 0.8f, 0.8f));
4607 ImGui::Button(label, ImVec2(40.0f + sinf((float)(line + n)) * 20.0f, 0.0f));
4608 ImGui::PopStyleColor(3);
4609 ImGui::PopID();
4610 }
4611 }
4612 float scroll_x = ImGui::GetScrollX();
4613 float scroll_max_x = ImGui::GetScrollMaxX();
4614 ImGui::EndChild();
4615 ImGui::PopStyleVar(2);
4616 float scroll_x_delta = 0.0f;
4617 ImGui::SmallButton("<<");
4618 if (ImGui::IsItemActive())
4619 scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f;
4620 ImGui::SameLine();
4621 ImGui::Text("Scroll from code"); ImGui::SameLine();
4622 ImGui::SmallButton(">>");
4623 if (ImGui::IsItemActive())
4624 scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f;
4625 ImGui::SameLine();
4626 ImGui::Text("%.0f/%.0f", scroll_x, scroll_max_x);
4627 if (scroll_x_delta != 0.0f)
4628 {
4629 // Demonstrate a trick: you can use Begin to set yourself in the context of another window
4630 // (here we are already out of your child window)
4631 ImGui::BeginChild("scrolling");
4632 ImGui::SetScrollX(ImGui::GetScrollX() + scroll_x_delta);
4633 ImGui::EndChild();
4634 }
4635 ImGui::Spacing();
4636
4637 static bool show_horizontal_contents_size_demo_window = false;
4638 ImGui::Checkbox("Show Horizontal contents size demo window", &show_horizontal_contents_size_demo_window);
4639
4640 if (show_horizontal_contents_size_demo_window)
4641 {
4642 static bool show_h_scrollbar = true;
4643 static bool show_button = true;
4644 static bool show_tree_nodes = true;
4645 static bool show_text_wrapped = false;
4646 static bool show_columns = true;
4647 static bool show_tab_bar = true;
4648 static bool show_child = false;
4649 static bool explicit_content_size = false;
4650 static float contents_size_x = 300.0f;
4651 if (explicit_content_size)
4652 ImGui::SetNextWindowContentSize(ImVec2(contents_size_x, 0.0f));
4653 ImGui::Begin("Horizontal contents size demo window", &show_horizontal_contents_size_demo_window, show_h_scrollbar ? ImGuiWindowFlags_HorizontalScrollbar : 0);
4654 IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal contents size demo window");
4655 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 0));
4656 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 0));
4657 HelpMarker(
4658 "Test how different widgets react and impact the work rectangle growing when horizontal scrolling is enabled.\n\n"
4659 "Use 'Metrics->Tools->Show windows rectangles' to visualize rectangles.");
4660 ImGui::Checkbox("H-scrollbar", &show_h_scrollbar);
4661 ImGui::Checkbox("Button", &show_button); // Will grow contents size (unless explicitly overwritten)
4662 ImGui::Checkbox("Tree nodes", &show_tree_nodes); // Will grow contents size and display highlight over full width
4663 ImGui::Checkbox("Text wrapped", &show_text_wrapped);// Will grow and use contents size
4664 ImGui::Checkbox("Columns", &show_columns); // Will use contents size
4665 ImGui::Checkbox("Tab bar", &show_tab_bar); // Will use contents size
4666 ImGui::Checkbox("Child", &show_child); // Will grow and use contents size
4667 ImGui::Checkbox("Explicit content size", &explicit_content_size);
4668 ImGui::Text("Scroll %.1f/%.1f %.1f/%.1f", ImGui::GetScrollX(), ImGui::GetScrollMaxX(), ImGui::GetScrollY(), ImGui::GetScrollMaxY());
4669 if (explicit_content_size)
4670 {
4671 ImGui::SameLine();
4672 ImGui::SetNextItemWidth(100);
4673 ImGui::DragFloat("##csx", &contents_size_x);
4674 ImVec2 p = ImGui::GetCursorScreenPos();
4675 ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + 10, p.y + 10), IM_COL32_WHITE);
4676 ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(p.x + contents_size_x - 10, p.y), ImVec2(p.x + contents_size_x, p.y + 10), IM_COL32_WHITE);
4677 ImGui::Dummy(ImVec2(0, 10));
4678 }
4679 ImGui::PopStyleVar(2);
4680 ImGui::Separator();
4681 if (show_button)
4682 {
4683 ImGui::Button("this is a 300-wide button", ImVec2(300, 0));
4684 }
4685 if (show_tree_nodes)
4686 {
4687 bool open = true;
4688 if (ImGui::TreeNode("this is a tree node"))
4689 {
4690 if (ImGui::TreeNode("another one of those tree node..."))
4691 {
4692 ImGui::Text("Some tree contents");
4693 ImGui::TreePop();
4694 }
4695 ImGui::TreePop();
4696 }
4697 ImGui::CollapsingHeader("CollapsingHeader", &open);
4698 }
4699 if (show_text_wrapped)
4700 {
4701 ImGui::TextWrapped("This text should automatically wrap on the edge of the work rectangle.");
4702 }
4703 if (show_columns)
4704 {
4705 ImGui::Text("Tables:");
4706 if (ImGui::BeginTable("table", 4, ImGuiTableFlags_Borders))
4707 {
4708 for (int n = 0; n < 4; n++)
4709 {
4710 ImGui::TableNextColumn();
4711 ImGui::Text("Width %.2f", ImGui::GetContentRegionAvail().x);
4712 }
4713 ImGui::EndTable();
4714 }
4715 ImGui::Text("Columns:");
4716 ImGui::Columns(4);
4717 for (int n = 0; n < 4; n++)
4718 {
4719 ImGui::Text("Width %.2f", ImGui::GetColumnWidth());
4720 ImGui::NextColumn();
4721 }
4722 ImGui::Columns(1);
4723 }
4724 if (show_tab_bar && ImGui::BeginTabBar("Hello"))
4725 {
4726 if (ImGui::BeginTabItem("OneOneOne")) { ImGui::EndTabItem(); }
4727 if (ImGui::BeginTabItem("TwoTwoTwo")) { ImGui::EndTabItem(); }
4728 if (ImGui::BeginTabItem("ThreeThreeThree")) { ImGui::EndTabItem(); }
4729 if (ImGui::BeginTabItem("FourFourFour")) { ImGui::EndTabItem(); }
4730 ImGui::EndTabBar();
4731 }
4732 if (show_child)
4733 {
4734 ImGui::BeginChild("child", ImVec2(0, 0), ImGuiChildFlags_Borders);
4735 ImGui::EndChild();
4736 }
4737 ImGui::End();
4738 }
4739
4740 ImGui::TreePop();
4741 }
4742
4743 IMGUI_DEMO_MARKER("Layout/Text Clipping");
4744 if (ImGui::TreeNode("Text Clipping"))
4745 {
4746 static ImVec2 size(100.0f, 100.0f);
4747 static ImVec2 offset(30.0f, 30.0f);
4748 ImGui::DragFloat2("size", (float*)&size, 0.5f, 1.0f, 200.0f, "%.0f");
4749 ImGui::TextWrapped("(Click and drag to scroll)");
4750
4751 HelpMarker(
4752 "(Left) Using ImGui::PushClipRect():\n"
4753 "Will alter ImGui hit-testing logic + ImDrawList rendering.\n"
4754 "(use this if you want your clipping rectangle to affect interactions)\n\n"
4755 "(Center) Using ImDrawList::PushClipRect():\n"
4756 "Will alter ImDrawList rendering only.\n"
4757 "(use this as a shortcut if you are only using ImDrawList calls)\n\n"
4758 "(Right) Using ImDrawList::AddText() with a fine ClipRect:\n"
4759 "Will alter only this specific ImDrawList::AddText() rendering.\n"
4760 "This is often used internally to avoid altering the clipping rectangle and minimize draw calls.");
4761
4762 for (int n = 0; n < 3; n++)
4763 {
4764 if (n > 0)
4765 ImGui::SameLine();
4766
4767 ImGui::PushID(n);
4768 ImGui::InvisibleButton("##canvas", size);
4769 if (ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left))
4770 {
4771 offset.x += ImGui::GetIO().MouseDelta.x;
4772 offset.y += ImGui::GetIO().MouseDelta.y;
4773 }
4774 ImGui::PopID();
4775 if (!ImGui::IsItemVisible()) // Skip rendering as ImDrawList elements are not clipped.
4776 continue;
4777
4778 const ImVec2 p0 = ImGui::GetItemRectMin();
4779 const ImVec2 p1 = ImGui::GetItemRectMax();
4780 const char* text_str = "Line 1 hello\nLine 2 clip me!";
4781 const ImVec2 text_pos = ImVec2(p0.x + offset.x, p0.y + offset.y);
4782 ImDrawList* draw_list = ImGui::GetWindowDrawList();
4783 switch (n)
4784 {
4785 case 0:
4786 ImGui::PushClipRect(p0, p1, true);
4787 draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
4788 draw_list->AddText(text_pos, IM_COL32_WHITE, text_str);
4789 ImGui::PopClipRect();
4790 break;
4791 case 1:
4792 draw_list->PushClipRect(p0, p1, true);
4793 draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
4794 draw_list->AddText(text_pos, IM_COL32_WHITE, text_str);
4795 draw_list->PopClipRect();
4796 break;
4797 case 2:
4798 ImVec4 clip_rect(p0.x, p0.y, p1.x, p1.y); // AddText() takes a ImVec4* here so let's convert.
4799 draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
4800 draw_list->AddText(ImGui::GetFont(), ImGui::GetFontSize(), text_pos, IM_COL32_WHITE, text_str, NULL, 0.0f, &clip_rect);
4801 break;
4802 }
4803 }
4804
4805 ImGui::TreePop();
4806 }
4807
4808 IMGUI_DEMO_MARKER("Layout/Overlap Mode");
4809 if (ImGui::TreeNode("Overlap Mode"))
4810 {
4811 static bool enable_allow_overlap = true;
4812
4813 HelpMarker(
4814 "Hit-testing is by default performed in item submission order, which generally is perceived as 'back-to-front'.\n\n"
4815 "By using SetNextItemAllowOverlap() you can notify that an item may be overlapped by another. "
4816 "Doing so alters the hovering logic: items using AllowOverlap mode requires an extra frame to accept hovered state.");
4817 ImGui::Checkbox("Enable AllowOverlap", &enable_allow_overlap);
4818
4819 ImVec2 button1_pos = ImGui::GetCursorScreenPos();
4820 ImVec2 button2_pos = ImVec2(button1_pos.x + 50.0f, button1_pos.y + 50.0f);
4821 if (enable_allow_overlap)
4822 ImGui::SetNextItemAllowOverlap();
4823 ImGui::Button("Button 1", ImVec2(80, 80));
4824 ImGui::SetCursorScreenPos(button2_pos);
4825 ImGui::Button("Button 2", ImVec2(80, 80));
4826
4827 // This is typically used with width-spanning items.
4828 // (note that Selectable() has a dedicated flag ImGuiSelectableFlags_AllowOverlap, which is a shortcut
4829 // for using SetNextItemAllowOverlap(). For demo purpose we use SetNextItemAllowOverlap() here.)
4830 if (enable_allow_overlap)
4831 ImGui::SetNextItemAllowOverlap();
4832 ImGui::Selectable("Some Selectable", false);
4833 ImGui::SameLine();
4834 ImGui::SmallButton("++");
4835
4836 ImGui::TreePop();
4837 }
4838}
4839
4840//-----------------------------------------------------------------------------
4841// [SECTION] ShowDemoWindowPopups()
4842//-----------------------------------------------------------------------------
4843
4844static void ShowDemoWindowPopups()
4845{
4846 IMGUI_DEMO_MARKER("Popups");
4847 if (!ImGui::CollapsingHeader("Popups & Modal windows"))
4848 return;
4849
4850 // The properties of popups windows are:
4851 // - They block normal mouse hovering detection outside them. (*)
4852 // - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE.
4853 // - Their visibility state (~bool) is held internally by Dear ImGui instead of being held by the programmer as
4854 // we are used to with regular Begin() calls. User can manipulate the visibility state by calling OpenPopup().
4855 // (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even
4856 // when normally blocked by a popup.
4857 // Those three properties are connected. The library needs to hold their visibility state BECAUSE it can close
4858 // popups at any time.
4859
4860 // Typical use for regular windows:
4861 // bool my_tool_is_active = false; if (ImGui::Button("Open")) my_tool_is_active = true; [...] if (my_tool_is_active) Begin("My Tool", &my_tool_is_active) { [...] } End();
4862 // Typical use for popups:
4863 // if (ImGui::Button("Open")) ImGui::OpenPopup("MyPopup"); if (ImGui::BeginPopup("MyPopup") { [...] EndPopup(); }
4864
4865 // With popups we have to go through a library call (here OpenPopup) to manipulate the visibility state.
4866 // This may be a bit confusing at first but it should quickly make sense. Follow on the examples below.
4867
4868 IMGUI_DEMO_MARKER("Popups/Popups");
4869 if (ImGui::TreeNode("Popups"))
4870 {
4871 ImGui::TextWrapped(
4872 "When a popup is active, it inhibits interacting with windows that are behind the popup. "
4873 "Clicking outside the popup closes it.");
4874
4875 static int selected_fish = -1;
4876 const char* names[] = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" };
4877 static bool toggles[] = { true, false, false, false, false };
4878
4879 // Simple selection popup (if you want to show the current selection inside the Button itself,
4880 // you may want to build a string using the "###" operator to preserve a constant ID with a variable label)
4881 if (ImGui::Button("Select.."))
4882 ImGui::OpenPopup("my_select_popup");
4883 ImGui::SameLine();
4884 ImGui::TextUnformatted(selected_fish == -1 ? "<None>" : names[selected_fish]);
4885 if (ImGui::BeginPopup("my_select_popup"))
4886 {
4887 ImGui::SeparatorText("Aquarium");
4888 for (int i = 0; i < IM_ARRAYSIZE(names); i++)
4889 if (ImGui::Selectable(names[i]))
4890 selected_fish = i;
4891 ImGui::EndPopup();
4892 }
4893
4894 // Showing a menu with toggles
4895 if (ImGui::Button("Toggle.."))
4896 ImGui::OpenPopup("my_toggle_popup");
4897 if (ImGui::BeginPopup("my_toggle_popup"))
4898 {
4899 for (int i = 0; i < IM_ARRAYSIZE(names); i++)
4900 ImGui::MenuItem(names[i], "", &toggles[i]);
4901 if (ImGui::BeginMenu("Sub-menu"))
4902 {
4903 ImGui::MenuItem("Click me");
4904 ImGui::EndMenu();
4905 }
4906
4907 ImGui::Separator();
4908 ImGui::Text("Tooltip here");
4909 ImGui::SetItemTooltip("I am a tooltip over a popup");
4910
4911 if (ImGui::Button("Stacked Popup"))
4912 ImGui::OpenPopup("another popup");
4913 if (ImGui::BeginPopup("another popup"))
4914 {
4915 for (int i = 0; i < IM_ARRAYSIZE(names); i++)
4916 ImGui::MenuItem(names[i], "", &toggles[i]);
4917 if (ImGui::BeginMenu("Sub-menu"))
4918 {
4919 ImGui::MenuItem("Click me");
4920 if (ImGui::Button("Stacked Popup"))
4921 ImGui::OpenPopup("another popup");
4922 if (ImGui::BeginPopup("another popup"))
4923 {
4924 ImGui::Text("I am the last one here.");
4925 ImGui::EndPopup();
4926 }
4927 ImGui::EndMenu();
4928 }
4929 ImGui::EndPopup();
4930 }
4931 ImGui::EndPopup();
4932 }
4933
4934 // Call the more complete ShowExampleMenuFile which we use in various places of this demo
4935 if (ImGui::Button("With a menu.."))
4936 ImGui::OpenPopup("my_file_popup");
4937 if (ImGui::BeginPopup("my_file_popup", ImGuiWindowFlags_MenuBar))
4938 {
4939 if (ImGui::BeginMenuBar())
4940 {
4941 if (ImGui::BeginMenu("File"))
4942 {
4943 ShowExampleMenuFile();
4944 ImGui::EndMenu();
4945 }
4946 if (ImGui::BeginMenu("Edit"))
4947 {
4948 ImGui::MenuItem("Dummy");
4949 ImGui::EndMenu();
4950 }
4951 ImGui::EndMenuBar();
4952 }
4953 ImGui::Text("Hello from popup!");
4954 ImGui::Button("This is a dummy button..");
4955 ImGui::EndPopup();
4956 }
4957
4958 ImGui::TreePop();
4959 }
4960
4961 IMGUI_DEMO_MARKER("Popups/Context menus");
4962 if (ImGui::TreeNode("Context menus"))
4963 {
4964 HelpMarker("\"Context\" functions are simple helpers to associate a Popup to a given Item or Window identifier.");
4965
4966 // BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing:
4967 // if (id == 0)
4968 // id = GetItemID(); // Use last item id
4969 // if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right))
4970 // OpenPopup(id);
4971 // return BeginPopup(id);
4972 // For advanced uses you may want to replicate and customize this code.
4973 // See more details in BeginPopupContextItem().
4974
4975 // Example 1
4976 // When used after an item that has an ID (e.g. Button), we can skip providing an ID to BeginPopupContextItem(),
4977 // and BeginPopupContextItem() will use the last item ID as the popup ID.
4978 {
4979 const char* names[5] = { "Label1", "Label2", "Label3", "Label4", "Label5" };
4980 static int selected = -1;
4981 for (int n = 0; n < 5; n++)
4982 {
4983 if (ImGui::Selectable(names[n], selected == n))
4984 selected = n;
4985 if (ImGui::BeginPopupContextItem()) // <-- use last item id as popup id
4986 {
4987 selected = n;
4988 ImGui::Text("This a popup for \"%s\"!", names[n]);
4989 if (ImGui::Button("Close"))
4990 ImGui::CloseCurrentPopup();
4991 ImGui::EndPopup();
4992 }
4993 ImGui::SetItemTooltip("Right-click to open popup");
4994 }
4995 }
4996
4997 // Example 2
4998 // Popup on a Text() element which doesn't have an identifier: we need to provide an identifier to BeginPopupContextItem().
4999 // Using an explicit identifier is also convenient if you want to activate the popups from different locations.
5000 {
5001 HelpMarker("Text() elements don't have stable identifiers so we need to provide one.");
5002 static float value = 0.5f;
5003 ImGui::Text("Value = %.3f <-- (1) right-click this text", value);
5004 if (ImGui::BeginPopupContextItem("my popup"))
5005 {
5006 if (ImGui::Selectable("Set to zero")) value = 0.0f;
5007 if (ImGui::Selectable("Set to PI")) value = 3.1415f;
5008 ImGui::SetNextItemWidth(-FLT_MIN);
5009 ImGui::DragFloat("##Value", &value, 0.1f, 0.0f, 0.0f);
5010 ImGui::EndPopup();
5011 }
5012
5013 // We can also use OpenPopupOnItemClick() to toggle the visibility of a given popup.
5014 // Here we make it that right-clicking this other text element opens the same popup as above.
5015 // The popup itself will be submitted by the code above.
5016 ImGui::Text("(2) Or right-click this text");
5017 ImGui::OpenPopupOnItemClick("my popup", ImGuiPopupFlags_MouseButtonRight);
5018
5019 // Back to square one: manually open the same popup.
5020 if (ImGui::Button("(3) Or click this button"))
5021 ImGui::OpenPopup("my popup");
5022 }
5023
5024 // Example 3
5025 // When using BeginPopupContextItem() with an implicit identifier (NULL == use last item ID),
5026 // we need to make sure your item identifier is stable.
5027 // In this example we showcase altering the item label while preserving its identifier, using the ### operator (see FAQ).
5028 {
5029 HelpMarker("Showcase using a popup ID linked to item ID, with the item having a changing label + stable ID using the ### operator.");
5030 static char name[32] = "Label1";
5031 char buf[64];
5032 sprintf(buf, "Button: %s###Button", name); // ### operator override ID ignoring the preceding label
5033 ImGui::Button(buf);
5034 if (ImGui::BeginPopupContextItem())
5035 {
5036 ImGui::Text("Edit name:");
5037 ImGui::InputText("##edit", name, IM_ARRAYSIZE(name));
5038 if (ImGui::Button("Close"))
5039 ImGui::CloseCurrentPopup();
5040 ImGui::EndPopup();
5041 }
5042 ImGui::SameLine(); ImGui::Text("(<-- right-click here)");
5043 }
5044
5045 ImGui::TreePop();
5046 }
5047
5048 IMGUI_DEMO_MARKER("Popups/Modals");
5049 if (ImGui::TreeNode("Modals"))
5050 {
5051 ImGui::TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside.");
5052
5053 if (ImGui::Button("Delete.."))
5054 ImGui::OpenPopup("Delete?");
5055
5056 // Always center this window when appearing
5057 ImVec2 center = ImGui::GetMainViewport()->GetCenter();
5058 ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
5059
5060 if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize))
5061 {
5062 ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!");
5063 ImGui::Separator();
5064
5065 //static int unused_i = 0;
5066 //ImGui::Combo("Combo", &unused_i, "Delete\0Delete harder\0");
5067
5068 static bool dont_ask_me_next_time = false;
5069 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
5070 ImGui::Checkbox("Don't ask me next time", &dont_ask_me_next_time);
5071 ImGui::PopStyleVar();
5072
5073 if (ImGui::Button("OK", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); }
5074 ImGui::SetItemDefaultFocus();
5075 ImGui::SameLine();
5076 if (ImGui::Button("Cancel", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); }
5077 ImGui::EndPopup();
5078 }
5079
5080 if (ImGui::Button("Stacked modals.."))
5081 ImGui::OpenPopup("Stacked 1");
5082 if (ImGui::BeginPopupModal("Stacked 1", NULL, ImGuiWindowFlags_MenuBar))
5083 {
5084 if (ImGui::BeginMenuBar())
5085 {
5086 if (ImGui::BeginMenu("File"))
5087 {
5088 if (ImGui::MenuItem("Some menu item")) {}
5089 ImGui::EndMenu();
5090 }
5091 ImGui::EndMenuBar();
5092 }
5093 ImGui::Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it.");
5094
5095 // Testing behavior of widgets stacking their own regular popups over the modal.
5096 static int item = 1;
5097 static float color[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
5098 ImGui::Combo("Combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
5099 ImGui::ColorEdit4("Color", color);
5100
5101 if (ImGui::Button("Add another modal.."))
5102 ImGui::OpenPopup("Stacked 2");
5103
5104 // Also demonstrate passing a bool* to BeginPopupModal(), this will create a regular close button which
5105 // will close the popup. Note that the visibility state of popups is owned by imgui, so the input value
5106 // of the bool actually doesn't matter here.
5107 bool unused_open = true;
5108 if (ImGui::BeginPopupModal("Stacked 2", &unused_open))
5109 {
5110 ImGui::Text("Hello from Stacked The Second!");
5111 ImGui::ColorEdit4("Color", color); // Allow opening another nested popup
5112 if (ImGui::Button("Close"))
5113 ImGui::CloseCurrentPopup();
5114 ImGui::EndPopup();
5115 }
5116
5117 if (ImGui::Button("Close"))
5118 ImGui::CloseCurrentPopup();
5119 ImGui::EndPopup();
5120 }
5121
5122 ImGui::TreePop();
5123 }
5124
5125 IMGUI_DEMO_MARKER("Popups/Menus inside a regular window");
5126 if (ImGui::TreeNode("Menus inside a regular window"))
5127 {
5128 ImGui::TextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!");
5129 ImGui::Separator();
5130
5131 ImGui::MenuItem("Menu item", "CTRL+M");
5132 if (ImGui::BeginMenu("Menu inside a regular window"))
5133 {
5134 ShowExampleMenuFile();
5135 ImGui::EndMenu();
5136 }
5137 ImGui::Separator();
5138 ImGui::TreePop();
5139 }
5140}
5141
5142// Dummy data structure that we use for the Table demo.
5143// (pre-C++11 doesn't allow us to instantiate ImVector<MyItem> template if this structure is defined inside the demo function)
5144namespace
5145{
5146// We are passing our own identifier to TableSetupColumn() to facilitate identifying columns in the sorting code.
5147// This identifier will be passed down into ImGuiTableSortSpec::ColumnUserID.
5148// But it is possible to omit the user id parameter of TableSetupColumn() and just use the column index instead! (ImGuiTableSortSpec::ColumnIndex)
5149// If you don't use sorting, you will generally never care about giving column an ID!
5150enum MyItemColumnID
5151{
5152 MyItemColumnID_ID,
5153 MyItemColumnID_Name,
5154 MyItemColumnID_Action,
5155 MyItemColumnID_Quantity,
5156 MyItemColumnID_Description
5157};
5158
5159struct MyItem
5160{
5161 int ID;
5162 const char* Name;
5163 int Quantity;
5164
5165 // We have a problem which is affecting _only this demo_ and should not affect your code:
5166 // As we don't rely on std:: or other third-party library to compile dear imgui, we only have reliable access to qsort(),
5167 // however qsort doesn't allow passing user data to comparing function.
5168 // As a workaround, we are storing the sort specs in a static/global for the comparing function to access.
5169 // In your own use case you would probably pass the sort specs to your sorting/comparing functions directly and not use a global.
5170 // We could technically call ImGui::TableGetSortSpecs() in CompareWithSortSpecs(), but considering that this function is called
5171 // very often by the sorting algorithm it would be a little wasteful.
5172 static const ImGuiTableSortSpecs* s_current_sort_specs;
5173
5174 static void SortWithSortSpecs(ImGuiTableSortSpecs* sort_specs, MyItem* items, int items_count)
5175 {
5176 s_current_sort_specs = sort_specs; // Store in variable accessible by the sort function.
5177 if (items_count > 1)
5178 qsort(items, (size_t)items_count, sizeof(items[0]), MyItem::CompareWithSortSpecs);
5179 s_current_sort_specs = NULL;
5180 }
5181
5182 // Compare function to be used by qsort()
5183 static int IMGUI_CDECL CompareWithSortSpecs(const void* lhs, const void* rhs)
5184 {
5185 const MyItem* a = (const MyItem*)lhs;
5186 const MyItem* b = (const MyItem*)rhs;
5187 for (int n = 0; n < s_current_sort_specs->SpecsCount; n++)
5188 {
5189 // Here we identify columns using the ColumnUserID value that we ourselves passed to TableSetupColumn()
5190 // We could also choose to identify columns based on their index (sort_spec->ColumnIndex), which is simpler!
5191 const ImGuiTableColumnSortSpecs* sort_spec = &s_current_sort_specs->Specs[n];
5192 int delta = 0;
5193 switch (sort_spec->ColumnUserID)
5194 {
5195 case MyItemColumnID_ID: delta = (a->ID - b->ID); break;
5196 case MyItemColumnID_Name: delta = (strcmp(a->Name, b->Name)); break;
5197 case MyItemColumnID_Quantity: delta = (a->Quantity - b->Quantity); break;
5198 case MyItemColumnID_Description: delta = (strcmp(a->Name, b->Name)); break;
5199 default: IM_ASSERT(0); break;
5200 }
5201 if (delta > 0)
5202 return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? +1 : -1;
5203 if (delta < 0)
5204 return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? -1 : +1;
5205 }
5206
5207 // qsort() is instable so always return a way to differenciate items.
5208 // Your own compare function may want to avoid fallback on implicit sort specs.
5209 // e.g. a Name compare if it wasn't already part of the sort specs.
5210 return (a->ID - b->ID);
5211 }
5212};
5213const ImGuiTableSortSpecs* MyItem::s_current_sort_specs = NULL;
5214}
5215
5216// Make the UI compact because there are so many fields
5217static void PushStyleCompact()
5218{
5219 ImGuiStyle& style = ImGui::GetStyle();
5220 ImGui::PushStyleVarY(ImGuiStyleVar_FramePadding, (float)(int)(style.FramePadding.y * 0.60f));
5221 ImGui::PushStyleVarY(ImGuiStyleVar_ItemSpacing, (float)(int)(style.ItemSpacing.y * 0.60f));
5222}
5223
5224static void PopStyleCompact()
5225{
5226 ImGui::PopStyleVar(2);
5227}
5228
5229// Show a combo box with a choice of sizing policies
5230static void EditTableSizingFlags(ImGuiTableFlags* p_flags)
5231{
5232 struct EnumDesc { ImGuiTableFlags Value; const char* Name; const char* Tooltip; };
5233 static const EnumDesc policies[] =
5234 {
5235 { ImGuiTableFlags_None, "Default", "Use default sizing policy:\n- ImGuiTableFlags_SizingFixedFit if ScrollX is on or if host window has ImGuiWindowFlags_AlwaysAutoResize.\n- ImGuiTableFlags_SizingStretchSame otherwise." },
5236 { ImGuiTableFlags_SizingFixedFit, "ImGuiTableFlags_SizingFixedFit", "Columns default to _WidthFixed (if resizable) or _WidthAuto (if not resizable), matching contents width." },
5237 { ImGuiTableFlags_SizingFixedSame, "ImGuiTableFlags_SizingFixedSame", "Columns are all the same width, matching the maximum contents width.\nImplicitly disable ImGuiTableFlags_Resizable and enable ImGuiTableFlags_NoKeepColumnsVisible." },
5238 { ImGuiTableFlags_SizingStretchProp, "ImGuiTableFlags_SizingStretchProp", "Columns default to _WidthStretch with weights proportional to their widths." },
5239 { ImGuiTableFlags_SizingStretchSame, "ImGuiTableFlags_SizingStretchSame", "Columns default to _WidthStretch with same weights." }
5240 };
5241 int idx;
5242 for (idx = 0; idx < IM_ARRAYSIZE(policies); idx++)
5243 if (policies[idx].Value == (*p_flags & ImGuiTableFlags_SizingMask_))
5244 break;
5245 const char* preview_text = (idx < IM_ARRAYSIZE(policies)) ? policies[idx].Name + (idx > 0 ? strlen("ImGuiTableFlags") : 0) : "";
5246 if (ImGui::BeginCombo("Sizing Policy", preview_text))
5247 {
5248 for (int n = 0; n < IM_ARRAYSIZE(policies); n++)
5249 if (ImGui::Selectable(policies[n].Name, idx == n))
5250 *p_flags = (*p_flags & ~ImGuiTableFlags_SizingMask_) | policies[n].Value;
5251 ImGui::EndCombo();
5252 }
5253 ImGui::SameLine();
5254 ImGui::TextDisabled("(?)");
5255 if (ImGui::BeginItemTooltip())
5256 {
5257 ImGui::PushTextWrapPos(ImGui::GetFontSize() * 50.0f);
5258 for (int m = 0; m < IM_ARRAYSIZE(policies); m++)
5259 {
5260 ImGui::Separator();
5261 ImGui::Text("%s:", policies[m].Name);
5262 ImGui::Separator();
5263 ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetStyle().IndentSpacing * 0.5f);
5264 ImGui::TextUnformatted(policies[m].Tooltip);
5265 }
5266 ImGui::PopTextWrapPos();
5267 ImGui::EndTooltip();
5268 }
5269}
5270
5271static void EditTableColumnsFlags(ImGuiTableColumnFlags* p_flags)
5272{
5273 ImGui::CheckboxFlags("_Disabled", p_flags, ImGuiTableColumnFlags_Disabled); ImGui::SameLine(); HelpMarker("Master disable flag (also hide from context menu)");
5274 ImGui::CheckboxFlags("_DefaultHide", p_flags, ImGuiTableColumnFlags_DefaultHide);
5275 ImGui::CheckboxFlags("_DefaultSort", p_flags, ImGuiTableColumnFlags_DefaultSort);
5276 if (ImGui::CheckboxFlags("_WidthStretch", p_flags, ImGuiTableColumnFlags_WidthStretch))
5277 *p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthStretch);
5278 if (ImGui::CheckboxFlags("_WidthFixed", p_flags, ImGuiTableColumnFlags_WidthFixed))
5279 *p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthFixed);
5280 ImGui::CheckboxFlags("_NoResize", p_flags, ImGuiTableColumnFlags_NoResize);
5281 ImGui::CheckboxFlags("_NoReorder", p_flags, ImGuiTableColumnFlags_NoReorder);
5282 ImGui::CheckboxFlags("_NoHide", p_flags, ImGuiTableColumnFlags_NoHide);
5283 ImGui::CheckboxFlags("_NoClip", p_flags, ImGuiTableColumnFlags_NoClip);
5284 ImGui::CheckboxFlags("_NoSort", p_flags, ImGuiTableColumnFlags_NoSort);
5285 ImGui::CheckboxFlags("_NoSortAscending", p_flags, ImGuiTableColumnFlags_NoSortAscending);
5286 ImGui::CheckboxFlags("_NoSortDescending", p_flags, ImGuiTableColumnFlags_NoSortDescending);
5287 ImGui::CheckboxFlags("_NoHeaderLabel", p_flags, ImGuiTableColumnFlags_NoHeaderLabel);
5288 ImGui::CheckboxFlags("_NoHeaderWidth", p_flags, ImGuiTableColumnFlags_NoHeaderWidth);
5289 ImGui::CheckboxFlags("_PreferSortAscending", p_flags, ImGuiTableColumnFlags_PreferSortAscending);
5290 ImGui::CheckboxFlags("_PreferSortDescending", p_flags, ImGuiTableColumnFlags_PreferSortDescending);
5291 ImGui::CheckboxFlags("_IndentEnable", p_flags, ImGuiTableColumnFlags_IndentEnable); ImGui::SameLine(); HelpMarker("Default for column 0");
5292 ImGui::CheckboxFlags("_IndentDisable", p_flags, ImGuiTableColumnFlags_IndentDisable); ImGui::SameLine(); HelpMarker("Default for column >0");
5293 ImGui::CheckboxFlags("_AngledHeader", p_flags, ImGuiTableColumnFlags_AngledHeader);
5294}
5295
5296static void ShowTableColumnsStatusFlags(ImGuiTableColumnFlags flags)
5297{
5298 ImGui::CheckboxFlags("_IsEnabled", &flags, ImGuiTableColumnFlags_IsEnabled);
5299 ImGui::CheckboxFlags("_IsVisible", &flags, ImGuiTableColumnFlags_IsVisible);
5300 ImGui::CheckboxFlags("_IsSorted", &flags, ImGuiTableColumnFlags_IsSorted);
5301 ImGui::CheckboxFlags("_IsHovered", &flags, ImGuiTableColumnFlags_IsHovered);
5302}
5303
5304//-----------------------------------------------------------------------------
5305// [SECTION] ShowDemoWindowTables()
5306//-----------------------------------------------------------------------------
5307
5308static void ShowDemoWindowTables()
5309{
5310 //ImGui::SetNextItemOpen(true, ImGuiCond_Once);
5311 IMGUI_DEMO_MARKER("Tables");
5312 if (!ImGui::CollapsingHeader("Tables & Columns"))
5313 return;
5314
5315 // Using those as a base value to create width/height that are factor of the size of our font
5316 const float TEXT_BASE_WIDTH = ImGui::CalcTextSize("A").x;
5317 const float TEXT_BASE_HEIGHT = ImGui::GetTextLineHeightWithSpacing();
5318
5319 ImGui::PushID("Tables");
5320
5321 int open_action = -1;
5322 if (ImGui::Button("Expand all"))
5323 open_action = 1;
5324 ImGui::SameLine();
5325 if (ImGui::Button("Collapse all"))
5326 open_action = 0;
5327 ImGui::SameLine();
5328
5329 // Options
5330 static bool disable_indent = false;
5331 ImGui::Checkbox("Disable tree indentation", &disable_indent);
5332 ImGui::SameLine();
5333 HelpMarker("Disable the indenting of tree nodes so demo tables can use the full window width.");
5334 ImGui::Separator();
5335 if (disable_indent)
5336 ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0.0f);
5337
5338 // About Styling of tables
5339 // Most settings are configured on a per-table basis via the flags passed to BeginTable() and TableSetupColumns APIs.
5340 // There are however a few settings that a shared and part of the ImGuiStyle structure:
5341 // style.CellPadding // Padding within each cell
5342 // style.Colors[ImGuiCol_TableHeaderBg] // Table header background
5343 // style.Colors[ImGuiCol_TableBorderStrong] // Table outer and header borders
5344 // style.Colors[ImGuiCol_TableBorderLight] // Table inner borders
5345 // style.Colors[ImGuiCol_TableRowBg] // Table row background when ImGuiTableFlags_RowBg is enabled (even rows)
5346 // style.Colors[ImGuiCol_TableRowBgAlt] // Table row background when ImGuiTableFlags_RowBg is enabled (odds rows)
5347
5348 // Demos
5349 if (open_action != -1)
5350 ImGui::SetNextItemOpen(open_action != 0);
5351 IMGUI_DEMO_MARKER("Tables/Basic");
5352 if (ImGui::TreeNode("Basic"))
5353 {
5354 // Here we will showcase three different ways to output a table.
5355 // They are very simple variations of a same thing!
5356
5357 // [Method 1] Using TableNextRow() to create a new row, and TableSetColumnIndex() to select the column.
5358 // In many situations, this is the most flexible and easy to use pattern.
5359 HelpMarker("Using TableNextRow() + calling TableSetColumnIndex() _before_ each cell, in a loop.");
5360 if (ImGui::BeginTable("table1", 3))
5361 {
5362 for (int row = 0; row < 4; row++)
5363 {
5364 ImGui::TableNextRow();
5365 for (int column = 0; column < 3; column++)
5366 {
5367 ImGui::TableSetColumnIndex(column);
5368 ImGui::Text("Row %d Column %d", row, column);
5369 }
5370 }
5371 ImGui::EndTable();
5372 }
5373
5374 // [Method 2] Using TableNextColumn() called multiple times, instead of using a for loop + TableSetColumnIndex().
5375 // This is generally more convenient when you have code manually submitting the contents of each column.
5376 HelpMarker("Using TableNextRow() + calling TableNextColumn() _before_ each cell, manually.");
5377 if (ImGui::BeginTable("table2", 3))
5378 {
5379 for (int row = 0; row < 4; row++)
5380 {
5381 ImGui::TableNextRow();
5382 ImGui::TableNextColumn();
5383 ImGui::Text("Row %d", row);
5384 ImGui::TableNextColumn();
5385 ImGui::Text("Some contents");
5386 ImGui::TableNextColumn();
5387 ImGui::Text("123.456");
5388 }
5389 ImGui::EndTable();
5390 }
5391
5392 // [Method 3] We call TableNextColumn() _before_ each cell. We never call TableNextRow(),
5393 // as TableNextColumn() will automatically wrap around and create new rows as needed.
5394 // This is generally more convenient when your cells all contains the same type of data.
5395 HelpMarker(
5396 "Only using TableNextColumn(), which tends to be convenient for tables where every cell contains "
5397 "the same type of contents.\n This is also more similar to the old NextColumn() function of the "
5398 "Columns API, and provided to facilitate the Columns->Tables API transition.");
5399 if (ImGui::BeginTable("table3", 3))
5400 {
5401 for (int item = 0; item < 14; item++)
5402 {
5403 ImGui::TableNextColumn();
5404 ImGui::Text("Item %d", item);
5405 }
5406 ImGui::EndTable();
5407 }
5408
5409 ImGui::TreePop();
5410 }
5411
5412 if (open_action != -1)
5413 ImGui::SetNextItemOpen(open_action != 0);
5414 IMGUI_DEMO_MARKER("Tables/Borders, background");
5415 if (ImGui::TreeNode("Borders, background"))
5416 {
5417 // Expose a few Borders related flags interactively
5418 enum ContentsType { CT_Text, CT_FillButton };
5419 static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg;
5420 static bool display_headers = false;
5421 static int contents_type = CT_Text;
5422
5423 PushStyleCompact();
5424 ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg);
5425 ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags, ImGuiTableFlags_Borders);
5426 ImGui::SameLine(); HelpMarker("ImGuiTableFlags_Borders\n = ImGuiTableFlags_BordersInnerV\n | ImGuiTableFlags_BordersOuterV\n | ImGuiTableFlags_BordersInnerH\n | ImGuiTableFlags_BordersOuterH");
5427 ImGui::Indent();
5428
5429 ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags, ImGuiTableFlags_BordersH);
5430 ImGui::Indent();
5431 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterH", &flags, ImGuiTableFlags_BordersOuterH);
5432 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerH", &flags, ImGuiTableFlags_BordersInnerH);
5433 ImGui::Unindent();
5434
5435 ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV);
5436 ImGui::Indent();
5437 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags, ImGuiTableFlags_BordersOuterV);
5438 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags, ImGuiTableFlags_BordersInnerV);
5439 ImGui::Unindent();
5440
5441 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuter", &flags, ImGuiTableFlags_BordersOuter);
5442 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInner", &flags, ImGuiTableFlags_BordersInner);
5443 ImGui::Unindent();
5444
5445 ImGui::AlignTextToFramePadding(); ImGui::Text("Cell contents:");
5446 ImGui::SameLine(); ImGui::RadioButton("Text", &contents_type, CT_Text);
5447 ImGui::SameLine(); ImGui::RadioButton("FillButton", &contents_type, CT_FillButton);
5448 ImGui::Checkbox("Display headers", &display_headers);
5449 ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers");
5450 PopStyleCompact();
5451
5452 if (ImGui::BeginTable("table1", 3, flags))
5453 {
5454 // Display headers so we can inspect their interaction with borders
5455 // (Headers are not the main purpose of this section of the demo, so we are not elaborating on them now. See other sections for details)
5456 if (display_headers)
5457 {
5458 ImGui::TableSetupColumn("One");
5459 ImGui::TableSetupColumn("Two");
5460 ImGui::TableSetupColumn("Three");
5461 ImGui::TableHeadersRow();
5462 }
5463
5464 for (int row = 0; row < 5; row++)
5465 {
5466 ImGui::TableNextRow();
5467 for (int column = 0; column < 3; column++)
5468 {
5469 ImGui::TableSetColumnIndex(column);
5470 char buf[32];
5471 sprintf(buf, "Hello %d,%d", column, row);
5472 if (contents_type == CT_Text)
5474 else if (contents_type == CT_FillButton)
5475 ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f));
5476 }
5477 }
5478 ImGui::EndTable();
5479 }
5480 ImGui::TreePop();
5481 }
5482
5483 if (open_action != -1)
5484 ImGui::SetNextItemOpen(open_action != 0);
5485 IMGUI_DEMO_MARKER("Tables/Resizable, stretch");
5486 if (ImGui::TreeNode("Resizable, stretch"))
5487 {
5488 // By default, if we don't enable ScrollX the sizing policy for each column is "Stretch"
5489 // All columns maintain a sizing weight, and they will occupy all available width.
5490 static ImGuiTableFlags flags = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody;
5491 PushStyleCompact();
5492 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
5493 ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV);
5494 ImGui::SameLine(); HelpMarker(
5495 "Using the _Resizable flag automatically enables the _BordersInnerV flag as well, "
5496 "this is why the resize borders are still showing when unchecking this.");
5497 PopStyleCompact();
5498
5499 if (ImGui::BeginTable("table1", 3, flags))
5500 {
5501 for (int row = 0; row < 5; row++)
5502 {
5503 ImGui::TableNextRow();
5504 for (int column = 0; column < 3; column++)
5505 {
5506 ImGui::TableSetColumnIndex(column);
5507 ImGui::Text("Hello %d,%d", column, row);
5508 }
5509 }
5510 ImGui::EndTable();
5511 }
5512 ImGui::TreePop();
5513 }
5514
5515 if (open_action != -1)
5516 ImGui::SetNextItemOpen(open_action != 0);
5517 IMGUI_DEMO_MARKER("Tables/Resizable, fixed");
5518 if (ImGui::TreeNode("Resizable, fixed"))
5519 {
5520 // Here we use ImGuiTableFlags_SizingFixedFit (even though _ScrollX is not set)
5521 // So columns will adopt the "Fixed" policy and will maintain a fixed width regardless of the whole available width (unless table is small)
5522 // If there is not enough available width to fit all columns, they will however be resized down.
5523 // FIXME-TABLE: Providing a stretch-on-init would make sense especially for tables which don't have saved settings
5524 HelpMarker(
5525 "Using _Resizable + _SizingFixedFit flags.\n"
5526 "Fixed-width columns generally makes more sense if you want to use horizontal scrolling.\n\n"
5527 "Double-click a column border to auto-fit the column to its contents.");
5528 PushStyleCompact();
5529 static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody;
5530 ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX);
5531 PopStyleCompact();
5532
5533 if (ImGui::BeginTable("table1", 3, flags))
5534 {
5535 for (int row = 0; row < 5; row++)
5536 {
5537 ImGui::TableNextRow();
5538 for (int column = 0; column < 3; column++)
5539 {
5540 ImGui::TableSetColumnIndex(column);
5541 ImGui::Text("Hello %d,%d", column, row);
5542 }
5543 }
5544 ImGui::EndTable();
5545 }
5546 ImGui::TreePop();
5547 }
5548
5549 if (open_action != -1)
5550 ImGui::SetNextItemOpen(open_action != 0);
5551 IMGUI_DEMO_MARKER("Tables/Resizable, mixed");
5552 if (ImGui::TreeNode("Resizable, mixed"))
5553 {
5554 HelpMarker(
5555 "Using TableSetupColumn() to alter resizing policy on a per-column basis.\n\n"
5556 "When combining Fixed and Stretch columns, generally you only want one, maybe two trailing columns to use _WidthStretch.");
5557 static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
5558
5559 if (ImGui::BeginTable("table1", 3, flags))
5560 {
5561 ImGui::TableSetupColumn("AAA", ImGuiTableColumnFlags_WidthFixed);
5562 ImGui::TableSetupColumn("BBB", ImGuiTableColumnFlags_WidthFixed);
5563 ImGui::TableSetupColumn("CCC", ImGuiTableColumnFlags_WidthStretch);
5564 ImGui::TableHeadersRow();
5565 for (int row = 0; row < 5; row++)
5566 {
5567 ImGui::TableNextRow();
5568 for (int column = 0; column < 3; column++)
5569 {
5570 ImGui::TableSetColumnIndex(column);
5571 ImGui::Text("%s %d,%d", (column == 2) ? "Stretch" : "Fixed", column, row);
5572 }
5573 }
5574 ImGui::EndTable();
5575 }
5576 if (ImGui::BeginTable("table2", 6, flags))
5577 {
5578 ImGui::TableSetupColumn("AAA", ImGuiTableColumnFlags_WidthFixed);
5579 ImGui::TableSetupColumn("BBB", ImGuiTableColumnFlags_WidthFixed);
5580 ImGui::TableSetupColumn("CCC", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_DefaultHide);
5581 ImGui::TableSetupColumn("DDD", ImGuiTableColumnFlags_WidthStretch);
5582 ImGui::TableSetupColumn("EEE", ImGuiTableColumnFlags_WidthStretch);
5583 ImGui::TableSetupColumn("FFF", ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_DefaultHide);
5584 ImGui::TableHeadersRow();
5585 for (int row = 0; row < 5; row++)
5586 {
5587 ImGui::TableNextRow();
5588 for (int column = 0; column < 6; column++)
5589 {
5590 ImGui::TableSetColumnIndex(column);
5591 ImGui::Text("%s %d,%d", (column >= 3) ? "Stretch" : "Fixed", column, row);
5592 }
5593 }
5594 ImGui::EndTable();
5595 }
5596 ImGui::TreePop();
5597 }
5598
5599 if (open_action != -1)
5600 ImGui::SetNextItemOpen(open_action != 0);
5601 IMGUI_DEMO_MARKER("Tables/Reorderable, hideable, with headers");
5602 if (ImGui::TreeNode("Reorderable, hideable, with headers"))
5603 {
5604 HelpMarker(
5605 "Click and drag column headers to reorder columns.\n\n"
5606 "Right-click on a header to open a context menu.");
5607 static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV;
5608 PushStyleCompact();
5609 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
5610 ImGui::CheckboxFlags("ImGuiTableFlags_Reorderable", &flags, ImGuiTableFlags_Reorderable);
5611 ImGui::CheckboxFlags("ImGuiTableFlags_Hideable", &flags, ImGuiTableFlags_Hideable);
5612 ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody);
5613 ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags, ImGuiTableFlags_NoBordersInBodyUntilResize); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body until hovered for resize (borders will always appear in Headers)");
5614 ImGui::CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", &flags, ImGuiTableFlags_HighlightHoveredColumn);
5615 PopStyleCompact();
5616
5617 if (ImGui::BeginTable("table1", 3, flags))
5618 {
5619 // Submit columns name with TableSetupColumn() and call TableHeadersRow() to create a row with a header in each column.
5620 // (Later we will show how TableSetupColumn() has other uses, optional flags, sizing weight etc.)
5621 ImGui::TableSetupColumn("One");
5622 ImGui::TableSetupColumn("Two");
5623 ImGui::TableSetupColumn("Three");
5624 ImGui::TableHeadersRow();
5625 for (int row = 0; row < 6; row++)
5626 {
5627 ImGui::TableNextRow();
5628 for (int column = 0; column < 3; column++)
5629 {
5630 ImGui::TableSetColumnIndex(column);
5631 ImGui::Text("Hello %d,%d", column, row);
5632 }
5633 }
5634 ImGui::EndTable();
5635 }
5636
5637 // Use outer_size.x == 0.0f instead of default to make the table as tight as possible
5638 // (only valid when no scrolling and no stretch column)
5639 if (ImGui::BeginTable("table2", 3, flags | ImGuiTableFlags_SizingFixedFit, ImVec2(0.0f, 0.0f)))
5640 {
5641 ImGui::TableSetupColumn("One");
5642 ImGui::TableSetupColumn("Two");
5643 ImGui::TableSetupColumn("Three");
5644 ImGui::TableHeadersRow();
5645 for (int row = 0; row < 6; row++)
5646 {
5647 ImGui::TableNextRow();
5648 for (int column = 0; column < 3; column++)
5649 {
5650 ImGui::TableSetColumnIndex(column);
5651 ImGui::Text("Fixed %d,%d", column, row);
5652 }
5653 }
5654 ImGui::EndTable();
5655 }
5656 ImGui::TreePop();
5657 }
5658
5659 if (open_action != -1)
5660 ImGui::SetNextItemOpen(open_action != 0);
5661 IMGUI_DEMO_MARKER("Tables/Padding");
5662 if (ImGui::TreeNode("Padding"))
5663 {
5664 // First example: showcase use of padding flags and effect of BorderOuterV/BorderInnerV on X padding.
5665 // We don't expose BorderOuterH/BorderInnerH here because they have no effect on X padding.
5666 HelpMarker(
5667 "We often want outer padding activated when any using features which makes the edges of a column visible:\n"
5668 "e.g.:\n"
5669 "- BorderOuterV\n"
5670 "- any form of row selection\n"
5671 "Because of this, activating BorderOuterV sets the default to PadOuterX. "
5672 "Using PadOuterX or NoPadOuterX you can override the default.\n\n"
5673 "Actual padding values are using style.CellPadding.\n\n"
5674 "In this demo we don't show horizontal borders to emphasize how they don't affect default horizontal padding.");
5675
5676 static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV;
5677 PushStyleCompact();
5678 ImGui::CheckboxFlags("ImGuiTableFlags_PadOuterX", &flags1, ImGuiTableFlags_PadOuterX);
5679 ImGui::SameLine(); HelpMarker("Enable outer-most padding (default if ImGuiTableFlags_BordersOuterV is set)");
5680 ImGui::CheckboxFlags("ImGuiTableFlags_NoPadOuterX", &flags1, ImGuiTableFlags_NoPadOuterX);
5681 ImGui::SameLine(); HelpMarker("Disable outer-most padding (default if ImGuiTableFlags_BordersOuterV is not set)");
5682 ImGui::CheckboxFlags("ImGuiTableFlags_NoPadInnerX", &flags1, ImGuiTableFlags_NoPadInnerX);
5683 ImGui::SameLine(); HelpMarker("Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off)");
5684 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags1, ImGuiTableFlags_BordersOuterV);
5685 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags1, ImGuiTableFlags_BordersInnerV);
5686 static bool show_headers = false;
5687 ImGui::Checkbox("show_headers", &show_headers);
5688 PopStyleCompact();
5689
5690 if (ImGui::BeginTable("table_padding", 3, flags1))
5691 {
5692 if (show_headers)
5693 {
5694 ImGui::TableSetupColumn("One");
5695 ImGui::TableSetupColumn("Two");
5696 ImGui::TableSetupColumn("Three");
5697 ImGui::TableHeadersRow();
5698 }
5699
5700 for (int row = 0; row < 5; row++)
5701 {
5702 ImGui::TableNextRow();
5703 for (int column = 0; column < 3; column++)
5704 {
5705 ImGui::TableSetColumnIndex(column);
5706 if (row == 0)
5707