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 {
5708 ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x);
5709 }
5710 else
5711 {
5712 char buf[32];
5713 sprintf(buf, "Hello %d,%d", column, row);
5714 ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f));
5715 }
5716 //if (ImGui::TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered)
5717 // ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, IM_COL32(0, 100, 0, 255));
5718 }
5719 }
5720 ImGui::EndTable();
5721 }
5722
5723 // Second example: set style.CellPadding to (0.0) or a custom value.
5724 // FIXME-TABLE: Vertical border effectively not displayed the same way as horizontal one...
5725 HelpMarker("Setting style.CellPadding to (0,0) or a custom value.");
5726 static ImGuiTableFlags flags2 = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg;
5727 static ImVec2 cell_padding(0.0f, 0.0f);
5728 static bool show_widget_frame_bg = true;
5729
5730 PushStyleCompact();
5731 ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags2, ImGuiTableFlags_Borders);
5732 ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags2, ImGuiTableFlags_BordersH);
5733 ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags2, ImGuiTableFlags_BordersV);
5734 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInner", &flags2, ImGuiTableFlags_BordersInner);
5735 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuter", &flags2, ImGuiTableFlags_BordersOuter);
5736 ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags2, ImGuiTableFlags_RowBg);
5737 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags2, ImGuiTableFlags_Resizable);
5738 ImGui::Checkbox("show_widget_frame_bg", &show_widget_frame_bg);
5739 ImGui::SliderFloat2("CellPadding", &cell_padding.x, 0.0f, 10.0f, "%.0f");
5740 PopStyleCompact();
5741
5742 ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, cell_padding);
5743 if (ImGui::BeginTable("table_padding_2", 3, flags2))
5744 {
5745 static char text_bufs[3 * 5][16]; // Mini text storage for 3x5 cells
5746 static bool init = true;
5747 if (!show_widget_frame_bg)
5748 ImGui::PushStyleColor(ImGuiCol_FrameBg, 0);
5749 for (int cell = 0; cell < 3 * 5; cell++)
5750 {
5751 ImGui::TableNextColumn();
5752 if (init)
5753 strcpy(text_bufs[cell], "edit me");
5754 ImGui::SetNextItemWidth(-FLT_MIN);
5755 ImGui::PushID(cell);
5756 ImGui::InputText("##cell", text_bufs[cell], IM_ARRAYSIZE(text_bufs[cell]));
5757 ImGui::PopID();
5758 }
5759 if (!show_widget_frame_bg)
5760 ImGui::PopStyleColor();
5761 init = false;
5762 ImGui::EndTable();
5763 }
5764 ImGui::PopStyleVar();
5765
5766 ImGui::TreePop();
5767 }
5768
5769 if (open_action != -1)
5770 ImGui::SetNextItemOpen(open_action != 0);
5771 IMGUI_DEMO_MARKER("Tables/Explicit widths");
5772 if (ImGui::TreeNode("Sizing policies"))
5773 {
5774 static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody;
5775 PushStyleCompact();
5776 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags1, ImGuiTableFlags_Resizable);
5777 ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags1, ImGuiTableFlags_NoHostExtendX);
5778 PopStyleCompact();
5779
5780 static ImGuiTableFlags sizing_policy_flags[4] = { ImGuiTableFlags_SizingFixedFit, ImGuiTableFlags_SizingFixedSame, ImGuiTableFlags_SizingStretchProp, ImGuiTableFlags_SizingStretchSame };
5781 for (int table_n = 0; table_n < 4; table_n++)
5782 {
5783 ImGui::PushID(table_n);
5784 ImGui::SetNextItemWidth(TEXT_BASE_WIDTH * 30);
5785 EditTableSizingFlags(&sizing_policy_flags[table_n]);
5786
5787 // To make it easier to understand the different sizing policy,
5788 // For each policy: we display one table where the columns have equal contents width,
5789 // and one where the columns have different contents width.
5790 if (ImGui::BeginTable("table1", 3, sizing_policy_flags[table_n] | flags1))
5791 {
5792 for (int row = 0; row < 3; row++)
5793 {
5794 ImGui::TableNextRow();
5795 ImGui::TableNextColumn(); ImGui::Text("Oh dear");
5796 ImGui::TableNextColumn(); ImGui::Text("Oh dear");
5797 ImGui::TableNextColumn(); ImGui::Text("Oh dear");
5798 }
5799 ImGui::EndTable();
5800 }
5801 if (ImGui::BeginTable("table2", 3, sizing_policy_flags[table_n] | flags1))
5802 {
5803 for (int row = 0; row < 3; row++)
5804 {
5805 ImGui::TableNextRow();
5806 ImGui::TableNextColumn(); ImGui::Text("AAAA");
5807 ImGui::TableNextColumn(); ImGui::Text("BBBBBBBB");
5808 ImGui::TableNextColumn(); ImGui::Text("CCCCCCCCCCCC");
5809 }
5810 ImGui::EndTable();
5811 }
5812 ImGui::PopID();
5813 }
5814
5815 ImGui::Spacing();
5816 ImGui::TextUnformatted("Advanced");
5817 ImGui::SameLine();
5818 HelpMarker(
5819 "This section allows you to interact and see the effect of various sizing policies "
5820 "depending on whether Scroll is enabled and the contents of your columns.");
5821
5822 enum ContentsType { CT_ShowWidth, CT_ShortText, CT_LongText, CT_Button, CT_FillButton, CT_InputText };
5823 static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable;
5824 static int contents_type = CT_ShowWidth;
5825 static int column_count = 3;
5826
5827 PushStyleCompact();
5828 ImGui::PushID("Advanced");
5829 ImGui::PushItemWidth(TEXT_BASE_WIDTH * 30);
5830 EditTableSizingFlags(&flags);
5831 ImGui::Combo("Contents", &contents_type, "Show width\0Short Text\0Long Text\0Button\0Fill Button\0InputText\0");
5832 if (contents_type == CT_FillButton)
5833 {
5834 ImGui::SameLine();
5835 HelpMarker(
5836 "Be mindful that using right-alignment (e.g. size.x = -FLT_MIN) creates a feedback loop "
5837 "where contents width can feed into auto-column width can feed into contents width.");
5838 }
5839 ImGui::DragInt("Columns", &column_count, 0.1f, 1, 64, "%d", ImGuiSliderFlags_AlwaysClamp);
5840 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
5841 ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths);
5842 ImGui::SameLine(); HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.");
5843 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX);
5844 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
5845 ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip);
5846 ImGui::PopItemWidth();
5847 ImGui::PopID();
5848 PopStyleCompact();
5849
5850 if (ImGui::BeginTable("table2", column_count, flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 7)))
5851 {
5852 for (int cell = 0; cell < 10 * column_count; cell++)
5853 {
5854 ImGui::TableNextColumn();
5855 int column = ImGui::TableGetColumnIndex();
5856 int row = ImGui::TableGetRowIndex();
5857
5858 ImGui::PushID(cell);
5859 char label[32];
5860 static char text_buf[32] = "";
5861 sprintf(label, "Hello %d,%d", column, row);
5862 switch (contents_type)
5863 {
5864 case CT_ShortText: ImGui::TextUnformatted(label); break;
5865 case CT_LongText: ImGui::Text("Some %s text %d,%d\nOver two lines..", column == 0 ? "long" : "longeeer", column, row); break;
5866 case CT_ShowWidth: ImGui::Text("W: %.1f", ImGui::GetContentRegionAvail().x); break;
5867 case CT_Button: ImGui::Button(label); break;
5868 case CT_FillButton: ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f)); break;
5869 case CT_InputText: ImGui::SetNextItemWidth(-FLT_MIN); ImGui::InputText("##", text_buf, IM_ARRAYSIZE(text_buf)); break;
5870 }
5871 ImGui::PopID();
5872 }
5873 ImGui::EndTable();
5874 }
5875 ImGui::TreePop();
5876 }
5877
5878 if (open_action != -1)
5879 ImGui::SetNextItemOpen(open_action != 0);
5880 IMGUI_DEMO_MARKER("Tables/Vertical scrolling, with clipping");
5881 if (ImGui::TreeNode("Vertical scrolling, with clipping"))
5882 {
5883 HelpMarker(
5884 "Here we activate ScrollY, which will create a child window container to allow hosting scrollable contents.\n\n"
5885 "We also demonstrate using ImGuiListClipper to virtualize the submission of many items.");
5886 static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
5887
5888 PushStyleCompact();
5889 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
5890 PopStyleCompact();
5891
5892 // When using ScrollX or ScrollY we need to specify a size for our table container!
5893 // Otherwise by default the table will fit all available space, like a BeginChild() call.
5894 ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 8);
5895 if (ImGui::BeginTable("table_scrolly", 3, flags, outer_size))
5896 {
5897 ImGui::TableSetupScrollFreeze(0, 1); // Make top row always visible
5898 ImGui::TableSetupColumn("One", ImGuiTableColumnFlags_None);
5899 ImGui::TableSetupColumn("Two", ImGuiTableColumnFlags_None);
5900 ImGui::TableSetupColumn("Three", ImGuiTableColumnFlags_None);
5901 ImGui::TableHeadersRow();
5902
5903 // Demonstrate using clipper for large vertical lists
5904 ImGuiListClipper clipper;
5905 clipper.Begin(1000);
5906 while (clipper.Step())
5907 {
5908 for (int row = clipper.DisplayStart; row < clipper.DisplayEnd; row++)
5909 {
5910 ImGui::TableNextRow();
5911 for (int column = 0; column < 3; column++)
5912 {
5913 ImGui::TableSetColumnIndex(column);
5914 ImGui::Text("Hello %d,%d", column, row);
5915 }
5916 }
5917 }
5918 ImGui::EndTable();
5919 }
5920 ImGui::TreePop();
5921 }
5922
5923 if (open_action != -1)
5924 ImGui::SetNextItemOpen(open_action != 0);
5925 IMGUI_DEMO_MARKER("Tables/Horizontal scrolling");
5926 if (ImGui::TreeNode("Horizontal scrolling"))
5927 {
5928 HelpMarker(
5929 "When ScrollX is enabled, the default sizing policy becomes ImGuiTableFlags_SizingFixedFit, "
5930 "as automatically stretching columns doesn't make much sense with horizontal scrolling.\n\n"
5931 "Also note that as of the current version, you will almost always want to enable ScrollY along with ScrollX, "
5932 "because the container window won't automatically extend vertically to fix contents "
5933 "(this may be improved in future versions).");
5934 static ImGuiTableFlags flags = ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
5935 static int freeze_cols = 1;
5936 static int freeze_rows = 1;
5937
5938 PushStyleCompact();
5939 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
5940 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX);
5941 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
5942 ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
5943 ImGui::DragInt("freeze_cols", &freeze_cols, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
5944 ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
5945 ImGui::DragInt("freeze_rows", &freeze_rows, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
5946 PopStyleCompact();
5947
5948 // When using ScrollX or ScrollY we need to specify a size for our table container!
5949 // Otherwise by default the table will fit all available space, like a BeginChild() call.
5950 ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 8);
5951 if (ImGui::BeginTable("table_scrollx", 7, flags, outer_size))
5952 {
5953 ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows);
5954 ImGui::TableSetupColumn("Line #", ImGuiTableColumnFlags_NoHide); // Make the first column not hideable to match our use of TableSetupScrollFreeze()
5955 ImGui::TableSetupColumn("One");
5956 ImGui::TableSetupColumn("Two");
5957 ImGui::TableSetupColumn("Three");
5958 ImGui::TableSetupColumn("Four");
5959 ImGui::TableSetupColumn("Five");
5960 ImGui::TableSetupColumn("Six");
5961 ImGui::TableHeadersRow();
5962 for (int row = 0; row < 20; row++)
5963 {
5964 ImGui::TableNextRow();
5965 for (int column = 0; column < 7; column++)
5966 {
5967 // Both TableNextColumn() and TableSetColumnIndex() return true when a column is visible or performing width measurement.
5968 // Because here we know that:
5969 // - A) all our columns are contributing the same to row height
5970 // - B) column 0 is always visible,
5971 // We only always submit this one column and can skip others.
5972 // More advanced per-column clipping behaviors may benefit from polling the status flags via TableGetColumnFlags().
5973 if (!ImGui::TableSetColumnIndex(column) && column > 0)
5974 continue;
5975 if (column == 0)
5976 ImGui::Text("Line %d", row);
5977 else
5978 ImGui::Text("Hello world %d,%d", column, row);
5979 }
5980 }
5981 ImGui::EndTable();
5982 }
5983
5984 ImGui::Spacing();
5985 ImGui::TextUnformatted("Stretch + ScrollX");
5986 ImGui::SameLine();
5987 HelpMarker(
5988 "Showcase using Stretch columns + ScrollX together: "
5989 "this is rather unusual and only makes sense when specifying an 'inner_width' for the table!\n"
5990 "Without an explicit value, inner_width is == outer_size.x and therefore using Stretch columns "
5991 "along with ScrollX doesn't make sense.");
5992 static ImGuiTableFlags flags2 = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody;
5993 static float inner_width = 1000.0f;
5994 PushStyleCompact();
5995 ImGui::PushID("flags3");
5996 ImGui::PushItemWidth(TEXT_BASE_WIDTH * 30);
5997 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags2, ImGuiTableFlags_ScrollX);
5998 ImGui::DragFloat("inner_width", &inner_width, 1.0f, 0.0f, FLT_MAX, "%.1f");
5999 ImGui::PopItemWidth();
6000 ImGui::PopID();
6001 PopStyleCompact();
6002 if (ImGui::BeginTable("table2", 7, flags2, outer_size, inner_width))
6003 {
6004 for (int cell = 0; cell < 20 * 7; cell++)
6005 {
6006 ImGui::TableNextColumn();
6007 ImGui::Text("Hello world %d,%d", ImGui::TableGetColumnIndex(), ImGui::TableGetRowIndex());
6008 }
6009 ImGui::EndTable();
6010 }
6011 ImGui::TreePop();
6012 }
6013
6014 if (open_action != -1)
6015 ImGui::SetNextItemOpen(open_action != 0);
6016 IMGUI_DEMO_MARKER("Tables/Columns flags");
6017 if (ImGui::TreeNode("Columns flags"))
6018 {
6019 // Create a first table just to show all the options/flags we want to make visible in our example!
6020 const int column_count = 3;
6021 const char* column_names[column_count] = { "One", "Two", "Three" };
6022 static ImGuiTableColumnFlags column_flags[column_count] = { ImGuiTableColumnFlags_DefaultSort, ImGuiTableColumnFlags_None, ImGuiTableColumnFlags_DefaultHide };
6023 static ImGuiTableColumnFlags column_flags_out[column_count] = { 0, 0, 0 }; // Output from TableGetColumnFlags()
6024
6025 if (ImGui::BeginTable("table_columns_flags_checkboxes", column_count, ImGuiTableFlags_None))
6026 {
6027 PushStyleCompact();
6028 for (int column = 0; column < column_count; column++)
6029 {
6030 ImGui::TableNextColumn();
6031 ImGui::PushID(column);
6032 ImGui::AlignTextToFramePadding(); // FIXME-TABLE: Workaround for wrong text baseline propagation across columns
6033 ImGui::Text("'%s'", column_names[column]);
6034 ImGui::Spacing();
6035 ImGui::Text("Input flags:");
6036 EditTableColumnsFlags(&column_flags[column]);
6037 ImGui::Spacing();
6038 ImGui::Text("Output flags:");
6039 ImGui::BeginDisabled();
6040 ShowTableColumnsStatusFlags(column_flags_out[column]);
6041 ImGui::EndDisabled();
6042 ImGui::PopID();
6043 }
6044 PopStyleCompact();
6045 ImGui::EndTable();
6046 }
6047
6048 // Create the real table we care about for the example!
6049 // We use a scrolling table to be able to showcase the difference between the _IsEnabled and _IsVisible flags above,
6050 // otherwise in a non-scrolling table columns are always visible (unless using ImGuiTableFlags_NoKeepColumnsVisible
6051 // + resizing the parent window down).
6052 const ImGuiTableFlags flags
6053 = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY
6054 | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV
6055 | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable;
6056 ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 9);
6057 if (ImGui::BeginTable("table_columns_flags", column_count, flags, outer_size))
6058 {
6059 bool has_angled_header = false;
6060 for (int column = 0; column < column_count; column++)
6061 {
6062 has_angled_header |= (column_flags[column] & ImGuiTableColumnFlags_AngledHeader) != 0;
6063 ImGui::TableSetupColumn(column_names[column], column_flags[column]);
6064 }
6065 if (has_angled_header)
6066 ImGui::TableAngledHeadersRow();
6067 ImGui::TableHeadersRow();
6068 for (int column = 0; column < column_count; column++)
6069 column_flags_out[column] = ImGui::TableGetColumnFlags(column);
6070 float indent_step = (float)((int)TEXT_BASE_WIDTH / 2);
6071 for (int row = 0; row < 8; row++)
6072 {
6073 // Add some indentation to demonstrate usage of per-column IndentEnable/IndentDisable flags.
6074 ImGui::Indent(indent_step);
6075 ImGui::TableNextRow();
6076 for (int column = 0; column < column_count; column++)
6077 {
6078 ImGui::TableSetColumnIndex(column);
6079 ImGui::Text("%s %s", (column == 0) ? "Indented" : "Hello", ImGui::TableGetColumnName(column));
6080 }
6081 }
6082 ImGui::Unindent(indent_step * 8.0f);
6083
6084 ImGui::EndTable();
6085 }
6086 ImGui::TreePop();
6087 }
6088
6089 if (open_action != -1)
6090 ImGui::SetNextItemOpen(open_action != 0);
6091 IMGUI_DEMO_MARKER("Tables/Columns widths");
6092 if (ImGui::TreeNode("Columns widths"))
6093 {
6094 HelpMarker("Using TableSetupColumn() to setup default width.");
6095
6096 static ImGuiTableFlags flags1 = ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBodyUntilResize;
6097 PushStyleCompact();
6098 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags1, ImGuiTableFlags_Resizable);
6099 ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags1, ImGuiTableFlags_NoBordersInBodyUntilResize);
6100 PopStyleCompact();
6101 if (ImGui::BeginTable("table1", 3, flags1))
6102 {
6103 // We could also set ImGuiTableFlags_SizingFixedFit on the table and all columns will default to ImGuiTableColumnFlags_WidthFixed.
6104 ImGui::TableSetupColumn("one", ImGuiTableColumnFlags_WidthFixed, 100.0f); // Default to 100.0f
6105 ImGui::TableSetupColumn("two", ImGuiTableColumnFlags_WidthFixed, 200.0f); // Default to 200.0f
6106 ImGui::TableSetupColumn("three", ImGuiTableColumnFlags_WidthFixed); // Default to auto
6107 ImGui::TableHeadersRow();
6108 for (int row = 0; row < 4; row++)
6109 {
6110 ImGui::TableNextRow();
6111 for (int column = 0; column < 3; column++)
6112 {
6113 ImGui::TableSetColumnIndex(column);
6114 if (row == 0)
6115 ImGui::Text("(w: %5.1f)", ImGui::GetContentRegionAvail().x);
6116 else
6117 ImGui::Text("Hello %d,%d", column, row);
6118 }
6119 }
6120 ImGui::EndTable();
6121 }
6122
6123 HelpMarker(
6124 "Using TableSetupColumn() to setup explicit width.\n\nUnless _NoKeepColumnsVisible is set, "
6125 "fixed columns with set width may still be shrunk down if there's not enough space in the host.");
6126
6127 static ImGuiTableFlags flags2 = ImGuiTableFlags_None;
6128 PushStyleCompact();
6129 ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags2, ImGuiTableFlags_NoKeepColumnsVisible);
6130 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags2, ImGuiTableFlags_BordersInnerV);
6131 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags2, ImGuiTableFlags_BordersOuterV);
6132 PopStyleCompact();
6133 if (ImGui::BeginTable("table2", 4, flags2))
6134 {
6135 // We could also set ImGuiTableFlags_SizingFixedFit on the table and then all columns
6136 // will default to ImGuiTableColumnFlags_WidthFixed.
6137 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 100.0f);
6138 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f);
6139 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 30.0f);
6140 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f);
6141 for (int row = 0; row < 5; row++)
6142 {
6143 ImGui::TableNextRow();
6144 for (int column = 0; column < 4; column++)
6145 {
6146 ImGui::TableSetColumnIndex(column);
6147 if (row == 0)
6148 ImGui::Text("(w: %5.1f)", ImGui::GetContentRegionAvail().x);
6149 else
6150 ImGui::Text("Hello %d,%d", column, row);
6151 }
6152 }
6153 ImGui::EndTable();
6154 }
6155 ImGui::TreePop();
6156 }
6157
6158 if (open_action != -1)
6159 ImGui::SetNextItemOpen(open_action != 0);
6160 IMGUI_DEMO_MARKER("Tables/Nested tables");
6161 if (ImGui::TreeNode("Nested tables"))
6162 {
6163 HelpMarker("This demonstrates embedding a table into another table cell.");
6164
6165 if (ImGui::BeginTable("table_nested1", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
6166 {
6167 ImGui::TableSetupColumn("A0");
6168 ImGui::TableSetupColumn("A1");
6169 ImGui::TableHeadersRow();
6170
6171 ImGui::TableNextColumn();
6172 ImGui::Text("A0 Row 0");
6173 {
6174 float rows_height = TEXT_BASE_HEIGHT * 2;
6175 if (ImGui::BeginTable("table_nested2", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
6176 {
6177 ImGui::TableSetupColumn("B0");
6178 ImGui::TableSetupColumn("B1");
6179 ImGui::TableHeadersRow();
6180
6181 ImGui::TableNextRow(ImGuiTableRowFlags_None, rows_height);
6182 ImGui::TableNextColumn();
6183 ImGui::Text("B0 Row 0");
6184 ImGui::TableNextColumn();
6185 ImGui::Text("B1 Row 0");
6186 ImGui::TableNextRow(ImGuiTableRowFlags_None, rows_height);
6187 ImGui::TableNextColumn();
6188 ImGui::Text("B0 Row 1");
6189 ImGui::TableNextColumn();
6190 ImGui::Text("B1 Row 1");
6191
6192 ImGui::EndTable();
6193 }
6194 }
6195 ImGui::TableNextColumn(); ImGui::Text("A1 Row 0");
6196 ImGui::TableNextColumn(); ImGui::Text("A0 Row 1");
6197 ImGui::TableNextColumn(); ImGui::Text("A1 Row 1");
6198 ImGui::EndTable();
6199 }
6200 ImGui::TreePop();
6201 }
6202
6203 if (open_action != -1)
6204 ImGui::SetNextItemOpen(open_action != 0);
6205 IMGUI_DEMO_MARKER("Tables/Row height");
6206 if (ImGui::TreeNode("Row height"))
6207 {
6208 HelpMarker(
6209 "You can pass a 'min_row_height' to TableNextRow().\n\nRows are padded with 'style.CellPadding.y' on top and bottom, "
6210 "so effectively the minimum row height will always be >= 'style.CellPadding.y * 2.0f'.\n\n"
6211 "We cannot honor a _maximum_ row height as that would require a unique clipping rectangle per row.");
6212 if (ImGui::BeginTable("table_row_height", 1, ImGuiTableFlags_Borders))
6213 {
6214 for (int row = 0; row < 8; row++)
6215 {
6216 float min_row_height = (float)(int)(TEXT_BASE_HEIGHT * 0.30f * row);
6217 ImGui::TableNextRow(ImGuiTableRowFlags_None, min_row_height);
6218 ImGui::TableNextColumn();
6219 ImGui::Text("min_row_height = %.2f", min_row_height);
6220 }
6221 ImGui::EndTable();
6222 }
6223
6224 HelpMarker(
6225 "Showcase using SameLine(0,0) to share Current Line Height between cells.\n\n"
6226 "Please note that Tables Row Height is not the same thing as Current Line Height, "
6227 "as a table cell may contains multiple lines.");
6228 if (ImGui::BeginTable("table_share_lineheight", 2, ImGuiTableFlags_Borders))
6229 {
6230 ImGui::TableNextRow();
6231 ImGui::TableNextColumn();
6232 ImGui::ColorButton("##1", ImVec4(0.13f, 0.26f, 0.40f, 1.0f), ImGuiColorEditFlags_None, ImVec2(40, 40));
6233 ImGui::TableNextColumn();
6234 ImGui::Text("Line 1");
6235 ImGui::Text("Line 2");
6236
6237 ImGui::TableNextRow();
6238 ImGui::TableNextColumn();
6239 ImGui::ColorButton("##2", ImVec4(0.13f, 0.26f, 0.40f, 1.0f), ImGuiColorEditFlags_None, ImVec2(40, 40));
6240 ImGui::TableNextColumn();
6241 ImGui::SameLine(0.0f, 0.0f); // Reuse line height from previous column
6242 ImGui::Text("Line 1, with SameLine(0,0)");
6243 ImGui::Text("Line 2");
6244
6245 ImGui::EndTable();
6246 }
6247
6248 HelpMarker("Showcase altering CellPadding.y between rows. Note that CellPadding.x is locked for the entire table.");
6249 if (ImGui::BeginTable("table_changing_cellpadding_y", 1, ImGuiTableFlags_Borders))
6250 {
6251 ImGuiStyle& style = ImGui::GetStyle();
6252 for (int row = 0; row < 8; row++)
6253 {
6254 if ((row % 3) == 2)
6255 ImGui::PushStyleVarY(ImGuiStyleVar_CellPadding, 20.0f);
6256 ImGui::TableNextRow(ImGuiTableRowFlags_None);
6257 ImGui::TableNextColumn();
6258 ImGui::Text("CellPadding.y = %.2f", style.CellPadding.y);
6259 if ((row % 3) == 2)
6260 ImGui::PopStyleVar();
6261 }
6262 ImGui::EndTable();
6263 }
6264
6265 ImGui::TreePop();
6266 }
6267
6268 if (open_action != -1)
6269 ImGui::SetNextItemOpen(open_action != 0);
6270 IMGUI_DEMO_MARKER("Tables/Outer size");
6271 if (ImGui::TreeNode("Outer size"))
6272 {
6273 // Showcasing use of ImGuiTableFlags_NoHostExtendX and ImGuiTableFlags_NoHostExtendY
6274 // Important to that note how the two flags have slightly different behaviors!
6275 ImGui::Text("Using NoHostExtendX and NoHostExtendY:");
6276 PushStyleCompact();
6277 static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_ContextMenuInBody | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX;
6278 ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX);
6279 ImGui::SameLine(); HelpMarker("Make outer width auto-fit to columns, overriding outer_size.x value.\n\nOnly available when ScrollX/ScrollY are disabled and Stretch columns are not used.");
6280 ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendY", &flags, ImGuiTableFlags_NoHostExtendY);
6281 ImGui::SameLine(); HelpMarker("Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).\n\nOnly available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible.");
6282 PopStyleCompact();
6283
6284 ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 5.5f);
6285 if (ImGui::BeginTable("table1", 3, flags, outer_size))
6286 {
6287 for (int row = 0; row < 10; row++)
6288 {
6289 ImGui::TableNextRow();
6290 for (int column = 0; column < 3; column++)
6291 {
6292 ImGui::TableNextColumn();
6293 ImGui::Text("Cell %d,%d", column, row);
6294 }
6295 }
6296 ImGui::EndTable();
6297 }
6298 ImGui::SameLine();
6299 ImGui::Text("Hello!");
6300
6301 ImGui::Spacing();
6302
6303 ImGui::Text("Using explicit size:");
6304 if (ImGui::BeginTable("table2", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(TEXT_BASE_WIDTH * 30, 0.0f)))
6305 {
6306 for (int row = 0; row < 5; row++)
6307 {
6308 ImGui::TableNextRow();
6309 for (int column = 0; column < 3; column++)
6310 {
6311 ImGui::TableNextColumn();
6312 ImGui::Text("Cell %d,%d", column, row);
6313 }
6314 }
6315 ImGui::EndTable();
6316 }
6317 ImGui::SameLine();
6318 if (ImGui::BeginTable("table3", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(TEXT_BASE_WIDTH * 30, 0.0f)))
6319 {
6320 for (int row = 0; row < 3; row++)
6321 {
6322 ImGui::TableNextRow(0, TEXT_BASE_HEIGHT * 1.5f);
6323 for (int column = 0; column < 3; column++)
6324 {
6325 ImGui::TableNextColumn();
6326 ImGui::Text("Cell %d,%d", column, row);
6327 }
6328 }
6329 ImGui::EndTable();
6330 }
6331
6332 ImGui::TreePop();
6333 }
6334
6335 if (open_action != -1)
6336 ImGui::SetNextItemOpen(open_action != 0);
6337 IMGUI_DEMO_MARKER("Tables/Background color");
6338 if (ImGui::TreeNode("Background color"))
6339 {
6340 static ImGuiTableFlags flags = ImGuiTableFlags_RowBg;
6341 static int row_bg_type = 1;
6342 static int row_bg_target = 1;
6343 static int cell_bg_type = 1;
6344
6345 PushStyleCompact();
6346 ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags, ImGuiTableFlags_Borders);
6347 ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg);
6348 ImGui::SameLine(); HelpMarker("ImGuiTableFlags_RowBg automatically sets RowBg0 to alternative colors pulled from the Style.");
6349 ImGui::Combo("row bg type", (int*)&row_bg_type, "None\0Red\0Gradient\0");
6350 ImGui::Combo("row bg target", (int*)&row_bg_target, "RowBg0\0RowBg1\0"); ImGui::SameLine(); HelpMarker("Target RowBg0 to override the alternating odd/even colors,\nTarget RowBg1 to blend with them.");
6351 ImGui::Combo("cell bg type", (int*)&cell_bg_type, "None\0Blue\0"); ImGui::SameLine(); HelpMarker("We are colorizing cells to B1->C2 here.");
6352 IM_ASSERT(row_bg_type >= 0 && row_bg_type <= 2);
6353 IM_ASSERT(row_bg_target >= 0 && row_bg_target <= 1);
6354 IM_ASSERT(cell_bg_type >= 0 && cell_bg_type <= 1);
6355 PopStyleCompact();
6356
6357 if (ImGui::BeginTable("table1", 5, flags))
6358 {
6359 for (int row = 0; row < 6; row++)
6360 {
6361 ImGui::TableNextRow();
6362
6363 // Demonstrate setting a row background color with 'ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBgX, ...)'
6364 // We use a transparent color so we can see the one behind in case our target is RowBg1 and RowBg0 was already targeted by the ImGuiTableFlags_RowBg flag.
6365 if (row_bg_type != 0)
6366 {
6367 ImU32 row_bg_color = ImGui::GetColorU32(row_bg_type == 1 ? ImVec4(0.7f, 0.3f, 0.3f, 0.65f) : ImVec4(0.2f + row * 0.1f, 0.2f, 0.2f, 0.65f)); // Flat or Gradient?
6368 ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0 + row_bg_target, row_bg_color);
6369 }
6370
6371 // Fill cells
6372 for (int column = 0; column < 5; column++)
6373 {
6374 ImGui::TableSetColumnIndex(column);
6375 ImGui::Text("%c%c", 'A' + row, '0' + column);
6376
6377 // Change background of Cells B1->C2
6378 // Demonstrate setting a cell background color with 'ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ...)'
6379 // (the CellBg color will be blended over the RowBg and ColumnBg colors)
6380 // We can also pass a column number as a third parameter to TableSetBgColor() and do this outside the column loop.
6381 if (row >= 1 && row <= 2 && column >= 1 && column <= 2 && cell_bg_type == 1)
6382 {
6383 ImU32 cell_bg_color = ImGui::GetColorU32(ImVec4(0.3f, 0.3f, 0.7f, 0.65f));
6384 ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, cell_bg_color);
6385 }
6386 }
6387 }
6388 ImGui::EndTable();
6389 }
6390 ImGui::TreePop();
6391 }
6392
6393 if (open_action != -1)
6394 ImGui::SetNextItemOpen(open_action != 0);
6395 IMGUI_DEMO_MARKER("Tables/Tree view");
6396 if (ImGui::TreeNode("Tree view"))
6397 {
6398 static ImGuiTableFlags flags = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody;
6399
6400 static ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAllColumns;
6401 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &tree_node_flags, ImGuiTreeNodeFlags_SpanFullWidth);
6402 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanTextWidth", &tree_node_flags, ImGuiTreeNodeFlags_SpanTextWidth);
6403 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &tree_node_flags, ImGuiTreeNodeFlags_SpanAllColumns);
6404
6405 HelpMarker("See \"Columns flags\" section to configure how indentation is applied to individual columns.");
6406 if (ImGui::BeginTable("3ways", 3, flags))
6407 {
6408 // The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On
6409 ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_NoHide);
6410 ImGui::TableSetupColumn("Size", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f);
6411 ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 18.0f);
6412 ImGui::TableHeadersRow();
6413
6414 // Simple storage to output a dummy file-system.
6415 struct MyTreeNode
6416 {
6417 const char* Name;
6418 const char* Type;
6419 int Size;
6420 int ChildIdx;
6421 int ChildCount;
6422 static void DisplayNode(const MyTreeNode* node, const MyTreeNode* all_nodes)
6423 {
6424 ImGui::TableNextRow();
6425 ImGui::TableNextColumn();
6426 const bool is_folder = (node->ChildCount > 0);
6427 if (is_folder)
6428 {
6429 bool open = ImGui::TreeNodeEx(node->Name, tree_node_flags);
6430 ImGui::TableNextColumn();
6431 ImGui::TextDisabled("--");
6432 ImGui::TableNextColumn();
6433 ImGui::TextUnformatted(node->Type);
6434 if (open)
6435 {
6436 for (int child_n = 0; child_n < node->ChildCount; child_n++)
6437 DisplayNode(&all_nodes[node->ChildIdx + child_n], all_nodes);
6438 ImGui::TreePop();
6439 }
6440 }
6441 else
6442 {
6443 ImGui::TreeNodeEx(node->Name, tree_node_flags | ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_NoTreePushOnOpen);
6444 ImGui::TableNextColumn();
6445 ImGui::Text("%d", node->Size);
6446 ImGui::TableNextColumn();
6447 ImGui::TextUnformatted(node->Type);
6448 }
6449 }
6450 };
6451 static const MyTreeNode nodes[] =
6452 {
6453 { "Root", "Folder", -1, 1, 3 }, // 0
6454 { "Music", "Folder", -1, 4, 2 }, // 1
6455 { "Textures", "Folder", -1, 6, 3 }, // 2
6456 { "desktop.ini", "System file", 1024, -1,-1 }, // 3
6457 { "File1_a.wav", "Audio file", 123000, -1,-1 }, // 4
6458 { "File1_b.wav", "Audio file", 456000, -1,-1 }, // 5
6459 { "Image001.png", "Image file", 203128, -1,-1 }, // 6
6460 { "Copy of Image001.png", "Image file", 203256, -1,-1 }, // 7
6461 { "Copy of Image001 (Final2).png","Image file", 203512, -1,-1 }, // 8
6462 };
6463
6464 MyTreeNode::DisplayNode(&nodes[0], nodes);
6465
6466 ImGui::EndTable();
6467 }
6468 ImGui::TreePop();
6469 }
6470
6471 if (open_action != -1)
6472 ImGui::SetNextItemOpen(open_action != 0);
6473 IMGUI_DEMO_MARKER("Tables/Item width");
6474 if (ImGui::TreeNode("Item width"))
6475 {
6476 HelpMarker(
6477 "Showcase using PushItemWidth() and how it is preserved on a per-column basis.\n\n"
6478 "Note that on auto-resizing non-resizable fixed columns, querying the content width for "
6479 "e.g. right-alignment doesn't make sense.");
6480 if (ImGui::BeginTable("table_item_width", 3, ImGuiTableFlags_Borders))
6481 {
6482 ImGui::TableSetupColumn("small");
6483 ImGui::TableSetupColumn("half");
6484 ImGui::TableSetupColumn("right-align");
6485 ImGui::TableHeadersRow();
6486
6487 for (int row = 0; row < 3; row++)
6488 {
6489 ImGui::TableNextRow();
6490 if (row == 0)
6491 {
6492 // Setup ItemWidth once (instead of setting up every time, which is also possible but less efficient)
6493 ImGui::TableSetColumnIndex(0);
6494 ImGui::PushItemWidth(TEXT_BASE_WIDTH * 3.0f); // Small
6495 ImGui::TableSetColumnIndex(1);
6496 ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.5f);
6497 ImGui::TableSetColumnIndex(2);
6498 ImGui::PushItemWidth(-FLT_MIN); // Right-aligned
6499 }
6500
6501 // Draw our contents
6502 static float dummy_f = 0.0f;
6503 ImGui::PushID(row);
6504 ImGui::TableSetColumnIndex(0);
6505 ImGui::SliderFloat("float0", &dummy_f, 0.0f, 1.0f);
6506 ImGui::TableSetColumnIndex(1);
6507 ImGui::SliderFloat("float1", &dummy_f, 0.0f, 1.0f);
6508 ImGui::TableSetColumnIndex(2);
6509 ImGui::SliderFloat("##float2", &dummy_f, 0.0f, 1.0f); // No visible label since right-aligned
6510 ImGui::PopID();
6511 }
6512 ImGui::EndTable();
6513 }
6514 ImGui::TreePop();
6515 }
6516
6517 // Demonstrate using TableHeader() calls instead of TableHeadersRow()
6518 if (open_action != -1)
6519 ImGui::SetNextItemOpen(open_action != 0);
6520 IMGUI_DEMO_MARKER("Tables/Custom headers");
6521 if (ImGui::TreeNode("Custom headers"))
6522 {
6523 const int COLUMNS_COUNT = 3;
6524 if (ImGui::BeginTable("table_custom_headers", COLUMNS_COUNT, ImGuiTableFlags_Borders | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
6525 {
6526 ImGui::TableSetupColumn("Apricot");
6527 ImGui::TableSetupColumn("Banana");
6528 ImGui::TableSetupColumn("Cherry");
6529
6530 // Dummy entire-column selection storage
6531 // FIXME: It would be nice to actually demonstrate full-featured selection using those checkbox.
6532 static bool column_selected[3] = {};
6533
6534 // Instead of calling TableHeadersRow() we'll submit custom headers ourselves.
6535 // (A different approach is also possible:
6536 // - Specify ImGuiTableColumnFlags_NoHeaderLabel in some TableSetupColumn() call.
6537 // - Call TableHeadersRow() normally. This will submit TableHeader() with no name.
6538 // - Then call TableSetColumnIndex() to position yourself in the column and submit your stuff e.g. Checkbox().)
6539 ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
6540 for (int column = 0; column < COLUMNS_COUNT; column++)
6541 {
6542 ImGui::TableSetColumnIndex(column);
6543 const char* column_name = ImGui::TableGetColumnName(column); // Retrieve name passed to TableSetupColumn()
6544 ImGui::PushID(column);
6545 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
6546 ImGui::Checkbox("##checkall", &column_selected[column]);
6547 ImGui::PopStyleVar();
6548 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
6549 ImGui::TableHeader(column_name);
6550 ImGui::PopID();
6551 }
6552
6553 // Submit table contents
6554 for (int row = 0; row < 5; row++)
6555 {
6556 ImGui::TableNextRow();
6557 for (int column = 0; column < 3; column++)
6558 {
6559 char buf[32];
6560 sprintf(buf, "Cell %d,%d", column, row);
6561 ImGui::TableSetColumnIndex(column);
6562 ImGui::Selectable(buf, column_selected[column]);
6563 }
6564 }
6565 ImGui::EndTable();
6566 }
6567 ImGui::TreePop();
6568 }
6569
6570 // Demonstrate using ImGuiTableColumnFlags_AngledHeader flag to create angled headers
6571 if (open_action != -1)
6572 ImGui::SetNextItemOpen(open_action != 0);
6573 IMGUI_DEMO_MARKER("Tables/Angled headers");
6574 if (ImGui::TreeNode("Angled headers"))
6575 {
6576 const char* column_names[] = { "Track", "cabasa", "ride", "smash", "tom-hi", "tom-mid", "tom-low", "hihat-o", "hihat-c", "snare-s", "snare-c", "clap", "rim", "kick" };
6577 const int columns_count = IM_ARRAYSIZE(column_names);
6578 const int rows_count = 12;
6579
6580 static ImGuiTableFlags table_flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_Hideable | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_HighlightHoveredColumn;
6581 static ImGuiTableColumnFlags column_flags = ImGuiTableColumnFlags_AngledHeader | ImGuiTableColumnFlags_WidthFixed;
6582 static bool bools[columns_count * rows_count] = {}; // Dummy storage selection storage
6583 static int frozen_cols = 1;
6584 static int frozen_rows = 2;
6585 ImGui::CheckboxFlags("_ScrollX", &table_flags, ImGuiTableFlags_ScrollX);
6586 ImGui::CheckboxFlags("_ScrollY", &table_flags, ImGuiTableFlags_ScrollY);
6587 ImGui::CheckboxFlags("_Resizable", &table_flags, ImGuiTableFlags_Resizable);
6588 ImGui::CheckboxFlags("_Sortable", &table_flags, ImGuiTableFlags_Sortable);
6589 ImGui::CheckboxFlags("_NoBordersInBody", &table_flags, ImGuiTableFlags_NoBordersInBody);
6590 ImGui::CheckboxFlags("_HighlightHoveredColumn", &table_flags, ImGuiTableFlags_HighlightHoveredColumn);
6591 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
6592 ImGui::SliderInt("Frozen columns", &frozen_cols, 0, 2);
6593 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
6594 ImGui::SliderInt("Frozen rows", &frozen_rows, 0, 2);
6595 ImGui::CheckboxFlags("Disable header contributing to column width", &column_flags, ImGuiTableColumnFlags_NoHeaderWidth);
6596
6597 if (ImGui::TreeNode("Style settings"))
6598 {
6599 ImGui::SameLine();
6600 HelpMarker("Giving access to some ImGuiStyle value in this demo for convenience.");
6601 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
6602 ImGui::SliderAngle("style.TableAngledHeadersAngle", &ImGui::GetStyle().TableAngledHeadersAngle, -50.0f, +50.0f);
6603 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
6604 ImGui::SliderFloat2("style.TableAngledHeadersTextAlign", (float*)&ImGui::GetStyle().TableAngledHeadersTextAlign, 0.0f, 1.0f, "%.2f");
6605 ImGui::TreePop();
6606 }
6607
6608 if (ImGui::BeginTable("table_angled_headers", columns_count, table_flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 12)))
6609 {
6610 ImGui::TableSetupColumn(column_names[0], ImGuiTableColumnFlags_NoHide | ImGuiTableColumnFlags_NoReorder);
6611 for (int n = 1; n < columns_count; n++)
6612 ImGui::TableSetupColumn(column_names[n], column_flags);
6613 ImGui::TableSetupScrollFreeze(frozen_cols, frozen_rows);
6614
6615 ImGui::TableAngledHeadersRow(); // Draw angled headers for all columns with the ImGuiTableColumnFlags_AngledHeader flag.
6616 ImGui::TableHeadersRow(); // Draw remaining headers and allow access to context-menu and other functions.
6617 for (int row = 0; row < rows_count; row++)
6618 {
6619 ImGui::PushID(row);
6620 ImGui::TableNextRow();
6621 ImGui::TableSetColumnIndex(0);
6622 ImGui::AlignTextToFramePadding();
6623 ImGui::Text("Track %d", row);
6624 for (int column = 1; column < columns_count; column++)
6625 if (ImGui::TableSetColumnIndex(column))
6626 {
6627 ImGui::PushID(column);
6628 ImGui::Checkbox("", &bools[row * columns_count + column]);
6629 ImGui::PopID();
6630 }
6631 ImGui::PopID();
6632 }
6633 ImGui::EndTable();
6634 }
6635 ImGui::TreePop();
6636 }
6637
6638 // Demonstrate creating custom context menus inside columns,
6639 // while playing it nice with context menus provided by TableHeadersRow()/TableHeader()
6640 if (open_action != -1)
6641 ImGui::SetNextItemOpen(open_action != 0);
6642 IMGUI_DEMO_MARKER("Tables/Context menus");
6643 if (ImGui::TreeNode("Context menus"))
6644 {
6645 HelpMarker(
6646 "By default, right-clicking over a TableHeadersRow()/TableHeader() line will open the default context-menu.\n"
6647 "Using ImGuiTableFlags_ContextMenuInBody we also allow right-clicking over columns body.");
6648 static ImGuiTableFlags flags1 = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_ContextMenuInBody;
6649
6650 PushStyleCompact();
6651 ImGui::CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", &flags1, ImGuiTableFlags_ContextMenuInBody);
6652 PopStyleCompact();
6653
6654 // Context Menus: first example
6655 // [1.1] Right-click on the TableHeadersRow() line to open the default table context menu.
6656 // [1.2] Right-click in columns also open the default table context menu (if ImGuiTableFlags_ContextMenuInBody is set)
6657 const int COLUMNS_COUNT = 3;
6658 if (ImGui::BeginTable("table_context_menu", COLUMNS_COUNT, flags1))
6659 {
6660 ImGui::TableSetupColumn("One");
6661 ImGui::TableSetupColumn("Two");
6662 ImGui::TableSetupColumn("Three");
6663
6664 // [1.1]] Right-click on the TableHeadersRow() line to open the default table context menu.
6665 ImGui::TableHeadersRow();
6666
6667 // Submit dummy contents
6668 for (int row = 0; row < 4; row++)
6669 {
6670 ImGui::TableNextRow();
6671 for (int column = 0; column < COLUMNS_COUNT; column++)
6672 {
6673 ImGui::TableSetColumnIndex(column);
6674 ImGui::Text("Cell %d,%d", column, row);
6675 }
6676 }
6677 ImGui::EndTable();
6678 }
6679
6680 // Context Menus: second example
6681 // [2.1] Right-click on the TableHeadersRow() line to open the default table context menu.
6682 // [2.2] Right-click on the ".." to open a custom popup
6683 // [2.3] Right-click in columns to open another custom popup
6684 HelpMarker(
6685 "Demonstrate mixing table context menu (over header), item context button (over button) "
6686 "and custom per-colunm context menu (over column body).");
6687 ImGuiTableFlags flags2 = ImGuiTableFlags_Resizable | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders;
6688 if (ImGui::BeginTable("table_context_menu_2", COLUMNS_COUNT, flags2))
6689 {
6690 ImGui::TableSetupColumn("One");
6691 ImGui::TableSetupColumn("Two");
6692 ImGui::TableSetupColumn("Three");
6693
6694 // [2.1] Right-click on the TableHeadersRow() line to open the default table context menu.
6695 ImGui::TableHeadersRow();
6696 for (int row = 0; row < 4; row++)
6697 {
6698 ImGui::TableNextRow();
6699 for (int column = 0; column < COLUMNS_COUNT; column++)
6700 {
6701 // Submit dummy contents
6702 ImGui::TableSetColumnIndex(column);
6703 ImGui::Text("Cell %d,%d", column, row);
6704 ImGui::SameLine();
6705
6706 // [2.2] Right-click on the ".." to open a custom popup
6707 ImGui::PushID(row * COLUMNS_COUNT + column);
6708 ImGui::SmallButton("..");
6709 if (ImGui::BeginPopupContextItem())
6710 {
6711 ImGui::Text("This is the popup for Button(\"..\") in Cell %d,%d", column, row);
6712 if (ImGui::Button("Close"))
6713 ImGui::CloseCurrentPopup();
6714 ImGui::EndPopup();
6715 }
6716 ImGui::PopID();
6717 }
6718 }
6719
6720 // [2.3] Right-click anywhere in columns to open another custom popup
6721 // (instead of testing for !IsAnyItemHovered() we could also call OpenPopup() with ImGuiPopupFlags_NoOpenOverExistingPopup
6722 // to manage popup priority as the popups triggers, here "are we hovering a column" are overlapping)
6723 int hovered_column = -1;
6724 for (int column = 0; column < COLUMNS_COUNT + 1; column++)
6725 {
6726 ImGui::PushID(column);
6727 if (ImGui::TableGetColumnFlags(column) & ImGuiTableColumnFlags_IsHovered)
6728 hovered_column = column;
6729 if (hovered_column == column && !ImGui::IsAnyItemHovered() && ImGui::IsMouseReleased(1))
6730 ImGui::OpenPopup("MyPopup");
6731 if (ImGui::BeginPopup("MyPopup"))
6732 {
6733 if (column == COLUMNS_COUNT)
6734 ImGui::Text("This is a custom popup for unused space after the last column.");
6735 else
6736 ImGui::Text("This is a custom popup for Column %d", column);
6737 if (ImGui::Button("Close"))
6738 ImGui::CloseCurrentPopup();
6739 ImGui::EndPopup();
6740 }
6741 ImGui::PopID();
6742 }
6743
6744 ImGui::EndTable();
6745 ImGui::Text("Hovered column: %d", hovered_column);
6746 }
6747 ImGui::TreePop();
6748 }
6749
6750 // Demonstrate creating multiple tables with the same ID
6751 if (open_action != -1)
6752 ImGui::SetNextItemOpen(open_action != 0);
6753 IMGUI_DEMO_MARKER("Tables/Synced instances");
6754 if (ImGui::TreeNode("Synced instances"))
6755 {
6756 HelpMarker("Multiple tables with the same identifier will share their settings, width, visibility, order etc.");
6757
6758 static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoSavedSettings;
6759 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
6760 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
6761 ImGui::CheckboxFlags("ImGuiTableFlags_SizingFixedFit", &flags, ImGuiTableFlags_SizingFixedFit);
6762 ImGui::CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", &flags, ImGuiTableFlags_HighlightHoveredColumn);
6763 for (int n = 0; n < 3; n++)
6764 {
6765 char buf[32];
6766 sprintf(buf, "Synced Table %d", n);
6767 bool open = ImGui::CollapsingHeader(buf, ImGuiTreeNodeFlags_DefaultOpen);
6768 if (open && ImGui::BeginTable("Table", 3, flags, ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 5)))
6769 {
6770 ImGui::TableSetupColumn("One");
6771 ImGui::TableSetupColumn("Two");
6772 ImGui::TableSetupColumn("Three");
6773 ImGui::TableHeadersRow();
6774 const int cell_count = (n == 1) ? 27 : 9; // Make second table have a scrollbar to verify that additional decoration is not affecting column positions.
6775 for (int cell = 0; cell < cell_count; cell++)
6776 {
6777 ImGui::TableNextColumn();
6778 ImGui::Text("this cell %d", cell);
6779 }
6780 ImGui::EndTable();
6781 }
6782 }
6783 ImGui::TreePop();
6784 }
6785
6786 // Demonstrate using Sorting facilities
6787 // This is a simplified version of the "Advanced" example, where we mostly focus on the code necessary to handle sorting.
6788 // Note that the "Advanced" example also showcase manually triggering a sort (e.g. if item quantities have been modified)
6789 static const char* template_items_names[] =
6790 {
6791 "Banana", "Apple", "Cherry", "Watermelon", "Grapefruit", "Strawberry", "Mango",
6792 "Kiwi", "Orange", "Pineapple", "Blueberry", "Plum", "Coconut", "Pear", "Apricot"
6793 };
6794 if (open_action != -1)
6795 ImGui::SetNextItemOpen(open_action != 0);
6796 IMGUI_DEMO_MARKER("Tables/Sorting");
6797 if (ImGui::TreeNode("Sorting"))
6798 {
6799 // Create item list
6800 static ImVector<MyItem> items;
6801 if (items.Size == 0)
6802 {
6803 items.resize(50, MyItem());
6804 for (int n = 0; n < items.Size; n++)
6805 {
6806 const int template_n = n % IM_ARRAYSIZE(template_items_names);
6807 MyItem& item = items[n];
6808 item.ID = n;
6809 item.Name = template_items_names[template_n];
6810 item.Quantity = (n * n - n) % 20; // Assign default quantities
6811 }
6812 }
6813
6814 // Options
6815 static ImGuiTableFlags flags =
6816 ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti
6817 | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_NoBordersInBody
6818 | ImGuiTableFlags_ScrollY;
6819 PushStyleCompact();
6820 ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti);
6821 ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).");
6822 ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate);
6823 ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).");
6824 PopStyleCompact();
6825
6826 if (ImGui::BeginTable("table_sorting", 4, flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 15), 0.0f))
6827 {
6828 // Declare columns
6829 // We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications.
6830 // This is so our sort function can identify a column given our own identifier. We could also identify them based on their index!
6831 // Demonstrate using a mixture of flags among available sort-related flags:
6832 // - ImGuiTableColumnFlags_DefaultSort
6833 // - ImGuiTableColumnFlags_NoSort / ImGuiTableColumnFlags_NoSortAscending / ImGuiTableColumnFlags_NoSortDescending
6834 // - ImGuiTableColumnFlags_PreferSortAscending / ImGuiTableColumnFlags_PreferSortDescending
6835 ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_ID);
6836 ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Name);
6837 ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Action);
6838 ImGui::TableSetupColumn("Quantity", ImGuiTableColumnFlags_PreferSortDescending | ImGuiTableColumnFlags_WidthStretch, 0.0f, MyItemColumnID_Quantity);
6839 ImGui::TableSetupScrollFreeze(0, 1); // Make row always visible
6840 ImGui::TableHeadersRow();
6841
6842 // Sort our data if sort specs have been changed!
6843 if (ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs())
6844 if (sort_specs->SpecsDirty)
6845 {
6846 MyItem::SortWithSortSpecs(sort_specs, items.Data, items.Size);
6847 sort_specs->SpecsDirty = false;
6848 }
6849
6850 // Demonstrate using clipper for large vertical lists
6851 ImGuiListClipper clipper;
6852 clipper.Begin(items.Size);
6853 while (clipper.Step())
6854 for (int row_n = clipper.DisplayStart; row_n < clipper.DisplayEnd; row_n++)
6855 {
6856 // Display a data item
6857 MyItem* item = &items[row_n];
6858 ImGui::PushID(item->ID);
6859 ImGui::TableNextRow();
6860 ImGui::TableNextColumn();
6861 ImGui::Text("%04d", item->ID);
6862 ImGui::TableNextColumn();
6863 ImGui::TextUnformatted(item->Name);
6864 ImGui::TableNextColumn();
6865 ImGui::SmallButton("None");
6866 ImGui::TableNextColumn();
6867 ImGui::Text("%d", item->Quantity);
6868 ImGui::PopID();
6869 }
6870 ImGui::EndTable();
6871 }
6872 ImGui::TreePop();
6873 }
6874
6875 // In this example we'll expose most table flags and settings.
6876 // For specific flags and settings refer to the corresponding section for more detailed explanation.
6877 // This section is mostly useful to experiment with combining certain flags or settings with each others.
6878 //ImGui::SetNextItemOpen(true, ImGuiCond_Once); // [DEBUG]
6879 if (open_action != -1)
6880 ImGui::SetNextItemOpen(open_action != 0);
6881 IMGUI_DEMO_MARKER("Tables/Advanced");
6882 if (ImGui::TreeNode("Advanced"))
6883 {
6884 static ImGuiTableFlags flags =
6885 ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable
6886 | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti
6887 | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBody
6888 | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY
6889 | ImGuiTableFlags_SizingFixedFit;
6890 static ImGuiTableColumnFlags columns_base_flags = ImGuiTableColumnFlags_None;
6891
6892 enum ContentsType { CT_Text, CT_Button, CT_SmallButton, CT_FillButton, CT_Selectable, CT_SelectableSpanRow };
6893 static int contents_type = CT_SelectableSpanRow;
6894 const char* contents_type_names[] = { "Text", "Button", "SmallButton", "FillButton", "Selectable", "Selectable (span row)" };
6895 static int freeze_cols = 1;
6896 static int freeze_rows = 1;
6897 static int items_count = IM_ARRAYSIZE(template_items_names) * 2;
6898 static ImVec2 outer_size_value = ImVec2(0.0f, TEXT_BASE_HEIGHT * 12);
6899 static float row_min_height = 0.0f; // Auto
6900 static float inner_width_with_scroll = 0.0f; // Auto-extend
6901 static bool outer_size_enabled = true;
6902 static bool show_headers = true;
6903 static bool show_wrapped_text = false;
6904 //static ImGuiTextFilter filter;
6905 //ImGui::SetNextItemOpen(true, ImGuiCond_Once); // FIXME-TABLE: Enabling this results in initial clipped first pass on table which tend to affect column sizing
6906 if (ImGui::TreeNode("Options"))
6907 {
6908 // Make the UI compact because there are so many fields
6909 PushStyleCompact();
6910 ImGui::PushItemWidth(TEXT_BASE_WIDTH * 28.0f);
6911
6912 if (ImGui::TreeNodeEx("Features:", ImGuiTreeNodeFlags_DefaultOpen))
6913 {
6914 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
6915 ImGui::CheckboxFlags("ImGuiTableFlags_Reorderable", &flags, ImGuiTableFlags_Reorderable);
6916 ImGui::CheckboxFlags("ImGuiTableFlags_Hideable", &flags, ImGuiTableFlags_Hideable);
6917 ImGui::CheckboxFlags("ImGuiTableFlags_Sortable", &flags, ImGuiTableFlags_Sortable);
6918 ImGui::CheckboxFlags("ImGuiTableFlags_NoSavedSettings", &flags, ImGuiTableFlags_NoSavedSettings);
6919 ImGui::CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", &flags, ImGuiTableFlags_ContextMenuInBody);
6920 ImGui::TreePop();
6921 }
6922
6923 if (ImGui::TreeNodeEx("Decorations:", ImGuiTreeNodeFlags_DefaultOpen))
6924 {
6925 ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg);
6926 ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV);
6927 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags, ImGuiTableFlags_BordersOuterV);
6928 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags, ImGuiTableFlags_BordersInnerV);
6929 ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags, ImGuiTableFlags_BordersH);
6930 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterH", &flags, ImGuiTableFlags_BordersOuterH);
6931 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerH", &flags, ImGuiTableFlags_BordersInnerH);
6932 ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers");
6933 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)");
6934 ImGui::TreePop();
6935 }
6936
6937 if (ImGui::TreeNodeEx("Sizing:", ImGuiTreeNodeFlags_DefaultOpen))
6938 {
6939 EditTableSizingFlags(&flags);
6940 ImGui::SameLine(); HelpMarker("In the Advanced demo we override the policy of each column so those table-wide settings have less effect that typical.");
6941 ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX);
6942 ImGui::SameLine(); HelpMarker("Make outer width auto-fit to columns, overriding outer_size.x value.\n\nOnly available when ScrollX/ScrollY are disabled and Stretch columns are not used.");
6943 ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendY", &flags, ImGuiTableFlags_NoHostExtendY);
6944 ImGui::SameLine(); HelpMarker("Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).\n\nOnly available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible.");
6945 ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags, ImGuiTableFlags_NoKeepColumnsVisible);
6946 ImGui::SameLine(); HelpMarker("Only available if ScrollX is disabled.");
6947 ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths);
6948 ImGui::SameLine(); HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.");
6949 ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip);
6950 ImGui::SameLine(); HelpMarker("Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with ScrollFreeze options.");
6951 ImGui::TreePop();
6952 }
6953
6954 if (ImGui::TreeNodeEx("Padding:", ImGuiTreeNodeFlags_DefaultOpen))
6955 {
6956 ImGui::CheckboxFlags("ImGuiTableFlags_PadOuterX", &flags, ImGuiTableFlags_PadOuterX);
6957 ImGui::CheckboxFlags("ImGuiTableFlags_NoPadOuterX", &flags, ImGuiTableFlags_NoPadOuterX);
6958 ImGui::CheckboxFlags("ImGuiTableFlags_NoPadInnerX", &flags, ImGuiTableFlags_NoPadInnerX);
6959 ImGui::TreePop();
6960 }
6961
6962 if (ImGui::TreeNodeEx("Scrolling:", ImGuiTreeNodeFlags_DefaultOpen))
6963 {
6964 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX);
6965 ImGui::SameLine();
6966 ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
6967 ImGui::DragInt("freeze_cols", &freeze_cols, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
6968 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
6969 ImGui::SameLine();
6970 ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
6971 ImGui::DragInt("freeze_rows", &freeze_rows, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
6972 ImGui::TreePop();
6973 }
6974
6975 if (ImGui::TreeNodeEx("Sorting:", ImGuiTreeNodeFlags_DefaultOpen))
6976 {
6977 ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti);
6978 ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).");
6979 ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate);
6980 ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).");
6981 ImGui::TreePop();
6982 }
6983
6984 if (ImGui::TreeNodeEx("Headers:", ImGuiTreeNodeFlags_DefaultOpen))
6985 {
6986 ImGui::Checkbox("show_headers", &show_headers);
6987 ImGui::CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", &flags, ImGuiTableFlags_HighlightHoveredColumn);
6988 ImGui::CheckboxFlags("ImGuiTableColumnFlags_AngledHeader", &columns_base_flags, ImGuiTableColumnFlags_AngledHeader);
6989 ImGui::SameLine(); HelpMarker("Enable AngledHeader on all columns. Best enabled on selected narrow columns (see \"Angled headers\" section of the demo).");
6990 ImGui::TreePop();
6991 }
6992
6993 if (ImGui::TreeNodeEx("Other:", ImGuiTreeNodeFlags_DefaultOpen))
6994 {
6995 ImGui::Checkbox("show_wrapped_text", &show_wrapped_text);
6996
6997 ImGui::DragFloat2("##OuterSize", &outer_size_value.x);
6998 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
6999 ImGui::Checkbox("outer_size", &outer_size_enabled);
7000 ImGui::SameLine();
7001 HelpMarker("If scrolling is disabled (ScrollX and ScrollY not set):\n"
7002 "- The table is output directly in the parent window.\n"
7003 "- OuterSize.x < 0.0f will right-align the table.\n"
7004 "- OuterSize.x = 0.0f will narrow fit the table unless there are any Stretch columns.\n"
7005 "- OuterSize.y then becomes the minimum size for the table, which will extend vertically if there are more rows (unless NoHostExtendY is set).");
7006
7007 // From a user point of view we will tend to use 'inner_width' differently depending on whether our table is embedding scrolling.
7008 // To facilitate toying with this demo we will actually pass 0.0f to the BeginTable() when ScrollX is disabled.
7009 ImGui::DragFloat("inner_width (when ScrollX active)", &inner_width_with_scroll, 1.0f, 0.0f, FLT_MAX);
7010
7011 ImGui::DragFloat("row_min_height", &row_min_height, 1.0f, 0.0f, FLT_MAX);
7012 ImGui::SameLine(); HelpMarker("Specify height of the Selectable item.");
7013
7014 ImGui::DragInt("items_count", &items_count, 0.1f, 0, 9999);
7015 ImGui::Combo("items_type (first column)", &contents_type, contents_type_names, IM_ARRAYSIZE(contents_type_names));
7016 //filter.Draw("filter");
7017 ImGui::TreePop();
7018 }
7019
7020 ImGui::PopItemWidth();
7021 PopStyleCompact();
7022 ImGui::Spacing();
7023 ImGui::TreePop();
7024 }
7025
7026 // Update item list if we changed the number of items
7027 static ImVector<MyItem> items;
7028 static ImVector<int> selection;
7029 static bool items_need_sort = false;
7030 if (items.Size != items_count)
7031 {
7032 items.resize(items_count, MyItem());
7033 for (int n = 0; n < items_count; n++)
7034 {
7035 const int template_n = n % IM_ARRAYSIZE(template_items_names);
7036 MyItem& item = items[n];
7037 item.ID = n;
7038 item.Name = template_items_names[template_n];
7039 item.Quantity = (template_n == 3) ? 10 : (template_n == 4) ? 20 : 0; // Assign default quantities
7040 }
7041 }
7042
7043 const ImDrawList* parent_draw_list = ImGui::GetWindowDrawList();
7044 const int parent_draw_list_draw_cmd_count = parent_draw_list->CmdBuffer.Size;
7045 ImVec2 table_scroll_cur, table_scroll_max; // For debug display
7046 const ImDrawList* table_draw_list = NULL; // "
7047
7048 // Submit table
7049 const float inner_width_to_use = (flags & ImGuiTableFlags_ScrollX) ? inner_width_with_scroll : 0.0f;
7050 if (ImGui::BeginTable("table_advanced", 6, flags, outer_size_enabled ? outer_size_value : ImVec2(0, 0), inner_width_to_use))
7051 {
7052 // Declare columns
7053 // We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications.
7054 // This is so our sort function can identify a column given our own identifier. We could also identify them based on their index!
7055 ImGui::TableSetupColumn("ID", columns_base_flags | ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoHide, 0.0f, MyItemColumnID_ID);
7056 ImGui::TableSetupColumn("Name", columns_base_flags | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Name);
7057 ImGui::TableSetupColumn("Action", columns_base_flags | ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Action);
7058 ImGui::TableSetupColumn("Quantity", columns_base_flags | ImGuiTableColumnFlags_PreferSortDescending, 0.0f, MyItemColumnID_Quantity);
7059 ImGui::TableSetupColumn("Description", columns_base_flags | ((flags & ImGuiTableFlags_NoHostExtendX) ? 0 : ImGuiTableColumnFlags_WidthStretch), 0.0f, MyItemColumnID_Description);
7060 ImGui::TableSetupColumn("Hidden", columns_base_flags | ImGuiTableColumnFlags_DefaultHide | ImGuiTableColumnFlags_NoSort);
7061 ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows);
7062
7063 // Sort our data if sort specs have been changed!
7064 ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs();
7065 if (sort_specs && sort_specs->SpecsDirty)
7066 items_need_sort = true;
7067 if (sort_specs && items_need_sort && items.Size > 1)
7068 {
7069 MyItem::SortWithSortSpecs(sort_specs, items.Data, items.Size);
7070 sort_specs->SpecsDirty = false;
7071 }
7072 items_need_sort = false;
7073
7074 // Take note of whether we are currently sorting based on the Quantity field,
7075 // we will use this to trigger sorting when we know the data of this column has been modified.
7076 const bool sorts_specs_using_quantity = (ImGui::TableGetColumnFlags(3) & ImGuiTableColumnFlags_IsSorted) != 0;
7077
7078 // Show headers
7079 if (show_headers && (columns_base_flags & ImGuiTableColumnFlags_AngledHeader) != 0)
7080 ImGui::TableAngledHeadersRow();
7081 if (show_headers)
7082 ImGui::TableHeadersRow();
7083
7084 // Show data
7085 // FIXME-TABLE FIXME-NAV: How we can get decent up/down even though we have the buttons here?
7086#if 1
7087 // Demonstrate using clipper for large vertical lists
7088 ImGuiListClipper clipper;
7089 clipper.Begin(items.Size);
7090 while (clipper.Step())
7091 {
7092 for (int row_n = clipper.DisplayStart; row_n < clipper.DisplayEnd; row_n++)
7093#else
7094 // Without clipper
7095 {
7096 for (int row_n = 0; row_n < items.Size; row_n++)
7097#endif
7098 {
7099 MyItem* item = &items[row_n];
7100 //if (!filter.PassFilter(item->Name))
7101 // continue;
7102
7103 const bool item_is_selected = selection.contains(item->ID);
7104 ImGui::PushID(item->ID);
7105 ImGui::TableNextRow(ImGuiTableRowFlags_None, row_min_height);
7106
7107 // For the demo purpose we can select among different type of items submitted in the first column
7108 ImGui::TableSetColumnIndex(0);
7109 char label[32];
7110 sprintf(label, "%04d", item->ID);
7111 if (contents_type == CT_Text)
7113 else if (contents_type == CT_Button)
7114 ImGui::Button(label);
7115 else if (contents_type == CT_SmallButton)
7116 ImGui::SmallButton(label);
7117 else if (contents_type == CT_FillButton)
7118 ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f));
7119 else if (contents_type == CT_Selectable || contents_type == CT_SelectableSpanRow)
7120 {
7121 ImGuiSelectableFlags selectable_flags = (contents_type == CT_SelectableSpanRow) ? ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap : ImGuiSelectableFlags_None;
7122 if (ImGui::Selectable(label, item_is_selected, selectable_flags, ImVec2(0, row_min_height)))
7123 {
7124 if (ImGui::GetIO().KeyCtrl)
7125 {
7126 if (item_is_selected)
7127 selection.find_erase_unsorted(item->ID);
7128 else
7129 selection.push_back(item->ID);
7130 }
7131 else
7132 {
7133 selection.clear();
7134 selection.push_back(item->ID);
7135 }
7136 }
7137 }
7138
7139 if (ImGui::TableSetColumnIndex(1))
7140 ImGui::TextUnformatted(item->Name);
7141
7142 // Here we demonstrate marking our data set as needing to be sorted again if we modified a quantity,
7143 // and we are currently sorting on the column showing the Quantity.
7144 // To avoid triggering a sort while holding the button, we only trigger it when the button has been released.
7145 // You will probably need some extra logic if you want to automatically sort when a specific entry changes.
7146 if (ImGui::TableSetColumnIndex(2))
7147 {
7148 if (ImGui::SmallButton("Chop")) { item->Quantity += 1; }
7149 if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) { items_need_sort = true; }
7150 ImGui::SameLine();
7151 if (ImGui::SmallButton("Eat")) { item->Quantity -= 1; }
7152 if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) { items_need_sort = true; }
7153 }
7154
7155 if (ImGui::TableSetColumnIndex(3))
7156 ImGui::Text("%d", item->Quantity);
7157
7158 ImGui::TableSetColumnIndex(4);
7159 if (show_wrapped_text)
7160 ImGui::TextWrapped("Lorem ipsum dolor sit amet");
7161 else
7162 ImGui::Text("Lorem ipsum dolor sit amet");
7163
7164 if (ImGui::TableSetColumnIndex(5))
7165 ImGui::Text("1234");
7166
7167 ImGui::PopID();
7168 }
7169 }
7170
7171 // Store some info to display debug details below
7172 table_scroll_cur = ImVec2(ImGui::GetScrollX(), ImGui::GetScrollY());
7173 table_scroll_max = ImVec2(ImGui::GetScrollMaxX(), ImGui::GetScrollMaxY());
7174 table_draw_list = ImGui::GetWindowDrawList();
7175 ImGui::EndTable();
7176 }
7177 static bool show_debug_details = false;
7178 ImGui::Checkbox("Debug details", &show_debug_details);
7179 if (show_debug_details && table_draw_list)
7180 {
7181 ImGui::SameLine(0.0f, 0.0f);
7182 const int table_draw_list_draw_cmd_count = table_draw_list->CmdBuffer.Size;
7183 if (table_draw_list == parent_draw_list)
7184 ImGui::Text(": DrawCmd: +%d (in same window)",
7185 table_draw_list_draw_cmd_count - parent_draw_list_draw_cmd_count);
7186 else
7187 ImGui::Text(": DrawCmd: +%d (in child window), Scroll: (%.f/%.f) (%.f/%.f)",
7188 table_draw_list_draw_cmd_count - 1, table_scroll_cur.x, table_scroll_max.x, table_scroll_cur.y, table_scroll_max.y);
7189 }
7190 ImGui::TreePop();
7191 }
7192
7193 ImGui::PopID();
7194
7195 ShowDemoWindowColumns();
7196
7197 if (disable_indent)
7198 ImGui::PopStyleVar();
7199}
7200
7201// Demonstrate old/legacy Columns API!
7202// [2020: Columns are under-featured and not maintained. Prefer using the more flexible and powerful BeginTable() API!]
7203static void ShowDemoWindowColumns()
7204{
7205 IMGUI_DEMO_MARKER("Columns (legacy API)");
7206 bool open = ImGui::TreeNode("Legacy Columns API");
7207 ImGui::SameLine();
7208 HelpMarker("Columns() is an old API! Prefer using the more flexible and powerful BeginTable() API!");
7209 if (!open)
7210 return;
7211
7212 // Basic columns
7213 IMGUI_DEMO_MARKER("Columns (legacy API)/Basic");
7214 if (ImGui::TreeNode("Basic"))
7215 {
7216 ImGui::Text("Without border:");
7217 ImGui::Columns(3, "mycolumns3", false); // 3-ways, no border
7218 ImGui::Separator();
7219 for (int n = 0; n < 14; n++)
7220 {
7221 char label[32];
7222 sprintf(label, "Item %d", n);
7223 if (ImGui::Selectable(label)) {}
7224 //if (ImGui::Button(label, ImVec2(-FLT_MIN,0.0f))) {}
7225 ImGui::NextColumn();
7226 }
7227 ImGui::Columns(1);
7228 ImGui::Separator();
7229
7230 ImGui::Text("With border:");
7231 ImGui::Columns(4, "mycolumns"); // 4-ways, with border
7232 ImGui::Separator();
7233 ImGui::Text("ID"); ImGui::NextColumn();
7234 ImGui::Text("Name"); ImGui::NextColumn();
7235 ImGui::Text("Path"); ImGui::NextColumn();
7236 ImGui::Text("Hovered"); ImGui::NextColumn();
7237 ImGui::Separator();
7238 const char* names[3] = { "One", "Two", "Three" };
7239 const char* paths[3] = { "/path/one", "/path/two", "/path/three" };
7240 static int selected = -1;
7241 for (int i = 0; i < 3; i++)
7242 {
7243 char label[32];
7244 sprintf(label, "%04d", i);
7245 if (ImGui::Selectable(label, selected == i, ImGuiSelectableFlags_SpanAllColumns))
7246 selected = i;
7247 bool hovered = ImGui::IsItemHovered();
7248 ImGui::NextColumn();
7249 ImGui::Text(names[i]); ImGui::NextColumn();
7250 ImGui::Text(paths[i]); ImGui::NextColumn();
7251 ImGui::Text("%d", hovered); ImGui::NextColumn();
7252 }
7253 ImGui::Columns(1);
7254 ImGui::Separator();
7255 ImGui::TreePop();
7256 }
7257
7258 IMGUI_DEMO_MARKER("Columns (legacy API)/Borders");
7259 if (ImGui::TreeNode("Borders"))
7260 {
7261 // NB: Future columns API should allow automatic horizontal borders.
7262 static bool h_borders = true;
7263 static bool v_borders = true;
7264 static int columns_count = 4;
7265 const int lines_count = 3;
7266 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
7267 ImGui::DragInt("##columns_count", &columns_count, 0.1f, 2, 10, "%d columns");
7268 if (columns_count < 2)
7269 columns_count = 2;
7270 ImGui::SameLine();
7271 ImGui::Checkbox("horizontal", &h_borders);
7272 ImGui::SameLine();
7273 ImGui::Checkbox("vertical", &v_borders);
7274 ImGui::Columns(columns_count, NULL, v_borders);
7275 for (int i = 0; i < columns_count * lines_count; i++)
7276 {
7277 if (h_borders && ImGui::GetColumnIndex() == 0)
7278 ImGui::Separator();
7279 ImGui::PushID(i);
7280 ImGui::Text("%c%c%c", 'a' + i, 'a' + i, 'a' + i);
7281 ImGui::Text("Width %.2f", ImGui::GetColumnWidth());
7282 ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x);
7283 ImGui::Text("Offset %.2f", ImGui::GetColumnOffset());
7284 ImGui::Text("Long text that is likely to clip");
7285 ImGui::Button("Button", ImVec2(-FLT_MIN, 0.0f));
7286 ImGui::PopID();
7287 ImGui::NextColumn();
7288 }
7289 ImGui::Columns(1);
7290 if (h_borders)
7291 ImGui::Separator();
7292 ImGui::TreePop();
7293 }
7294
7295 // Create multiple items in a same cell before switching to next column
7296 IMGUI_DEMO_MARKER("Columns (legacy API)/Mixed items");
7297 if (ImGui::TreeNode("Mixed items"))
7298 {
7299 ImGui::Columns(3, "mixed");
7300 ImGui::Separator();
7301
7302 ImGui::Text("Hello");
7303 ImGui::Button("Banana");
7304 ImGui::NextColumn();
7305
7306 ImGui::Text("ImGui");
7307 ImGui::Button("Apple");
7308 static float foo = 1.0f;
7309 ImGui::InputFloat("red", &foo, 0.05f, 0, "%.3f");
7310 ImGui::Text("An extra line here.");
7311 ImGui::NextColumn();
7312
7313 ImGui::Text("Sailor");
7314 ImGui::Button("Corniflower");
7315 static float bar = 1.0f;
7316 ImGui::InputFloat("blue", &bar, 0.05f, 0, "%.3f");
7317 ImGui::NextColumn();
7318
7319 if (ImGui::CollapsingHeader("Category A")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
7320 if (ImGui::CollapsingHeader("Category B")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
7321 if (ImGui::CollapsingHeader("Category C")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
7322 ImGui::Columns(1);
7323 ImGui::Separator();
7324 ImGui::TreePop();
7325 }
7326
7327 // Word wrapping
7328 IMGUI_DEMO_MARKER("Columns (legacy API)/Word-wrapping");
7329 if (ImGui::TreeNode("Word-wrapping"))
7330 {
7331 ImGui::Columns(2, "word-wrapping");
7332 ImGui::Separator();
7333 ImGui::TextWrapped("The quick brown fox jumps over the lazy dog.");
7334 ImGui::TextWrapped("Hello Left");
7335 ImGui::NextColumn();
7336 ImGui::TextWrapped("The quick brown fox jumps over the lazy dog.");
7337 ImGui::TextWrapped("Hello Right");
7338 ImGui::Columns(1);
7339 ImGui::Separator();
7340 ImGui::TreePop();
7341 }
7342
7343 IMGUI_DEMO_MARKER("Columns (legacy API)/Horizontal Scrolling");
7344 if (ImGui::TreeNode("Horizontal Scrolling"))
7345 {
7346 ImGui::SetNextWindowContentSize(ImVec2(1500.0f, 0.0f));
7347 ImVec2 child_size = ImVec2(0, ImGui::GetFontSize() * 20.0f);
7348 ImGui::BeginChild("##ScrollingRegion", child_size, ImGuiChildFlags_None, ImGuiWindowFlags_HorizontalScrollbar);
7349 ImGui::Columns(10);
7350
7351 // Also demonstrate using clipper for large vertical lists
7352 int ITEMS_COUNT = 2000;
7353 ImGuiListClipper clipper;
7354 clipper.Begin(ITEMS_COUNT);
7355 while (clipper.Step())
7356 {
7357 for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
7358 for (int j = 0; j < 10; j++)
7359 {
7360 ImGui::Text("Line %d Column %d...", i, j);
7361 ImGui::NextColumn();
7362 }
7363 }
7364 ImGui::Columns(1);
7365 ImGui::EndChild();
7366 ImGui::TreePop();
7367 }
7368
7369 IMGUI_DEMO_MARKER("Columns (legacy API)/Tree");
7370 if (ImGui::TreeNode("Tree"))
7371 {
7372 ImGui::Columns(2, "tree", true);
7373 for (int x = 0; x < 3; x++)
7374 {
7375 bool open1 = ImGui::TreeNode((void*)(intptr_t)x, "Node%d", x);
7376 ImGui::NextColumn();
7377 ImGui::Text("Node contents");
7378 ImGui::NextColumn();
7379 if (open1)
7380 {
7381 for (int y = 0; y < 3; y++)
7382 {
7383 bool open2 = ImGui::TreeNode((void*)(intptr_t)y, "Node%d.%d", x, y);
7384 ImGui::NextColumn();
7385 ImGui::Text("Node contents");
7386 if (open2)
7387 {
7388 ImGui::Text("Even more contents");
7389 if (ImGui::TreeNode("Tree in column"))
7390 {
7391 ImGui::Text("The quick brown fox jumps over the lazy dog");
7392 ImGui::TreePop();
7393 }
7394 }
7395 ImGui::NextColumn();
7396 if (open2)
7397 ImGui::TreePop();
7398 }
7399 ImGui::TreePop();
7400 }
7401 }
7402 ImGui::Columns(1);
7403 ImGui::TreePop();
7404 }
7405
7406 ImGui::TreePop();
7407}
7408
7409//-----------------------------------------------------------------------------
7410// [SECTION] ShowDemoWindowInputs()
7411//-----------------------------------------------------------------------------
7412
7413static void ShowDemoWindowInputs()
7414{
7415 IMGUI_DEMO_MARKER("Inputs & Focus");
7416 if (ImGui::CollapsingHeader("Inputs & Focus"))
7417 {
7418 ImGuiIO& io = ImGui::GetIO();
7419
7420 // Display inputs submitted to ImGuiIO
7421 IMGUI_DEMO_MARKER("Inputs & Focus/Inputs");
7422 ImGui::SetNextItemOpen(true, ImGuiCond_Once);
7423 bool inputs_opened = ImGui::TreeNode("Inputs");
7424 ImGui::SameLine();
7425 HelpMarker(
7426 "This is a simplified view. See more detailed input state:\n"
7427 "- in 'Tools->Metrics/Debugger->Inputs'.\n"
7428 "- in 'Tools->Debug Log->IO'.");
7429 if (inputs_opened)
7430 {
7431 if (ImGui::IsMousePosValid())
7432 ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y);
7433 else
7434 ImGui::Text("Mouse pos: <INVALID>");
7435 ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y);
7436 ImGui::Text("Mouse down:");
7437 for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDown(i)) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); }
7438 ImGui::Text("Mouse wheel: %.1f", io.MouseWheel);
7439
7440 // We iterate both legacy native range and named ImGuiKey ranges. This is a little unusual/odd but this allows
7441 // displaying the data for old/new backends.
7442 // User code should never have to go through such hoops!
7443 // You can generally iterate between ImGuiKey_NamedKey_BEGIN and ImGuiKey_NamedKey_END.
7444#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO
7445 struct funcs { static bool IsLegacyNativeDupe(ImGuiKey) { return false; } };
7446 ImGuiKey start_key = ImGuiKey_NamedKey_BEGIN;
7447#else
7448 struct funcs { static bool IsLegacyNativeDupe(ImGuiKey key) { return key >= 0 && key < 512 && ImGui::GetIO().KeyMap[key] != -1; } }; // Hide Native<>ImGuiKey duplicates when both exists in the array
7449 ImGuiKey start_key = (ImGuiKey)0;
7450#endif
7451 ImGui::Text("Keys down:"); for (ImGuiKey key = start_key; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !ImGui::IsKeyDown(key)) continue; ImGui::SameLine(); ImGui::Text((key < ImGuiKey_NamedKey_BEGIN) ? "\"%s\"" : "\"%s\" %d", ImGui::GetKeyName(key), key); }
7452 ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : "");
7453 ImGui::Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; ImGui::SameLine(); ImGui::Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public.
7454
7455 ImGui::TreePop();
7456 }
7457
7458 // Display ImGuiIO output flags
7459 IMGUI_DEMO_MARKER("Inputs & Focus/Outputs");
7460 ImGui::SetNextItemOpen(true, ImGuiCond_Once);
7461 bool outputs_opened = ImGui::TreeNode("Outputs");
7462 ImGui::SameLine();
7463 HelpMarker(
7464 "The value of io.WantCaptureMouse and io.WantCaptureKeyboard are normally set by Dear ImGui "
7465 "to instruct your application of how to route inputs. Typically, when a value is true, it means "
7466 "Dear ImGui wants the corresponding inputs and we expect the underlying application to ignore them.\n\n"
7467 "The most typical case is: when hovering a window, Dear ImGui set io.WantCaptureMouse to true, "
7468 "and underlying application should ignore mouse inputs (in practice there are many and more subtle "
7469 "rules leading to how those flags are set).");
7470 if (outputs_opened)
7471 {
7472 ImGui::Text("io.WantCaptureMouse: %d", io.WantCaptureMouse);
7473 ImGui::Text("io.WantCaptureMouseUnlessPopupClose: %d", io.WantCaptureMouseUnlessPopupClose);
7474 ImGui::Text("io.WantCaptureKeyboard: %d", io.WantCaptureKeyboard);
7475 ImGui::Text("io.WantTextInput: %d", io.WantTextInput);
7476 ImGui::Text("io.WantSetMousePos: %d", io.WantSetMousePos);
7477 ImGui::Text("io.NavActive: %d, io.NavVisible: %d", io.NavActive, io.NavVisible);
7478
7479 IMGUI_DEMO_MARKER("Inputs & Focus/Outputs/WantCapture override");
7480 if (ImGui::TreeNode("WantCapture override"))
7481 {
7482 HelpMarker(
7483 "Hovering the colored canvas will override io.WantCaptureXXX fields.\n"
7484 "Notice how normally (when set to none), the value of io.WantCaptureKeyboard would be false when hovering "
7485 "and true when clicking.");
7486 static int capture_override_mouse = -1;
7487 static int capture_override_keyboard = -1;
7488 const char* capture_override_desc[] = { "None", "Set to false", "Set to true" };
7489 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15);
7490 ImGui::SliderInt("SetNextFrameWantCaptureMouse() on hover", &capture_override_mouse, -1, +1, capture_override_desc[capture_override_mouse + 1], ImGuiSliderFlags_AlwaysClamp);
7491 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15);
7492 ImGui::SliderInt("SetNextFrameWantCaptureKeyboard() on hover", &capture_override_keyboard, -1, +1, capture_override_desc[capture_override_keyboard + 1], ImGuiSliderFlags_AlwaysClamp);
7493
7494 ImGui::ColorButton("##panel", ImVec4(0.7f, 0.1f, 0.7f, 1.0f), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop, ImVec2(128.0f, 96.0f)); // Dummy item
7495 if (ImGui::IsItemHovered() && capture_override_mouse != -1)
7496 ImGui::SetNextFrameWantCaptureMouse(capture_override_mouse == 1);
7497 if (ImGui::IsItemHovered() && capture_override_keyboard != -1)
7498 ImGui::SetNextFrameWantCaptureKeyboard(capture_override_keyboard == 1);
7499
7500 ImGui::TreePop();
7501 }
7502 ImGui::TreePop();
7503 }
7504
7505 // Demonstrate using Shortcut() and Routing Policies.
7506 // The general flow is:
7507 // - Code interested in a chord (e.g. "Ctrl+A") declares their intent.
7508 // - Multiple locations may be interested in same chord! Routing helps find a winner.
7509 // - Every frame, we resolve all claims and assign one owner if the modifiers are matching.
7510 // - The lower-level function is 'bool SetShortcutRouting()', returns true when caller got the route.
7511 // - Most of the times, SetShortcutRouting() is not called directly. User mostly calls Shortcut() with routing flags.
7512 // - If you call Shortcut() WITHOUT any routing option, it uses ImGuiInputFlags_RouteFocused.
7513 // TL;DR: Most uses will simply be:
7514 // - Shortcut(ImGuiMod_Ctrl | ImGuiKey_A); // Use ImGuiInputFlags_RouteFocused policy.
7515 IMGUI_DEMO_MARKER("Inputs & Focus/Shortcuts");
7516 if (ImGui::TreeNode("Shortcuts"))
7517 {
7518 static ImGuiInputFlags route_options = ImGuiInputFlags_Repeat;
7519 static ImGuiInputFlags route_type = ImGuiInputFlags_RouteFocused;
7520 ImGui::CheckboxFlags("ImGuiInputFlags_Repeat", &route_options, ImGuiInputFlags_Repeat);
7521 ImGui::RadioButton("ImGuiInputFlags_RouteActive", &route_type, ImGuiInputFlags_RouteActive);
7522 ImGui::RadioButton("ImGuiInputFlags_RouteFocused (default)", &route_type, ImGuiInputFlags_RouteFocused);
7523 ImGui::RadioButton("ImGuiInputFlags_RouteGlobal", &route_type, ImGuiInputFlags_RouteGlobal);
7524 ImGui::Indent();
7525 ImGui::BeginDisabled(route_type != ImGuiInputFlags_RouteGlobal);
7526 ImGui::CheckboxFlags("ImGuiInputFlags_RouteOverFocused", &route_options, ImGuiInputFlags_RouteOverFocused);
7527 ImGui::CheckboxFlags("ImGuiInputFlags_RouteOverActive", &route_options, ImGuiInputFlags_RouteOverActive);
7528 ImGui::CheckboxFlags("ImGuiInputFlags_RouteUnlessBgFocused", &route_options, ImGuiInputFlags_RouteUnlessBgFocused);
7529 ImGui::EndDisabled();
7530 ImGui::Unindent();
7531 ImGui::RadioButton("ImGuiInputFlags_RouteAlways", &route_type, ImGuiInputFlags_RouteAlways);
7532 ImGuiInputFlags flags = route_type | route_options; // Merged flags
7533 if (route_type != ImGuiInputFlags_RouteGlobal)
7534 flags &= ~(ImGuiInputFlags_RouteOverFocused | ImGuiInputFlags_RouteOverActive | ImGuiInputFlags_RouteUnlessBgFocused);
7535
7536 ImGui::SeparatorText("Using SetNextItemShortcut()");
7537 ImGui::Text("Ctrl+S");
7538 ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_S, flags | ImGuiInputFlags_Tooltip);
7539 ImGui::Button("Save");
7540 ImGui::Text("Alt+F");
7541 ImGui::SetNextItemShortcut(ImGuiMod_Alt | ImGuiKey_F, flags | ImGuiInputFlags_Tooltip);
7542 static float f = 0.5f;
7543 ImGui::SliderFloat("Factor", &f, 0.0f, 1.0f);
7544
7545 ImGui::SeparatorText("Using Shortcut()");
7546 const float line_height = ImGui::GetTextLineHeightWithSpacing();
7547 const ImGuiKeyChord key_chord = ImGuiMod_Ctrl | ImGuiKey_A;
7548
7549 ImGui::Text("Ctrl+A");
7550 ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "...");
7551
7552 ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 0.0f, 1.0f, 0.1f));
7553
7554 ImGui::BeginChild("WindowA", ImVec2(-FLT_MIN, line_height * 14), true);
7555 ImGui::Text("Press CTRL+A and see who receives it!");
7556 ImGui::Separator();
7557
7558 // 1: Window polling for CTRL+A
7559 ImGui::Text("(in WindowA)");
7560 ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "...");
7561
7562 // 2: InputText also polling for CTRL+A: it always uses _RouteFocused internally (gets priority when active)
7563 // (Commmented because the owner-aware version of Shortcut() is still in imgui_internal.h)
7564 //char str[16] = "Press CTRL+A";
7565 //ImGui::Spacing();
7566 //ImGui::InputText("InputTextB", str, IM_ARRAYSIZE(str), ImGuiInputTextFlags_ReadOnly);
7567 //ImGuiID item_id = ImGui::GetItemID();
7568 //ImGui::SameLine(); HelpMarker("Internal widgets always use _RouteFocused");
7569 //ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags, item_id) ? "PRESSED" : "...");
7570
7571 // 3: Dummy child is not claiming the route: focusing them shouldn't steal route away from WindowA
7572 ImGui::BeginChild("ChildD", ImVec2(-FLT_MIN, line_height * 4), true);
7573 ImGui::Text("(in ChildD: not using same Shortcut)");
7574 ImGui::Text("IsWindowFocused: %d", ImGui::IsWindowFocused());
7575 ImGui::EndChild();
7576
7577 // 4: Child window polling for CTRL+A. It is deeper than WindowA and gets priority when focused.
7578 ImGui::BeginChild("ChildE", ImVec2(-FLT_MIN, line_height * 4), true);
7579 ImGui::Text("(in ChildE: using same Shortcut)");
7580 ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "...");
7581 ImGui::EndChild();
7582
7583 // 5: In a popup
7584 if (ImGui::Button("Open Popup"))
7585 ImGui::OpenPopup("PopupF");
7586 if (ImGui::BeginPopup("PopupF"))
7587 {
7588 ImGui::Text("(in PopupF)");
7589 ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "...");
7590 // (Commmented because the owner-aware version of Shortcut() is still in imgui_internal.h)
7591 //ImGui::InputText("InputTextG", str, IM_ARRAYSIZE(str), ImGuiInputTextFlags_ReadOnly);
7592 //ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags, ImGui::GetItemID()) ? "PRESSED" : "...");
7593 ImGui::EndPopup();
7594 }
7595 ImGui::EndChild();
7596 ImGui::PopStyleColor();
7597
7598 ImGui::TreePop();
7599 }
7600
7601 // Display mouse cursors
7602 IMGUI_DEMO_MARKER("Inputs & Focus/Mouse Cursors");
7603 if (ImGui::TreeNode("Mouse Cursors"))
7604 {
7605 const char* mouse_cursors_names[] = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "NotAllowed" };
7606 IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT);
7607
7608 ImGuiMouseCursor current = ImGui::GetMouseCursor();
7609 const char* cursor_name = (current >= ImGuiMouseCursor_Arrow) && (current < ImGuiMouseCursor_COUNT) ? mouse_cursors_names[current] : "N/A";
7610 ImGui::Text("Current mouse cursor = %d: %s", current, cursor_name);
7611 ImGui::BeginDisabled(true);
7612 ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors);
7613 ImGui::EndDisabled();
7614
7615 ImGui::Text("Hover to see mouse cursors:");
7616 ImGui::SameLine(); HelpMarker(
7617 "Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. "
7618 "If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, "
7619 "otherwise your backend needs to handle it.");
7620 for (int i = 0; i < ImGuiMouseCursor_COUNT; i++)
7621 {
7622 char label[32];
7623 sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]);
7624 ImGui::Bullet(); ImGui::Selectable(label, false);
7625 if (ImGui::IsItemHovered())
7626 ImGui::SetMouseCursor(i);
7627 }
7628 ImGui::TreePop();
7629 }
7630
7631 IMGUI_DEMO_MARKER("Inputs & Focus/Tabbing");
7632 if (ImGui::TreeNode("Tabbing"))
7633 {
7634 ImGui::Text("Use TAB/SHIFT+TAB to cycle through keyboard editable fields.");
7635 static char buf[32] = "hello";
7636 ImGui::InputText("1", buf, IM_ARRAYSIZE(buf));
7637 ImGui::InputText("2", buf, IM_ARRAYSIZE(buf));
7638 ImGui::InputText("3", buf, IM_ARRAYSIZE(buf));
7639 ImGui::PushItemFlag(ImGuiItemFlags_NoTabStop, true);
7640 ImGui::InputText("4 (tab skip)", buf, IM_ARRAYSIZE(buf));
7641 ImGui::SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab.");
7642 ImGui::PopItemFlag();
7643 ImGui::InputText("5", buf, IM_ARRAYSIZE(buf));
7644 ImGui::TreePop();
7645 }
7646
7647 IMGUI_DEMO_MARKER("Inputs & Focus/Focus from code");
7648 if (ImGui::TreeNode("Focus from code"))
7649 {
7650 bool focus_1 = ImGui::Button("Focus on 1"); ImGui::SameLine();
7651 bool focus_2 = ImGui::Button("Focus on 2"); ImGui::SameLine();
7652 bool focus_3 = ImGui::Button("Focus on 3");
7653 int has_focus = 0;
7654 static char buf[128] = "click on a button to set focus";
7655
7656 if (focus_1) ImGui::SetKeyboardFocusHere();
7657 ImGui::InputText("1", buf, IM_ARRAYSIZE(buf));
7658 if (ImGui::IsItemActive()) has_focus = 1;
7659
7660 if (focus_2) ImGui::SetKeyboardFocusHere();
7661 ImGui::InputText("2", buf, IM_ARRAYSIZE(buf));
7662 if (ImGui::IsItemActive()) has_focus = 2;
7663
7664 ImGui::PushItemFlag(ImGuiItemFlags_NoTabStop, true);
7665 if (focus_3) ImGui::SetKeyboardFocusHere();
7666 ImGui::InputText("3 (tab skip)", buf, IM_ARRAYSIZE(buf));
7667 if (ImGui::IsItemActive()) has_focus = 3;
7668 ImGui::SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab.");
7669 ImGui::PopItemFlag();
7670
7671 if (has_focus)
7672 ImGui::Text("Item with focus: %d", has_focus);
7673 else
7674 ImGui::Text("Item with focus: <none>");
7675
7676 // Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item
7677 static float f3[3] = { 0.0f, 0.0f, 0.0f };
7678 int focus_ahead = -1;
7679 if (ImGui::Button("Focus on X")) { focus_ahead = 0; } ImGui::SameLine();
7680 if (ImGui::Button("Focus on Y")) { focus_ahead = 1; } ImGui::SameLine();
7681 if (ImGui::Button("Focus on Z")) { focus_ahead = 2; }
7682 if (focus_ahead != -1) ImGui::SetKeyboardFocusHere(focus_ahead);
7683 ImGui::SliderFloat3("Float3", &f3[0], 0.0f, 1.0f);
7684
7685 ImGui::TextWrapped("NB: Cursor & selection are preserved when refocusing last used item in code.");
7686 ImGui::TreePop();
7687 }
7688
7689 IMGUI_DEMO_MARKER("Inputs & Focus/Dragging");
7690 if (ImGui::TreeNode("Dragging"))
7691 {
7692 ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget.");
7693 for (int button = 0; button < 3; button++)
7694 {
7695 ImGui::Text("IsMouseDragging(%d):", button);
7696 ImGui::Text(" w/ default threshold: %d,", ImGui::IsMouseDragging(button));
7697 ImGui::Text(" w/ zero threshold: %d,", ImGui::IsMouseDragging(button, 0.0f));
7698 ImGui::Text(" w/ large threshold: %d,", ImGui::IsMouseDragging(button, 20.0f));
7699 }
7700
7701 ImGui::Button("Drag Me");
7702 if (ImGui::IsItemActive())
7703 ImGui::GetForegroundDrawList()->AddLine(io.MouseClickedPos[0], io.MousePos, ImGui::GetColorU32(ImGuiCol_Button), 4.0f); // Draw a line between the button and the mouse cursor
7704
7705 // Drag operations gets "unlocked" when the mouse has moved past a certain threshold
7706 // (the default threshold is stored in io.MouseDragThreshold). You can request a lower or higher
7707 // threshold using the second parameter of IsMouseDragging() and GetMouseDragDelta().
7708 ImVec2 value_raw = ImGui::GetMouseDragDelta(0, 0.0f);
7709 ImVec2 value_with_lock_threshold = ImGui::GetMouseDragDelta(0);
7710 ImVec2 mouse_delta = io.MouseDelta;
7711 ImGui::Text("GetMouseDragDelta(0):");
7712 ImGui::Text(" w/ default threshold: (%.1f, %.1f)", value_with_lock_threshold.x, value_with_lock_threshold.y);
7713 ImGui::Text(" w/ zero threshold: (%.1f, %.1f)", value_raw.x, value_raw.y);
7714 ImGui::Text("io.MouseDelta: (%.1f, %.1f)", mouse_delta.x, mouse_delta.y);
7715 ImGui::TreePop();
7716 }
7717 }
7718}
7719
7720//-----------------------------------------------------------------------------
7721// [SECTION] About Window / ShowAboutWindow()
7722// Access from Dear ImGui Demo -> Tools -> About
7723//-----------------------------------------------------------------------------
7724
7725void ImGui::ShowAboutWindow(bool* p_open)
7726{
7727 if (!ImGui::Begin("About Dear ImGui", p_open, ImGuiWindowFlags_AlwaysAutoResize))
7728 {
7729 ImGui::End();
7730 return;
7731 }
7732 IMGUI_DEMO_MARKER("Tools/About Dear ImGui");
7733 ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
7734
7735 ImGui::TextLinkOpenURL("Homepage", "https://github.com/ocornut/imgui");
7736 ImGui::SameLine();
7737 ImGui::TextLinkOpenURL("FAQ", "https://github.com/ocornut/imgui/blob/master/docs/FAQ.md");
7738 ImGui::SameLine();
7739 ImGui::TextLinkOpenURL("Wiki", "https://github.com/ocornut/imgui/wiki");
7740 ImGui::SameLine();
7741 ImGui::TextLinkOpenURL("Releases", "https://github.com/ocornut/imgui/releases");
7742 ImGui::SameLine();
7743 ImGui::TextLinkOpenURL("Funding", "https://github.com/ocornut/imgui/wiki/Funding");
7744
7745 ImGui::Separator();
7746 ImGui::Text("By Omar Cornut and all Dear ImGui contributors.");
7747 ImGui::Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information.");
7748 ImGui::Text("If your company uses this, please consider funding the project.");
7749
7750 static bool show_config_info = false;
7751 ImGui::Checkbox("Config/Build Information", &show_config_info);
7752 if (show_config_info)
7753 {
7754 ImGuiIO& io = ImGui::GetIO();
7755 ImGuiStyle& style = ImGui::GetStyle();
7756
7757 bool copy_to_clipboard = ImGui::Button("Copy to clipboard");
7758 ImVec2 child_size = ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 18);
7759 ImGui::BeginChild(ImGui::GetID("cfg_infos"), child_size, ImGuiChildFlags_FrameStyle);
7760 if (copy_to_clipboard)
7761 {
7762 ImGui::LogToClipboard();
7763 ImGui::LogText("```\n"); // Back quotes will make text appears without formatting when pasting on GitHub
7764 }
7765
7766 ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
7767 ImGui::Separator();
7768 ImGui::Text("sizeof(size_t): %d, sizeof(ImDrawIdx): %d, sizeof(ImDrawVert): %d", (int)sizeof(size_t), (int)sizeof(ImDrawIdx), (int)sizeof(ImDrawVert));
7769 ImGui::Text("define: __cplusplus=%d", (int)__cplusplus);
7770#ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
7771 ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_FUNCTIONS");
7772#endif
7773#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO
7774 ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_KEYIO");
7775#endif
7776#ifdef IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS
7777 ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS");
7778#endif
7779#ifdef IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
7780 ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS");
7781#endif
7782#ifdef IMGUI_DISABLE_WIN32_FUNCTIONS
7783 ImGui::Text("define: IMGUI_DISABLE_WIN32_FUNCTIONS");
7784#endif
7785#ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
7786 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS");
7787#endif
7788#ifdef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS
7789 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS");
7790#endif
7791#ifdef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
7792 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS");
7793#endif
7794#ifdef IMGUI_DISABLE_FILE_FUNCTIONS
7795 ImGui::Text("define: IMGUI_DISABLE_FILE_FUNCTIONS");
7796#endif
7797#ifdef IMGUI_DISABLE_DEFAULT_ALLOCATORS
7798 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_ALLOCATORS");
7799#endif
7800#ifdef IMGUI_USE_BGRA_PACKED_COLOR
7801 ImGui::Text("define: IMGUI_USE_BGRA_PACKED_COLOR");
7802#endif
7803#ifdef _WIN32
7804 ImGui::Text("define: _WIN32");
7805#endif
7806#ifdef _WIN64
7807 ImGui::Text("define: _WIN64");
7808#endif
7809#ifdef __linux__
7810 ImGui::Text("define: __linux__");
7811#endif
7812#ifdef __APPLE__
7813 ImGui::Text("define: __APPLE__");
7814#endif
7815#ifdef _MSC_VER
7816 ImGui::Text("define: _MSC_VER=%d", _MSC_VER);
7817#endif
7818#ifdef _MSVC_LANG
7819 ImGui::Text("define: _MSVC_LANG=%d", (int)_MSVC_LANG);
7820#endif
7821#ifdef __MINGW32__
7822 ImGui::Text("define: __MINGW32__");
7823#endif
7824#ifdef __MINGW64__
7825 ImGui::Text("define: __MINGW64__");
7826#endif
7827#ifdef __GNUC__
7828 ImGui::Text("define: __GNUC__=%d", (int)__GNUC__);
7829#endif
7830#ifdef __clang_version__
7831 ImGui::Text("define: __clang_version__=%s", __clang_version__);
7832#endif
7833#ifdef __EMSCRIPTEN__
7834 ImGui::Text("define: __EMSCRIPTEN__");
7835 ImGui::Text("Emscripten: %d.%d.%d", __EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__);
7836#endif
7837#ifdef IMGUI_HAS_VIEWPORT
7838 ImGui::Text("define: IMGUI_HAS_VIEWPORT");
7839#endif
7840#ifdef IMGUI_HAS_DOCK
7841 ImGui::Text("define: IMGUI_HAS_DOCK");
7842#endif
7843 ImGui::Separator();
7844 ImGui::Text("io.BackendPlatformName: %s", io.BackendPlatformName ? io.BackendPlatformName : "NULL");
7845 ImGui::Text("io.BackendRendererName: %s", io.BackendRendererName ? io.BackendRendererName : "NULL");
7846 ImGui::Text("io.ConfigFlags: 0x%08X", io.ConfigFlags);
7847 if (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) ImGui::Text(" NavEnableKeyboard");
7848 if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) ImGui::Text(" NavEnableGamepad");
7849 if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) ImGui::Text(" NoMouse");
7850 if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) ImGui::Text(" NoMouseCursorChange");
7851 if (io.ConfigFlags & ImGuiConfigFlags_NoKeyboard) ImGui::Text(" NoKeyboard");
7852 if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable) ImGui::Text(" DockingEnable");
7853 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) ImGui::Text(" ViewportsEnable");
7854 if (io.ConfigFlags & ImGuiConfigFlags_DpiEnableScaleViewports) ImGui::Text(" DpiEnableScaleViewports");
7855 if (io.ConfigFlags & ImGuiConfigFlags_DpiEnableScaleFonts) ImGui::Text(" DpiEnableScaleFonts");
7856 if (io.MouseDrawCursor) ImGui::Text("io.MouseDrawCursor");
7857 if (io.ConfigViewportsNoAutoMerge) ImGui::Text("io.ConfigViewportsNoAutoMerge");
7858 if (io.ConfigViewportsNoTaskBarIcon) ImGui::Text("io.ConfigViewportsNoTaskBarIcon");
7859 if (io.ConfigViewportsNoDecoration) ImGui::Text("io.ConfigViewportsNoDecoration");
7860 if (io.ConfigViewportsNoDefaultParent) ImGui::Text("io.ConfigViewportsNoDefaultParent");
7861 if (io.ConfigDockingNoSplit) ImGui::Text("io.ConfigDockingNoSplit");
7862 if (io.ConfigDockingWithShift) ImGui::Text("io.ConfigDockingWithShift");
7863 if (io.ConfigDockingAlwaysTabBar) ImGui::Text("io.ConfigDockingAlwaysTabBar");
7864 if (io.ConfigDockingTransparentPayload) ImGui::Text("io.ConfigDockingTransparentPayload");
7865 if (io.ConfigMacOSXBehaviors) ImGui::Text("io.ConfigMacOSXBehaviors");
7866 if (io.ConfigNavMoveSetMousePos) ImGui::Text("io.ConfigNavMoveSetMousePos");
7867 if (io.ConfigNavCaptureKeyboard) ImGui::Text("io.ConfigNavCaptureKeyboard");
7868 if (io.ConfigInputTextCursorBlink) ImGui::Text("io.ConfigInputTextCursorBlink");
7869 if (io.ConfigWindowsResizeFromEdges) ImGui::Text("io.ConfigWindowsResizeFromEdges");
7870 if (io.ConfigWindowsMoveFromTitleBarOnly) ImGui::Text("io.ConfigWindowsMoveFromTitleBarOnly");
7871 if (io.ConfigMemoryCompactTimer >= 0.0f) ImGui::Text("io.ConfigMemoryCompactTimer = %.1f", io.ConfigMemoryCompactTimer);
7872 ImGui::Text("io.BackendFlags: 0x%08X", io.BackendFlags);
7873 if (io.BackendFlags & ImGuiBackendFlags_HasGamepad) ImGui::Text(" HasGamepad");
7874 if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) ImGui::Text(" HasMouseCursors");
7875 if (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos) ImGui::Text(" HasSetMousePos");
7876 if (io.BackendFlags & ImGuiBackendFlags_PlatformHasViewports) ImGui::Text(" PlatformHasViewports");
7877 if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport)ImGui::Text(" HasMouseHoveredViewport");
7878 if (io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) ImGui::Text(" RendererHasVtxOffset");
7879 if (io.BackendFlags & ImGuiBackendFlags_RendererHasViewports) ImGui::Text(" RendererHasViewports");
7880 ImGui::Separator();
7881 ImGui::Text("io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", io.Fonts->Fonts.Size, io.Fonts->Flags, io.Fonts->TexWidth, io.Fonts->TexHeight);
7882 ImGui::Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y);
7883 ImGui::Text("io.DisplayFramebufferScale: %.2f,%.2f", io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y);
7884 ImGui::Separator();
7885 ImGui::Text("style.WindowPadding: %.2f,%.2f", style.WindowPadding.x, style.WindowPadding.y);
7886 ImGui::Text("style.WindowBorderSize: %.2f", style.WindowBorderSize);
7887 ImGui::Text("style.FramePadding: %.2f,%.2f", style.FramePadding.x, style.FramePadding.y);
7888 ImGui::Text("style.FrameRounding: %.2f", style.FrameRounding);
7889 ImGui::Text("style.FrameBorderSize: %.2f", style.FrameBorderSize);
7890 ImGui::Text("style.ItemSpacing: %.2f,%.2f", style.ItemSpacing.x, style.ItemSpacing.y);
7891 ImGui::Text("style.ItemInnerSpacing: %.2f,%.2f", style.ItemInnerSpacing.x, style.ItemInnerSpacing.y);
7892
7893 if (copy_to_clipboard)
7894 {
7895 ImGui::LogText("\n```\n");
7896 ImGui::LogFinish();
7897 }
7898 ImGui::EndChild();
7899 }
7900 ImGui::End();
7901}
7902
7903//-----------------------------------------------------------------------------
7904// [SECTION] Style Editor / ShowStyleEditor()
7905//-----------------------------------------------------------------------------
7906// - ShowFontSelector()
7907// - ShowStyleSelector()
7908// - ShowStyleEditor()
7909//-----------------------------------------------------------------------------
7910
7911// Forward declare ShowFontAtlas() which isn't worth putting in public API yet
7912namespace ImGui { IMGUI_API void ShowFontAtlas(ImFontAtlas* atlas); }
7913
7914// Demo helper function to select among loaded fonts.
7915// Here we use the regular BeginCombo()/EndCombo() api which is the more flexible one.
7916void ImGui::ShowFontSelector(const char* label)
7917{
7918 ImGuiIO& io = ImGui::GetIO();
7919 ImFont* font_current = ImGui::GetFont();
7920 if (ImGui::BeginCombo(label, font_current->GetDebugName()))
7921 {
7922 for (ImFont* font : io.Fonts->Fonts)
7923 {
7924 ImGui::PushID((void*)font);
7925 if (ImGui::Selectable(font->GetDebugName(), font == font_current))
7926 io.FontDefault = font;
7927 ImGui::PopID();
7928 }
7929 ImGui::EndCombo();
7930 }
7931 ImGui::SameLine();
7932 HelpMarker(
7933 "- Load additional fonts with io.Fonts->AddFontFromFileTTF().\n"
7934 "- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n"
7935 "- Read FAQ and docs/FONTS.md for more details.\n"
7936 "- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame().");
7937}
7938
7939// Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options.
7940// Here we use the simplified Combo() api that packs items into a single literal string.
7941// Useful for quick combo boxes where the choices are known locally.
7942bool ImGui::ShowStyleSelector(const char* label)
7943{
7944 static int style_idx = -1;
7945 if (ImGui::Combo(label, &style_idx, "Dark\0Light\0Classic\0"))
7946 {
7947 switch (style_idx)
7948 {
7949 case 0: ImGui::StyleColorsDark(); break;
7950 case 1: ImGui::StyleColorsLight(); break;
7951 case 2: ImGui::StyleColorsClassic(); break;
7952 }
7953 return true;
7954 }
7955 return false;
7956}
7957
7958void ImGui::ShowStyleEditor(ImGuiStyle* ref)
7959{
7960 IMGUI_DEMO_MARKER("Tools/Style Editor");
7961 // You can pass in a reference ImGuiStyle structure to compare to, revert to and save to
7962 // (without a reference style pointer, we will use one compared locally as a reference)
7963 ImGuiStyle& style = ImGui::GetStyle();
7964 static ImGuiStyle ref_saved_style;
7965
7966 // Default to using internal storage as reference
7967 static bool init = true;
7968 if (init && ref == NULL)
7969 ref_saved_style = style;
7970 init = false;
7971 if (ref == NULL)
7972 ref = &ref_saved_style;
7973
7974 ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.50f);
7975
7976 if (ImGui::ShowStyleSelector("Colors##Selector"))
7977 ref_saved_style = style;
7978 ImGui::ShowFontSelector("Fonts##Selector");
7979
7980 // Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f)
7981 if (ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"))
7982 style.GrabRounding = style.FrameRounding; // Make GrabRounding always the same value as FrameRounding
7983 { bool border = (style.WindowBorderSize > 0.0f); if (ImGui::Checkbox("WindowBorder", &border)) { style.WindowBorderSize = border ? 1.0f : 0.0f; } }
7984 ImGui::SameLine();
7985 { bool border = (style.FrameBorderSize > 0.0f); if (ImGui::Checkbox("FrameBorder", &border)) { style.FrameBorderSize = border ? 1.0f : 0.0f; } }
7986 ImGui::SameLine();
7987 { bool border = (style.PopupBorderSize > 0.0f); if (ImGui::Checkbox("PopupBorder", &border)) { style.PopupBorderSize = border ? 1.0f : 0.0f; } }
7988
7989 // Save/Revert button
7990 if (ImGui::Button("Save Ref"))
7991 *ref = ref_saved_style = style;
7992 ImGui::SameLine();
7993 if (ImGui::Button("Revert Ref"))
7994 style = *ref;
7995 ImGui::SameLine();
7996 HelpMarker(
7997 "Save/Revert in local non-persistent storage. Default Colors definition are not affected. "
7998 "Use \"Export\" below to save them somewhere.");
7999
8000 ImGui::Separator();
8001
8002 if (ImGui::BeginTabBar("##tabs", ImGuiTabBarFlags_None))
8003 {
8004 if (ImGui::BeginTabItem("Sizes"))
8005 {
8006 ImGui::SeparatorText("Main");
8007 ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f");
8008 ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f");
8009 ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f");
8010 ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f");
8011 ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f");
8012 ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f");
8013 ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f");
8014 ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f");
8015
8016 ImGui::SeparatorText("Borders");
8017 ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f");
8018 ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f");
8019 ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f");
8020 ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f");
8021 ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f");
8022 ImGui::SliderFloat("TabBarBorderSize", &style.TabBarBorderSize, 0.0f, 2.0f, "%.0f");
8023 ImGui::SliderFloat("TabBarOverlineSize", &style.TabBarOverlineSize, 0.0f, 2.0f, "%.0f");
8024 ImGui::SameLine(); HelpMarker("Overline is only drawn over the selected tab when ImGuiTabBarFlags_DrawSelectedOverline is set.");
8025
8026 ImGui::SeparatorText("Rounding");
8027 ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f");
8028 ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f");
8029 ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f");
8030 ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f, "%.0f");
8031 ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f");
8032 ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f");
8033 ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f");
8034
8035 ImGui::SeparatorText("Tables");
8036 ImGui::SliderFloat2("CellPadding", (float*)&style.CellPadding, 0.0f, 20.0f, "%.0f");
8037 ImGui::SliderAngle("TableAngledHeadersAngle", &style.TableAngledHeadersAngle, -50.0f, +50.0f);
8038 ImGui::SliderFloat2("TableAngledHeadersTextAlign", (float*)&style.TableAngledHeadersTextAlign, 0.0f, 1.0f, "%.2f");
8039
8040 ImGui::SeparatorText("Widgets");
8041 ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f");
8042 int window_menu_button_position = style.WindowMenuButtonPosition + 1;
8043 if (ImGui::Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0"))
8044 style.WindowMenuButtonPosition = (ImGuiDir)(window_menu_button_position - 1);
8045 ImGui::Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, "Left\0Right\0");
8046 ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f");
8047 ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content.");
8048 ImGui::SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f");
8049 ImGui::SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content.");
8050 ImGui::SliderFloat("SeparatorTextBorderSize", &style.SeparatorTextBorderSize, 0.0f, 10.0f, "%.0f");
8051 ImGui::SliderFloat2("SeparatorTextAlign", (float*)&style.SeparatorTextAlign, 0.0f, 1.0f, "%.2f");
8052 ImGui::SliderFloat2("SeparatorTextPadding", (float*)&style.SeparatorTextPadding, 0.0f, 40.0f, "%.0f");
8053 ImGui::SliderFloat("LogSliderDeadzone", &style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f");
8054
8055 ImGui::SeparatorText("Docking");
8056 ImGui::SliderFloat("DockingSplitterSize", &style.DockingSeparatorSize, 0.0f, 12.0f, "%.0f");
8057
8058 ImGui::SeparatorText("Tooltips");
8059 for (int n = 0; n < 2; n++)
8060 if (ImGui::TreeNodeEx(n == 0 ? "HoverFlagsForTooltipMouse" : "HoverFlagsForTooltipNav"))
8061 {
8062 ImGuiHoveredFlags* p = (n == 0) ? &style.HoverFlagsForTooltipMouse : &style.HoverFlagsForTooltipNav;
8063 ImGui::CheckboxFlags("ImGuiHoveredFlags_DelayNone", p, ImGuiHoveredFlags_DelayNone);
8064 ImGui::CheckboxFlags("ImGuiHoveredFlags_DelayShort", p, ImGuiHoveredFlags_DelayShort);
8065 ImGui::CheckboxFlags("ImGuiHoveredFlags_DelayNormal", p, ImGuiHoveredFlags_DelayNormal);
8066 ImGui::CheckboxFlags("ImGuiHoveredFlags_Stationary", p, ImGuiHoveredFlags_Stationary);
8067 ImGui::CheckboxFlags("ImGuiHoveredFlags_NoSharedDelay", p, ImGuiHoveredFlags_NoSharedDelay);
8068 ImGui::TreePop();
8069 }
8070
8071 ImGui::SeparatorText("Misc");
8072 ImGui::SliderFloat2("DisplayWindowPadding", (float*)&style.DisplayWindowPadding, 0.0f, 30.0f, "%.0f"); ImGui::SameLine(); HelpMarker("Apply to regular windows: amount which we enforce to keep visible when moving near edges of your screen.");
8073 ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); ImGui::SameLine(); HelpMarker("Apply to every windows, menus, popups, tooltips: amount where we avoid displaying contents. Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).");
8074
8075 ImGui::EndTabItem();
8076 }
8077
8078 if (ImGui::BeginTabItem("Colors"))
8079 {
8080 static int output_dest = 0;
8081 static bool output_only_modified = true;
8082 if (ImGui::Button("Export"))
8083 {
8084 if (output_dest == 0)
8085 ImGui::LogToClipboard();
8086 else
8087 ImGui::LogToTTY();
8088 ImGui::LogText("ImVec4* colors = ImGui::GetStyle().Colors;" IM_NEWLINE);
8089 for (int i = 0; i < ImGuiCol_COUNT; i++)
8090 {
8091 const ImVec4& col = style.Colors[i];
8092 const char* name = ImGui::GetStyleColorName(i);
8093 if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0)
8094 ImGui::LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE,
8095 name, 23 - (int)strlen(name), "", col.x, col.y, col.z, col.w);
8096 }
8097 ImGui::LogFinish();
8098 }
8099 ImGui::SameLine(); ImGui::SetNextItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0");
8100 ImGui::SameLine(); ImGui::Checkbox("Only Modified Colors", &output_only_modified);
8101
8102 static ImGuiTextFilter filter;
8103 filter.Draw("Filter colors", ImGui::GetFontSize() * 16);
8104
8105 static ImGuiColorEditFlags alpha_flags = 0;
8106 if (ImGui::RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_None)) { alpha_flags = ImGuiColorEditFlags_None; } ImGui::SameLine();
8107 if (ImGui::RadioButton("Alpha", alpha_flags == ImGuiColorEditFlags_AlphaPreview)) { alpha_flags = ImGuiColorEditFlags_AlphaPreview; } ImGui::SameLine();
8108 if (ImGui::RadioButton("Both", alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } ImGui::SameLine();
8109 HelpMarker(
8110 "In the color list:\n"
8111 "Left-click on color square to open color picker,\n"
8112 "Right-click to open edit options menu.");
8113
8114 ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 10), ImVec2(FLT_MAX, FLT_MAX));
8115 ImGui::BeginChild("##colors", ImVec2(0, 0), ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar);
8116 ImGui::PushItemWidth(ImGui::GetFontSize() * -12);
8117 for (int i = 0; i < ImGuiCol_COUNT; i++)
8118 {
8119 const char* name = ImGui::GetStyleColorName(i);
8120 if (!filter.PassFilter(name))
8121 continue;
8122 ImGui::PushID(i);
8123#ifndef IMGUI_DISABLE_DEBUG_TOOLS
8124 if (ImGui::Button("?"))
8125 ImGui::DebugFlashStyleColor((ImGuiCol)i);
8126 ImGui::SetItemTooltip("Flash given color to identify places where it is used.");
8127 ImGui::SameLine();
8128#endif
8129 ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags);
8130 if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0)
8131 {
8132 // Tips: in a real user application, you may want to merge and use an icon font into the main font,
8133 // so instead of "Save"/"Revert" you'd use icons!
8134 // Read the FAQ and docs/FONTS.md about using icon fonts. It's really easy and super convenient!
8135 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) { ref->Colors[i] = style.Colors[i]; }
8136 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) { style.Colors[i] = ref->Colors[i]; }
8137 }
8138 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x);
8140 ImGui::PopID();
8141 }
8142 ImGui::PopItemWidth();
8143 ImGui::EndChild();
8144
8145 ImGui::EndTabItem();
8146 }
8147
8148 if (ImGui::BeginTabItem("Fonts"))
8149 {
8150 ImGuiIO& io = ImGui::GetIO();
8151 ImFontAtlas* atlas = io.Fonts;
8152 HelpMarker("Read FAQ and docs/FONTS.md for details on font loading.");
8153 ImGui::ShowFontAtlas(atlas);
8154
8155 // Post-baking font scaling. Note that this is NOT the nice way of scaling fonts, read below.
8156 // (we enforce hard clamping manually as by default DragFloat/SliderFloat allows CTRL+Click text to get out of bounds).
8157 const float MIN_SCALE = 0.3f;
8158 const float MAX_SCALE = 2.0f;
8159 HelpMarker(
8160 "Those are old settings provided for convenience.\n"
8161 "However, the _correct_ way of scaling your UI is currently to reload your font at the designed size, "
8162 "rebuild the font atlas, and call style.ScaleAllSizes() on a reference ImGuiStyle structure.\n"
8163 "Using those settings here will give you poor quality results.");
8164 static float window_scale = 1.0f;
8165 ImGui::PushItemWidth(ImGui::GetFontSize() * 8);
8166 if (ImGui::DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp)) // Scale only this window
8167 ImGui::SetWindowFontScale(window_scale);
8168 ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp); // Scale everything
8169 ImGui::PopItemWidth();
8170
8171 ImGui::EndTabItem();
8172 }
8173
8174 if (ImGui::BeginTabItem("Rendering"))
8175 {
8176 ImGui::Checkbox("Anti-aliased lines", &style.AntiAliasedLines);
8177 ImGui::SameLine();
8178 HelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well.");
8179
8180 ImGui::Checkbox("Anti-aliased lines use texture", &style.AntiAliasedLinesUseTex);
8181 ImGui::SameLine();
8182 HelpMarker("Faster lines using texture data. Require backend to render with bilinear filtering (not point/nearest filtering).");
8183
8184 ImGui::Checkbox("Anti-aliased fill", &style.AntiAliasedFill);
8185 ImGui::PushItemWidth(ImGui::GetFontSize() * 8);
8186 ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, 10.0f, "%.2f");
8187 if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f;
8188
8189 // When editing the "Circle Segment Max Error" value, draw a preview of its effect on auto-tessellated circles.
8190 ImGui::DragFloat("Circle Tessellation Max Error", &style.CircleTessellationMaxError , 0.005f, 0.10f, 5.0f, "%.2f", ImGuiSliderFlags_AlwaysClamp);
8191 const bool show_samples = ImGui::IsItemActive();
8192 if (show_samples)
8193 ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos());
8194 if (show_samples && ImGui::BeginTooltip())
8195 {
8196 ImGui::TextUnformatted("(R = radius, N = approx number of segments)");
8197 ImGui::Spacing();
8198 ImDrawList* draw_list = ImGui::GetWindowDrawList();
8199 const float min_widget_width = ImGui::CalcTextSize("R: MMM\nN: MMM").x;
8200 for (int n = 0; n < 8; n++)
8201 {
8202 const float RAD_MIN = 5.0f;
8203 const float RAD_MAX = 70.0f;
8204 const float rad = RAD_MIN + (RAD_MAX - RAD_MIN) * (float)n / (8.0f - 1.0f);
8205
8206 ImGui::BeginGroup();
8207
8208 // N is not always exact here due to how PathArcTo() function work internally
8209 ImGui::Text("R: %.f\nN: %d", rad, draw_list->_CalcCircleAutoSegmentCount(rad));
8210
8211 const float canvas_width = IM_MAX(min_widget_width, rad * 2.0f);
8212 const float offset_x = floorf(canvas_width * 0.5f);
8213 const float offset_y = floorf(RAD_MAX);
8214
8215 const ImVec2 p1 = ImGui::GetCursorScreenPos();
8216 draw_list->AddCircle(ImVec2(p1.x + offset_x, p1.y + offset_y), rad, ImGui::GetColorU32(ImGuiCol_Text));
8217 ImGui::Dummy(ImVec2(canvas_width, RAD_MAX * 2));
8218
8219 /*
8220 const ImVec2 p2 = ImGui::GetCursorScreenPos();
8221 draw_list->AddCircleFilled(ImVec2(p2.x + offset_x, p2.y + offset_y), rad, ImGui::GetColorU32(ImGuiCol_Text));
8222 ImGui::Dummy(ImVec2(canvas_width, RAD_MAX * 2));
8223 */
8224
8225 ImGui::EndGroup();
8226 ImGui::SameLine();
8227 }
8228 ImGui::EndTooltip();
8229 }
8230 ImGui::SameLine();
8231 HelpMarker("When drawing circle primitives with \"num_segments == 0\" tesselation will be calculated automatically.");
8232
8233 ImGui::DragFloat("Global Alpha", &style.Alpha, 0.005f, 0.20f, 1.0f, "%.2f"); // Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero.
8234 ImGui::DragFloat("Disabled Alpha", &style.DisabledAlpha, 0.005f, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); HelpMarker("Additional alpha multiplier for disabled items (multiply over current value of Alpha).");
8235 ImGui::PopItemWidth();
8236
8237 ImGui::EndTabItem();
8238 }
8239
8240 ImGui::EndTabBar();
8241 }
8242
8243 ImGui::PopItemWidth();
8244}
8245
8246//-----------------------------------------------------------------------------
8247// [SECTION] User Guide / ShowUserGuide()
8248//-----------------------------------------------------------------------------
8249
8250void ImGui::ShowUserGuide()
8251{
8252 ImGuiIO& io = ImGui::GetIO();
8253 ImGui::BulletText("Double-click on title bar to collapse window.");
8254 ImGui::BulletText(
8255 "Click and drag on lower corner to resize window\n"
8256 "(double-click to auto fit window to its contents).");
8257 ImGui::BulletText("CTRL+Click on a slider or drag box to input value as text.");
8258 ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields.");
8259 ImGui::BulletText("CTRL+Tab to select a window.");
8260 if (io.FontAllowUserScaling)
8261 ImGui::BulletText("CTRL+Mouse Wheel to zoom window contents.");
8262 ImGui::BulletText("While inputing text:\n");
8263 ImGui::Indent();
8264 ImGui::BulletText("CTRL+Left/Right to word jump.");
8265 ImGui::BulletText("CTRL+A or double-click to select all.");
8266 ImGui::BulletText("CTRL+X/C/V to use clipboard cut/copy/paste.");
8267 ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo.");
8268 ImGui::BulletText("ESCAPE to revert.");
8269 ImGui::Unindent();
8270 ImGui::BulletText("With keyboard navigation enabled:");
8271 ImGui::Indent();
8272 ImGui::BulletText("Arrow keys to navigate.");
8273 ImGui::BulletText("Space to activate a widget.");
8274 ImGui::BulletText("Return to input text into a widget.");
8275 ImGui::BulletText("Escape to deactivate a widget, close popup, exit child window.");
8276 ImGui::BulletText("Alt to jump to the menu layer of a window.");
8277 ImGui::Unindent();
8278}
8279
8280//-----------------------------------------------------------------------------
8281// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar()
8282//-----------------------------------------------------------------------------
8283// - ShowExampleAppMainMenuBar()
8284// - ShowExampleMenuFile()
8285//-----------------------------------------------------------------------------
8286
8287// Demonstrate creating a "main" fullscreen menu bar and populating it.
8288// Note the difference between BeginMainMenuBar() and BeginMenuBar():
8289// - BeginMenuBar() = menu-bar inside current window (which needs the ImGuiWindowFlags_MenuBar flag!)
8290// - BeginMainMenuBar() = helper to create menu-bar-sized window at the top of the main viewport + call BeginMenuBar() into it.
8291static void ShowExampleAppMainMenuBar()
8292{
8293 if (ImGui::BeginMainMenuBar())
8294 {
8295 if (ImGui::BeginMenu("File"))
8296 {
8297 ShowExampleMenuFile();
8298 ImGui::EndMenu();
8299 }
8300 if (ImGui::BeginMenu("Edit"))
8301 {
8302 if (ImGui::MenuItem("Undo", "CTRL+Z")) {}
8303 if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) {} // Disabled item
8304 ImGui::Separator();
8305 if (ImGui::MenuItem("Cut", "CTRL+X")) {}
8306 if (ImGui::MenuItem("Copy", "CTRL+C")) {}
8307 if (ImGui::MenuItem("Paste", "CTRL+V")) {}
8308 ImGui::EndMenu();
8309 }
8310 ImGui::EndMainMenuBar();
8311 }
8312}
8313
8314// Note that shortcuts are currently provided for display only
8315// (future version will add explicit flags to BeginMenu() to request processing shortcuts)
8316static void ShowExampleMenuFile()
8317{
8318 IMGUI_DEMO_MARKER("Examples/Menu");
8319 ImGui::MenuItem("(demo menu)", NULL, false, false);
8320 if (ImGui::MenuItem("New")) {}
8321 if (ImGui::MenuItem("Open", "Ctrl+O")) {}
8322 if (ImGui::BeginMenu("Open Recent"))
8323 {
8324 ImGui::MenuItem("fish_hat.c");
8325 ImGui::MenuItem("fish_hat.inl");
8326 ImGui::MenuItem("fish_hat.h");
8327 if (ImGui::BeginMenu("More.."))
8328 {
8329 ImGui::MenuItem("Hello");
8330 ImGui::MenuItem("Sailor");
8331 if (ImGui::BeginMenu("Recurse.."))
8332 {
8333 ShowExampleMenuFile();
8334 ImGui::EndMenu();
8335 }
8336 ImGui::EndMenu();
8337 }
8338 ImGui::EndMenu();
8339 }
8340 if (ImGui::MenuItem("Save", "Ctrl+S")) {}
8341 if (ImGui::MenuItem("Save As..")) {}
8342
8343 ImGui::Separator();
8344 IMGUI_DEMO_MARKER("Examples/Menu/Options");
8345 if (ImGui::BeginMenu("Options"))
8346 {
8347 static bool enabled = true;
8348 ImGui::MenuItem("Enabled", "", &enabled);
8349 ImGui::BeginChild("child", ImVec2(0, 60), ImGuiChildFlags_Borders);
8350 for (int i = 0; i < 10; i++)
8351 ImGui::Text("Scrolling Text %d", i);
8352 ImGui::EndChild();
8353 static float f = 0.5f;
8354 static int n = 0;
8355 ImGui::SliderFloat("Value", &f, 0.0f, 1.0f);
8356 ImGui::InputFloat("Input", &f, 0.1f);
8357 ImGui::Combo("Combo", &n, "Yes\0No\0Maybe\0\0");
8358 ImGui::EndMenu();
8359 }
8360
8361 IMGUI_DEMO_MARKER("Examples/Menu/Colors");
8362 if (ImGui::BeginMenu("Colors"))
8363 {
8364 float sz = ImGui::GetTextLineHeight();
8365 for (int i = 0; i < ImGuiCol_COUNT; i++)
8366 {
8367 const char* name = ImGui::GetStyleColorName((ImGuiCol)i);
8368 ImVec2 p = ImGui::GetCursorScreenPos();
8369 ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + sz, p.y + sz), ImGui::GetColorU32((ImGuiCol)i));
8370 ImGui::Dummy(ImVec2(sz, sz));
8371 ImGui::SameLine();
8372 ImGui::MenuItem(name);
8373 }
8374 ImGui::EndMenu();
8375 }
8376
8377 // Here we demonstrate appending again to the "Options" menu (which we already created above)
8378 // Of course in this demo it is a little bit silly that this function calls BeginMenu("Options") twice.
8379 // In a real code-base using it would make senses to use this feature from very different code locations.
8380 if (ImGui::BeginMenu("Options")) // <-- Append!
8381 {
8382 IMGUI_DEMO_MARKER("Examples/Menu/Append to an existing menu");
8383 static bool b = true;
8384 ImGui::Checkbox("SomeOption", &b);
8385 ImGui::EndMenu();
8386 }
8387
8388 if (ImGui::BeginMenu("Disabled", false)) // Disabled
8389 {
8390 IM_ASSERT(0);
8391 }
8392 if (ImGui::MenuItem("Checked", NULL, true)) {}
8393 ImGui::Separator();
8394 if (ImGui::MenuItem("Quit", "Alt+F4")) {}
8395}
8396
8397//-----------------------------------------------------------------------------
8398// [SECTION] Example App: Debug Console / ShowExampleAppConsole()
8399//-----------------------------------------------------------------------------
8400
8401// Demonstrate creating a simple console window, with scrolling, filtering, completion and history.
8402// For the console example, we are using a more C++ like approach of declaring a class to hold both data and functions.
8404{
8405 char InputBuf[256];
8406 ImVector<char*> Items;
8407 ImVector<const char*> Commands;
8408 ImVector<char*> History;
8409 int HistoryPos; // -1: new line, 0..History.Size-1 browsing history.
8410 ImGuiTextFilter Filter;
8413
8415 {
8416 IMGUI_DEMO_MARKER("Examples/Console");
8417 ClearLog();
8418 memset(InputBuf, 0, sizeof(InputBuf));
8419 HistoryPos = -1;
8420
8421 // "CLASSIFY" is here to provide the test case where "C"+[tab] completes to "CL" and display multiple matches.
8422 Commands.push_back("HELP");
8423 Commands.push_back("HISTORY");
8424 Commands.push_back("CLEAR");
8425 Commands.push_back("CLASSIFY");
8426 AutoScroll = true;
8427 ScrollToBottom = false;
8428 AddLog("Welcome to Dear ImGui!");
8429 }
8431 {
8432 ClearLog();
8433 for (int i = 0; i < History.Size; i++)
8434 ImGui::MemFree(History[i]);
8435 }
8436
8437 // Portable helpers
8438 static int Stricmp(const char* s1, const char* s2) { int d; while ((d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; } return d; }
8439 static int Strnicmp(const char* s1, const char* s2, int n) { int d = 0; while (n > 0 && (d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; n--; } return d; }
8440 static char* Strdup(const char* s) { IM_ASSERT(s); size_t len = strlen(s) + 1; void* buf = ImGui::MemAlloc(len); IM_ASSERT(buf); return (char*)memcpy(buf, (const void*)s, len); }
8441 static void Strtrim(char* s) { char* str_end = s + strlen(s); while (str_end > s && str_end[-1] == ' ') str_end--; *str_end = 0; }
8442
8444 {
8445 for (int i = 0; i < Items.Size; i++)
8446 ImGui::MemFree(Items[i]);
8447 Items.clear();
8448 }
8449
8450 void AddLog(const char* fmt, ...) IM_FMTARGS(2)
8451 {
8452 // FIXME-OPT
8453 char buf[1024];
8454 va_list args;
8455 va_start(args, fmt);
8456 vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args);
8457 buf[IM_ARRAYSIZE(buf)-1] = 0;
8458 va_end(args);
8459 Items.push_back(Strdup(buf));
8460 }
8461
8462 void Draw(const char* title, bool* p_open)
8463 {
8464 ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
8465 if (!ImGui::Begin(title, p_open))
8466 {
8467 ImGui::End();
8468 return;
8469 }
8470
8471 // As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar.
8472 // So e.g. IsItemHovered() will return true when hovering the title bar.
8473 // Here we create a context menu only available from the title bar.
8474 if (ImGui::BeginPopupContextItem())
8475 {
8476 if (ImGui::MenuItem("Close Console"))
8477 *p_open = false;
8478 ImGui::EndPopup();
8479 }
8480
8481 ImGui::TextWrapped(
8482 "This example implements a console with basic coloring, completion (TAB key) and history (Up/Down keys). A more elaborate "
8483 "implementation may want to store entries along with extra data such as timestamp, emitter, etc.");
8484 ImGui::TextWrapped("Enter 'HELP' for help.");
8485
8486 // TODO: display items starting from the bottom
8487
8488 if (ImGui::SmallButton("Add Debug Text")) { AddLog("%d some text", Items.Size); AddLog("some more text"); AddLog("display very important message here!"); }
8489 ImGui::SameLine();
8490 if (ImGui::SmallButton("Add Debug Error")) { AddLog("[error] something went wrong"); }
8491 ImGui::SameLine();
8492 if (ImGui::SmallButton("Clear")) { ClearLog(); }
8493 ImGui::SameLine();
8494 bool copy_to_clipboard = ImGui::SmallButton("Copy");
8495 //static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); }
8496
8497 ImGui::Separator();
8498
8499 // Options menu
8500 if (ImGui::BeginPopup("Options"))
8501 {
8502 ImGui::Checkbox("Auto-scroll", &AutoScroll);
8503 ImGui::EndPopup();
8504 }
8505
8506 // Options, Filter
8507 ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_O, ImGuiInputFlags_Tooltip);
8508 if (ImGui::Button("Options"))
8509 ImGui::OpenPopup("Options");
8510 ImGui::SameLine();
8511 Filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180);
8512 ImGui::Separator();
8513
8514 // Reserve enough left-over height for 1 separator + 1 input text
8515 const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
8516 if (ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_HorizontalScrollbar))
8517 {
8518 if (ImGui::BeginPopupContextWindow())
8519 {
8520 if (ImGui::Selectable("Clear")) ClearLog();
8521 ImGui::EndPopup();
8522 }
8523
8524 // Display every line as a separate entry so we can change their color or add custom widgets.
8525 // If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end());
8526 // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping
8527 // to only process visible items. The clipper will automatically measure the height of your first item and then
8528 // "seek" to display only items in the visible area.
8529 // To use the clipper we can replace your standard loop:
8530 // for (int i = 0; i < Items.Size; i++)
8531 // With:
8532 // ImGuiListClipper clipper;
8533 // clipper.Begin(Items.Size);
8534 // while (clipper.Step())
8535 // for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
8536 // - That your items are evenly spaced (same height)
8537 // - That you have cheap random access to your elements (you can access them given their index,
8538 // without processing all the ones before)
8539 // You cannot this code as-is if a filter is active because it breaks the 'cheap random-access' property.
8540 // We would need random-access on the post-filtered list.
8541 // A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices
8542 // or offsets of items that passed the filtering test, recomputing this array when user changes the filter,
8543 // and appending newly elements as they are inserted. This is left as a task to the user until we can manage
8544 // to improve this example code!
8545 // If your items are of variable height:
8546 // - Split them into same height items would be simpler and facilitate random-seeking into your list.
8547 // - Consider using manual call to IsRectVisible() and skipping extraneous decoration from your items.
8548 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing
8549 if (copy_to_clipboard)
8550 ImGui::LogToClipboard();
8551 for (const char* item : Items)
8552 {
8553 if (!Filter.PassFilter(item))
8554 continue;
8555
8556 // Normally you would store more information in your item than just a string.
8557 // (e.g. make Items[] an array of structure, store color/type etc.)
8558 ImVec4 color;
8559 bool has_color = false;
8560 if (strstr(item, "[error]")) { color = ImVec4(1.0f, 0.4f, 0.4f, 1.0f); has_color = true; }
8561 else if (strncmp(item, "# ", 2) == 0) { color = ImVec4(1.0f, 0.8f, 0.6f, 1.0f); has_color = true; }
8562 if (has_color)
8563 ImGui::PushStyleColor(ImGuiCol_Text, color);
8565 if (has_color)
8566 ImGui::PopStyleColor();
8567 }
8568 if (copy_to_clipboard)
8569 ImGui::LogFinish();
8570
8571 // Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame.
8572 // Using a scrollbar or mouse-wheel will take away from the bottom edge.
8573 if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()))
8574 ImGui::SetScrollHereY(1.0f);
8575 ScrollToBottom = false;
8576
8577 ImGui::PopStyleVar();
8578 }
8579 ImGui::EndChild();
8580 ImGui::Separator();
8581
8582 // Command-line
8583 bool reclaim_focus = false;
8584 ImGuiInputTextFlags input_text_flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_EscapeClearsAll | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory;
8585 if (ImGui::InputText("Input", InputBuf, IM_ARRAYSIZE(InputBuf), input_text_flags, &TextEditCallbackStub, (void*)this))
8586 {
8587 char* s = InputBuf;
8588 Strtrim(s);
8589 if (s[0])
8590 ExecCommand(s);
8591 strcpy(s, "");
8592 reclaim_focus = true;
8593 }
8594
8595 // Auto-focus on window apparition
8596 ImGui::SetItemDefaultFocus();
8597 if (reclaim_focus)
8598 ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget
8599
8600 ImGui::End();
8601 }
8602
8603 void ExecCommand(const char* command_line)
8604 {
8605 AddLog("# %s\n", command_line);
8606
8607 // Insert into history. First find match and delete it so it can be pushed to the back.
8608 // This isn't trying to be smart or optimal.
8609 HistoryPos = -1;
8610 for (int i = History.Size - 1; i >= 0; i--)
8611 if (Stricmp(History[i], command_line) == 0)
8612 {
8613 ImGui::MemFree(History[i]);
8614 History.erase(History.begin() + i);
8615 break;
8616 }
8617 History.push_back(Strdup(command_line));
8618
8619 // Process command
8620 if (Stricmp(command_line, "CLEAR") == 0)
8621 {
8622 ClearLog();
8623 }
8624 else if (Stricmp(command_line, "HELP") == 0)
8625 {
8626 AddLog("Commands:");
8627 for (int i = 0; i < Commands.Size; i++)
8628 AddLog("- %s", Commands[i]);
8629 }
8630 else if (Stricmp(command_line, "HISTORY") == 0)
8631 {
8632 int first = History.Size - 10;
8633 for (int i = first > 0 ? first : 0; i < History.Size; i++)
8634 AddLog("%3d: %s\n", i, History[i]);
8635 }
8636 else
8637 {
8638 AddLog("Unknown command: '%s'\n", command_line);
8639 }
8640
8641 // On command input, we scroll to bottom even if AutoScroll==false
8642 ScrollToBottom = true;
8643 }
8644
8645 // In C++11 you'd be better off using lambdas for this sort of forwarding callbacks
8646 static int TextEditCallbackStub(ImGuiInputTextCallbackData* data)
8647 {
8648 ExampleAppConsole* console = (ExampleAppConsole*)data->UserData;
8649 return console->TextEditCallback(data);
8650 }
8651
8652 int TextEditCallback(ImGuiInputTextCallbackData* data)
8653 {
8654 //AddLog("cursor: %d, selection: %d-%d", data->CursorPos, data->SelectionStart, data->SelectionEnd);
8655 switch (data->EventFlag)
8656 {
8657 case ImGuiInputTextFlags_CallbackCompletion:
8658 {
8659 // Example of TEXT COMPLETION
8660
8661 // Locate beginning of current word
8662 const char* word_end = data->Buf + data->CursorPos;
8663 const char* word_start = word_end;
8664 while (word_start > data->Buf)
8665 {
8666 const char c = word_start[-1];
8667 if (c == ' ' || c == '\t' || c == ',' || c == ';')
8668 break;
8669 word_start--;
8670 }
8671
8672 // Build a list of candidates
8673 ImVector<const char*> candidates;
8674 for (int i = 0; i < Commands.Size; i++)
8675 if (Strnicmp(Commands[i], word_start, (int)(word_end - word_start)) == 0)
8676 candidates.push_back(Commands[i]);
8677
8678 if (candidates.Size == 0)
8679 {
8680 // No match
8681 AddLog("No match for \"%.*s\"!\n", (int)(word_end - word_start), word_start);
8682 }
8683 else if (candidates.Size == 1)
8684 {
8685 // Single match. Delete the beginning of the word and replace it entirely so we've got nice casing.
8686 data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start));
8687 data->InsertChars(data->CursorPos, candidates[0]);
8688 data->InsertChars(data->CursorPos, " ");
8689 }
8690 else
8691 {
8692 // Multiple matches. Complete as much as we can..
8693 // So inputing "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches.
8694 int match_len = (int)(word_end - word_start);
8695 for (;;)
8696 {
8697 int c = 0;
8698 bool all_candidates_matches = true;
8699 for (int i = 0; i < candidates.Size && all_candidates_matches; i++)
8700 if (i == 0)
8701 c = toupper(candidates[i][match_len]);
8702 else if (c == 0 || c != toupper(candidates[i][match_len]))
8703 all_candidates_matches = false;
8704 if (!all_candidates_matches)
8705 break;
8706 match_len++;
8707 }
8708
8709 if (match_len > 0)
8710 {
8711 data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start));
8712 data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len);
8713 }
8714
8715 // List matches
8716 AddLog("Possible matches:\n");
8717 for (int i = 0; i < candidates.Size; i++)
8718 AddLog("- %s\n", candidates[i]);
8719 }
8720
8721 break;
8722 }
8723 case ImGuiInputTextFlags_CallbackHistory:
8724 {
8725 // Example of HISTORY
8726 const int prev_history_pos = HistoryPos;
8727 if (data->EventKey == ImGuiKey_UpArrow)
8728 {
8729 if (HistoryPos == -1)
8730 HistoryPos = History.Size - 1;
8731 else if (HistoryPos > 0)
8732 HistoryPos--;
8733 }
8734 else if (data->EventKey == ImGuiKey_DownArrow)
8735 {
8736 if (HistoryPos != -1)
8737 if (++HistoryPos >= History.Size)
8738 HistoryPos = -1;
8739 }
8740
8741 // A better implementation would preserve the data on the current input line along with cursor position.
8742 if (prev_history_pos != HistoryPos)
8743 {
8744 const char* history_str = (HistoryPos >= 0) ? History[HistoryPos] : "";
8745 data->DeleteChars(0, data->BufTextLen);
8746 data->InsertChars(0, history_str);
8747 }
8748 }
8749 }
8750 return 0;
8751 }
8752};
8753
8754static void ShowExampleAppConsole(bool* p_open)
8755{
8756 static ExampleAppConsole console;
8757 console.Draw("Example: Console", p_open);
8758}
8759
8760//-----------------------------------------------------------------------------
8761// [SECTION] Example App: Debug Log / ShowExampleAppLog()
8762//-----------------------------------------------------------------------------
8763
8764// Usage:
8765// static ExampleAppLog my_log;
8766// my_log.AddLog("Hello %d world\n", 123);
8767// my_log.Draw("title");
8769{
8770 ImGuiTextBuffer Buf;
8771 ImGuiTextFilter Filter;
8772 ImVector<int> LineOffsets; // Index to lines offset. We maintain this with AddLog() calls.
8773 bool AutoScroll; // Keep scrolling if already at the bottom.
8774
8776 {
8777 AutoScroll = true;
8778 Clear();
8779 }
8780
8781 void Clear()
8782 {
8783 Buf.clear();
8784 LineOffsets.clear();
8785 LineOffsets.push_back(0);
8786 }
8787
8788 void AddLog(const char* fmt, ...) IM_FMTARGS(2)
8789 {
8790 int old_size = Buf.size();
8791 va_list args;
8792 va_start(args, fmt);
8793 Buf.appendfv(fmt, args);
8794 va_end(args);
8795 for (int new_size = Buf.size(); old_size < new_size; old_size++)
8796 if (Buf[old_size] == '\n')
8797 LineOffsets.push_back(old_size + 1);
8798 }
8799
8800 void Draw(const char* title, bool* p_open = NULL)
8801 {
8802 if (!ImGui::Begin(title, p_open))
8803 {
8804 ImGui::End();
8805 return;
8806 }
8807
8808 // Options menu
8809 if (ImGui::BeginPopup("Options"))
8810 {
8811 ImGui::Checkbox("Auto-scroll", &AutoScroll);
8812 ImGui::EndPopup();
8813 }
8814
8815 // Main window
8816 if (ImGui::Button("Options"))
8817 ImGui::OpenPopup("Options");
8818 ImGui::SameLine();
8819 bool clear = ImGui::Button("Clear");
8820 ImGui::SameLine();
8821 bool copy = ImGui::Button("Copy");
8822 ImGui::SameLine();
8823 Filter.Draw("Filter", -100.0f);
8824
8825 ImGui::Separator();
8826
8827 if (ImGui::BeginChild("scrolling", ImVec2(0, 0), ImGuiChildFlags_None, ImGuiWindowFlags_HorizontalScrollbar))
8828 {
8829 if (clear)
8830 Clear();
8831 if (copy)
8832 ImGui::LogToClipboard();
8833
8834 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
8835 const char* buf = Buf.begin();
8836 const char* buf_end = Buf.end();
8837 if (Filter.IsActive())
8838 {
8839 // In this example we don't use the clipper when Filter is enabled.
8840 // This is because we don't have random access to the result of our filter.
8841 // A real application processing logs with ten of thousands of entries may want to store the result of
8842 // search/filter.. especially if the filtering function is not trivial (e.g. reg-exp).
8843 for (int line_no = 0; line_no < LineOffsets.Size; line_no++)
8844 {
8845 const char* line_start = buf + LineOffsets[line_no];
8846 const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
8847 if (Filter.PassFilter(line_start, line_end))
8848 ImGui::TextUnformatted(line_start, line_end);
8849 }
8850 }
8851 else
8852 {
8853 // The simplest and easy way to display the entire buffer:
8854 // ImGui::TextUnformatted(buf_begin, buf_end);
8855 // And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward
8856 // to skip non-visible lines. Here we instead demonstrate using the clipper to only process lines that are
8857 // within the visible area.
8858 // If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them
8859 // on your side is recommended. Using ImGuiListClipper requires
8860 // - A) random access into your data
8861 // - B) items all being the same height,
8862 // both of which we can handle since we have an array pointing to the beginning of each line of text.
8863 // When using the filter (in the block of code above) we don't have random access into the data to display
8864 // anymore, which is why we don't use the clipper. Storing or skimming through the search result would make
8865 // it possible (and would be recommended if you want to search through tens of thousands of entries).
8866 ImGuiListClipper clipper;
8867 clipper.Begin(LineOffsets.Size);
8868 while (clipper.Step())
8869 {
8870 for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++)
8871 {
8872 const char* line_start = buf + LineOffsets[line_no];
8873 const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
8874 ImGui::TextUnformatted(line_start, line_end);
8875 }
8876 }
8877 clipper.End();
8878 }
8879 ImGui::PopStyleVar();
8880
8881 // Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame.
8882 // Using a scrollbar or mouse-wheel will take away from the bottom edge.
8883 if (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())
8884 ImGui::SetScrollHereY(1.0f);
8885 }
8886 ImGui::EndChild();
8887 ImGui::End();
8888 }
8889};
8890
8891// Demonstrate creating a simple log window with basic filtering.
8892static void ShowExampleAppLog(bool* p_open)
8893{
8894 static ExampleAppLog log;
8895
8896 // For the demo: add a debug button _BEFORE_ the normal log window contents
8897 // We take advantage of a rarely used feature: multiple calls to Begin()/End() are appending to the _same_ window.
8898 // Most of the contents of the window will be added by the log.Draw() call.
8899 ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver);
8900 ImGui::Begin("Example: Log", p_open);
8901 IMGUI_DEMO_MARKER("Examples/Log");
8902 if (ImGui::SmallButton("[Debug] Add 5 entries"))
8903 {
8904 static int counter = 0;
8905 const char* categories[3] = { "info", "warn", "error" };
8906 const char* words[] = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" };
8907 for (int n = 0; n < 5; n++)
8908 {
8909 const char* category = categories[counter % IM_ARRAYSIZE(categories)];
8910 const char* word = words[counter % IM_ARRAYSIZE(words)];
8911 log.AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n",
8912 ImGui::GetFrameCount(), category, ImGui::GetTime(), word);
8913 counter++;
8914 }
8915 }
8916 ImGui::End();
8917
8918 // Actually call in the regular Log helper (which will Begin() into the same window as we just did)
8919 log.Draw("Example: Log", p_open);
8920}
8921
8922//-----------------------------------------------------------------------------
8923// [SECTION] Example App: Simple Layout / ShowExampleAppLayout()
8924//-----------------------------------------------------------------------------
8925
8926// Demonstrate create a window with multiple child windows.
8927static void ShowExampleAppLayout(bool* p_open)
8928{
8929 ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiCond_FirstUseEver);
8930 if (ImGui::Begin("Example: Simple layout", p_open, ImGuiWindowFlags_MenuBar))
8931 {
8932 IMGUI_DEMO_MARKER("Examples/Simple layout");
8933 if (ImGui::BeginMenuBar())
8934 {
8935 if (ImGui::BeginMenu("File"))
8936 {
8937 if (ImGui::MenuItem("Close", "Ctrl+W")) { *p_open = false; }
8938 ImGui::EndMenu();
8939 }
8940 ImGui::EndMenuBar();
8941 }
8942
8943 // Left
8944 static int selected = 0;
8945 {
8946 ImGui::BeginChild("left pane", ImVec2(150, 0), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeX);
8947 for (int i = 0; i < 100; i++)
8948 {
8949 // FIXME: Good candidate to use ImGuiSelectableFlags_SelectOnNav
8950 char label[128];
8951 sprintf(label, "MyObject %d", i);
8952 if (ImGui::Selectable(label, selected == i))
8953 selected = i;
8954 }
8955 ImGui::EndChild();
8956 }
8957 ImGui::SameLine();
8958
8959 // Right
8960 {
8961 ImGui::BeginGroup();
8962 ImGui::BeginChild("item view", ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us
8963 ImGui::Text("MyObject: %d", selected);
8964 ImGui::Separator();
8965 if (ImGui::BeginTabBar("##Tabs", ImGuiTabBarFlags_None))
8966 {
8967 if (ImGui::BeginTabItem("Description"))
8968 {
8969 ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ");
8970 ImGui::EndTabItem();
8971 }
8972 if (ImGui::BeginTabItem("Details"))
8973 {
8974 ImGui::Text("ID: 0123456789");
8975 ImGui::EndTabItem();
8976 }
8977 ImGui::EndTabBar();
8978 }
8979 ImGui::EndChild();
8980 if (ImGui::Button("Revert")) {}
8981 ImGui::SameLine();
8982 if (ImGui::Button("Save")) {}
8983 ImGui::EndGroup();
8984 }
8985 }
8986 ImGui::End();
8987}
8988
8989//-----------------------------------------------------------------------------
8990// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor()
8991//-----------------------------------------------------------------------------
8992// Some of the interactions are a bit lack-luster:
8993// - We would want pressing validating or leaving the filter to somehow restore focus.
8994// - We may want more advanced filtering (child nodes) and clipper support: both will need extra work.
8995// - We would want to customize some keyboard interactions to easily keyboard navigate between the tree and the properties.
8996//-----------------------------------------------------------------------------
8997
8999{
9000 ImGuiTextFilter Filter;
9002
9003 void Draw(ExampleTreeNode* root_node)
9004 {
9005 // Left side: draw tree
9006 // - Currently using a table to benefit from RowBg feature
9007 if (ImGui::BeginChild("##tree", ImVec2(300, 0), ImGuiChildFlags_ResizeX | ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened))
9008 {
9009 ImGui::SetNextItemWidth(-FLT_MIN);
9010 ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F, ImGuiInputFlags_Tooltip);
9011 ImGui::PushItemFlag(ImGuiItemFlags_NoNavDefaultFocus, true);
9012 if (ImGui::InputTextWithHint("##Filter", "incl,-excl", Filter.InputBuf, IM_ARRAYSIZE(Filter.InputBuf), ImGuiInputTextFlags_EscapeClearsAll))
9013 Filter.Build();
9014 ImGui::PopItemFlag();
9015
9016 if (ImGui::BeginTable("##bg", 1, ImGuiTableFlags_RowBg))
9017 {
9018 for (ExampleTreeNode* node : root_node->Childs)
9019 if (Filter.PassFilter(node->Name)) // Filter root node
9020 DrawTreeNode(node);
9021 ImGui::EndTable();
9022 }
9023 }
9024 ImGui::EndChild();
9025
9026 // Right side: draw properties
9027 ImGui::SameLine();
9028
9029 ImGui::BeginGroup(); // Lock X position
9030 if (ExampleTreeNode* node = VisibleNode)
9031 {
9032 ImGui::Text("%s", node->Name);
9033 ImGui::TextDisabled("UID: 0x%08X", node->UID);
9034 ImGui::Separator();
9035 if (ImGui::BeginTable("##properties", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY))
9036 {
9037 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed);
9038 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 2.0f); // Default twice larger
9039 if (node->HasData)
9040 {
9041 // In a typical application, the structure description would be derived from a data-driven system.
9042 // - We try to mimic this with our ExampleMemberInfo structure and the ExampleTreeNodeMemberInfos[] array.
9043 // - Limits and some details are hard-coded to simplify the demo.
9044 for (const ExampleMemberInfo& field_desc : ExampleTreeNodeMemberInfos)
9045 {
9046 ImGui::TableNextRow();
9047 ImGui::PushID(field_desc.Name);
9048 ImGui::TableNextColumn();
9049 ImGui::AlignTextToFramePadding();
9050 ImGui::TextUnformatted(field_desc.Name);
9051 ImGui::TableNextColumn();
9052 void* field_ptr = (void*)(((unsigned char*)node) + field_desc.Offset);
9053 switch (field_desc.DataType)
9054 {
9055 case ImGuiDataType_Bool:
9056 {
9057 IM_ASSERT(field_desc.DataCount == 1);
9058 ImGui::Checkbox("##Editor", (bool*)field_ptr);
9059 break;
9060 }
9061 case ImGuiDataType_S32:
9062 {
9063 int v_min = INT_MIN, v_max = INT_MAX;
9064 ImGui::SetNextItemWidth(-FLT_MIN);
9065 ImGui::DragScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, 1.0f, &v_min, &v_max);
9066 break;
9067 }
9068 case ImGuiDataType_Float:
9069 {
9070 float v_min = 0.0f, v_max = 1.0f;
9071 ImGui::SetNextItemWidth(-FLT_MIN);
9072 ImGui::SliderScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, &v_min, &v_max);
9073 break;
9074 }
9075 }
9076 ImGui::PopID();
9077 }
9078 }
9079 ImGui::EndTable();
9080 }
9081 }
9082 ImGui::EndGroup();
9083 }
9084
9086 {
9087 ImGui::TableNextRow();
9088 ImGui::TableNextColumn();
9089 ImGui::PushID(node->UID);
9090 ImGuiTreeNodeFlags tree_flags = ImGuiTreeNodeFlags_None;
9091 tree_flags |= ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; // Standard opening mode as we are likely to want to add selection afterwards
9092 tree_flags |= ImGuiTreeNodeFlags_NavLeftJumpsBackHere; // Left arrow support
9093 if (node == VisibleNode)
9094 tree_flags |= ImGuiTreeNodeFlags_Selected;
9095 if (node->Childs.Size == 0)
9096 tree_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet;
9097 if (node->DataMyBool == false)
9098 ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]);
9099 bool node_open = ImGui::TreeNodeEx("", tree_flags, "%s", node->Name);
9100 if (node->DataMyBool == false)
9101 ImGui::PopStyleColor();
9102 if (ImGui::IsItemFocused())
9103 VisibleNode = node;
9104 if (node_open)
9105 {
9106 for (ExampleTreeNode* child : node->Childs)
9107 DrawTreeNode(child);
9108 ImGui::TreePop();
9109 }
9110 ImGui::PopID();
9111 }
9112};
9113
9114// Demonstrate creating a simple property editor.
9115static void ShowExampleAppPropertyEditor(bool* p_open, ImGuiDemoWindowData* demo_data)
9116{
9117 ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver);
9118 if (!ImGui::Begin("Example: Property editor", p_open))
9119 {
9120 ImGui::End();
9121 return;
9122 }
9123
9124 IMGUI_DEMO_MARKER("Examples/Property Editor");
9125 static ExampleAppPropertyEditor property_editor;
9126 if (demo_data->DemoTree == NULL)
9127 demo_data->DemoTree = ExampleTree_CreateDemoTree();
9128 property_editor.Draw(demo_data->DemoTree);
9129
9130 ImGui::End();
9131}
9132
9133//-----------------------------------------------------------------------------
9134// [SECTION] Example App: Long Text / ShowExampleAppLongText()
9135//-----------------------------------------------------------------------------
9136
9137// Demonstrate/test rendering huge amount of text, and the incidence of clipping.
9138static void ShowExampleAppLongText(bool* p_open)
9139{
9140 ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
9141 if (!ImGui::Begin("Example: Long text display", p_open))
9142 {
9143 ImGui::End();
9144 return;
9145 }
9146 IMGUI_DEMO_MARKER("Examples/Long text display");
9147
9148 static int test_type = 0;
9149 static ImGuiTextBuffer log;
9150 static int lines = 0;
9151 ImGui::Text("Printing unusually long amount of text.");
9152 ImGui::Combo("Test type", &test_type,
9153 "Single call to TextUnformatted()\0"
9154 "Multiple calls to Text(), clipped\0"
9155 "Multiple calls to Text(), not clipped (slow)\0");
9156 ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size());
9157 if (ImGui::Button("Clear")) { log.clear(); lines = 0; }
9158 ImGui::SameLine();
9159 if (ImGui::Button("Add 1000 lines"))
9160 {
9161 for (int i = 0; i < 1000; i++)
9162 log.appendf("%i The quick brown fox jumps over the lazy dog\n", lines + i);
9163 lines += 1000;
9164 }
9165 ImGui::BeginChild("Log");
9166 switch (test_type)
9167 {
9168 case 0:
9169 // Single call to TextUnformatted() with a big buffer
9170 ImGui::TextUnformatted(log.begin(), log.end());
9171 break;
9172 case 1:
9173 {
9174 // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper.
9175 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
9176 ImGuiListClipper clipper;
9177 clipper.Begin(lines);
9178 while (clipper.Step())
9179 for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
9180 ImGui::Text("%i The quick brown fox jumps over the lazy dog", i);
9181 ImGui::PopStyleVar();
9182 break;
9183 }
9184 case 2:
9185 // Multiple calls to Text(), not clipped (slow)
9186 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
9187 for (int i = 0; i < lines; i++)
9188 ImGui::Text("%i The quick brown fox jumps over the lazy dog", i);
9189 ImGui::PopStyleVar();
9190 break;
9191 }
9192 ImGui::EndChild();
9193 ImGui::End();
9194}
9195
9196//-----------------------------------------------------------------------------
9197// [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize()
9198//-----------------------------------------------------------------------------
9199
9200// Demonstrate creating a window which gets auto-resized according to its content.
9201static void ShowExampleAppAutoResize(bool* p_open)
9202{
9203 if (!ImGui::Begin("Example: Auto-resizing window", p_open, ImGuiWindowFlags_AlwaysAutoResize))
9204 {
9205 ImGui::End();
9206 return;
9207 }
9208 IMGUI_DEMO_MARKER("Examples/Auto-resizing window");
9209
9210 static int lines = 10;
9212 "Window will resize every-frame to the size of its content.\n"
9213 "Note that you probably don't want to query the window size to\n"
9214 "output your content because that would create a feedback loop.");
9215 ImGui::SliderInt("Number of lines", &lines, 1, 20);
9216 for (int i = 0; i < lines; i++)
9217 ImGui::Text("%*sThis is line %d", i * 4, "", i); // Pad with space to extend size horizontally
9218 ImGui::End();
9219}
9220
9221//-----------------------------------------------------------------------------
9222// [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize()
9223//-----------------------------------------------------------------------------
9224
9225// Demonstrate creating a window with custom resize constraints.
9226// Note that size constraints currently don't work on a docked window (when in 'docking' branch)
9227static void ShowExampleAppConstrainedResize(bool* p_open)
9228{
9229 struct CustomConstraints
9230 {
9231 // Helper functions to demonstrate programmatic constraints
9232 // FIXME: This doesn't take account of decoration size (e.g. title bar), library should make this easier.
9233 // FIXME: None of the three demos works consistently when resizing from borders.
9234 static void AspectRatio(ImGuiSizeCallbackData* data)
9235 {
9236 float aspect_ratio = *(float*)data->UserData;
9237 data->DesiredSize.y = (float)(int)(data->DesiredSize.x / aspect_ratio);
9238 }
9239 static void Square(ImGuiSizeCallbackData* data)
9240 {
9241 data->DesiredSize.x = data->DesiredSize.y = IM_MAX(data->DesiredSize.x, data->DesiredSize.y);
9242 }
9243 static void Step(ImGuiSizeCallbackData* data)
9244 {
9245 float step = *(float*)data->UserData;
9246 data->DesiredSize = ImVec2((int)(data->DesiredSize.x / step + 0.5f) * step, (int)(data->DesiredSize.y / step + 0.5f) * step);
9247 }
9248 };
9249
9250 const char* test_desc[] =
9251 {
9252 "Between 100x100 and 500x500",
9253 "At least 100x100",
9254 "Resize vertical + lock current width",
9255 "Resize horizontal + lock current height",
9256 "Width Between 400 and 500",
9257 "Height at least 400",
9258 "Custom: Aspect Ratio 16:9",
9259 "Custom: Always Square",
9260 "Custom: Fixed Steps (100)",
9261 };
9262
9263 // Options
9264 static bool auto_resize = false;
9265 static bool window_padding = true;
9266 static int type = 6; // Aspect Ratio
9267 static int display_lines = 10;
9268
9269 // Submit constraint
9270 float aspect_ratio = 16.0f / 9.0f;
9271 float fixed_step = 100.0f;
9272 if (type == 0) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(500, 500)); // Between 100x100 and 500x500
9273 if (type == 1) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100
9274 if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, FLT_MAX)); // Resize vertical + lock current width
9275 if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(FLT_MAX, -1)); // Resize horizontal + lock current height
9276 if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)); // Width Between and 400 and 500
9277 if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, FLT_MAX)); // Height at least 400
9278 if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::AspectRatio, (void*)&aspect_ratio); // Aspect ratio
9279 if (type == 7) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square
9280 if (type == 8) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)&fixed_step); // Fixed Step
9281
9282 // Submit window
9283 if (!window_padding)
9284 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
9285 const ImGuiWindowFlags window_flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0;
9286 const bool window_open = ImGui::Begin("Example: Constrained Resize", p_open, window_flags);
9287 if (!window_padding)
9288 ImGui::PopStyleVar();
9289 if (window_open)
9290 {
9291 IMGUI_DEMO_MARKER("Examples/Constrained Resizing window");
9292 if (ImGui::GetIO().KeyShift)
9293 {
9294 // Display a dummy viewport (in your real app you would likely use ImageButton() to display a texture.
9295 ImVec2 avail_size = ImGui::GetContentRegionAvail();
9296 ImVec2 pos = ImGui::GetCursorScreenPos();
9297 ImGui::ColorButton("viewport", ImVec4(0.5f, 0.2f, 0.5f, 1.0f), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop, avail_size);
9298 ImGui::SetCursorScreenPos(ImVec2(pos.x + 10, pos.y + 10));
9299 ImGui::Text("%.2f x %.2f", avail_size.x, avail_size.y);
9300 }
9301 else
9302 {
9303 ImGui::Text("(Hold SHIFT to display a dummy viewport)");
9304 if (ImGui::IsWindowDocked())
9305 ImGui::Text("Warning: Sizing Constraints won't work if the window is docked!");
9306 if (ImGui::Button("Set 200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine();
9307 if (ImGui::Button("Set 500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine();
9308 if (ImGui::Button("Set 800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); }
9309 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20);
9310 ImGui::Combo("Constraint", &type, test_desc, IM_ARRAYSIZE(test_desc));
9311 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20);
9312 ImGui::DragInt("Lines", &display_lines, 0.2f, 1, 100);
9313 ImGui::Checkbox("Auto-resize", &auto_resize);
9314 ImGui::Checkbox("Window padding", &window_padding);
9315 for (int i = 0; i < display_lines; i++)
9316 ImGui::Text("%*sHello, sailor! Making this line long enough for the example.", i * 4, "");
9317 }
9318 }
9319 ImGui::End();
9320}
9321
9322//-----------------------------------------------------------------------------
9323// [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay()
9324//-----------------------------------------------------------------------------
9325
9326// Demonstrate creating a simple static window with no decoration
9327// + a context-menu to choose which corner of the screen to use.
9328static void ShowExampleAppSimpleOverlay(bool* p_open)
9329{
9330 static int location = 0;
9331 ImGuiIO& io = ImGui::GetIO();
9332 ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav;
9333 if (location >= 0)
9334 {
9335 const float PAD = 10.0f;
9336 const ImGuiViewport* viewport = ImGui::GetMainViewport();
9337 ImVec2 work_pos = viewport->WorkPos; // Use work area to avoid menu-bar/task-bar, if any!
9338 ImVec2 work_size = viewport->WorkSize;
9339 ImVec2 window_pos, window_pos_pivot;
9340 window_pos.x = (location & 1) ? (work_pos.x + work_size.x - PAD) : (work_pos.x + PAD);
9341 window_pos.y = (location & 2) ? (work_pos.y + work_size.y - PAD) : (work_pos.y + PAD);
9342 window_pos_pivot.x = (location & 1) ? 1.0f : 0.0f;
9343 window_pos_pivot.y = (location & 2) ? 1.0f : 0.0f;
9344 ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot);
9345 ImGui::SetNextWindowViewport(viewport->ID);
9346 window_flags |= ImGuiWindowFlags_NoMove;
9347 }
9348 else if (location == -2)
9349 {
9350 // Center window
9351 ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Always, ImVec2(0.5f, 0.5f));
9352 window_flags |= ImGuiWindowFlags_NoMove;
9353 }
9354 ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background
9355 if (ImGui::Begin("Example: Simple overlay", p_open, window_flags))
9356 {
9357 IMGUI_DEMO_MARKER("Examples/Simple Overlay");
9358 ImGui::Text("Simple overlay\n" "(right-click to change position)");
9359 ImGui::Separator();
9360 if (ImGui::IsMousePosValid())
9361 ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y);
9362 else
9363 ImGui::Text("Mouse Position: <invalid>");
9364 if (ImGui::BeginPopupContextWindow())
9365 {
9366 if (ImGui::MenuItem("Custom", NULL, location == -1)) location = -1;
9367 if (ImGui::MenuItem("Center", NULL, location == -2)) location = -2;
9368 if (ImGui::MenuItem("Top-left", NULL, location == 0)) location = 0;
9369 if (ImGui::MenuItem("Top-right", NULL, location == 1)) location = 1;
9370 if (ImGui::MenuItem("Bottom-left", NULL, location == 2)) location = 2;
9371 if (ImGui::MenuItem("Bottom-right", NULL, location == 3)) location = 3;
9372 if (p_open && ImGui::MenuItem("Close")) *p_open = false;
9373 ImGui::EndPopup();
9374 }
9375 }
9376 ImGui::End();
9377}
9378
9379//-----------------------------------------------------------------------------
9380// [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen()
9381//-----------------------------------------------------------------------------
9382
9383// Demonstrate creating a window covering the entire screen/viewport
9384static void ShowExampleAppFullscreen(bool* p_open)
9385{
9386 static bool use_work_area = true;
9387 static ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings;
9388
9389 // We demonstrate using the full viewport area or the work area (without menu-bars, task-bars etc.)
9390 // Based on your use case you may want one or the other.
9391 const ImGuiViewport* viewport = ImGui::GetMainViewport();
9392 ImGui::SetNextWindowPos(use_work_area ? viewport->WorkPos : viewport->Pos);
9393 ImGui::SetNextWindowSize(use_work_area ? viewport->WorkSize : viewport->Size);
9394
9395 if (ImGui::Begin("Example: Fullscreen window", p_open, flags))
9396 {
9397 ImGui::Checkbox("Use work area instead of main area", &use_work_area);
9398 ImGui::SameLine();
9399 HelpMarker("Main Area = entire viewport,\nWork Area = entire viewport minus sections used by the main menu bars, task bars etc.\n\nEnable the main-menu bar in Examples menu to see the difference.");
9400
9401 ImGui::CheckboxFlags("ImGuiWindowFlags_NoBackground", &flags, ImGuiWindowFlags_NoBackground);
9402 ImGui::CheckboxFlags("ImGuiWindowFlags_NoDecoration", &flags, ImGuiWindowFlags_NoDecoration);
9403 ImGui::Indent();
9404 ImGui::CheckboxFlags("ImGuiWindowFlags_NoTitleBar", &flags, ImGuiWindowFlags_NoTitleBar);
9405 ImGui::CheckboxFlags("ImGuiWindowFlags_NoCollapse", &flags, ImGuiWindowFlags_NoCollapse);
9406 ImGui::CheckboxFlags("ImGuiWindowFlags_NoScrollbar", &flags, ImGuiWindowFlags_NoScrollbar);
9407 ImGui::Unindent();
9408
9409 if (p_open && ImGui::Button("Close this window"))
9410 *p_open = false;
9411 }
9412 ImGui::End();
9413}
9414
9415//-----------------------------------------------------------------------------
9416// [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles()
9417//-----------------------------------------------------------------------------
9418
9419// Demonstrate the use of "##" and "###" in identifiers to manipulate ID generation.
9420// This applies to all regular items as well.
9421// Read FAQ section "How can I have multiple widgets with the same label?" for details.
9422static void ShowExampleAppWindowTitles(bool*)
9423{
9424 const ImGuiViewport* viewport = ImGui::GetMainViewport();
9425 const ImVec2 base_pos = viewport->Pos;
9426
9427 // By default, Windows are uniquely identified by their title.
9428 // You can use the "##" and "###" markers to manipulate the display/ID.
9429
9430 // Using "##" to display same title but have unique identifier.
9431 ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 100), ImGuiCond_FirstUseEver);
9432 ImGui::Begin("Same title as another window##1");
9433 IMGUI_DEMO_MARKER("Examples/Manipulating window titles");
9434 ImGui::Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique.");
9435 ImGui::End();
9436
9437 ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 200), ImGuiCond_FirstUseEver);
9438 ImGui::Begin("Same title as another window##2");
9439 ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique.");
9440 ImGui::End();
9441
9442 // Using "###" to display a changing title but keep a static identifier "AnimatedTitle"
9443 char buf[128];
9444 sprintf(buf, "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime() / 0.25f) & 3], ImGui::GetFrameCount());
9445 ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 300), ImGuiCond_FirstUseEver);
9446 ImGui::Begin(buf);
9447 ImGui::Text("This window has a changing title.");
9448 ImGui::End();
9449}
9450
9451//-----------------------------------------------------------------------------
9452// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering()
9453//-----------------------------------------------------------------------------
9454
9455// Add a |_| looking shape
9456static void PathConcaveShape(ImDrawList* draw_list, float x, float y, float sz)
9457{
9458 const ImVec2 pos_norms[] = { { 0.0f, 0.0f }, { 0.3f, 0.0f }, { 0.3f, 0.7f }, { 0.7f, 0.7f }, { 0.7f, 0.0f }, { 1.0f, 0.0f }, { 1.0f, 1.0f }, { 0.0f, 1.0f } };
9459 for (const ImVec2& p : pos_norms)
9460 draw_list->PathLineTo(ImVec2(x + 0.5f + (int)(sz * p.x), y + 0.5f + (int)(sz * p.y)));
9461}
9462
9463// Demonstrate using the low-level ImDrawList to draw custom shapes.
9464static void ShowExampleAppCustomRendering(bool* p_open)
9465{
9466 if (!ImGui::Begin("Example: Custom rendering", p_open))
9467 {
9468 ImGui::End();
9469 return;
9470 }
9471 IMGUI_DEMO_MARKER("Examples/Custom Rendering");
9472
9473 // Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of
9474 // overloaded operators, etc. Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your
9475 // types and ImVec2/ImVec4. Dear ImGui defines overloaded operators but they are internal to imgui.cpp and not
9476 // exposed outside (to avoid messing with your types) In this example we are not using the maths operators!
9477
9478 if (ImGui::BeginTabBar("##TabBar"))
9479 {
9480 if (ImGui::BeginTabItem("Primitives"))
9481 {
9482 ImGui::PushItemWidth(-ImGui::GetFontSize() * 15);
9483 ImDrawList* draw_list = ImGui::GetWindowDrawList();
9484
9485 // Draw gradients
9486 // (note that those are currently exacerbating our sRGB/Linear issues)
9487 // Calling ImGui::GetColorU32() multiplies the given colors by the current Style Alpha, but you may pass the IM_COL32() directly as well..
9488 ImGui::Text("Gradients");
9489 ImVec2 gradient_size = ImVec2(ImGui::CalcItemWidth(), ImGui::GetFrameHeight());
9490 {
9491 ImVec2 p0 = ImGui::GetCursorScreenPos();
9492 ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y);
9493 ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 0, 0, 255));
9494 ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 255, 255, 255));
9495 draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a);
9496 ImGui::InvisibleButton("##gradient1", gradient_size);
9497 }
9498 {
9499 ImVec2 p0 = ImGui::GetCursorScreenPos();
9500 ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y);
9501 ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 255, 0, 255));
9502 ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 0, 0, 255));
9503 draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a);
9504 ImGui::InvisibleButton("##gradient2", gradient_size);
9505 }
9506
9507 // Draw a bunch of primitives
9508 ImGui::Text("All primitives");
9509 static float sz = 36.0f;
9510 static float thickness = 3.0f;
9511 static int ngon_sides = 6;
9512 static bool circle_segments_override = false;
9513 static int circle_segments_override_v = 12;
9514 static bool curve_segments_override = false;
9515 static int curve_segments_override_v = 8;
9516 static ImVec4 colf = ImVec4(1.0f, 1.0f, 0.4f, 1.0f);
9517 ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 100.0f, "%.0f");
9518 ImGui::DragFloat("Thickness", &thickness, 0.05f, 1.0f, 8.0f, "%.02f");
9519 ImGui::SliderInt("N-gon sides", &ngon_sides, 3, 12);
9520 ImGui::Checkbox("##circlesegmentoverride", &circle_segments_override);
9521 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
9522 circle_segments_override |= ImGui::SliderInt("Circle segments override", &circle_segments_override_v, 3, 40);
9523 ImGui::Checkbox("##curvessegmentoverride", &curve_segments_override);
9524 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
9525 curve_segments_override |= ImGui::SliderInt("Curves segments override", &curve_segments_override_v, 3, 40);
9526 ImGui::ColorEdit4("Color", &colf.x);
9527
9528 const ImVec2 p = ImGui::GetCursorScreenPos();
9529 const ImU32 col = ImColor(colf);
9530 const float spacing = 10.0f;
9531 const ImDrawFlags corners_tl_br = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersBottomRight;
9532 const float rounding = sz / 5.0f;
9533 const int circle_segments = circle_segments_override ? circle_segments_override_v : 0;
9534 const int curve_segments = curve_segments_override ? curve_segments_override_v : 0;
9535 const ImVec2 cp3[3] = { ImVec2(0.0f, sz * 0.6f), ImVec2(sz * 0.5f, -sz * 0.4f), ImVec2(sz, sz) }; // Control points for curves
9536 const ImVec2 cp4[4] = { ImVec2(0.0f, 0.0f), ImVec2(sz * 1.3f, sz * 0.3f), ImVec2(sz - sz * 1.3f, sz - sz * 0.3f), ImVec2(sz, sz) };
9537
9538 float x = p.x + 4.0f;
9539 float y = p.y + 4.0f;
9540 for (int n = 0; n < 2; n++)
9541 {
9542 // First line uses a thickness of 1.0f, second line uses the configurable thickness
9543 float th = (n == 0) ? 1.0f : thickness;
9544 draw_list->AddNgon(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, ngon_sides, th); x += sz + spacing; // N-gon
9545 draw_list->AddCircle(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments, th); x += sz + spacing; // Circle
9546 draw_list->AddEllipse(ImVec2(x + sz*0.5f, y + sz*0.5f), ImVec2(sz*0.5f, sz*0.3f), col, -0.3f, circle_segments, th); x += sz + spacing; // Ellipse
9547 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0f, ImDrawFlags_None, th); x += sz + spacing; // Square
9548 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, ImDrawFlags_None, th); x += sz + spacing; // Square with all rounded corners
9549 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, corners_tl_br, th); x += sz + spacing; // Square with two rounded corners
9550 draw_list->AddTriangle(ImVec2(x+sz*0.5f,y), ImVec2(x+sz, y+sz-0.5f), ImVec2(x, y+sz-0.5f), col, th);x += sz + spacing; // Triangle
9551 //draw_list->AddTriangle(ImVec2(x+sz*0.2f,y), ImVec2(x, y+sz-0.5f), ImVec2(x+sz*0.4f, y+sz-0.5f), col, th);x+= sz*0.4f + spacing; // Thin triangle
9552 PathConcaveShape(draw_list, x, y, sz); draw_list->PathStroke(col, ImDrawFlags_Closed, th); x += sz + spacing; // Concave Shape
9553 //draw_list->AddPolyline(concave_shape, IM_ARRAYSIZE(concave_shape), col, ImDrawFlags_Closed, th);
9554 draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y), col, th); x += sz + spacing; // Horizontal line (note: drawing a filled rectangle will be faster!)
9555 draw_list->AddLine(ImVec2(x, y), ImVec2(x, y + sz), col, th); x += spacing; // Vertical line (note: drawing a filled rectangle will be faster!)
9556 draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y + sz), col, th); x += sz + spacing; // Diagonal line
9557
9558 // Path
9559 draw_list->PathArcTo(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, 3.141592f, 3.141592f * -0.5f);
9560 draw_list->PathStroke(col, ImDrawFlags_None, th);
9561 x += sz + spacing;
9562
9563 // Quadratic Bezier Curve (3 control points)
9564 draw_list->AddBezierQuadratic(ImVec2(x + cp3[0].x, y + cp3[0].y), ImVec2(x + cp3[1].x, y + cp3[1].y), ImVec2(x + cp3[2].x, y + cp3[2].y), col, th, curve_segments);
9565 x += sz + spacing;
9566
9567 // Cubic Bezier Curve (4 control points)
9568 draw_list->AddBezierCubic(ImVec2(x + cp4[0].x, y + cp4[0].y), ImVec2(x + cp4[1].x, y + cp4[1].y), ImVec2(x + cp4[2].x, y + cp4[2].y), ImVec2(x + cp4[3].x, y + cp4[3].y), col, th, curve_segments);
9569
9570 x = p.x + 4;
9571 y += sz + spacing;
9572 }
9573
9574 // Filled shapes
9575 draw_list->AddNgonFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, col, ngon_sides); x += sz + spacing; // N-gon
9576 draw_list->AddCircleFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, col, circle_segments); x += sz + spacing; // Circle
9577 draw_list->AddEllipseFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), ImVec2(sz * 0.5f, sz * 0.3f), col, -0.3f, circle_segments); x += sz + spacing;// Ellipse
9578 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col); x += sz + spacing; // Square
9579 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f); x += sz + spacing; // Square with all rounded corners
9580 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_tl_br); x += sz + spacing; // Square with two rounded corners
9581 draw_list->AddTriangleFilled(ImVec2(x+sz*0.5f,y), ImVec2(x+sz, y+sz-0.5f), ImVec2(x, y+sz-0.5f), col); x += sz + spacing; // Triangle
9582 //draw_list->AddTriangleFilled(ImVec2(x+sz*0.2f,y), ImVec2(x, y+sz-0.5f), ImVec2(x+sz*0.4f, y+sz-0.5f), col); x += sz*0.4f + spacing; // Thin triangle
9583 PathConcaveShape(draw_list, x, y, sz); draw_list->PathFillConcave(col); x += sz + spacing; // Concave shape
9584 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + thickness), col); x += sz + spacing; // Horizontal line (faster than AddLine, but only handle integer thickness)
9585 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + thickness, y + sz), col); x += spacing * 2.0f;// Vertical line (faster than AddLine, but only handle integer thickness)
9586 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + 1, y + 1), col); x += sz; // Pixel (faster than AddLine)
9587
9588 // Path
9589 draw_list->PathArcTo(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, 3.141592f * -0.5f, 3.141592f);
9590 draw_list->PathFillConvex(col);
9591 x += sz + spacing;
9592
9593 // Quadratic Bezier Curve (3 control points)
9594 draw_list->PathLineTo(ImVec2(x + cp3[0].x, y + cp3[0].y));
9595 draw_list->PathBezierQuadraticCurveTo(ImVec2(x + cp3[1].x, y + cp3[1].y), ImVec2(x + cp3[2].x, y + cp3[2].y), curve_segments);
9596 draw_list->PathFillConvex(col);
9597 x += sz + spacing;
9598
9599 draw_list->AddRectFilledMultiColor(ImVec2(x, y), ImVec2(x + sz, y + sz), IM_COL32(0, 0, 0, 255), IM_COL32(255, 0, 0, 255), IM_COL32(255, 255, 0, 255), IM_COL32(0, 255, 0, 255));
9600 x += sz + spacing;
9601
9602 ImGui::Dummy(ImVec2((sz + spacing) * 13.2f, (sz + spacing) * 3.0f));
9603 ImGui::PopItemWidth();
9604 ImGui::EndTabItem();
9605 }
9606
9607 if (ImGui::BeginTabItem("Canvas"))
9608 {
9609 static ImVector<ImVec2> points;
9610 static ImVec2 scrolling(0.0f, 0.0f);
9611 static bool opt_enable_grid = true;
9612 static bool opt_enable_context_menu = true;
9613 static bool adding_line = false;
9614
9615 ImGui::Checkbox("Enable grid", &opt_enable_grid);
9616 ImGui::Checkbox("Enable context menu", &opt_enable_context_menu);
9617 ImGui::Text("Mouse Left: drag to add lines,\nMouse Right: drag to scroll, click for context menu.");
9618
9619 // Typically you would use a BeginChild()/EndChild() pair to benefit from a clipping region + own scrolling.
9620 // Here we demonstrate that this can be replaced by simple offsetting + custom drawing + PushClipRect/PopClipRect() calls.
9621 // To use a child window instead we could use, e.g:
9622 // ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); // Disable padding
9623 // ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(50, 50, 50, 255)); // Set a background color
9624 // ImGui::BeginChild("canvas", ImVec2(0.0f, 0.0f), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove);
9625 // ImGui::PopStyleColor();
9626 // ImGui::PopStyleVar();
9627 // [...]
9628 // ImGui::EndChild();
9629
9630 // Using InvisibleButton() as a convenience 1) it will advance the layout cursor and 2) allows us to use IsItemHovered()/IsItemActive()
9631 ImVec2 canvas_p0 = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates!
9632 ImVec2 canvas_sz = ImGui::GetContentRegionAvail(); // Resize canvas to what's available
9633 if (canvas_sz.x < 50.0f) canvas_sz.x = 50.0f;
9634 if (canvas_sz.y < 50.0f) canvas_sz.y = 50.0f;
9635 ImVec2 canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y);
9636
9637 // Draw border and background color
9638 ImGuiIO& io = ImGui::GetIO();
9639 ImDrawList* draw_list = ImGui::GetWindowDrawList();
9640 draw_list->AddRectFilled(canvas_p0, canvas_p1, IM_COL32(50, 50, 50, 255));
9641 draw_list->AddRect(canvas_p0, canvas_p1, IM_COL32(255, 255, 255, 255));
9642
9643 // This will catch our interactions
9644 ImGui::InvisibleButton("canvas", canvas_sz, ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight);
9645 const bool is_hovered = ImGui::IsItemHovered(); // Hovered
9646 const bool is_active = ImGui::IsItemActive(); // Held
9647 const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y); // Lock scrolled origin
9648 const ImVec2 mouse_pos_in_canvas(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
9649
9650 // Add first and second point
9651 if (is_hovered && !adding_line && ImGui::IsMouseClicked(ImGuiMouseButton_Left))
9652 {
9653 points.push_back(mouse_pos_in_canvas);
9654 points.push_back(mouse_pos_in_canvas);
9655 adding_line = true;
9656 }
9657 if (adding_line)
9658 {
9659 points.back() = mouse_pos_in_canvas;
9660 if (!ImGui::IsMouseDown(ImGuiMouseButton_Left))
9661 adding_line = false;
9662 }
9663
9664 // Pan (we use a zero mouse threshold when there's no context menu)
9665 // You may decide to make that threshold dynamic based on whether the mouse is hovering something etc.
9666 const float mouse_threshold_for_pan = opt_enable_context_menu ? -1.0f : 0.0f;
9667 if (is_active && ImGui::IsMouseDragging(ImGuiMouseButton_Right, mouse_threshold_for_pan))
9668 {
9669 scrolling.x += io.MouseDelta.x;
9670 scrolling.y += io.MouseDelta.y;
9671 }
9672
9673 // Context menu (under default mouse threshold)
9674 ImVec2 drag_delta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Right);
9675 if (opt_enable_context_menu && drag_delta.x == 0.0f && drag_delta.y == 0.0f)
9676 ImGui::OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight);
9677 if (ImGui::BeginPopup("context"))
9678 {
9679 if (adding_line)
9680 points.resize(points.size() - 2);
9681 adding_line = false;
9682 if (ImGui::MenuItem("Remove one", NULL, false, points.Size > 0)) { points.resize(points.size() - 2); }
9683 if (ImGui::MenuItem("Remove all", NULL, false, points.Size > 0)) { points.clear(); }
9684 ImGui::EndPopup();
9685 }
9686
9687 // Draw grid + all lines in the canvas
9688 draw_list->PushClipRect(canvas_p0, canvas_p1, true);
9689 if (opt_enable_grid)
9690 {
9691 const float GRID_STEP = 64.0f;
9692 for (float x = fmodf(scrolling.x, GRID_STEP); x < canvas_sz.x; x += GRID_STEP)
9693 draw_list->AddLine(ImVec2(canvas_p0.x + x, canvas_p0.y), ImVec2(canvas_p0.x + x, canvas_p1.y), IM_COL32(200, 200, 200, 40));
9694 for (float y = fmodf(scrolling.y, GRID_STEP); y < canvas_sz.y; y += GRID_STEP)
9695 draw_list->AddLine(ImVec2(canvas_p0.x, canvas_p0.y + y), ImVec2(canvas_p1.x, canvas_p0.y + y), IM_COL32(200, 200, 200, 40));
9696 }
9697 for (int n = 0; n < points.Size; n += 2)
9698 draw_list->AddLine(ImVec2(origin.x + points[n].x, origin.y + points[n].y), ImVec2(origin.x + points[n + 1].x, origin.y + points[n + 1].y), IM_COL32(255, 255, 0, 255), 2.0f);
9699 draw_list->PopClipRect();
9700
9701 ImGui::EndTabItem();
9702 }
9703
9704 if (ImGui::BeginTabItem("BG/FG draw lists"))
9705 {
9706 static bool draw_bg = true;
9707 static bool draw_fg = true;
9708 ImGui::Checkbox("Draw in Background draw list", &draw_bg);
9709 ImGui::SameLine(); HelpMarker("The Background draw list will be rendered below every Dear ImGui windows.");
9710 ImGui::Checkbox("Draw in Foreground draw list", &draw_fg);
9711 ImGui::SameLine(); HelpMarker("The Foreground draw list will be rendered over every Dear ImGui windows.");
9712 ImVec2 window_pos = ImGui::GetWindowPos();
9713 ImVec2 window_size = ImGui::GetWindowSize();
9714 ImVec2 window_center = ImVec2(window_pos.x + window_size.x * 0.5f, window_pos.y + window_size.y * 0.5f);
9715 if (draw_bg)
9716 ImGui::GetBackgroundDrawList()->AddCircle(window_center, window_size.x * 0.6f, IM_COL32(255, 0, 0, 200), 0, 10 + 4);
9717 if (draw_fg)
9718 ImGui::GetForegroundDrawList()->AddCircle(window_center, window_size.y * 0.6f, IM_COL32(0, 255, 0, 200), 0, 10);
9719 ImGui::EndTabItem();
9720 }
9721
9722 // Demonstrate out-of-order rendering via channels splitting
9723 // We use functions in ImDrawList as each draw list contains a convenience splitter,
9724 // but you can also instantiate your own ImDrawListSplitter if you need to nest them.
9725 if (ImGui::BeginTabItem("Draw Channels"))
9726 {
9727 ImDrawList* draw_list = ImGui::GetWindowDrawList();
9728 {
9729 ImGui::Text("Blue shape is drawn first: appears in back");
9730 ImGui::Text("Red shape is drawn after: appears in front");
9731 ImVec2 p0 = ImGui::GetCursorScreenPos();
9732 draw_list->AddRectFilled(ImVec2(p0.x, p0.y), ImVec2(p0.x + 50, p0.y + 50), IM_COL32(0, 0, 255, 255)); // Blue
9733 draw_list->AddRectFilled(ImVec2(p0.x + 25, p0.y + 25), ImVec2(p0.x + 75, p0.y + 75), IM_COL32(255, 0, 0, 255)); // Red
9734 ImGui::Dummy(ImVec2(75, 75));
9735 }
9736 ImGui::Separator();
9737 {
9738 ImGui::Text("Blue shape is drawn first, into channel 1: appears in front");
9739 ImGui::Text("Red shape is drawn after, into channel 0: appears in back");
9740 ImVec2 p1 = ImGui::GetCursorScreenPos();
9741
9742 // Create 2 channels and draw a Blue shape THEN a Red shape.
9743 // You can create any number of channels. Tables API use 1 channel per column in order to better batch draw calls.
9744 draw_list->ChannelsSplit(2);
9745 draw_list->ChannelsSetCurrent(1);
9746 draw_list->AddRectFilled(ImVec2(p1.x, p1.y), ImVec2(p1.x + 50, p1.y + 50), IM_COL32(0, 0, 255, 255)); // Blue
9747 draw_list->ChannelsSetCurrent(0);
9748 draw_list->AddRectFilled(ImVec2(p1.x + 25, p1.y + 25), ImVec2(p1.x + 75, p1.y + 75), IM_COL32(255, 0, 0, 255)); // Red
9749
9750 // Flatten/reorder channels. Red shape is in channel 0 and it appears below the Blue shape in channel 1.
9751 // This works by copying draw indices only (vertices are not copied).
9752 draw_list->ChannelsMerge();
9753 ImGui::Dummy(ImVec2(75, 75));
9754 ImGui::Text("After reordering, contents of channel 0 appears below channel 1.");
9755 }
9756 ImGui::EndTabItem();
9757 }
9758
9759 ImGui::EndTabBar();
9760 }
9761
9762 ImGui::End();
9763}
9764
9765//-----------------------------------------------------------------------------
9766// [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace()
9767//-----------------------------------------------------------------------------
9768
9769// Demonstrate using DockSpace() to create an explicit docking node within an existing window.
9770// Note: You can use most Docking facilities without calling any API. You DO NOT need to call DockSpace() to use Docking!
9771// - Drag from window title bar or their tab to dock/undock. Hold SHIFT to disable docking.
9772// - Drag from window menu button (upper-left button) to undock an entire node (all windows).
9773// - When io.ConfigDockingWithShift == true, you instead need to hold SHIFT to enable docking.
9774// About dockspaces:
9775// - Use DockSpace() to create an explicit dock node _within_ an existing window.
9776// - Use DockSpaceOverViewport() to create an explicit dock node covering the screen or a specific viewport.
9777// This is often used with ImGuiDockNodeFlags_PassthruCentralNode.
9778// - Important: Dockspaces need to be submitted _before_ any window they can host. Submit it early in your frame! (*)
9779// - Important: Dockspaces need to be kept alive if hidden, otherwise windows docked into it will be undocked.
9780// e.g. if you have multiple tabs with a dockspace inside each tab: submit the non-visible dockspaces with ImGuiDockNodeFlags_KeepAliveOnly.
9781// (*) because of this constraint, the implicit \"Debug\" window can not be docked into an explicit DockSpace() node,
9782// because that window is submitted as part of the part of the NewFrame() call. An easy workaround is that you can create
9783// your own implicit "Debug##2" window after calling DockSpace() and leave it in the window stack for anyone to use.
9784void ShowExampleAppDockSpace(bool* p_open)
9785{
9786 // READ THIS !!!
9787 // TL;DR; this demo is more complicated than what most users you would normally use.
9788 // If we remove all options we are showcasing, this demo would become:
9789 // void ShowExampleAppDockSpace()
9790 // {
9791 // ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport());
9792 // }
9793 // In most cases you should be able to just call DockSpaceOverViewport() and ignore all the code below!
9794 // In this specific demo, we are not using DockSpaceOverViewport() because:
9795 // - (1) we allow the host window to be floating/moveable instead of filling the viewport (when opt_fullscreen == false)
9796 // - (2) we allow the host window to have padding (when opt_padding == true)
9797 // - (3) we expose many flags and need a way to have them visible.
9798 // - (4) we have a local menu bar in the host window (vs. you could use BeginMainMenuBar() + DockSpaceOverViewport()
9799 // in your code, but we don't here because we allow the window to be floating)
9800
9801 static bool opt_fullscreen = true;
9802 static bool opt_padding = false;
9803 static ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_None;
9804
9805 // We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into,
9806 // because it would be confusing to have two docking targets within each others.
9807 ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking;
9808 if (opt_fullscreen)
9809 {
9810 const ImGuiViewport* viewport = ImGui::GetMainViewport();
9811 ImGui::SetNextWindowPos(viewport->WorkPos);
9812 ImGui::SetNextWindowSize(viewport->WorkSize);
9813 ImGui::SetNextWindowViewport(viewport->ID);
9814 ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
9815 ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
9816 window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
9817 window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
9818 }
9819 else
9820 {
9821 dockspace_flags &= ~ImGuiDockNodeFlags_PassthruCentralNode;
9822 }
9823
9824 // When using ImGuiDockNodeFlags_PassthruCentralNode, DockSpace() will render our background
9825 // and handle the pass-thru hole, so we ask Begin() to not render a background.
9826 if (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode)
9827 window_flags |= ImGuiWindowFlags_NoBackground;
9828
9829 // Important: note that we proceed even if Begin() returns false (aka window is collapsed).
9830 // This is because we want to keep our DockSpace() active. If a DockSpace() is inactive,
9831 // all active windows docked into it will lose their parent and become undocked.
9832 // We cannot preserve the docking relationship between an active window and an inactive docking, otherwise
9833 // any change of dockspace/settings would lead to windows being stuck in limbo and never being visible.
9834 if (!opt_padding)
9835 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
9836 ImGui::Begin("DockSpace Demo", p_open, window_flags);
9837 if (!opt_padding)
9838 ImGui::PopStyleVar();
9839
9840 if (opt_fullscreen)
9841 ImGui::PopStyleVar(2);
9842
9843 // Submit the DockSpace
9844 ImGuiIO& io = ImGui::GetIO();
9845 if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
9846 {
9847 ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
9848 ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
9849 }
9850 else
9851 {
9852 ShowDockingDisabledMessage();
9853 }
9854
9855 if (ImGui::BeginMenuBar())
9856 {
9857 if (ImGui::BeginMenu("Options"))
9858 {
9859 // Disabling fullscreen would allow the window to be moved to the front of other windows,
9860 // which we can't undo at the moment without finer window depth/z control.
9861 ImGui::MenuItem("Fullscreen", NULL, &opt_fullscreen);
9862 ImGui::MenuItem("Padding", NULL, &opt_padding);
9863 ImGui::Separator();
9864
9865 if (ImGui::MenuItem("Flag: NoDockingOverCentralNode", "", (dockspace_flags & ImGuiDockNodeFlags_NoDockingOverCentralNode) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoDockingOverCentralNode; }
9866 if (ImGui::MenuItem("Flag: NoDockingSplit", "", (dockspace_flags & ImGuiDockNodeFlags_NoDockingSplit) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoDockingSplit; }
9867 if (ImGui::MenuItem("Flag: NoUndocking", "", (dockspace_flags & ImGuiDockNodeFlags_NoUndocking) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoUndocking; }
9868 if (ImGui::MenuItem("Flag: NoResize", "", (dockspace_flags & ImGuiDockNodeFlags_NoResize) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoResize; }
9869 if (ImGui::MenuItem("Flag: AutoHideTabBar", "", (dockspace_flags & ImGuiDockNodeFlags_AutoHideTabBar) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_AutoHideTabBar; }
9870 if (ImGui::MenuItem("Flag: PassthruCentralNode", "", (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode) != 0, opt_fullscreen)) { dockspace_flags ^= ImGuiDockNodeFlags_PassthruCentralNode; }
9871 ImGui::Separator();
9872
9873 if (ImGui::MenuItem("Close", NULL, false, p_open != NULL))
9874 *p_open = false;
9875 ImGui::EndMenu();
9876 }
9877 HelpMarker(
9878 "When docking is enabled, you can ALWAYS dock MOST window into another! Try it now!" "\n"
9879 "- Drag from window title bar or their tab to dock/undock." "\n"
9880 "- Drag from window menu button (upper-left button) to undock an entire node (all windows)." "\n"
9881 "- Hold SHIFT to disable docking (if io.ConfigDockingWithShift == false, default)" "\n"
9882 "- Hold SHIFT to enable docking (if io.ConfigDockingWithShift == true)" "\n"
9883 "This demo app has nothing to do with enabling docking!" "\n\n"
9884 "This demo app only demonstrate the use of ImGui::DockSpace() which allows you to manually create a docking node _within_ another window." "\n\n"
9885 "Read comments in ShowExampleAppDockSpace() for more details.");
9886
9887 ImGui::EndMenuBar();
9888 }
9889
9890 ImGui::End();
9891}
9892
9893//-----------------------------------------------------------------------------
9894// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
9895//-----------------------------------------------------------------------------
9896
9897// Simplified structure to mimic a Document model
9899{
9900 char Name[32]; // Document title
9901 int UID; // Unique ID (necessary as we can change title)
9902 bool Open; // Set when open (we keep an array of all available documents to simplify demo code!)
9903 bool OpenPrev; // Copy of Open from last update.
9904 bool Dirty; // Set when the document has been modified
9905 ImVec4 Color; // An arbitrary variable associated to the document
9906
9907 MyDocument(int uid, const char* name, bool open = true, const ImVec4& color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f))
9908 {
9909 UID = uid;
9910 snprintf(Name, sizeof(Name), "%s", name);
9911 Open = OpenPrev = open;
9912 Dirty = false;
9913 Color = color;
9914 }
9915 void DoOpen() { Open = true; }
9916 void DoForceClose() { Open = false; Dirty = false; }
9917 void DoSave() { Dirty = false; }
9918};
9919
9921{
9922 ImVector<MyDocument> Documents;
9923 ImVector<MyDocument*> CloseQueue;
9925 bool RenamingStarted = false;
9926
9928 {
9929 Documents.push_back(MyDocument(0, "Lettuce", true, ImVec4(0.4f, 0.8f, 0.4f, 1.0f)));
9930 Documents.push_back(MyDocument(1, "Eggplant", true, ImVec4(0.8f, 0.5f, 1.0f, 1.0f)));
9931 Documents.push_back(MyDocument(2, "Carrot", true, ImVec4(1.0f, 0.8f, 0.5f, 1.0f)));
9932 Documents.push_back(MyDocument(3, "Tomato", false, ImVec4(1.0f, 0.3f, 0.4f, 1.0f)));
9933 Documents.push_back(MyDocument(4, "A Rather Long Title", false, ImVec4(0.4f, 0.8f, 0.8f, 1.0f)));
9934 Documents.push_back(MyDocument(5, "Some Document", false, ImVec4(0.8f, 0.8f, 1.0f, 1.0f)));
9935 }
9936
9937 // As we allow to change document name, we append a never-changing document ID so tabs are stable
9938 void GetTabName(MyDocument* doc, char* out_buf, size_t out_buf_size)
9939 {
9940 snprintf(out_buf, out_buf_size, "%s###doc%d", doc->Name, doc->UID);
9941 }
9942
9943 // Display placeholder contents for the Document
9945 {
9946 ImGui::PushID(doc);
9947 ImGui::Text("Document \"%s\"", doc->Name);
9948 ImGui::PushStyleColor(ImGuiCol_Text, doc->Color);
9949 ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.");
9950 ImGui::PopStyleColor();
9951
9952 ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_R, ImGuiInputFlags_Tooltip);
9953 if (ImGui::Button("Rename.."))
9954 {
9955 RenamingDoc = doc;
9956 RenamingStarted = true;
9957 }
9958 ImGui::SameLine();
9959
9960 ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_M, ImGuiInputFlags_Tooltip);
9961 if (ImGui::Button("Modify"))
9962 doc->Dirty = true;
9963
9964 ImGui::SameLine();
9965 ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_S, ImGuiInputFlags_Tooltip);
9966 if (ImGui::Button("Save"))
9967 doc->DoSave();
9968
9969 ImGui::SameLine();
9970 ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_W, ImGuiInputFlags_Tooltip);
9971 if (ImGui::Button("Close"))
9972 CloseQueue.push_back(doc);
9973 ImGui::ColorEdit3("color", &doc->Color.x); // Useful to test drag and drop and hold-dragged-to-open-tab behavior.
9974 ImGui::PopID();
9975 }
9976
9977 // Display context menu for the Document
9979 {
9980 if (!ImGui::BeginPopupContextItem())
9981 return;
9982
9983 char buf[256];
9984 sprintf(buf, "Save %s", doc->Name);
9985 if (ImGui::MenuItem(buf, "Ctrl+S", false, doc->Open))
9986 doc->DoSave();
9987 if (ImGui::MenuItem("Rename...", "Ctrl+R", false, doc->Open))
9988 RenamingDoc = doc;
9989 if (ImGui::MenuItem("Close", "Ctrl+W", false, doc->Open))
9990 CloseQueue.push_back(doc);
9991 ImGui::EndPopup();
9992 }
9993
9994 // [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface.
9995 // If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo,
9996 // as opposed to clicking on the regular tab closing button) and stops being submitted, it will take a frame for
9997 // the tab bar to notice its absence. During this frame there will be a gap in the tab bar, and if the tab that has
9998 // disappeared was the selected one, the tab bar will report no selected tab during the frame. This will effectively
9999 // give the impression of a flicker for one frame.
10000 // We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch.
10001 // Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag.
10003 {
10004 for (MyDocument& doc : Documents)
10005 {
10006 if (!doc.Open && doc.OpenPrev)
10007 ImGui::SetTabItemClosed(doc.Name);
10008 doc.OpenPrev = doc.Open;
10009 }
10010 }
10011};
10012
10013void ShowExampleAppDocuments(bool* p_open)
10014{
10015 static ExampleAppDocuments app;
10016
10017 // Options
10018 enum Target
10019 {
10020 Target_None,
10021 Target_Tab, // Create documents as local tab into a local tab bar
10022 Target_DockSpaceAndWindow // Create documents as regular windows, and create an embedded dockspace
10023 };
10024 static Target opt_target = Target_Tab;
10025 static bool opt_reorderable = true;
10026 static ImGuiTabBarFlags opt_fitting_flags = ImGuiTabBarFlags_FittingPolicyDefault_;
10027
10028 // When (opt_target == Target_DockSpaceAndWindow) there is the possibily that one of our child Document window (e.g. "Eggplant")
10029 // that we emit gets docked into the same spot as the parent window ("Example: Documents").
10030 // This would create a problematic feedback loop because selecting the "Eggplant" tab would make the "Example: Documents" tab
10031 // not visible, which in turn would stop submitting the "Eggplant" window.
10032 // We avoid this problem by submitting our documents window even if our parent window is not currently visible.
10033 // Another solution may be to make the "Example: Documents" window use the ImGuiWindowFlags_NoDocking.
10034
10035 bool window_contents_visible = ImGui::Begin("Example: Documents", p_open, ImGuiWindowFlags_MenuBar);
10036 if (!window_contents_visible && opt_target != Target_DockSpaceAndWindow)
10037 {
10038 ImGui::End();
10039 return;
10040 }
10041
10042 // Menu
10043 if (ImGui::BeginMenuBar())
10044 {
10045 if (ImGui::BeginMenu("File"))
10046 {
10047 int open_count = 0;
10048 for (MyDocument& doc : app.Documents)
10049 open_count += doc.Open ? 1 : 0;
10050
10051 if (ImGui::BeginMenu("Open", open_count < app.Documents.Size))
10052 {
10053 for (MyDocument& doc : app.Documents)
10054 if (!doc.Open && ImGui::MenuItem(doc.Name))
10055 doc.DoOpen();
10056 ImGui::EndMenu();
10057 }
10058 if (ImGui::MenuItem("Close All Documents", NULL, false, open_count > 0))
10059 for (MyDocument& doc : app.Documents)
10060 app.CloseQueue.push_back(&doc);
10061 if (ImGui::MenuItem("Exit") && p_open)
10062 *p_open = false;
10063 ImGui::EndMenu();
10064 }
10065 ImGui::EndMenuBar();
10066 }
10067
10068 // [Debug] List documents with one checkbox for each
10069 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
10070 {
10071 MyDocument& doc = app.Documents[doc_n];
10072 if (doc_n > 0)
10073 ImGui::SameLine();
10074 ImGui::PushID(&doc);
10075 if (ImGui::Checkbox(doc.Name, &doc.Open))
10076 if (!doc.Open)
10077 doc.DoForceClose();
10078 ImGui::PopID();
10079 }
10080 ImGui::PushItemWidth(ImGui::GetFontSize() * 12);
10081 ImGui::Combo("Output", (int*)&opt_target, "None\0TabBar+Tabs\0DockSpace+Window\0");
10082 ImGui::PopItemWidth();
10083 bool redock_all = false;
10084 if (opt_target == Target_Tab) { ImGui::SameLine(); ImGui::Checkbox("Reorderable Tabs", &opt_reorderable); }
10085 if (opt_target == Target_DockSpaceAndWindow) { ImGui::SameLine(); redock_all = ImGui::Button("Redock all"); }
10086
10087 ImGui::Separator();
10088
10089 // About the ImGuiWindowFlags_UnsavedDocument / ImGuiTabItemFlags_UnsavedDocument flags.
10090 // They have multiple effects:
10091 // - Display a dot next to the title.
10092 // - Tab is selected when clicking the X close button.
10093 // - Closure is not assumed (will wait for user to stop submitting the tab).
10094 // Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar.
10095 // We need to assume closure by default otherwise waiting for "lack of submission" on the next frame would leave an empty
10096 // hole for one-frame, both in the tab-bar and in tab-contents when closing a tab/window.
10097 // The rarely used SetTabItemClosed() function is a way to notify of programmatic closure to avoid the one-frame hole.
10098
10099 // Tabs
10100 if (opt_target == Target_Tab)
10101 {
10102 ImGuiTabBarFlags tab_bar_flags = (opt_fitting_flags) | (opt_reorderable ? ImGuiTabBarFlags_Reorderable : 0);
10103 tab_bar_flags |= ImGuiTabBarFlags_DrawSelectedOverline;
10104 if (ImGui::BeginTabBar("##tabs", tab_bar_flags))
10105 {
10106 if (opt_reorderable)
10108
10109 // [DEBUG] Stress tests
10110 //if ((ImGui::GetFrameCount() % 30) == 0) docs[1].Open ^= 1; // [DEBUG] Automatically show/hide a tab. Test various interactions e.g. dragging with this on.
10111 //if (ImGui::GetIO().KeyCtrl) ImGui::SetTabItemSelected(docs[1].Name); // [DEBUG] Test SetTabItemSelected(), probably not very useful as-is anyway..
10112
10113 // Submit Tabs
10114 for (MyDocument& doc : app.Documents)
10115 {
10116 if (!doc.Open)
10117 continue;
10118
10119 // As we allow to change document name, we append a never-changing document id so tabs are stable
10120 char doc_name_buf[64];
10121 app.GetTabName(&doc, doc_name_buf, sizeof(doc_name_buf));
10122 ImGuiTabItemFlags tab_flags = (doc.Dirty ? ImGuiTabItemFlags_UnsavedDocument : 0);
10123 bool visible = ImGui::BeginTabItem(doc_name_buf, &doc.Open, tab_flags);
10124
10125 // Cancel attempt to close when unsaved add to save queue so we can display a popup.
10126 if (!doc.Open && doc.Dirty)
10127 {
10128 doc.Open = true;
10129 app.CloseQueue.push_back(&doc);
10130 }
10131
10132 app.DisplayDocContextMenu(&doc);
10133 if (visible)
10134 {
10135 app.DisplayDocContents(&doc);
10136 ImGui::EndTabItem();
10137 }
10138 }
10139
10140 ImGui::EndTabBar();
10141 }
10142 }
10143 else if (opt_target == Target_DockSpaceAndWindow)
10144 {
10145 if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_DockingEnable)
10146 {
10148
10149 // Create a DockSpace node where any window can be docked
10150 ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
10151 ImGui::DockSpace(dockspace_id);
10152
10153 // Create Windows
10154 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
10155 {
10156 MyDocument* doc = &app.Documents[doc_n];
10157 if (!doc->Open)
10158 continue;
10159
10160 ImGui::SetNextWindowDockID(dockspace_id, redock_all ? ImGuiCond_Always : ImGuiCond_FirstUseEver);
10161 ImGuiWindowFlags window_flags = (doc->Dirty ? ImGuiWindowFlags_UnsavedDocument : 0);
10162 bool visible = ImGui::Begin(doc->Name, &doc->Open, window_flags);
10163
10164 // Cancel attempt to close when unsaved add to save queue so we can display a popup.
10165 if (!doc->Open && doc->Dirty)
10166 {
10167 doc->Open = true;
10168 app.CloseQueue.push_back(doc);
10169 }
10170
10171 app.DisplayDocContextMenu(doc);
10172 if (visible)
10173 app.DisplayDocContents(doc);
10174
10175 ImGui::End();
10176 }
10177 }
10178 else
10179 {
10180 ShowDockingDisabledMessage();
10181 }
10182 }
10183
10184 // Early out other contents
10185 if (!window_contents_visible)
10186 {
10187 ImGui::End();
10188 return;
10189 }
10190
10191 // Display renaming UI
10192 if (app.RenamingDoc != NULL)
10193 {
10194 if (app.RenamingStarted)
10195 ImGui::OpenPopup("Rename");
10196 if (ImGui::BeginPopup("Rename"))
10197 {
10198 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 30);
10199 if (ImGui::InputText("###Name", app.RenamingDoc->Name, IM_ARRAYSIZE(app.RenamingDoc->Name), ImGuiInputTextFlags_EnterReturnsTrue))
10200 {
10201 ImGui::CloseCurrentPopup();
10202 app.RenamingDoc = NULL;
10203 }
10204 if (app.RenamingStarted)
10205 ImGui::SetKeyboardFocusHere(-1);
10206 ImGui::EndPopup();
10207 }
10208 else
10209 {
10210 app.RenamingDoc = NULL;
10211 }
10212 app.RenamingStarted = false;
10213 }
10214
10215 // Display closing confirmation UI
10216 if (!app.CloseQueue.empty())
10217 {
10218 int close_queue_unsaved_documents = 0;
10219 for (int n = 0; n < app.CloseQueue.Size; n++)
10220 if (app.CloseQueue[n]->Dirty)
10221 close_queue_unsaved_documents++;
10222
10223 if (close_queue_unsaved_documents == 0)
10224 {
10225 // Close documents when all are unsaved
10226 for (int n = 0; n < app.CloseQueue.Size; n++)
10227 app.CloseQueue[n]->DoForceClose();
10228 app.CloseQueue.clear();
10229 }
10230 else
10231 {
10232 if (!ImGui::IsPopupOpen("Save?"))
10233 ImGui::OpenPopup("Save?");
10234 if (ImGui::BeginPopupModal("Save?", NULL, ImGuiWindowFlags_AlwaysAutoResize))
10235 {
10236 ImGui::Text("Save change to the following items?");
10237 float item_height = ImGui::GetTextLineHeightWithSpacing();
10238 if (ImGui::BeginChild(ImGui::GetID("frame"), ImVec2(-FLT_MIN, 6.25f * item_height), ImGuiChildFlags_FrameStyle))
10239 for (MyDocument* doc : app.CloseQueue)
10240 if (doc->Dirty)
10241 ImGui::Text("%s", doc->Name);
10242 ImGui::EndChild();
10243
10244 ImVec2 button_size(ImGui::GetFontSize() * 7.0f, 0.0f);
10245 if (ImGui::Button("Yes", button_size))
10246 {
10247 for (MyDocument* doc : app.CloseQueue)
10248 {
10249 if (doc->Dirty)
10250 doc->DoSave();
10251 doc->DoForceClose();
10252 }
10253 app.CloseQueue.clear();
10254 ImGui::CloseCurrentPopup();
10255 }
10256 ImGui::SameLine();
10257 if (ImGui::Button("No", button_size))
10258 {
10259 for (MyDocument* doc : app.CloseQueue)
10260 doc->DoForceClose();
10261 app.CloseQueue.clear();
10262 ImGui::CloseCurrentPopup();
10263 }
10264 ImGui::SameLine();
10265 if (ImGui::Button("Cancel", button_size))
10266 {
10267 app.CloseQueue.clear();
10268 ImGui::CloseCurrentPopup();
10269 }
10270 ImGui::EndPopup();
10271 }
10272 }
10273 }
10274
10275 ImGui::End();
10276}
10277
10278//-----------------------------------------------------------------------------
10279// [SECTION] Example App: Assets Browser / ShowExampleAppAssetsBrowser()
10280//-----------------------------------------------------------------------------
10281
10282//#include "imgui_internal.h" // NavMoveRequestTryWrapping()
10283
10285{
10286 ImGuiID ID;
10287 int Type;
10288
10289 ExampleAsset(ImGuiID id, int type) { ID = id; Type = type; }
10290
10291 static const ImGuiTableSortSpecs* s_current_sort_specs;
10292
10293 static void SortWithSortSpecs(ImGuiTableSortSpecs* sort_specs, ExampleAsset* items, int items_count)
10294 {
10295 s_current_sort_specs = sort_specs; // Store in variable accessible by the sort function.
10296 if (items_count > 1)
10297 qsort(items, (size_t)items_count, sizeof(items[0]), ExampleAsset::CompareWithSortSpecs);
10298 s_current_sort_specs = NULL;
10299 }
10300
10301 // Compare function to be used by qsort()
10302 static int IMGUI_CDECL CompareWithSortSpecs(const void* lhs, const void* rhs)
10303 {
10304 const ExampleAsset* a = (const ExampleAsset*)lhs;
10305 const ExampleAsset* b = (const ExampleAsset*)rhs;
10306 for (int n = 0; n < s_current_sort_specs->SpecsCount; n++)
10307 {
10308 const ImGuiTableColumnSortSpecs* sort_spec = &s_current_sort_specs->Specs[n];
10309 int delta = 0;
10310 if (sort_spec->ColumnIndex == 0)
10311 delta = ((int)a->ID - (int)b->ID);
10312 else if (sort_spec->ColumnIndex == 1)
10313 delta = (a->Type - b->Type);
10314 if (delta > 0)
10315 return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? +1 : -1;
10316 if (delta < 0)
10317 return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? -1 : +1;
10318 }
10319 return ((int)a->ID - (int)b->ID);
10320 }
10321};
10322const ImGuiTableSortSpecs* ExampleAsset::s_current_sort_specs = NULL;
10323
10325{
10326 // Options
10327 bool ShowTypeOverlay = true;
10328 bool AllowSorting = true;
10330 bool AllowBoxSelect = true;
10331 float IconSize = 32.0f;
10332 int IconSpacing = 10;
10333 int IconHitSpacing = 4; // Increase hit-spacing if you want to make it possible to clear or box-select from gaps. Some spacing is required to able to amend with Shift+box-select. Value is small in Explorer.
10334 bool StretchSpacing = true;
10335
10336 // State
10337 ImVector<ExampleAsset> Items; // Our items
10338 ExampleSelectionWithDeletion Selection; // Our selection (ImGuiSelectionBasicStorage + helper funcs to handle deletion)
10339 ImGuiID NextItemId = 0; // Unique identifier when creating new items
10340 bool RequestDelete = false; // Deferred deletion request
10341 bool RequestSort = false; // Deferred sort request
10342 float ZoomWheelAccum = 0.0f; // Mouse wheel accumulator to handle smooth wheels better
10343
10344 // Calculated sizes for layout, output of UpdateLayoutSizes(). Could be locals but our code is simpler this way.
10346 ImVec2 LayoutItemStep; // == LayoutItemSize + LayoutItemSpacing
10347 float LayoutItemSpacing = 0.0f;
10352
10353 // Functions
10355 {
10356 AddItems(10000);
10357 }
10358 void AddItems(int count)
10359 {
10360 if (Items.Size == 0)
10361 NextItemId = 0;
10362 Items.reserve(Items.Size + count);
10363 for (int n = 0; n < count; n++, NextItemId++)
10364 Items.push_back(ExampleAsset(NextItemId, (NextItemId % 20) < 15 ? 0 : (NextItemId % 20) < 18 ? 1 : 2));
10365 RequestSort = true;
10366 }
10368 {
10369 Items.clear();
10370 Selection.Clear();
10371 }
10372
10373 // Logic would be written in the main code BeginChild() and outputing to local variables.
10374 // We extracted it into a function so we can call it easily from multiple places.
10375 void UpdateLayoutSizes(float avail_width)
10376 {
10377 // Layout: when not stretching: allow extending into right-most spacing.
10379 if (StretchSpacing == false)
10380 avail_width += floorf(LayoutItemSpacing * 0.5f);
10381
10382 // Layout: calculate number of icon per line and number of lines
10383 LayoutItemSize = ImVec2(floorf(IconSize), floorf(IconSize));
10384 LayoutColumnCount = IM_MAX((int)(avail_width / (LayoutItemSize.x + LayoutItemSpacing)), 1);
10386
10387 // Layout: when stretching: allocate remaining space to more spacing. Round before division, so item_spacing may be non-integer.
10390
10393 LayoutOuterPadding = floorf(LayoutItemSpacing * 0.5f);
10394 }
10395
10396 void Draw(const char* title, bool* p_open)
10397 {
10398 ImGui::SetNextWindowSize(ImVec2(IconSize * 25, IconSize * 15), ImGuiCond_FirstUseEver);
10399 if (!ImGui::Begin(title, p_open, ImGuiWindowFlags_MenuBar))
10400 {
10401 ImGui::End();
10402 return;
10403 }
10404
10405 // Menu bar
10406 if (ImGui::BeginMenuBar())
10407 {
10408 if (ImGui::BeginMenu("File"))
10409 {
10410 if (ImGui::MenuItem("Add 10000 items"))
10411 AddItems(10000);
10412 if (ImGui::MenuItem("Clear items"))
10413 ClearItems();
10414 ImGui::Separator();
10415 if (ImGui::MenuItem("Close", NULL, false, p_open != NULL))
10416 *p_open = false;
10417 ImGui::EndMenu();
10418 }
10419 if (ImGui::BeginMenu("Edit"))
10420 {
10421 if (ImGui::MenuItem("Delete", "Del", false, Selection.Size > 0))
10422 RequestDelete = true;
10423 ImGui::EndMenu();
10424 }
10425 if (ImGui::BeginMenu("Options"))
10426 {
10427 ImGui::PushItemWidth(ImGui::GetFontSize() * 10);
10428
10429 ImGui::SeparatorText("Contents");
10430 ImGui::Checkbox("Show Type Overlay", &ShowTypeOverlay);
10431 ImGui::Checkbox("Allow Sorting", &AllowSorting);
10432
10433 ImGui::SeparatorText("Selection Behavior");
10434 ImGui::Checkbox("Allow dragging unselected item", &AllowDragUnselected);
10435 ImGui::Checkbox("Allow box-selection", &AllowBoxSelect);
10436
10437 ImGui::SeparatorText("Layout");
10438 ImGui::SliderFloat("Icon Size", &IconSize, 16.0f, 128.0f, "%.0f");
10439 ImGui::SameLine(); HelpMarker("Use CTRL+Wheel to zoom");
10440 ImGui::SliderInt("Icon Spacing", &IconSpacing, 0, 32);
10441 ImGui::SliderInt("Icon Hit Spacing", &IconHitSpacing, 0, 32);
10442 ImGui::Checkbox("Stretch Spacing", &StretchSpacing);
10443 ImGui::PopItemWidth();
10444 ImGui::EndMenu();
10445 }
10446 ImGui::EndMenuBar();
10447 }
10448
10449 // Show a table with ONLY one header row to showcase the idea/possibility of using this to provide a sorting UI
10450 if (AllowSorting)
10451 {
10452 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
10453 ImGuiTableFlags table_flags_for_sort_specs = ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Borders;
10454 if (ImGui::BeginTable("for_sort_specs_only", 2, table_flags_for_sort_specs, ImVec2(0.0f, ImGui::GetFrameHeight())))
10455 {
10456 ImGui::TableSetupColumn("Index");
10457 ImGui::TableSetupColumn("Type");
10458 ImGui::TableHeadersRow();
10459 if (ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs())
10460 if (sort_specs->SpecsDirty || RequestSort)
10461 {
10462 ExampleAsset::SortWithSortSpecs(sort_specs, Items.Data, Items.Size);
10463 sort_specs->SpecsDirty = RequestSort = false;
10464 }
10465 ImGui::EndTable();
10466 }
10467 ImGui::PopStyleVar();
10468 }
10469
10470 ImGuiIO& io = ImGui::GetIO();
10471 ImGui::SetNextWindowContentSize(ImVec2(0.0f, LayoutOuterPadding + LayoutLineCount * (LayoutItemSize.x + LayoutItemSpacing)));
10472 if (ImGui::BeginChild("Assets", ImVec2(0.0f, -ImGui::GetTextLineHeightWithSpacing()), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove))
10473 {
10474 ImDrawList* draw_list = ImGui::GetWindowDrawList();
10475
10476 const float avail_width = ImGui::GetContentRegionAvail().x;
10477 UpdateLayoutSizes(avail_width);
10478
10479 // Calculate and store start position.
10480 ImVec2 start_pos = ImGui::GetCursorScreenPos();
10481 start_pos = ImVec2(start_pos.x + LayoutOuterPadding, start_pos.y + LayoutOuterPadding);
10482 ImGui::SetCursorScreenPos(start_pos);
10483
10484 // Multi-select
10485 ImGuiMultiSelectFlags ms_flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_ClearOnClickVoid;
10486
10487 // - Enable box-select (in 2D mode, so that changing box-select rectangle X1/X2 boundaries will affect clipped items)
10488 if (AllowBoxSelect)
10489 ms_flags |= ImGuiMultiSelectFlags_BoxSelect2d;
10490
10491 // - This feature allows dragging an unselected item without selecting it (rarely used)
10493 ms_flags |= ImGuiMultiSelectFlags_SelectOnClickRelease;
10494
10495 // - Enable keyboard wrapping on X axis
10496 // (FIXME-MULTISELECT: We haven't designed/exposed a general nav wrapping api yet, so this flag is provided as a courtesy to avoid doing:
10497 // ImGui::NavMoveRequestTryWrapping(ImGui::GetCurrentWindow(), ImGuiNavMoveFlags_WrapX);
10498 // When we finish implementing a more general API for this, we will obsolete this flag in favor of the new system)
10499 ms_flags |= ImGuiMultiSelectFlags_NavWrapX;
10500
10501 ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(ms_flags, Selection.Size, Items.Size);
10502
10503 // Use custom selection adapter: store ID in selection (recommended)
10504 Selection.UserData = this;
10505 Selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self_, int idx) { ExampleAssetsBrowser* self = (ExampleAssetsBrowser*)self_->UserData; return self->Items[idx].ID; };
10506 Selection.ApplyRequests(ms_io);
10507
10508 const bool want_delete = (ImGui::Shortcut(ImGuiKey_Delete, ImGuiInputFlags_Repeat) && (Selection.Size > 0)) || RequestDelete;
10509 const int item_curr_idx_to_focus = want_delete ? Selection.ApplyDeletionPreLoop(ms_io, Items.Size) : -1;
10510 RequestDelete = false;
10511
10512 // Push LayoutSelectableSpacing (which is LayoutItemSpacing minus hit-spacing, if we decide to have hit gaps between items)
10513 // Altering style ItemSpacing may seem unnecessary as we position every items using SetCursorScreenPos()...
10514 // But it is necessary for two reasons:
10515 // - Selectables uses it by default to visually fill the space between two items.
10516 // - The vertical spacing would be measured by Clipper to calculate line height if we didn't provide it explicitly (here we do).
10517 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(LayoutSelectableSpacing, LayoutSelectableSpacing));
10518
10519 // Rendering parameters
10520 const ImU32 icon_type_overlay_colors[3] = { 0, IM_COL32(200, 70, 70, 255), IM_COL32(70, 170, 70, 255) };
10521 const ImU32 icon_bg_color = ImGui::GetColorU32(IM_COL32(35, 35, 35, 220));
10522 const ImVec2 icon_type_overlay_size = ImVec2(4.0f, 4.0f);
10523 const bool display_label = (LayoutItemSize.x >= ImGui::CalcTextSize("999").x);
10524
10525 const int column_count = LayoutColumnCount;
10526 ImGuiListClipper clipper;
10527 clipper.Begin(LayoutLineCount, LayoutItemStep.y);
10528 if (item_curr_idx_to_focus != -1)
10529 clipper.IncludeItemByIndex(item_curr_idx_to_focus / column_count); // Ensure focused item line is not clipped.
10530 if (ms_io->RangeSrcItem != -1)
10531 clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem / column_count); // Ensure RangeSrc item line is not clipped.
10532 while (clipper.Step())
10533 {
10534 for (int line_idx = clipper.DisplayStart; line_idx < clipper.DisplayEnd; line_idx++)
10535 {
10536 const int item_min_idx_for_current_line = line_idx * column_count;
10537 const int item_max_idx_for_current_line = IM_MIN((line_idx + 1) * column_count, Items.Size);
10538 for (int item_idx = item_min_idx_for_current_line; item_idx < item_max_idx_for_current_line; ++item_idx)
10539 {
10540 ExampleAsset* item_data = &Items[item_idx];
10541 ImGui::PushID((int)item_data->ID);
10542
10543 // Position item
10544 ImVec2 pos = ImVec2(start_pos.x + (item_idx % column_count) * LayoutItemStep.x, start_pos.y + line_idx * LayoutItemStep.y);
10545 ImGui::SetCursorScreenPos(pos);
10546
10547 ImGui::SetNextItemSelectionUserData(item_idx);
10548 bool item_is_selected = Selection.Contains((ImGuiID)item_data->ID);
10549 bool item_is_visible = ImGui::IsRectVisible(LayoutItemSize);
10550 ImGui::Selectable("", item_is_selected, ImGuiSelectableFlags_None, LayoutItemSize);
10551
10552 // Update our selection state immediately (without waiting for EndMultiSelect() requests)
10553 // because we use this to alter the color of our text/icon.
10554 if (ImGui::IsItemToggledSelection())
10555 item_is_selected = !item_is_selected;
10556
10557 // Focus (for after deletion)
10558 if (item_curr_idx_to_focus == item_idx)
10559 ImGui::SetKeyboardFocusHere(-1);
10560
10561 // Drag and drop
10562 if (ImGui::BeginDragDropSource())
10563 {
10564 // Create payload with full selection OR single unselected item.
10565 // (the later is only possible when using ImGuiMultiSelectFlags_SelectOnClickRelease)
10566 if (ImGui::GetDragDropPayload() == NULL)
10567 {
10568 ImVector<ImGuiID> payload_items;
10569 void* it = NULL;
10570 ImGuiID id = 0;
10571 if (!item_is_selected)
10572 payload_items.push_back(item_data->ID);
10573 else
10574 while (Selection.GetNextSelectedItem(&it, &id))
10575 payload_items.push_back(id);
10576 ImGui::SetDragDropPayload("ASSETS_BROWSER_ITEMS", payload_items.Data, (size_t)payload_items.size_in_bytes());
10577 }
10578
10579 // Display payload content in tooltip, by extracting it from the payload data
10580 // (we could read from selection, but it is more correct and reusable to read from payload)
10581 const ImGuiPayload* payload = ImGui::GetDragDropPayload();
10582 const int payload_count = (int)payload->DataSize / (int)sizeof(ImGuiID);
10583 ImGui::Text("%d assets", payload_count);
10584
10585 ImGui::EndDragDropSource();
10586 }
10587
10588 // Render icon (a real app would likely display an image/thumbnail here)
10589 // Because we use ImGuiMultiSelectFlags_BoxSelect2d, clipping vertical may occasionally be larger, so we coarse-clip our rendering as well.
10590 if (item_is_visible)
10591 {
10592 ImVec2 box_min(pos.x - 1, pos.y - 1);
10593 ImVec2 box_max(box_min.x + LayoutItemSize.x + 2, box_min.y + LayoutItemSize.y + 2); // Dubious
10594 draw_list->AddRectFilled(box_min, box_max, icon_bg_color); // Background color
10595 if (ShowTypeOverlay && item_data->Type != 0)
10596 {
10597 ImU32 type_col = icon_type_overlay_colors[item_data->Type % IM_ARRAYSIZE(icon_type_overlay_colors)];
10598 draw_list->AddRectFilled(ImVec2(box_max.x - 2 - icon_type_overlay_size.x, box_min.y + 2), ImVec2(box_max.x - 2, box_min.y + 2 + icon_type_overlay_size.y), type_col);
10599 }
10600 if (display_label)
10601 {
10602 ImU32 label_col = ImGui::GetColorU32(item_is_selected ? ImGuiCol_Text : ImGuiCol_TextDisabled);
10603 char label[32];
10604 sprintf(label, "%d", item_data->ID);
10605 draw_list->AddText(ImVec2(box_min.x, box_max.y - ImGui::GetFontSize()), label_col, label);
10606 }
10607 }
10608
10609 ImGui::PopID();
10610 }
10611 }
10612 }
10613 clipper.End();
10614 ImGui::PopStyleVar(); // ImGuiStyleVar_ItemSpacing
10615
10616 // Context menu
10617 if (ImGui::BeginPopupContextWindow())
10618 {
10619 ImGui::Text("Selection: %d items", Selection.Size);
10620 ImGui::Separator();
10621 if (ImGui::MenuItem("Delete", "Del", false, Selection.Size > 0))
10622 RequestDelete = true;
10623 ImGui::EndPopup();
10624 }
10625
10626 ms_io = ImGui::EndMultiSelect();
10627 Selection.ApplyRequests(ms_io);
10628 if (want_delete)
10629 Selection.ApplyDeletionPostLoop(ms_io, Items, item_curr_idx_to_focus);
10630
10631 // Zooming with CTRL+Wheel
10632 if (ImGui::IsWindowAppearing())
10633 ZoomWheelAccum = 0.0f;
10634 if (ImGui::IsWindowHovered() && io.MouseWheel != 0.0f && ImGui::IsKeyDown(ImGuiMod_Ctrl) && ImGui::IsAnyItemActive() == false)
10635 {
10636 ZoomWheelAccum += io.MouseWheel;
10637 if (fabsf(ZoomWheelAccum) >= 1.0f)
10638 {
10639 // Calculate hovered item index from mouse location
10640 // FIXME: Locking aiming on 'hovered_item_idx' (with a cool-down timer) would ensure zoom keeps on it.
10641 const float hovered_item_nx = (io.MousePos.x - start_pos.x + LayoutItemSpacing * 0.5f) / LayoutItemStep.x;
10642 const float hovered_item_ny = (io.MousePos.y - start_pos.y + LayoutItemSpacing * 0.5f) / LayoutItemStep.y;
10643 const int hovered_item_idx = ((int)hovered_item_ny * LayoutColumnCount) + (int)hovered_item_nx;
10644 //ImGui::SetTooltip("%f,%f -> item %d", hovered_item_nx, hovered_item_ny, hovered_item_idx); // Move those 4 lines in block above for easy debugging
10645
10646 // Zoom
10647 IconSize *= powf(1.1f, (float)(int)ZoomWheelAccum);
10648 IconSize = IM_CLAMP(IconSize, 16.0f, 128.0f);
10650 UpdateLayoutSizes(avail_width);
10651
10652 // Manipulate scroll to that we will land at the same Y location of currently hovered item.
10653 // - Calculate next frame position of item under mouse
10654 // - Set new scroll position to be used in next ImGui::BeginChild() call.
10655 float hovered_item_rel_pos_y = ((float)(hovered_item_idx / LayoutColumnCount) + fmodf(hovered_item_ny, 1.0f)) * LayoutItemStep.y;
10656 hovered_item_rel_pos_y += ImGui::GetStyle().WindowPadding.y;
10657 float mouse_local_y = io.MousePos.y - ImGui::GetWindowPos().y;
10658 ImGui::SetScrollY(hovered_item_rel_pos_y - mouse_local_y);
10659 }
10660 }
10661 }
10662 ImGui::EndChild();
10663
10664 ImGui::Text("Selected: %d/%d items", Selection.Size, Items.Size);
10665 ImGui::End();
10666 }
10667};
10668
10669void ShowExampleAppAssetsBrowser(bool* p_open)
10670{
10671 IMGUI_DEMO_MARKER("Examples/Assets Browser");
10672 static ExampleAssetsBrowser assets_browser;
10673 assets_browser.Draw("Example: Assets Browser", p_open);
10674}
10675
10676// End of Demo code
10677#else
10678
10679void ImGui::ShowAboutWindow(bool*) {}
10680void ImGui::ShowDemoWindow(bool*) {}
10681void ImGui::ShowUserGuide() {}
10682void ImGui::ShowStyleEditor(ImGuiStyle*) {}
10683
10684#endif
10685
10686#endif // #ifndef IMGUI_DISABLE
uintptr_t id
imat3 i3(ivec3(1, 2, 3), ivec3(4, 5, 6), ivec3(7, 8, 9))
#define IM_NEWLINE
#define IM_CLAMP(V, MN, MX)
#define IMGUI_CDECL
void * GImGuiDemoMarkerCallbackUserData
#define IM_MAX(A, B)
ImGuiDemoMarkerCallback GImGuiDemoMarkerCallback
#define PRIu64
void(* ImGuiDemoMarkerCallback)(const char *file, int line, const char *section, void *user_data)
#define PRId64
#define IM_MIN(A, B)
#define IMGUI_DEMO_MARKER(section)
IMGUI_API void ShowFontAtlas(ImFontAtlas *atlas)
Definition imgui.cc:20981
auto CalcTextSize(std::string_view str)
Definition ImGuiUtils.hh:39
void TextUnformatted(const std::string &str)
Definition ImGuiUtils.hh:26
constexpr double e
Definition Math.hh:21
constexpr double log(double x)
Definition cstd.hh:208
void ID(const char *str_id, std::invocable<> auto next)
Definition ImGuiCpp.hh:244
void Tooltip(std::invocable<> auto next)
Definition ImGuiCpp.hh:374
uint16_t word
16 bit unsigned integer
Definition openmsx.hh:29
size_t size(std::string_view utf8)
auto filter(ForwardRange &&range, Predicate pred)
Definition view.hh:538
constexpr auto values(Map &&map)
Definition view.hh:531
void Draw(const char *title, bool *p_open)
int TextEditCallback(ImGuiInputTextCallbackData *data)
ImVector< char * > History
ImVector< const char * > Commands
static int TextEditCallbackStub(ImGuiInputTextCallbackData *data)
static void Strtrim(char *s)
static int Stricmp(const char *s1, const char *s2)
ImGuiTextFilter Filter
void AddLog(const char *fmt,...) IM_FMTARGS(2)
static int Strnicmp(const char *s1, const char *s2, int n)
void ExecCommand(const char *command_line)
static char * Strdup(const char *s)
ImVector< char * > Items
void NotifyOfDocumentsClosedElsewhere()
void DisplayDocContents(MyDocument *doc)
void DisplayDocContextMenu(MyDocument *doc)
MyDocument * RenamingDoc
ImVector< MyDocument > Documents
void GetTabName(MyDocument *doc, char *out_buf, size_t out_buf_size)
ImVector< MyDocument * > CloseQueue
ImGuiTextFilter Filter
void Draw(const char *title, bool *p_open=NULL)
ImGuiTextBuffer Buf
ImVector< int > LineOffsets
void AddLog(const char *fmt,...) IM_FMTARGS(2)
ExampleTreeNode * VisibleNode
void DrawTreeNode(ExampleTreeNode *node)
void Draw(ExampleTreeNode *root_node)
ExampleAsset(ImGuiID id, int type)
static void SortWithSortSpecs(ImGuiTableSortSpecs *sort_specs, ExampleAsset *items, int items_count)
static int IMGUI_CDECL CompareWithSortSpecs(const void *lhs, const void *rhs)
static const ImGuiTableSortSpecs * s_current_sort_specs
void Draw(const char *title, bool *p_open)
void UpdateLayoutSizes(float avail_width)
void AddItems(int count)
ImVector< ExampleAsset > Items
ExampleSelectionWithDeletion Selection
ImVector< ImGuiID > Items[2]
static int IMGUI_CDECL CompareItemsByValue(const void *lhs, const void *rhs)
void SortItems(int n)
void MoveSelected(int src, int dst)
void ApplySelectionRequests(ImGuiMultiSelectIO *ms_io, int side)
void MoveAll(int src, int dst)
ImGuiSelectionBasicStorage Selections[2]
const char * Name
ImGuiDataType DataType
int ApplyDeletionPreLoop(ImGuiMultiSelectIO *ms_io, int items_count)
void ApplyDeletionPostLoop(ImGuiMultiSelectIO *ms_io, ImVector< ITEM_TYPE > &items, int item_curr_idx_to_select)
ExampleTreeNode * Parent
unsigned short IndexInParent
ImVector< ExampleTreeNode * > Childs
ExampleTreeNode * DemoTree
void DoOpen()
void DoSave()
void DoForceClose()
MyDocument(int uid, const char *name, bool open=true, const ImVec4 &color=ImVec4(1.0f, 1.0f, 1.0f, 1.0f))
char Name[32]
constexpr auto begin(const zstring_view &x)
constexpr auto end(const zstring_view &x)