OXYGENHUB
◆ main openmsx / src / 3rdparty / imgui / imgui_demo.cc
596.3 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
// dear imgui, v1.92.9 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 pthom's online imgui_explorer: web version the demo w/ source code browser: https://pthom.github.io/imgui_explorer
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
69
Index of this file:
70
71
// [SECTION] Forward Declarations
72
// [SECTION] Helpers
73
// [SECTION] Demo Window / ShowDemoWindow()
74
// [SECTION] DemoWindowMenuBar()
75
// [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor & Multi-Select demos)
76
// [SECTION] Helpers: ExampleImageViewer
77
// [SECTION] DemoWindowWidgetsBasic()
78
// [SECTION] DemoWindowWidgetsBullets()
79
// [SECTION] DemoWindowWidgetsCollapsingHeaders()
80
// [SECTION] DemoWindowWidgetsComboBoxes()
81
// [SECTION] DemoWindowWidgetsColorAndPickers()
82
// [SECTION] DemoWindowWidgetsDataTypes()
83
// [SECTION] DemoWindowWidgetsDisableBlocks()
84
// [SECTION] DemoWindowWidgetsDragAndDrop()
85
// [SECTION] DemoWindowWidgetsDragsAndSliders()
86
// [SECTION] DemoWindowWidgetsFonts()
87
// [SECTION] DemoWindowWidgetsImages()
88
// [SECTION] DemoWindowWidgetsListBoxes()
89
// [SECTION] DemoWindowWidgetsMultiComponents()
90
// [SECTION] DemoWindowWidgetsPlotting()
91
// [SECTION] DemoWindowWidgetsProgressBars()
92
// [SECTION] DemoWindowWidgetsQueryingStatuses()
93
// [SECTION] DemoWindowWidgetsSelectables()
94
// [SECTION] DemoWindowWidgetsSelectionAndMultiSelect()
95
// [SECTION] DemoWindowWidgetsTabs()
96
// [SECTION] DemoWindowWidgetsText()
97
// [SECTION] DemoWindowWidgetsTextFilter()
98
// [SECTION] DemoWindowWidgetsTextInput()
99
// [SECTION] DemoWindowWidgetsTooltips()
100
// [SECTION] DemoWindowWidgetsTreeNodes()
101
// [SECTION] DemoWindowWidgetsVerticalSliders()
102
// [SECTION] DemoWindowWidgets()
103
// [SECTION] DemoWindowLayout()
104
// [SECTION] DemoWindowPopups()
105
// [SECTION] DemoWindowTables()
106
// [SECTION] DemoWindowInputs()
107
// [SECTION] About Window / ShowAboutWindow()
108
// [SECTION] Style Editor / ShowStyleEditor()
109
// [SECTION] User Guide / ShowUserGuide()
110
// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar()
111
// [SECTION] Example App: Debug Console / ShowExampleAppConsole()
112
// [SECTION] Example App: Image Viewer / ShowExampleAppImageViewer()
113
// [SECTION] Example App: Debug Log / ShowExampleAppLog()
114
// [SECTION] Example App: Simple Layout / ShowExampleAppLayout()
115
// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor()
116
// [SECTION] Example App: Long Text / ShowExampleAppLongText()
117
// [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize()
118
// [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize()
119
// [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay()
120
// [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen()
121
// [SECTION] Example App: Manipulating window titles / ShowExampleAppWindowTitles()
122
// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering()
123
// [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace()
124
// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
125
// [SECTION] Example App: Assets Browser / ShowExampleAppAssetsBrowser()
126
127
*/
128
129
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
130
#define _CRT_SECURE_NO_WARNINGS
131
#endif
132
133
#include "imgui.h"
134
#ifndef IMGUI_DISABLE
135
136
// System includes
137
#include <ctype.h>          // toupper
138
#include <limits.h>         // INT_MIN, INT_MAX
139
#include <math.h>           // sqrtf, powf, cosf, sinf, floorf, ceilf
140
#include <stdio.h>          // vsnprintf, sscanf, printf
141
#include <stdlib.h>         // NULL, malloc, free, atoi
142
#include <stdint.h>         // intptr_t
143
#if !defined(_MSC_VER) || _MSC_VER >= 1800
144
#include <inttypes.h>       // PRId64/PRIu64, not avail in some MinGW headers.
145
#endif
146
#ifdef __EMSCRIPTEN__
147
#include <emscripten/version.h>     // __EMSCRIPTEN_MAJOR__ etc.
148
#endif
149
150
// Visual Studio warnings
151
#ifdef _MSC_VER
152
#pragma warning (disable: 4127)     // condition expression is constant
153
#pragma warning (disable: 4996)     // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
154
#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).
155
#endif
156
157
// Clang/GCC warnings with -Weverything
158
#if defined(__clang__)
159
#if __has_warning("-Wunknown-warning-option")
160
#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!
161
#endif
162
#pragma clang diagnostic ignored "-Wunknown-pragmas"                // warning: unknown warning group 'xxx'
163
#pragma clang diagnostic ignored "-Wold-style-cast"                 // warning: use of old-style cast                           // yes, they are more terse.
164
#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)
165
#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast"       // warning: cast to 'void *' from smaller integer type
166
#pragma clang diagnostic ignored "-Wformat"                         // warning: format specifies type 'int' but the argument has type 'unsigned int'
167
#pragma clang diagnostic ignored "-Wformat-security"                // warning: format string is not a string literal
168
#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.
169
#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.
170
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"  // warning: zero as null pointer constant                   // some standard header variations use #define NULL 0
171
#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.
172
#pragma clang diagnostic ignored "-Wreserved-id-macro"              // warning: macro name is a reserved identifier
173
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"  // warning: implicit conversion from 'xxx' to 'float' may lose precision
174
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"            // warning: 'xxx' is an unsafe pointer used for buffer access
175
#pragma clang diagnostic ignored "-Wswitch-default"                 // warning: 'switch' missing 'default' label
176
#elif defined(__GNUC__)
177
#pragma GCC diagnostic ignored "-Wpragmas"                          // warning: unknown option after '#pragma GCC diagnostic' kind
178
#pragma GCC diagnostic ignored "-Wfloat-equal"                      // warning: comparing floating-point with '==' or '!=' is unsafe
179
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"              // warning: cast to pointer from integer of different size
180
#pragma GCC diagnostic ignored "-Wformat"                           // warning: format '%p' expects argument of type 'int'/'void*', but argument X has type 'unsigned int'/'ImGuiWindow*'
181
#pragma GCC diagnostic ignored "-Wformat-security"                  // warning: format string is not a string literal (potentially insecure)
182
#pragma GCC diagnostic ignored "-Wdouble-promotion"                 // warning: implicit conversion from 'float' to 'double' when passing argument to function
183
#pragma GCC diagnostic ignored "-Wconversion"                       // warning: conversion to 'xxxx' from 'xxxx' may alter its value
184
#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.
185
#pragma GCC diagnostic ignored "-Wstrict-overflow"                  // warning: assuming signed overflow does not occur when simplifying division / ..when changing X +- C1 cmp C2 to X cmp C2 -+ C1
186
#pragma GCC diagnostic ignored "-Wcast-qual"                        // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers
187
#endif
188
189
// Play it nice with Windows users (Update: May 2018, Notepad now supports Unix-style carriage returns!)
190
#ifdef _WIN32
191
#define IM_NEWLINE  "\r\n"
192
#else
193
#define IM_NEWLINE  "\n"
194
#endif
195
196
// Helpers
197
#if defined(_MSC_VER) && !defined(snprintf)
198
#define snprintf    _snprintf
199
#endif
200
#if defined(_MSC_VER) && !defined(vsnprintf)
201
#define vsnprintf   _vsnprintf
202
#endif
203
204
// Format specifiers for 64-bit values (hasn't been decently standardized before VS2013)
205
#if !defined(PRId64) && defined(_MSC_VER)
206
#define PRId64 "I64d"
207
#define PRIu64 "I64u"
208
#elif !defined(PRId64)
209
#define PRId64 "lld"
210
#define PRIu64 "llu"
211
#endif
212
213
// Helpers macros
214
// We normally try to not use many helpers in imgui_demo.cpp in order to make code easier to copy and paste,
215
// but making an exception here as those are largely simplifying code...
216
// In other imgui sources we can use nicer internal functions from imgui_internal.h (ImMin/ImMax) but not in the demo.
217
#define IM_MIN(A, B)            (((A) < (B)) ? (A) : (B))
218
#define IM_MAX(A, B)            (((A) >= (B)) ? (A) : (B))
219
#define IM_CLAMP(V, MN, MX)     ((V) < (MN) ? (MN) : (V) > (MX) ? (MX) : (V))
220
221
// Enforce cdecl calling convention for functions called by the standard library,
222
// in case compilation settings changed the default to e.g. __vectorcall
223
#ifndef IMGUI_CDECL
224
#ifdef _MSC_VER
225
#define IMGUI_CDECL __cdecl
226
#else
227
#define IMGUI_CDECL
228
#endif
229
#endif
230
231
//-----------------------------------------------------------------------------
232
// [SECTION] Forward Declarations
233
//-----------------------------------------------------------------------------
234
235
#if !defined(IMGUI_DISABLE_DEMO_WINDOWS)
236
237
// Forward Declarations
238
struct ImGuiDemoWindowData;
239
static void ShowExampleAppMainMenuBar();
240
static void ShowExampleAppAssetsBrowser(bool* p_open);
241
static void ShowExampleAppConsole(bool* p_open);
242
static void ShowExampleAppCustomRendering(bool* p_open);
243
static void ShowExampleAppDockSpace(bool* p_open);
244
static void ShowExampleAppDocuments(bool* p_open);
245
static void ShowExampleAppImageViewer(bool* p_open);
246
static void ShowExampleAppLog(bool* p_open);
247
static void ShowExampleAppLayout(bool* p_open);
248
static void ShowExampleAppPropertyEditor(bool* p_open, ImGuiDemoWindowData* demo_data);
249
static void ShowExampleAppSimpleOverlay(bool* p_open);
250
static void ShowExampleAppAutoResize(bool* p_open);
251
static void ShowExampleAppConstrainedResize(bool* p_open);
252
static void ShowExampleAppFullscreen(bool* p_open);
253
static void ShowExampleAppLongText(bool* p_open);
254
static void ShowExampleAppWindowTitles(bool* p_open);
255
static void ShowExampleMenuFile();
256
257
// We split the contents of the big ShowDemoWindow() function into smaller functions
258
// (because the link time of very large functions tends to grow non-linearly)
259
static void DemoWindowMenuBar(ImGuiDemoWindowData* demo_data);
260
static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data);
261
static void DemoWindowLayout();
262
static void DemoWindowPopups();
263
static void DemoWindowTables();
264
static void DemoWindowColumns();
265
static void DemoWindowInputs();
266
267
// Helper tree functions used by Property Editor & Multi-Select demos
268
struct ExampleTreeNode;
269
static ExampleTreeNode* ExampleTree_CreateNode(const char* name, int uid, ExampleTreeNode* parent);
270
static void             ExampleTree_DestroyNode(ExampleTreeNode* node);
271
272
//-----------------------------------------------------------------------------
273
// [SECTION] Helpers
274
//-----------------------------------------------------------------------------
275
276
// Helper to display a little (?) mark which shows a tooltip when hovered.
277
// In your own code you may want to display an actual icon if you are using a merged icon fonts (see docs/FONTS.md)
278
static void HelpMarker(const char* desc)
279
{
280
    ImGui::TextDisabled("(?)");
281
    if (ImGui::BeginItemTooltip())
282
    {
283
        ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
284
        ImGui::TextUnformatted(desc);
285
        ImGui::PopTextWrapPos();
286
        ImGui::EndTooltip();
287
    }
288
}
289
290
static void ShowDockingDisabledMessage()
291
{
292
    ImGuiIO& io = ImGui::GetIO();
293
    ImGui::Text("ERROR: Docking is not enabled! See Demo > Configuration.");
294
    ImGui::Text("Set io.ConfigFlags |= ImGuiConfigFlags_DockingEnable in your code, or ");
295
    ImGui::SameLine(0.0f, 0.0f);
296
    if (ImGui::SmallButton("click here"))
297
        io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
298
}
299
300
// Helper to wire demo markers located in code to an interactive browser (e.g. https://pthom.github.io/imgui_explorer)
301
#if IMGUI_VERSION_NUM >= 19263
302
namespace ImGui { extern IMGUI_API void DemoMarker(const char* file, int line, const char* section); }
303
#define IMGUI_DEMO_MARKER(section)  do { ImGui::DemoMarker("imgui_demo.cpp", __LINE__, section); } while (0)
304
#endif
305
306
// Sneakily forward declare functions which aren't worth putting in public API yet
307
namespace ImGui
308
{
309
    IMGUI_API void ShowFontAtlas(ImFontAtlas* atlas);
310
    IMGUI_API void TreeNodeSetOpen(ImGuiID storage_id, bool is_open);
311
}
312
313
//-----------------------------------------------------------------------------
314
// [SECTION] Demo Window / ShowDemoWindow()
315
//-----------------------------------------------------------------------------
316
317
// Data to be shared across different functions of the demo.
318
struct ImGuiDemoWindowData
319
{
320
    // Examples Apps (accessible from the "Examples" menu)
321
    bool ShowMainMenuBar = false;
322
    bool ShowAppAssetsBrowser = false;
323
    bool ShowAppConsole = false;
324
    bool ShowAppCustomRendering = false;
325
    bool ShowAppDocuments = false;
326
    bool ShowAppDockSpace = false;
327
    bool ShowAppImageViewer = false;
328
    bool ShowAppLog = false;
329
    bool ShowAppLayout = false;
330
    bool ShowAppPropertyEditor = false;
331
    bool ShowAppSimpleOverlay = false;
332
    bool ShowAppAutoResize = false;
333
    bool ShowAppConstrainedResize = false;
334
    bool ShowAppFullscreen = false;
335
    bool ShowAppLongText = false;
336
    bool ShowAppWindowTitles = false;
337
338
    // Dear ImGui Tools (accessible from the "Tools" menu)
339
    bool ShowMetrics = false;
340
    bool ShowDebugLog = false;
341
    bool ShowIDStackTool = false;
342
    bool ShowStyleEditor = false;
343
    bool ShowAbout = false;
344
345
    // Other data
346
    bool DisableSections = false;
347
    ExampleTreeNode* DemoTree = NULL;
348
349
    ~ImGuiDemoWindowData() { if (DemoTree) ExampleTree_DestroyNode(DemoTree); }
350
};
351
352
// Demonstrate most Dear ImGui features (this is big function!)
353
// You may execute this function to experiment with the UI and understand what it does.
354
// You may then search for keywords in the code when you are interested by a specific feature.
355
void ImGui::ShowDemoWindow(bool* p_open)
356
{
357
    // Exceptionally add an extra assert here for people confused about initial Dear ImGui setup
358
    // Most functions would normally just assert/crash if the context is missing.
359
    IM_ASSERT(ImGui::GetCurrentContext() != NULL && "Missing Dear ImGui context. Refer to examples app!");
360
361
    // Verify ABI compatibility between caller code and compiled version of Dear ImGui. This helps detects some build issues.
362
    IMGUI_CHECKVERSION();
363
364
    // Stored data
365
    static ImGuiDemoWindowData demo_data;
366
367
    // Examples Apps (accessible from the "Examples" menu)
368
    if (demo_data.ShowMainMenuBar)          { ShowExampleAppMainMenuBar(); }
369
    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)
370
    if (demo_data.ShowAppDocuments)         { ShowExampleAppDocuments(&demo_data.ShowAppDocuments); } // ...process the Document app next, as it may also use a DockSpace()
371
    if (demo_data.ShowAppAssetsBrowser)     { ShowExampleAppAssetsBrowser(&demo_data.ShowAppAssetsBrowser); }
372
    if (demo_data.ShowAppConsole)           { ShowExampleAppConsole(&demo_data.ShowAppConsole); }
373
    if (demo_data.ShowAppCustomRendering)   { ShowExampleAppCustomRendering(&demo_data.ShowAppCustomRendering); }
374
    if (demo_data.ShowAppImageViewer)       { ShowExampleAppImageViewer(&demo_data.ShowAppImageViewer); }
375
    if (demo_data.ShowAppLog)               { ShowExampleAppLog(&demo_data.ShowAppLog); }
376
    if (demo_data.ShowAppLayout)            { ShowExampleAppLayout(&demo_data.ShowAppLayout); }
377
    if (demo_data.ShowAppPropertyEditor)    { ShowExampleAppPropertyEditor(&demo_data.ShowAppPropertyEditor, &demo_data); }
378
    if (demo_data.ShowAppSimpleOverlay)     { ShowExampleAppSimpleOverlay(&demo_data.ShowAppSimpleOverlay); }
379
    if (demo_data.ShowAppAutoResize)        { ShowExampleAppAutoResize(&demo_data.ShowAppAutoResize); }
380
    if (demo_data.ShowAppConstrainedResize) { ShowExampleAppConstrainedResize(&demo_data.ShowAppConstrainedResize); }
381
    if (demo_data.ShowAppFullscreen)        { ShowExampleAppFullscreen(&demo_data.ShowAppFullscreen); }
382
    if (demo_data.ShowAppLongText)          { ShowExampleAppLongText(&demo_data.ShowAppLongText); }
383
    if (demo_data.ShowAppWindowTitles)      { ShowExampleAppWindowTitles(&demo_data.ShowAppWindowTitles); }
384
385
    // Dear ImGui Tools (accessible from the "Tools" menu)
386
    if (demo_data.ShowMetrics)              { ImGui::ShowMetricsWindow(&demo_data.ShowMetrics); }
387
    if (demo_data.ShowDebugLog)             { ImGui::ShowDebugLogWindow(&demo_data.ShowDebugLog); }
388
    if (demo_data.ShowIDStackTool)          { ImGui::ShowIDStackToolWindow(&demo_data.ShowIDStackTool); }
389
    if (demo_data.ShowAbout)                { ImGui::ShowAboutWindow(&demo_data.ShowAbout); }
390
    if (demo_data.ShowStyleEditor)
391
    {
392
        ImGui::Begin("Dear ImGui Style Editor", &demo_data.ShowStyleEditor);
393
        ImGui::ShowStyleEditor();
394
        ImGui::End();
395
    }
396
397
    // Demonstrate the various window flags. Typically you would just use the default!
398
    static bool no_titlebar = false;
399
    static bool no_scrollbar = false;
400
    static bool no_menu = false;
401
    static bool no_move = false;
402
    static bool no_resize = false;
403
    static bool no_collapse = false;
404
    static bool no_close = false;
405
    static bool no_nav = false;
406
    static bool no_background = false;
407
    static bool no_bring_to_front = false;
408
    static bool no_docking = false;
409
    static bool unsaved_document = false;
410
411
    ImGuiWindowFlags window_flags = 0;
412
    if (no_titlebar)        window_flags |= ImGuiWindowFlags_NoTitleBar;
413
    if (no_scrollbar)       window_flags |= ImGuiWindowFlags_NoScrollbar;
414
    if (!no_menu)           window_flags |= ImGuiWindowFlags_MenuBar;
415
    if (no_move)            window_flags |= ImGuiWindowFlags_NoMove;
416
    if (no_resize)          window_flags |= ImGuiWindowFlags_NoResize;
417
    if (no_collapse)        window_flags |= ImGuiWindowFlags_NoCollapse;
418
    if (no_nav)             window_flags |= ImGuiWindowFlags_NoNav;
419
    if (no_background)      window_flags |= ImGuiWindowFlags_NoBackground;
420
    if (no_bring_to_front)  window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus;
421
    if (no_docking)         window_flags |= ImGuiWindowFlags_NoDocking;
422
    if (unsaved_document)   window_flags |= ImGuiWindowFlags_UnsavedDocument;
423
    if (no_close)           p_open = NULL; // Don't pass our bool* to Begin
424
425
    // We specify a default position/size in case there's no data in the .ini file.
426
    // We only do it to make the demo applications a little more welcoming, but typically this isn't required.
427
    const ImGuiViewport* main_viewport = ImGui::GetMainViewport();
428
    ImGui::SetNextWindowPos(ImVec2(main_viewport->WorkPos.x + 650, main_viewport->WorkPos.y + 20), ImGuiCond_FirstUseEver);
429
    ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver);
430
431
    // Main body of the Demo window starts here.
432
    if (!ImGui::Begin("Dear ImGui Demo", p_open, window_flags))
433
    {
434
        // Early out if the window is collapsed, as an optimization.
435
        ImGui::End();
436
        return;
437
    }
438
439
    // Most framed widgets share a common width settings. Remaining width is used for the label.
440
    // The width of the frame may be changed with PushItemWidth() or SetNextItemWidth().
441
    // - Positive value for absolute size, negative value for right-alignment.
442
    // - The default value is about GetWindowWidth() * 0.65f.
443
    // - See 'Demo->Layout->Widgets Width' for details.
444
    // Here we change the frame width based on how much width we want to give to the label.
445
    const float label_width_base = ImGui::GetFontSize() * 12;               // Some amount of width for label, based on font size.
446
    const float label_width_max = ImGui::GetContentRegionAvail().x * 0.40f; // ...but always leave some room for framed widgets.
447
    const float label_width = IM_MIN(label_width_base, label_width_max);
448
    ImGui::PushItemWidth(-label_width);                                     // Right-align: framed items will leave 'label_width' available for the label.
449
    //ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * 0.40f);       // e.g. Use 40% width for framed widgets, leaving 60% width for labels.
450
    //ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.40f);      // e.g. Use 40% width for labels, leaving 60% width for framed widgets.
451
    //ImGui::PushItemWidth(ImGui::GetFontSize() * -12);                     // e.g. Use XXX width for labels, leaving the rest for framed widgets.
452
453
    // Menu Bar
454
    DemoWindowMenuBar(&demo_data);
455
456
    ImGui::Text("dear imgui says hello! (%s) (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
457
    ImGui::Spacing();
458
459
    if (ImGui::CollapsingHeader("Help"))
460
    {
461
        IMGUI_DEMO_MARKER("Help");
462
        ImGui::SeparatorText("ABOUT THIS DEMO:");
463
        ImGui::BulletText("Sections below are demonstrating many aspects of the library.");
464
        ImGui::BulletText("The \"Examples\" menu above leads to more demo contents.");
465
        ImGui::BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n"
466
                          "and Metrics/Debugger (general purpose Dear ImGui debugging tool).");
467
        ImGui::BulletText("Web demo (w/ source code browser): ");
468
        ImGui::SameLine(0, 0);
469
        ImGui::TextLinkOpenURL("https://pthom.github.io/imgui_explorer");
470
471
        ImGui::SeparatorText("PROGRAMMER GUIDE:");
472
        ImGui::BulletText("See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!");
473
        ImGui::BulletText("See comments in imgui.cpp.");
474
        ImGui::BulletText("See example applications in the examples/ folder.");
475
        ImGui::BulletText("Read the FAQ at ");
476
        ImGui::SameLine(0, 0);
477
        ImGui::TextLinkOpenURL("https://www.dearimgui.com/faq/");
478
        ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls.");
479
        ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls.");
480
481
        ImGui::SeparatorText("USER GUIDE:");
482
        ImGui::ShowUserGuide();
483
    }
484
485
    if (ImGui::CollapsingHeader("Configuration"))
486
    {
487
        ImGuiIO& io = ImGui::GetIO();
488
489
        if (ImGui::TreeNode("Configuration##2"))
490
        {
491
            IMGUI_DEMO_MARKER("Configuration");
492
            ImGui::SeparatorText("General");
493
            ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard",    &io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard);
494
            ImGui::SameLine(); HelpMarker("Enable keyboard controls.");
495
            ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad",     &io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad);
496
            ImGui::SameLine(); HelpMarker("Enable gamepad controls. Require backend to set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details.");
497
            ImGui::CheckboxFlags("io.ConfigFlags: NoMouse",              &io.ConfigFlags, ImGuiConfigFlags_NoMouse);
498
            ImGui::SameLine(); HelpMarker("Instruct dear imgui to disable mouse inputs and interactions.");
499
500
            // The "NoMouse" option can get us stuck with a disabled mouse! Let's provide an alternative way to fix it:
501
            if (io.ConfigFlags & ImGuiConfigFlags_NoMouse)
502
            {
503
                if (fmodf((float)ImGui::GetTime(), 0.40f) < 0.20f)
504
                {
505
                    ImGui::SameLine();
506
                    ImGui::Text("<<PRESS SPACE TO DISABLE>>");
507
                }
508
                // Prevent both being checked
509
                if (ImGui::IsKeyPressed(ImGuiKey_Space) || (io.ConfigFlags & ImGuiConfigFlags_NoKeyboard))
510
                    io.ConfigFlags &= ~ImGuiConfigFlags_NoMouse;
511
            }
512
513
            ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange",  &io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange);
514
            ImGui::SameLine(); HelpMarker("Instruct backend to not alter mouse cursor shape and visibility.");
515
            ImGui::CheckboxFlags("io.ConfigFlags: NoKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NoKeyboard);
516
            ImGui::SameLine(); HelpMarker("Instruct dear imgui to disable keyboard inputs and interactions.");
517
518
            ImGui::Checkbox("io.ConfigInputTrickleEventQueue", &io.ConfigInputTrickleEventQueue);
519
            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.");
520
            ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor);
521
            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).");
522
523
            ImGui::SeparatorText("Keyboard/Gamepad Navigation");
524
            ImGui::Checkbox("io.ConfigNavSwapGamepadButtons", &io.ConfigNavSwapGamepadButtons);
525
            ImGui::Checkbox("io.ConfigNavMoveSetMousePos", &io.ConfigNavMoveSetMousePos);
526
            ImGui::SameLine(); HelpMarker("Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is difficult");
527
            ImGui::Checkbox("io.ConfigNavCaptureKeyboard", &io.ConfigNavCaptureKeyboard);
528
            ImGui::Checkbox("io.ConfigNavEscapeClearFocusItem", &io.ConfigNavEscapeClearFocusItem);
529
            ImGui::SameLine(); HelpMarker("Pressing Escape clears focused item.");
530
            ImGui::Checkbox("io.ConfigNavEscapeClearFocusWindow", &io.ConfigNavEscapeClearFocusWindow);
531
            ImGui::SameLine(); HelpMarker("Pressing Escape clears focused window.");
532
            ImGui::Checkbox("io.ConfigNavCursorVisibleAuto", &io.ConfigNavCursorVisibleAuto);
533
            ImGui::SameLine(); HelpMarker("Using directional navigation key makes the cursor visible. Mouse click hides the cursor.");
534
            ImGui::Checkbox("io.ConfigNavCursorVisibleAlways", &io.ConfigNavCursorVisibleAlways);
535
            ImGui::SameLine(); HelpMarker("Navigation cursor is always visible.");
536
537
            ImGui::SeparatorText("Docking");
538
            ImGui::CheckboxFlags("io.ConfigFlags: DockingEnable", &io.ConfigFlags, ImGuiConfigFlags_DockingEnable);
539
            ImGui::SameLine();
540
            if (io.ConfigDockingWithShift)
541
                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).");
542
            else
543
                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).");
544
            if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
545
            {
546
                ImGui::Indent();
547
                ImGui::Checkbox("io.ConfigDockingNoSplit", &io.ConfigDockingNoSplit);
548
                ImGui::SameLine(); HelpMarker("Simplified docking mode: disable window splitting, so docking is limited to merging multiple windows together into tab-bars.");
549
                ImGui::Checkbox("io.ConfigDockingNoDockingOver", &io.ConfigDockingNoDockingOver);
550
                ImGui::SameLine(); HelpMarker("Simplified docking mode: disable window merging into a same tab-bar, so docking is limited to splitting windows.");
551
                ImGui::Checkbox("io.ConfigDockingWithShift", &io.ConfigDockingWithShift);
552
                ImGui::SameLine(); HelpMarker("Enable docking when holding Shift only (allow to drop in wider space, reduce visual noise)");
553
                ImGui::Checkbox("io.ConfigDockingAlwaysTabBar", &io.ConfigDockingAlwaysTabBar);
554
                ImGui::SameLine(); HelpMarker("Create a docking node and tab-bar on single floating windows.");
555
                ImGui::Checkbox("io.ConfigDockingTransparentPayload", &io.ConfigDockingTransparentPayload);
556
                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.");
557
                ImGui::Unindent();
558
            }
559
560
            ImGui::SeparatorText("Multi-viewports");
561
            ImGui::CheckboxFlags("io.ConfigFlags: ViewportsEnable", &io.ConfigFlags, ImGuiConfigFlags_ViewportsEnable);
562
            ImGui::SameLine(); HelpMarker("[beta] Enable beta multi-viewports support. See ImGuiPlatformIO for details.");
563
            if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
564
            {
565
                ImGui::Indent();
566
                ImGui::Checkbox("io.ConfigViewportsNoAutoMerge", &io.ConfigViewportsNoAutoMerge);
567
                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.");
568
                ImGui::Checkbox("io.ConfigViewportsNoTaskBarIcon", &io.ConfigViewportsNoTaskBarIcon);
569
                ImGui::SameLine(); HelpMarker("(note: some platform backends may not reflect a change of this value for existing viewports, and may need the viewport to be recreated)");
570
                ImGui::Checkbox("io.ConfigViewportsNoDecoration", &io.ConfigViewportsNoDecoration);
571
                ImGui::SameLine(); HelpMarker("(note: some platform backends may not reflect a change of this value for existing viewports, and may need the viewport to be recreated)");
572
                ImGui::Checkbox("io.ConfigViewportsNoDefaultParent", &io.ConfigViewportsNoDefaultParent);
573
                ImGui::SameLine(); HelpMarker("(note: some platform backends may not reflect a change of this value for existing viewports, and may need the viewport to be recreated)");
574
                ImGui::Checkbox("io.ConfigViewportsPlatformFocusSetsImGuiFocus", &io.ConfigViewportsPlatformFocusSetsImGuiFocus);
575
                ImGui::SameLine(); HelpMarker("When a platform window is focused (e.g. using Alt+Tab, clicking Platform Title Bar), apply corresponding focus on imgui windows (may clear focus/active id from imgui windows location in other platform windows). In principle this is better enabled but we provide an opt-out, because some Linux window managers tend to eagerly focus windows (e.g. on mouse hover, or even a simple window pos/size change).");
576
                ImGui::Unindent();
577
            }
578
579
            //ImGui::SeparatorText("DPI/Scaling");
580
            //ImGui::Checkbox("io.ConfigDpiScaleFonts", &io.ConfigDpiScaleFonts);
581
            //ImGui::SameLine(); HelpMarker("Experimental: Automatically update style.FontScaleDpi when Monitor DPI changes. This will scale fonts but NOT style sizes/padding for now.");
582
            //ImGui::Checkbox("io.ConfigDpiScaleViewports", &io.ConfigDpiScaleViewports);
583
            //ImGui::SameLine(); HelpMarker("Experimental: Scale Dear ImGui and Platform Windows when Monitor DPI changes.");
584
585
            ImGui::SeparatorText("Windows");
586
            ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges);
587
            ImGui::SameLine(); HelpMarker("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback.");
588
            ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly);
589
            ImGui::Checkbox("io.ConfigWindowsCopyContentsWithCtrlC", &io.ConfigWindowsCopyContentsWithCtrlC); // [EXPERIMENTAL]
590
            ImGui::SameLine(); HelpMarker("*EXPERIMENTAL* Ctrl+C copy the contents of focused window into the clipboard.\n\nExperimental because:\n- (1) has known issues with nested Begin/End pairs.\n- (2) text output quality varies.\n- (3) text output is in submission order rather than spatial order.");
591
            ImGui::Checkbox("io.ConfigScrollbarScrollByPage", &io.ConfigScrollbarScrollByPage);
592
            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.");
593
594
            ImGui::SeparatorText("Widgets");
595
            ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink);
596
            ImGui::SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting).");
597
            ImGui::Checkbox("io.ConfigInputTextEnterKeepActive", &io.ConfigInputTextEnterKeepActive);
598
            ImGui::SameLine(); HelpMarker("Pressing Enter will reactivate item and select all text (single-line only).");
599
            ImGui::Checkbox("io.ConfigDragClickToInputText", &io.ConfigDragClickToInputText);
600
            ImGui::SameLine(); HelpMarker("Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving).");
601
            ImGui::Checkbox("io.ConfigMacOSXBehaviors", &io.ConfigMacOSXBehaviors);
602
            ImGui::SameLine(); HelpMarker("Swap Cmd<>Ctrl keys, enable various MacOS style behaviors.");
603
            ImGui::Text("Also see Style->Rendering for rendering options.");
604
605
            // Also read: https://github.com/ocornut/imgui/wiki/Error-Handling
606
            ImGui::SeparatorText("Error Handling");
607
608
            ImGui::Checkbox("io.ConfigErrorRecovery", &io.ConfigErrorRecovery);
609
            ImGui::SameLine(); HelpMarker(
610
                "Options to configure how we handle recoverable errors.\n"
611
                "- Error recovery is not perfect nor guaranteed! It is a feature to ease development.\n"
612
                "- You not are not supposed to rely on it in the course of a normal application run.\n"
613
                "- Possible usage: facilitate recovery from errors triggered from a scripting language or after specific exceptions handlers.\n"
614
                "- Always ensure that on programmers seat you have at minimum Asserts or Tooltips enabled when making direct imgui API call! "
615
                "Otherwise it would severely hinder your ability to catch and correct mistakes!");
616
            ImGui::Checkbox("io.ConfigErrorRecoveryEnableAssert", &io.ConfigErrorRecoveryEnableAssert);
617
            ImGui::Checkbox("io.ConfigErrorRecoveryEnableDebugLog", &io.ConfigErrorRecoveryEnableDebugLog);
618
            ImGui::Checkbox("io.ConfigErrorRecoveryEnableTooltip", &io.ConfigErrorRecoveryEnableTooltip);
619
            if (!io.ConfigErrorRecoveryEnableAssert && !io.ConfigErrorRecoveryEnableDebugLog && !io.ConfigErrorRecoveryEnableTooltip)
620
                io.ConfigErrorRecoveryEnableAssert = io.ConfigErrorRecoveryEnableDebugLog = io.ConfigErrorRecoveryEnableTooltip = true;
621
622
            // Also read: https://github.com/ocornut/imgui/wiki/Debug-Tools
623
            ImGui::SeparatorText("Debug");
624
            ImGui::Checkbox("io.ConfigDebugIsDebuggerPresent", &io.ConfigDebugIsDebuggerPresent);
625
            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.");
626
            ImGui::Checkbox("io.ConfigDebugHighlightIdConflicts", &io.ConfigDebugHighlightIdConflicts);
627
            ImGui::SameLine(); HelpMarker("Highlight and show an error message when multiple items have conflicting identifiers.");
628
            ImGui::BeginDisabled();
629
            ImGui::Checkbox("io.ConfigDebugBeginReturnValueOnce", &io.ConfigDebugBeginReturnValueOnce);
630
            ImGui::EndDisabled();
631
            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.");
632
            ImGui::Checkbox("io.ConfigDebugBeginReturnValueLoop", &io.ConfigDebugBeginReturnValueLoop);
633
            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.");
634
            ImGui::Checkbox("io.ConfigDebugIgnoreFocusLoss", &io.ConfigDebugIgnoreFocusLoss);
635
            ImGui::SameLine(); HelpMarker("Option to deactivate io.AddFocusEvent(false) handling. May facilitate interactions with a debugger when focus loss leads to clearing inputs data.");
636
            ImGui::Checkbox("io.ConfigDebugIniSettings", &io.ConfigDebugIniSettings);
637
            ImGui::SameLine(); HelpMarker("Option to save .ini data with extra comments (particularly helpful for Docking, but makes saving slower).");
638
639
            ImGui::TreePop();
640
            ImGui::Spacing();
641
        }
642
643
        if (ImGui::TreeNode("Backend Flags"))
644
        {
645
            IMGUI_DEMO_MARKER("Configuration/Backend Flags");
646
            HelpMarker(
647
                "Those flags are set by the backends (imgui_impl_xxx files) to specify their capabilities.\n"
648
                "Here we expose them as read-only fields to avoid breaking interactions with your backend.");
649
650
            // Make a local copy to avoid modifying actual backend flags.
651
            // FIXME: Maybe we need a BeginReadonly() equivalent to keep label bright?
652
            ImGui::BeginDisabled();
653
            ImGui::CheckboxFlags("io.BackendFlags: HasGamepad",             &io.BackendFlags, ImGuiBackendFlags_HasGamepad);
654
            ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors",        &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors);
655
            ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos",         &io.BackendFlags, ImGuiBackendFlags_HasSetMousePos);
656
            ImGui::CheckboxFlags("io.BackendFlags: PlatformHasViewports",   &io.BackendFlags, ImGuiBackendFlags_PlatformHasViewports);
657
            ImGui::CheckboxFlags("io.BackendFlags: HasMouseHoveredViewport",&io.BackendFlags, ImGuiBackendFlags_HasMouseHoveredViewport);
658
            ImGui::CheckboxFlags("io.BackendFlags: HasParentViewport",      &io.BackendFlags, ImGuiBackendFlags_HasParentViewport);
659
            ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset",   &io.BackendFlags, ImGuiBackendFlags_RendererHasVtxOffset);
660
            ImGui::CheckboxFlags("io.BackendFlags: RendererHasTextures",    &io.BackendFlags, ImGuiBackendFlags_RendererHasTextures);
661
            ImGui::CheckboxFlags("io.BackendFlags: RendererHasViewports",   &io.BackendFlags, ImGuiBackendFlags_RendererHasViewports);
662
            ImGui::EndDisabled();
663
664
            ImGui::TreePop();
665
            ImGui::Spacing();
666
        }
667
668
        if (ImGui::TreeNode("Style, Fonts"))
669
        {
670
            IMGUI_DEMO_MARKER("Configuration/Style, Fonts");
671
            ImGui::Checkbox("Style Editor", &demo_data.ShowStyleEditor);
672
            ImGui::SameLine();
673
            HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function.");
674
            ImGui::TreePop();
675
            ImGui::Spacing();
676
        }
677
678
        if (ImGui::TreeNode("Capture/Logging"))
679
        {
680
            IMGUI_DEMO_MARKER("Configuration/Capture, Logging");
681
            HelpMarker(
682
                "The logging API redirects all text output so you can easily capture the content of "
683
                "a window or a block. Tree nodes can be automatically expanded.\n"
684
                "Try opening any of the contents below in this window and then click one of the \"Log To\" button.");
685
            ImGui::LogButtons();
686
687
            HelpMarker("You can also call ImGui::LogText() to output directly to the log without a visual output.");
688
            if (ImGui::Button("Copy \"Hello, world!\" to clipboard"))
689
            {
690
                ImGui::LogToClipboard();
691
                ImGui::LogText("Hello, world!");
692
                ImGui::LogFinish();
693
            }
694
            ImGui::TreePop();
695
        }
696
    }
697
698
    if (ImGui::CollapsingHeader("Window options"))
699
    {
700
        IMGUI_DEMO_MARKER("Window options");
701
        if (ImGui::BeginTable("split", 3))
702
        {
703
            ImGui::TableNextColumn(); ImGui::Checkbox("No titlebar", &no_titlebar);
704
            ImGui::TableNextColumn(); ImGui::Checkbox("No scrollbar", &no_scrollbar);
705
            ImGui::TableNextColumn(); ImGui::Checkbox("No menu", &no_menu);
706
            ImGui::TableNextColumn(); ImGui::Checkbox("No move", &no_move);
707
            ImGui::TableNextColumn(); ImGui::Checkbox("No resize", &no_resize);
708
            ImGui::TableNextColumn(); ImGui::Checkbox("No collapse", &no_collapse);
709
            ImGui::TableNextColumn(); ImGui::Checkbox("No close", &no_close);
710
            ImGui::TableNextColumn(); ImGui::Checkbox("No nav", &no_nav);
711
            ImGui::TableNextColumn(); ImGui::Checkbox("No background", &no_background);
712
            ImGui::TableNextColumn(); ImGui::Checkbox("No bring to front", &no_bring_to_front);
713
            ImGui::TableNextColumn(); ImGui::Checkbox("No docking", &no_docking);
714
            ImGui::TableNextColumn(); ImGui::Checkbox("Unsaved document", &unsaved_document);
715
            ImGui::EndTable();
716
        }
717
    }
718
719
    // All demo contents
720
    DemoWindowWidgets(&demo_data);
721
    DemoWindowLayout();
722
    DemoWindowPopups();
723
    DemoWindowTables();
724
    DemoWindowInputs();
725
726
    // End of ShowDemoWindow()
727
    ImGui::PopItemWidth();
728
    ImGui::End();
729
}
730
731
//-----------------------------------------------------------------------------
732
// [SECTION] DemoWindowMenuBar()
733
//-----------------------------------------------------------------------------
734
735
static void DemoWindowMenuBar(ImGuiDemoWindowData* demo_data)
736
{
737
    if (ImGui::BeginMenuBar())
738
    {
739
        if (ImGui::BeginMenu("Menu"))
740
        {
741
            IMGUI_DEMO_MARKER("Menu/File");
742
            ShowExampleMenuFile();
743
            ImGui::EndMenu();
744
        }
745
        if (ImGui::BeginMenu("Examples"))
746
        {
747
            IMGUI_DEMO_MARKER("Menu/Examples");
748
            ImGui::MenuItem("Main menu bar", NULL, &demo_data->ShowMainMenuBar);
749
750
            ImGui::SeparatorText("Mini apps");
751
            ImGui::MenuItem("Assets Browser", NULL, &demo_data->ShowAppAssetsBrowser);
752
            ImGui::MenuItem("Console", NULL, &demo_data->ShowAppConsole);
753
            ImGui::MenuItem("Custom rendering", NULL, &demo_data->ShowAppCustomRendering);
754
            ImGui::MenuItem("Documents", NULL, &demo_data->ShowAppDocuments);
755
            ImGui::MenuItem("Dockspace", NULL, &demo_data->ShowAppDockSpace);
756
            ImGui::MenuItem("Image Viewer", NULL, &demo_data->ShowAppImageViewer);
757
            ImGui::MenuItem("Log", NULL, &demo_data->ShowAppLog);
758
            ImGui::MenuItem("Property editor", NULL, &demo_data->ShowAppPropertyEditor);
759
            ImGui::MenuItem("Simple layout", NULL, &demo_data->ShowAppLayout);
760
            ImGui::MenuItem("Simple overlay", NULL, &demo_data->ShowAppSimpleOverlay);
761
762
            ImGui::SeparatorText("Concepts");
763
            ImGui::MenuItem("Auto-resizing window", NULL, &demo_data->ShowAppAutoResize);
764
            ImGui::MenuItem("Constrained-resizing window", NULL, &demo_data->ShowAppConstrainedResize);
765
            ImGui::MenuItem("Fullscreen window", NULL, &demo_data->ShowAppFullscreen);
766
            ImGui::MenuItem("Long text display", NULL, &demo_data->ShowAppLongText);
767
            ImGui::MenuItem("Manipulating window titles", NULL, &demo_data->ShowAppWindowTitles);
768
769
            ImGui::EndMenu();
770
        }
771
        //if (ImGui::MenuItem("MenuItem")) {} // You can also use MenuItem() inside a menu bar!
772
        if (ImGui::BeginMenu("Tools"))
773
        {
774
            IMGUI_DEMO_MARKER("Menu/Tools");
775
            ImGuiIO& io = ImGui::GetIO();
776
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
777
            const bool has_debug_tools = true;
778
#else
779
            const bool has_debug_tools = false;
780
#endif
781
            ImGui::MenuItem("Metrics/Debugger", NULL, &demo_data->ShowMetrics, has_debug_tools);
782
            if (ImGui::BeginMenu("Debug Options"))
783
            {
784
                ImGui::BeginDisabled(!has_debug_tools);
785
                ImGui::Checkbox("Highlight ID Conflicts", &io.ConfigDebugHighlightIdConflicts);
786
                ImGui::EndDisabled();
787
                ImGui::Checkbox("Assert on error recovery", &io.ConfigErrorRecoveryEnableAssert);
788
                ImGui::TextDisabled("(see Demo->Configuration for more)");
789
                ImGui::EndMenu();
790
            }
791
            ImGui::MenuItem("Debug Log", NULL, &demo_data->ShowDebugLog, has_debug_tools);
792
            ImGui::MenuItem("ID Stack Tool", NULL, &demo_data->ShowIDStackTool, has_debug_tools);
793
            bool is_debugger_present = io.ConfigDebugIsDebuggerPresent;
794
            if (ImGui::MenuItem("Item Picker", NULL, false, has_debug_tools))// && is_debugger_present))
795
                ImGui::DebugStartItemPicker();
796
            if (!is_debugger_present)
797
                ImGui::SetItemTooltip("Requires io.ConfigDebugIsDebuggerPresent=true to be set.\n\nWe otherwise disable some extra features to avoid casual users crashing the application.");
798
            ImGui::MenuItem("Style Editor", NULL, &demo_data->ShowStyleEditor);
799
            ImGui::MenuItem("About Dear ImGui", NULL, &demo_data->ShowAbout);
800
801
            ImGui::EndMenu();
802
        }
803
        ImGui::EndMenuBar();
804
    }
805
}
806
807
//-----------------------------------------------------------------------------
808
// [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor & Multi-Select demos)
809
//-----------------------------------------------------------------------------
810
811
// Simple representation for a tree
812
// (this is designed to be simple to understand for our demos, not to be fancy or efficient etc.)
813
struct ExampleTreeNode
814
{
815
    // Tree structure
816
    char                        Name[28] = "";
817
    int                         UID = 0;
818
    ExampleTreeNode*            Parent = NULL;
819
    ImVector<ExampleTreeNode*>  Childs;
820
    int                         IndexInParent = 0;  // Maintaining this allows us to implement linear traversal more easily
821
822
    // Leaf Data
823
    bool                        HasData = false;    // All leaves have data
824
    bool                        DataMyBool = true;
825
    int                         DataMyInt = 128;
826
    ImVec2                      DataMyVec2 = ImVec2(0.0f, 3.141592f);
827
};
828
829
// Simple representation of struct metadata/serialization data.
830
// (this is a minimal version of what a typical advanced application may provide)
831
struct ExampleMemberInfo
832
{
833
    const char*     Name;       // Member name
834
    ImGuiDataType   DataType;   // Member type
835
    int             DataCount;  // Member count (1 when scalar)
836
    int             Offset;     // Offset inside parent structure
837
};
838
839
// Metadata description of ExampleTreeNode struct.
840
static const ExampleMemberInfo ExampleTreeNodeMemberInfos[]
841
{
842
    { "MyName",     ImGuiDataType_String,  1, offsetof(ExampleTreeNode, Name) },
843
    { "MyBool",     ImGuiDataType_Bool,    1, offsetof(ExampleTreeNode, DataMyBool) },
844
    { "MyInt",      ImGuiDataType_S32,     1, offsetof(ExampleTreeNode, DataMyInt) },
845
    { "MyVec2",     ImGuiDataType_Float,   2, offsetof(ExampleTreeNode, DataMyVec2) },
846
};
847
848
static ExampleTreeNode* ExampleTree_CreateNode(const char* name, int uid, ExampleTreeNode* parent)
849
{
850
    ExampleTreeNode* node = IM_NEW(ExampleTreeNode);
851
    snprintf(node->Name, IM_COUNTOF(node->Name), "%s", name);
852
    node->UID = uid;
853
    node->Parent = parent;
854
    node->IndexInParent = parent ? parent->Childs.Size : 0;
855
    if (parent)
856
        parent->Childs.push_back(node);
857
    return node;
858
}
859
860
static void ExampleTree_DestroyNode(ExampleTreeNode* node)
861
{
862
    for (ExampleTreeNode* child_node : node->Childs)
863
        ExampleTree_DestroyNode(child_node);
864
    IM_DELETE(node);
865
}
866
867
// Create example tree data
868
// (warning: this can allocates MANY MANY more times than other code in all of Dear ImGui + demo combined)
869
// (a real application managing one million nodes would likely store its tree data differently)
870
static ExampleTreeNode* ExampleTree_CreateDemoTree()
871
{
872
    //     20 root nodes ->    211 total nodes,   ~261 allocs.
873
    //   1000 root nodes ->   ~11K total nodes,   ~14K allocs.
874
    //  10000 root nodes ->  ~123K total nodes,  ~154K allocs.
875
    // 100000 root nodes -> ~1338K total nodes, ~1666K allocs.
876
    const int ROOT_ITEMS_COUNT = 20;
877
878
    static const char* category_names[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pear", "Pineapple", "Strawberry", "Watermelon" };
879
    const int category_count = IM_COUNTOF(category_names);
880
    const size_t NAME_MAX_LEN = sizeof(ExampleTreeNode::Name);
881
    char name_buf[NAME_MAX_LEN];
882
    int uid = 0;
883
    ExampleTreeNode* node_L0 = ExampleTree_CreateNode("<ROOT>", ++uid, NULL);
884
    for (int idx_L0 = 0; idx_L0 < ROOT_ITEMS_COUNT; idx_L0++)
885
    {
886
        snprintf(name_buf, IM_COUNTOF(name_buf), "%s %d", category_names[idx_L0 / (ROOT_ITEMS_COUNT / category_count)], idx_L0 % (ROOT_ITEMS_COUNT / category_count));
887
        ExampleTreeNode* node_L1 = ExampleTree_CreateNode(name_buf, ++uid, node_L0);
888
        const int number_of_childs = (int)strlen(node_L1->Name);
889
        for (int idx_L1 = 0; idx_L1 < number_of_childs; idx_L1++)
890
        {
891
            snprintf(name_buf, IM_COUNTOF(name_buf), "Child %d", idx_L1);
892
            ExampleTreeNode* node_L2 = ExampleTree_CreateNode(name_buf, ++uid, node_L1);
893
            node_L2->HasData = true;
894
            if (idx_L1 == 0)
895
            {
896
                snprintf(name_buf, IM_COUNTOF(name_buf), "Sub-child %d", 0);
897
                ExampleTreeNode* node_L3 = ExampleTree_CreateNode(name_buf, ++uid, node_L2);
898
                node_L3->HasData = true;
899
            }
900
        }
901
    }
902
    return node_L0;
903
}
904
905
//-----------------------------------------------------------------------------
906
// [SECTION] Helpers: ExampleImageViewer
907
//-----------------------------------------------------------------------------
908
909
struct ExampleImageViewerData
910
{
911
    ImU32   ImageBgColor = IM_COL32(100, 100, 100, 255);
912
    ImU32   GridColor = IM_COL32(255, 255, 255, 100);
913
    bool    GridEnabled = true;
914
    bool    ViewReset = true;
915
    ImVec2  ViewOffset; // in image space
916
    float   Zoom = 10.0f;
917
    float   ZoomMin = 1.0f;
918
    float   ZoomMax = 10000.0f;
919
};
920
921
static void ExampleImageViewer_DrawOptions(ExampleImageViewerData* data)
922
{
923
    ImGui::SetNextItemShortcut(ImGuiKey_G, ImGuiInputFlags_Tooltip); // | ImGuiInputFlags_RouteGlobal
924
    ImGui::Checkbox("Grid", &data->GridEnabled);
925
    ImGui::SameLine();
926
    ImGui::SetNextItemWidth(ImGui::GetFontSize() * 10.0f);
927
    float zoom_100 = data->Zoom * 100.0f;
928
    if (ImGui::DragFloat("##Zoom", &zoom_100, 5.0f, data->ZoomMin * 100.0f, data->ZoomMax * 100.0f, "%.0f%%", ImGuiSliderFlags_AlwaysClamp))
929
        data->Zoom = zoom_100 / 100.0f;
930
}
931
932
static void ExampleImageViewer_DrawCanvas(ExampleImageViewerData* data, ImVec2 canvas_size, ImTextureRef image_tex_ref, int image_w, int image_h)
933
{
934
    ImGuiIO& io = ImGui::GetIO();
935
    ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
936
    ImDrawList* draw_list = ImGui::GetWindowDrawList();
937
    IM_ASSERT(canvas_size.x >= 0.0f && canvas_size.y >= 0.0f);
938
939
    // Layout canvas
940
    ImGui::InvisibleButton("##Canvas", canvas_size);
941
    ImVec2 canvas_min = ImGui::GetItemRectMin();
942
    ImVec2 canvas_max = ImGui::GetItemRectMax();
943
944
    if (data->ViewReset)
945
        data->ViewOffset = ImVec2((canvas_size.x * 0.5f / data->Zoom) - 0.5f, (canvas_size.y * 0.5f / data->Zoom) - 0.5f); // Add half a pixel padding
946
    data->ViewReset = false;
947
948
    // Handle inputs
949
    if (ImGui::SetItemKeyOwner(ImGuiKey_MouseWheelY))
950
        if (io.MouseWheel != 0.0f)
951
            data->Zoom = IM_CLAMP(data->Zoom * (1.0f + io.MouseWheel * 0.10f), data->ZoomMin, data->ZoomMax);
952
    float zoom = data->Zoom; // (float)(int)ViewZoom;
953
    if (ImGui::IsItemActive() && ImGui::IsMouseDragging(0))
954
    {
955
        data->ViewOffset.x -= io.MouseDelta.x / zoom;
956
        data->ViewOffset.y -= io.MouseDelta.y / zoom;
957
    }
958
959
    // Display image
960
    ImVec2 image_min, image_max;
961
    image_min.x = (float)(int)((canvas_min.x - (data->ViewOffset.x * zoom)) + (canvas_size.x * 0.5f));
962
    image_min.y = (float)(int)((canvas_min.y - (data->ViewOffset.y * zoom)) + (canvas_size.y * 0.5f));
963
    image_max.x = (float)(int)(image_min.x + image_w * zoom);
964
    image_max.y = (float)(int)(image_min.y + image_h * zoom);
965
    draw_list->AddRect(ImVec2(canvas_min.x - 1.0f, canvas_min.y - 1.0f), ImVec2(canvas_max.x + 1.0f, canvas_max.y + 1.0f), IM_COL32(255, 255, 255, 255));
966
    draw_list->PushClipRect(canvas_min, canvas_max, true);
967
    draw_list->AddRectFilled(image_min, image_max, data->ImageBgColor);
968
    if (platform_io.DrawCallback_SetSamplerNearest != NULL)
969
        draw_list->AddCallback(platform_io.DrawCallback_SetSamplerNearest);
970
    draw_list->AddImage(image_tex_ref, image_min, image_max);
971
    if (platform_io.DrawCallback_SetSamplerLinear != NULL)
972
        draw_list->AddCallback(ImGui::GetPlatformIO().DrawCallback_SetSamplerLinear);
973
974
    // Display grid lines for visible pixels
975
    if (data->GridEnabled && zoom > 6.0f)
976
    {
977
        const float step = (float)zoom;
978
        for (int px = (int)((canvas_min.x - image_min.x) / step); px <= (int)((canvas_max.x - image_min.x) / step); px++)
979
            draw_list->AddLineV(image_min.x + px * step, canvas_min.y, canvas_max.y, data->GridColor, 1.0f);
980
        for (int py = (int)((canvas_min.y - image_min.y) / step); py <= (int)((canvas_max.y - image_min.y) / step); py++)
981
            draw_list->AddLineH(canvas_min.x, canvas_max.x, image_min.y + py * step, data->GridColor, 1.0f);
982
    }
983
    draw_list->PopClipRect();
984
}
985
986
//-----------------------------------------------------------------------------
987
// [SECTION] DemoWindowWidgetsBasic()
988
//-----------------------------------------------------------------------------
989
990
static void DemoWindowWidgetsBasic()
991
{
992
    if (ImGui::TreeNode("Basic"))
993
    {
994
        IMGUI_DEMO_MARKER("Widgets/Basic");
995
        ImGui::SeparatorText("General");
996
997
        IMGUI_DEMO_MARKER("Widgets/Basic/Button");
998
        static int clicked = 0;
999
        if (ImGui::Button("Button"))
1000
            clicked++;
1001
        if (clicked & 1)
1002
        {
1003
            ImGui::SameLine();
1004
            ImGui::Text("Thanks for clicking me!");
1005
        }
1006
1007
        IMGUI_DEMO_MARKER("Widgets/Basic/Checkbox");
1008
        static bool check = true;
1009
        ImGui::Checkbox("checkbox", &check);
1010
1011
        IMGUI_DEMO_MARKER("Widgets/Basic/RadioButton");
1012
        static int e = 0;
1013
        ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine();
1014
        ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine();
1015
        ImGui::RadioButton("radio c", &e, 2);
1016
1017
        ImGui::AlignTextToFramePadding();
1018
        ImGui::TextLinkOpenURL("Hyperlink", "https://github.com/ocornut/imgui/wiki/Error-Handling");
1019
1020
        // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style.
1021
        IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Colored)");
1022
        for (int i = 0; i < 7; i++)
1023
        {
1024
            if (i > 0)
1025
                ImGui::SameLine();
1026
            ImGui::PushID(i);
1027
            ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.6f));
1028
            ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.7f));
1029
            ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.8f, 0.8f));
1030
            ImGui::Button("Click");
1031
            ImGui::PopStyleColor(3);
1032
            ImGui::PopID();
1033
        }
1034
1035
        // Use AlignTextToFramePadding() to align text baseline to the baseline of framed widgets elements
1036
        // (otherwise a Text+SameLine+Button sequence will have the text a little too high by default!)
1037
        // See 'Demo->Layout->Text Baseline Alignment' for details.
1038
        ImGui::AlignTextToFramePadding();
1039
        ImGui::Text("Hold to repeat:");
1040
        ImGui::SameLine();
1041
1042
        // Arrow buttons with Repeater
1043
        IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Repeating)");
1044
        static int counter = 0;
1045
        float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
1046
        ImGui::PushItemFlag(ImGuiItemFlags_ButtonRepeat, true);
1047
        if (ImGui::ArrowButton("##left", ImGuiDir_Left)) { counter--; }
1048
        ImGui::SameLine(0.0f, spacing);
1049
        if (ImGui::ArrowButton("##right", ImGuiDir_Right)) { counter++; }
1050
        ImGui::PopItemFlag();
1051
        ImGui::SameLine();
1052
        ImGui::Text("%d", counter);
1053
1054
        ImGui::Button("Tooltip");
1055
        ImGui::SetItemTooltip("I am a tooltip");
1056
1057
        ImGui::LabelText("label", "Value");
1058
1059
        ImGui::SeparatorText("Inputs");
1060
1061
        {
1062
            // If you want to use InputText() with std::string or any custom dynamic string type:
1063
            // - For std::string: use the wrapper in misc/cpp/imgui_stdlib.h/.cpp
1064
            // - Otherwise, see the 'Dear ImGui Demo->Widgets->Text Input->Resize Callback' for using ImGuiInputTextFlags_CallbackResize.
1065
            IMGUI_DEMO_MARKER("Widgets/Basic/InputText");
1066
            static char str0[128] = "Hello, world!";
1067
            ImGui::InputText("input text", str0, IM_COUNTOF(str0));
1068
            ImGui::SameLine(); HelpMarker(
1069
                "USER:\n"
1070
                "Hold Shift or use mouse to select text.\n"
1071
                "Ctrl+Left/Right to word jump.\n"
1072
                "Ctrl+A or Double-Click to select all.\n"
1073
                "Ctrl+X,Ctrl+C,Ctrl+V for clipboard.\n"
1074
                "Ctrl+Z to undo, Ctrl+Y/Ctrl+Shift+Z to redo.\n"
1075
                "Escape to revert.\n\n"
1076
                "PROGRAMMER:\n"
1077
                "You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() "
1078
                "to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example (this is not demonstrated "
1079
                "in imgui_demo.cpp).");
1080
1081
            static char str1[128] = "";
1082
            ImGui::InputTextWithHint("input text (w/ hint)", "enter text here", str1, IM_COUNTOF(str1));
1083
1084
            IMGUI_DEMO_MARKER("Widgets/Basic/InputInt, InputFloat");
1085
            static int i0 = 123;
1086
            ImGui::InputInt("input int", &i0);
1087
1088
            static float f0 = 0.001f;
1089
            ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f");
1090
1091
            static double d0 = 999999.00000001;
1092
            ImGui::InputDouble("input double", &d0, 0.01f, 1.0f, "%.8f");
1093
1094
            static float f1 = 1.e10f;
1095
            ImGui::InputFloat("input scientific", &f1, 0.0f, 0.0f, "%e");
1096
            ImGui::SameLine(); HelpMarker(
1097
                "You can input value using the scientific notation,\n"
1098
                "  e.g. \"1e+8\" becomes \"100000000\".");
1099
1100
            static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f };
1101
            ImGui::InputFloat3("input float3", vec4a);
1102
        }
1103
1104
        ImGui::SeparatorText("Drags");
1105
1106
        {
1107
            IMGUI_DEMO_MARKER("Widgets/Basic/DragInt, DragFloat");
1108
            static int i1 = 50, i2 = 42, i3 = 128;
1109
            ImGui::DragInt("drag int", &i1, 1);
1110
            ImGui::SameLine(); HelpMarker(
1111
                "Click and drag to edit value.\n"
1112
                "Hold Shift/Alt for faster/slower edit.\n"
1113
                "Double-Click or Ctrl+Click to input value.");
1114
            ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp);
1115
            ImGui::DragInt("drag int wrap 100..200", &i3, 1, 100, 200, "%d", ImGuiSliderFlags_WrapAround);
1116
1117
            static float f1 = 1.00f, f2 = 0.0067f;
1118
            ImGui::DragFloat("drag float", &f1, 0.005f);
1119
            ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns");
1120
            //ImGui::DragFloat("drag wrap -1..1", &f3, 0.005f, -1.0f, 1.0f, NULL, ImGuiSliderFlags_WrapAround);
1121
        }
1122
1123
        ImGui::SeparatorText("Sliders");
1124
1125
        {
1126
            IMGUI_DEMO_MARKER("Widgets/Basic/SliderInt, SliderFloat");
1127
            static int i1 = 0;
1128
            ImGui::SliderInt("slider int", &i1, -1, 3);
1129
            ImGui::SameLine(); HelpMarker("Ctrl+Click to input value.");
1130
1131
            static float f1 = 0.123f, f2 = 0.0f;
1132
            ImGui::SliderFloat("slider float", &f1, 0.0f, 1.0f, "ratio = %.3f");
1133
            ImGui::SliderFloat("slider float (log)", &f2, -10.0f, 10.0f, "%.4f", ImGuiSliderFlags_Logarithmic);
1134
1135
            IMGUI_DEMO_MARKER("Widgets/Basic/SliderAngle");
1136
            static float angle = 0.0f;
1137
            ImGui::SliderAngle("slider angle", &angle);
1138
1139
            // Using the format string to display a name instead of an integer.
1140
            // Here we completely omit '%d' from the format string, so it'll only display a name.
1141
            // This technique can also be used with DragInt().
1142
            IMGUI_DEMO_MARKER("Widgets/Basic/Slider (enum)");
1143
            enum Element { Element_Fire, Element_Earth, Element_Air, Element_Water, Element_COUNT };
1144
            static int elem = Element_Fire;
1145
            const char* elems_names[Element_COUNT] = { "Fire", "Earth", "Air", "Water" };
1146
            const char* elem_name = (elem >= 0 && elem < Element_COUNT) ? elems_names[elem] : "Unknown";
1147
            ImGui::SliderInt("slider enum", &elem, 0, Element_COUNT - 1, elem_name); // Use ImGuiSliderFlags_NoInput flag to disable Ctrl+Click here.
1148
            ImGui::SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer.");
1149
        }
1150
1151
        ImGui::SeparatorText("Selectors/Pickers");
1152
1153
        {
1154
            IMGUI_DEMO_MARKER("Widgets/Basic/ColorEdit3, ColorEdit4");
1155
            static float col1[3] = { 1.0f, 0.0f, 0.2f };
1156
            static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
1157
            ImGui::ColorEdit3("color 1", col1);
1158
            ImGui::SameLine(); HelpMarker(
1159
                "Click on the color square to open a color picker.\n"
1160
                "Click and hold to use drag and drop.\n"
1161
                "Right-Click on the color square to show options.\n"
1162
                "Ctrl+Click on individual component to input value.\n");
1163
1164
            ImGui::ColorEdit4("color 2", col2);
1165
        }
1166
1167
        {
1168
            // Using the _simplified_ one-liner Combo() api here
1169
            // See "Combo" section for examples of how to use the more flexible BeginCombo()/EndCombo() api.
1170
            IMGUI_DEMO_MARKER("Widgets/Basic/Combo");
1171
            const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" };
1172
            static int item_current = 0;
1173
            ImGui::Combo("combo", &item_current, items, IM_COUNTOF(items));
1174
            ImGui::SameLine(); HelpMarker(
1175
                "Using the simplified one-liner Combo API here.\n"
1176
                "Refer to the \"Combo\" section below for an explanation of how to use the more flexible and general BeginCombo/EndCombo API.");
1177
        }
1178
1179
        {
1180
            // Using the _simplified_ one-liner ListBox() api here
1181
            // See "List boxes" section for examples of how to use the more flexible BeginListBox()/EndListBox() api.
1182
            IMGUI_DEMO_MARKER("Widgets/Basic/ListBox");
1183
            const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" };
1184
            static int item_current = 1;
1185
            ImGui::ListBox("listbox", &item_current, items, IM_COUNTOF(items), 4);
1186
            ImGui::SameLine(); HelpMarker(
1187
                "Using the simplified one-liner ListBox API here.\n"
1188
                "Refer to the \"List boxes\" section below for an explanation of how to use the more flexible and general BeginListBox/EndListBox API.");
1189
        }
1190
1191
        // Testing ImGuiOnceUponAFrame helper.
1192
        //static ImGuiOnceUponAFrame once;
1193
        //for (int i = 0; i < 5; i++)
1194
        //    if (once)
1195
        //        ImGui::Text("This will be displayed only once.");
1196
1197
        ImGui::TreePop();
1198
    }
1199
}
1200
1201
//-----------------------------------------------------------------------------
1202
// [SECTION] DemoWindowWidgetsBullets()
1203
//-----------------------------------------------------------------------------
1204
1205
static void DemoWindowWidgetsBullets()
1206
{
1207
    if (ImGui::TreeNode("Bullets"))
1208
    {
1209
        IMGUI_DEMO_MARKER("Widgets/Bullets");
1210
        ImGui::BulletText("Bullet point 1");
1211
        ImGui::BulletText("Bullet point 2\nOn multiple lines");
1212
        if (ImGui::TreeNode("Tree node"))
1213
        {
1214
            ImGui::BulletText("Another bullet point");
1215
            ImGui::TreePop();
1216
        }
1217
        ImGui::Bullet(); ImGui::Text("Bullet point 3 (two calls)");
1218
        ImGui::Bullet(); ImGui::SmallButton("Button");
1219
        ImGui::TreePop();
1220
    }
1221
}
1222
1223
//-----------------------------------------------------------------------------
1224
// [SECTION] DemoWindowWidgetsCollapsingHeaders()
1225
//-----------------------------------------------------------------------------
1226
1227
static void DemoWindowWidgetsCollapsingHeaders()
1228
{
1229
    if (ImGui::TreeNode("Collapsing Headers"))
1230
    {
1231
        IMGUI_DEMO_MARKER("Widgets/Collapsing Headers");
1232
        static bool closable_group = true;
1233
        ImGui::Checkbox("Show 2nd header", &closable_group);
1234
        if (ImGui::CollapsingHeader("Header", ImGuiTreeNodeFlags_None))
1235
        {
1236
            ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
1237
            for (int i = 0; i < 5; i++)
1238
                ImGui::Text("Some content %d", i);
1239
        }
1240
        if (ImGui::CollapsingHeader("Header with a close button", &closable_group))
1241
        {
1242
            ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
1243
            for (int i = 0; i < 5; i++)
1244
                ImGui::Text("More content %d", i);
1245
        }
1246
        /*
1247
        if (ImGui::CollapsingHeader("Header with a bullet", ImGuiTreeNodeFlags_Bullet))
1248
            ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
1249
        */
1250
        ImGui::TreePop();
1251
    }
1252
}
1253
1254
//-----------------------------------------------------------------------------
1255
// [SECTION] DemoWindowWidgetsColorAndPickers()
1256
//-----------------------------------------------------------------------------
1257
1258
static void DemoWindowWidgetsColorAndPickers()
1259
{
1260
    if (ImGui::TreeNode("Color/Picker Widgets"))
1261
    {
1262
        IMGUI_DEMO_MARKER("Widgets/Color");
1263
        static ImVec4 color = ImVec4(114.0f / 255.0f, 144.0f / 255.0f, 154.0f / 255.0f, 200.0f / 255.0f);
1264
        static ImGuiColorEditFlags base_flags = ImGuiColorEditFlags_None;
1265
1266
        ImGui::SeparatorText("Options");
1267
        ImGui::CheckboxFlags("ImGuiColorEditFlags_NoAlpha", &base_flags, ImGuiColorEditFlags_NoAlpha);
1268
        ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaOpaque", &base_flags, ImGuiColorEditFlags_AlphaOpaque);
1269
        ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaNoBg", &base_flags, ImGuiColorEditFlags_AlphaNoBg);
1270
        ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaPreviewHalf", &base_flags, ImGuiColorEditFlags_AlphaPreviewHalf);
1271
        ImGui::CheckboxFlags("ImGuiColorEditFlags_NoOptions", &base_flags, ImGuiColorEditFlags_NoOptions); ImGui::SameLine(); HelpMarker("Right-click on the individual color widget to show options.");
1272
        ImGui::CheckboxFlags("ImGuiColorEditFlags_NoDragDrop", &base_flags, ImGuiColorEditFlags_NoDragDrop);
1273
        ImGui::CheckboxFlags("ImGuiColorEditFlags_NoColorMarkers", &base_flags, ImGuiColorEditFlags_NoColorMarkers);
1274
        ImGui::CheckboxFlags("ImGuiColorEditFlags_HDR", &base_flags, ImGuiColorEditFlags_HDR); ImGui::SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets.");
1275
1276
        IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit");
1277
        ImGui::SeparatorText("Inline color editor");
1278
        ImGui::Text("Color widget:");
1279
        ImGui::SameLine(); HelpMarker(
1280
            "Click on the color square to open a color picker.\n"
1281
            "Ctrl+Click on individual component to input value.\n");
1282
        ImGui::ColorEdit3("MyColor##1", (float*)&color, base_flags);
1283
1284
        IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (HSV, with Alpha)");
1285
        ImGui::Text("Color widget HSV with Alpha:");
1286
        ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_DisplayHSV | base_flags);
1287
1288
        IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (float display)");
1289
        ImGui::Text("Color widget with Float Display:");
1290
        ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | base_flags);
1291
1292
        IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with Picker)");
1293
        ImGui::Text("Color button with Picker:");
1294
        ImGui::SameLine(); HelpMarker(
1295
            "With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\n"
1296
            "With the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only "
1297
            "be used for the tooltip and picker popup.");
1298
        ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | base_flags);
1299
1300
        IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with custom Picker popup)");
1301
        ImGui::Text("Color button with Custom Picker Popup:");
1302
1303
        // Generate a default palette. The palette will persist and can be edited.
1304
        static bool saved_palette_init = true;
1305
        static ImVec4 saved_palette[32] = {};
1306
        if (saved_palette_init)
1307
        {
1308
            for (int n = 0; n < IM_COUNTOF(saved_palette); n++)
1309
            {
1310
                ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f,
1311
                    saved_palette[n].x, saved_palette[n].y, saved_palette[n].z);
1312
                saved_palette[n].w = 1.0f; // Alpha
1313
            }
1314
            saved_palette_init = false;
1315
        }
1316
1317
        static ImVec4 backup_color;
1318
        bool open_popup = ImGui::ColorButton("MyColor##3b", color, base_flags);
1319
        ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x);
1320
        open_popup |= ImGui::Button("Palette");
1321
        if (open_popup)
1322
        {
1323
            ImGui::OpenPopup("mypicker");
1324
            backup_color = color;
1325
        }
1326
        if (ImGui::BeginPopup("mypicker"))
1327
        {
1328
            ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!");
1329
            ImGui::Separator();
1330
            ImGui::ColorPicker4("##picker", (float*)&color, base_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview);
1331
            ImGui::SameLine();
1332
1333
            ImGui::BeginGroup(); // Lock X position
1334
            ImGui::Text("Current");
1335
            ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40));
1336
            ImGui::Text("Previous");
1337
            if (ImGui::ColorButton("##previous", backup_color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40)))
1338
                color = backup_color;
1339
            ImGui::Separator();
1340
            ImGui::Text("Palette");
1341
            for (int n = 0; n < IM_COUNTOF(saved_palette); n++)
1342
            {
1343
                ImGui::PushID(n);
1344
                if ((n % 8) != 0)
1345
                    ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y);
1346
1347
                ImGuiColorEditFlags palette_button_flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip;
1348
                if (ImGui::ColorButton("##palette", saved_palette[n], palette_button_flags, ImVec2(20, 20)))
1349
                    color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha!
1350
1351
                // Allow user to drop colors into each palette entry. Note that ColorButton() is already a
1352
                // drag source by default, unless specifying the ImGuiColorEditFlags_NoDragDrop flag.
1353
                if (ImGui::BeginDragDropTarget())
1354
                {
1355
                    if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
1356
                        memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3);
1357
                    if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F))
1358
                        memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4);
1359
                    ImGui::EndDragDropTarget();
1360
                }
1361
1362
                ImGui::PopID();
1363
            }
1364
            ImGui::EndGroup();
1365
            ImGui::EndPopup();
1366
        }
1367
1368
        IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (simple)");
1369
        ImGui::Text("Color button only:");
1370
        static bool no_border = false;
1371
        ImGui::Checkbox("ImGuiColorEditFlags_NoBorder", &no_border);
1372
        ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, base_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80));
1373
1374
        IMGUI_DEMO_MARKER("Widgets/Color/ColorPicker");
1375
        ImGui::SeparatorText("Color picker");
1376
1377
        static bool ref_color = false;
1378
        static ImVec4 ref_color_v(1.0f, 0.0f, 1.0f, 0.5f);
1379
        static int picker_mode = 0;
1380
        static int display_mode = 0;
1381
        static ImGuiColorEditFlags color_picker_flags = ImGuiColorEditFlags_AlphaBar;
1382
1383
        ImGui::PushID("Color picker");
1384
        ImGui::CheckboxFlags("ImGuiColorEditFlags_NoAlpha", &color_picker_flags, ImGuiColorEditFlags_NoAlpha);
1385
        ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaBar", &color_picker_flags, ImGuiColorEditFlags_AlphaBar);
1386
        ImGui::CheckboxFlags("ImGuiColorEditFlags_NoSidePreview", &color_picker_flags, ImGuiColorEditFlags_NoSidePreview);
1387
        if (color_picker_flags & ImGuiColorEditFlags_NoSidePreview)
1388
        {
1389
            ImGui::SameLine();
1390
            ImGui::Checkbox("With Ref Color", &ref_color);
1391
            if (ref_color)
1392
            {
1393
                ImGui::SameLine();
1394
                ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | base_flags);
1395
            }
1396
        }
1397
1398
        ImGui::Combo("Picker Mode", &picker_mode, "Auto/Current\0ImGuiColorEditFlags_PickerHueBar\0ImGuiColorEditFlags_PickerHueWheel\0");
1399
        ImGui::SameLine(); HelpMarker("When not specified explicitly, user can right-click the picker to change mode.");
1400
1401
        ImGui::Combo("Display Mode", &display_mode, "Auto/Current\0ImGuiColorEditFlags_NoInputs\0ImGuiColorEditFlags_DisplayRGB\0ImGuiColorEditFlags_DisplayHSV\0ImGuiColorEditFlags_DisplayHex\0");
1402
        ImGui::SameLine(); HelpMarker(
1403
            "ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, "
1404
            "but the user can change it with a right-click on those inputs.\n\nColorPicker defaults to displaying RGB+HSV+Hex "
1405
            "if you don't specify a display mode.\n\nYou can change the defaults using SetColorEditOptions().");
1406
1407
        ImGuiColorEditFlags flags = base_flags | color_picker_flags;
1408
        if (picker_mode == 1)  flags |= ImGuiColorEditFlags_PickerHueBar;
1409
        if (picker_mode == 2)  flags |= ImGuiColorEditFlags_PickerHueWheel;
1410
        if (display_mode == 1) flags |= ImGuiColorEditFlags_NoInputs;       // Disable all RGB/HSV/Hex displays
1411
        if (display_mode == 2) flags |= ImGuiColorEditFlags_DisplayRGB;     // Override display mode
1412
        if (display_mode == 3) flags |= ImGuiColorEditFlags_DisplayHSV;
1413
        if (display_mode == 4) flags |= ImGuiColorEditFlags_DisplayHex;
1414
        ImGui::ColorPicker4("MyColor##4", (float*)&color, flags, ref_color ? &ref_color_v.x : NULL);
1415
1416
        ImGui::Text("Set defaults in code:");
1417
        ImGui::SameLine(); HelpMarker(
1418
            "SetColorEditOptions() is designed to allow you to set boot-time default.\n"
1419
            "We don't have Push/Pop functions because you can force options on a per-widget basis if needed, "
1420
            "and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid "
1421
            "encouraging you to persistently save values that aren't forward-compatible.");
1422
        if (ImGui::Button("Default: Uint8 + HSV + Hue Bar"))
1423
            ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_PickerHueBar);
1424
        if (ImGui::Button("Default: Float + HDR + Hue Wheel"))
1425
            ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel);
1426
1427
        // Always display a small version of both types of pickers
1428
        // (that's in order to make it more visible in the demo to people who are skimming quickly through it)
1429
        ImGui::Text("Both types:");
1430
        float w = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.y) * 0.40f;
1431
        ImGui::SetNextItemWidth(w);
1432
        ImGui::ColorPicker3("##MyColor##5", (float*)&color, ImGuiColorEditFlags_PickerHueBar | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha);
1433
        ImGui::SameLine();
1434
        ImGui::SetNextItemWidth(w);
1435
        ImGui::ColorPicker3("##MyColor##6", (float*)&color, ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha);
1436
        ImGui::PopID();
1437
1438
        // HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0)
1439
        static ImVec4 color_hsv(0.23f, 1.0f, 1.0f, 1.0f); // Stored as HSV!
1440
        ImGui::Spacing();
1441
        ImGui::Text("HSV encoded colors");
1442
        ImGui::SameLine(); HelpMarker(
1443
            "By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV "
1444
            "allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV. This comes with the "
1445
            "added benefit that you can manipulate hue values with the picker even when saturation or value are zero.");
1446
        ImGui::Text("Color widget with InputHSV:");
1447
        ImGui::ColorEdit4("HSV shown as RGB##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float);
1448
        ImGui::ColorEdit4("HSV shown as HSV##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float);
1449
        ImGui::DragFloat4("Raw HSV values", (float*)&color_hsv, 0.01f, 0.0f, 1.0f);
1450
1451
        ImGui::TreePop();
1452
    }
1453
}
1454
1455
//-----------------------------------------------------------------------------
1456
// [SECTION] DemoWindowWidgetsComboBoxes()
1457
//-----------------------------------------------------------------------------
1458
1459
static void DemoWindowWidgetsComboBoxes()
1460
{
1461
    if (ImGui::TreeNode("Combo"))
1462
    {
1463
        IMGUI_DEMO_MARKER("Widgets/Combo");
1464
        // Combo Boxes are also called "Dropdown" in other systems
1465
        // Expose flags as checkbox for the demo
1466
        static ImGuiComboFlags flags = 0;
1467
        ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", &flags, ImGuiComboFlags_PopupAlignLeft);
1468
        ImGui::SameLine(); HelpMarker("Only makes a difference if the popup is larger than the combo");
1469
        if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", &flags, ImGuiComboFlags_NoArrowButton))
1470
            flags &= ~ImGuiComboFlags_NoPreview;     // Clear incompatible flags
1471
        if (ImGui::CheckboxFlags("ImGuiComboFlags_NoPreview", &flags, ImGuiComboFlags_NoPreview))
1472
            flags &= ~(ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_WidthFitPreview); // Clear incompatible flags
1473
        if (ImGui::CheckboxFlags("ImGuiComboFlags_WidthFitPreview", &flags, ImGuiComboFlags_WidthFitPreview))
1474
            flags &= ~ImGuiComboFlags_NoPreview;
1475
1476
        // Override default popup height
1477
        if (ImGui::CheckboxFlags("ImGuiComboFlags_HeightSmall", &flags, ImGuiComboFlags_HeightSmall))
1478
            flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightSmall);
1479
        if (ImGui::CheckboxFlags("ImGuiComboFlags_HeightRegular", &flags, ImGuiComboFlags_HeightRegular))
1480
            flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightRegular);
1481
        if (ImGui::CheckboxFlags("ImGuiComboFlags_HeightLargest", &flags, ImGuiComboFlags_HeightLargest))
1482
            flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightLargest);
1483
1484
        // Using the generic BeginCombo() API, you have full control over how to display the combo contents.
1485
        // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
1486
        // stored in the object itself, etc.)
1487
        const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" };
1488
        static int item_selected_idx = 0; // Here we store our selection data as an index.
1489
1490
        // Pass in the preview value visible before opening the combo (it could technically be different contents or not pulled from items[])
1491
        const char* combo_preview_value = items[item_selected_idx];
1492
        if (ImGui::BeginCombo("combo 1", combo_preview_value, flags))
1493
        {
1494
            for (int n = 0; n < IM_COUNTOF(items); n++)
1495
            {
1496
                const bool is_selected = (item_selected_idx == n);
1497
                if (ImGui::Selectable(items[n], is_selected))
1498
                    item_selected_idx = n;
1499
1500
                // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
1501
                if (is_selected)
1502
                    ImGui::SetItemDefaultFocus();
1503
            }
1504
            ImGui::EndCombo();
1505
        }
1506
1507
        // Show case embedding a filter using a simple trick: displaying the filter inside combo contents.
1508
        // See https://github.com/ocornut/imgui/issues/718 for advanced/esoteric alternatives.
1509
        if (ImGui::BeginCombo("combo 2 (w/ filter)", combo_preview_value, flags))
1510
        {
1511
            static ImGuiTextFilter filter;
1512
            if (ImGui::IsWindowAppearing())
1513
            {
1514
                ImGui::SetKeyboardFocusHere();
1515
                filter.Clear();
1516
            }
1517
            ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F);
1518
            filter.Draw("##Filter", -FLT_MIN);
1519
1520
            for (int n = 0; n < IM_COUNTOF(items); n++)
1521
            {
1522
                const bool is_selected = (item_selected_idx == n);
1523
                if (filter.PassFilter(items[n]))
1524
                    if (ImGui::Selectable(items[n], is_selected))
1525
                        item_selected_idx = n;
1526
            }
1527
            ImGui::EndCombo();
1528
        }
1529
1530
        ImGui::Spacing();
1531
        ImGui::SeparatorText("One-liner variants");
1532
        HelpMarker("The Combo() function is not greatly useful apart from cases were you want to embed all options in a single strings.\nFlags above don't apply to this section.");
1533
1534
        // Simplified one-liner Combo() API, using values packed in a single constant string
1535
        // This is a convenience for when the selection set is small and known at compile-time.
1536
        static int item_current_2 = 0;
1537
        ImGui::Combo("combo 3 (one-liner)", &item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
1538
1539
        // Simplified one-liner Combo() using an array of const char*
1540
        // This is not very useful (may obsolete): prefer using BeginCombo()/EndCombo() for full control.
1541
        static int item_current_3 = -1; // If the selection isn't within 0..count, Combo won't display a preview
1542
        ImGui::Combo("combo 4 (array)", &item_current_3, items, IM_COUNTOF(items));
1543
1544
        // Simplified one-liner Combo() using an accessor function
1545
        static int item_current_4 = 0;
1546
        ImGui::Combo("combo 5 (function)", &item_current_4, [](void* data, int n) { return ((const char**)data)[n]; }, items, IM_COUNTOF(items));
1547
1548
        ImGui::TreePop();
1549
    }
1550
}
1551
1552
//-----------------------------------------------------------------------------
1553
// [SECTION] DemoWindowWidgetsDataTypes()
1554
//-----------------------------------------------------------------------------
1555
1556
static void DemoWindowWidgetsDataTypes()
1557
{
1558
    if (ImGui::TreeNode("Data Types"))
1559
    {
1560
        IMGUI_DEMO_MARKER("Widgets/Data Types");
1561
        // DragScalar/InputScalar/SliderScalar functions allow various data types
1562
        // - signed/unsigned
1563
        // - 8/16/32/64-bits
1564
        // - integer/float/double
1565
        // To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum
1566
        // to pass the type, and passing all arguments by pointer.
1567
        // This is the reason the test code below creates local variables to hold "zero" "one" etc. for each type.
1568
        // In practice, if you frequently use a given type that is not covered by the normal API entry points,
1569
        // you can wrap it yourself inside a 1 line function which can take typed argument as value instead of void*,
1570
        // and then pass their address to the generic function. For example:
1571
        //   bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld")
1572
        //   {
1573
        //      return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format);
1574
        //   }
1575
1576
        // Setup limits (as helper variables so we can take their address, as explained above)
1577
        // Note: SliderScalar() functions have a maximum usable range of half the natural type maximum, hence the /2.
1578
        #ifndef LLONG_MIN
1579
        ImS64 LLONG_MIN = -9223372036854775807LL - 1;
1580
        ImS64 LLONG_MAX = 9223372036854775807LL;
1581
        ImU64 ULLONG_MAX = (2ULL * 9223372036854775807LL + 1);
1582
        #endif
1583
        const char    s8_zero  = 0,   s8_one  = 1,   s8_fifty  = 50, s8_min  = -128,        s8_max = 127;
1584
        const ImU8    u8_zero  = 0,   u8_one  = 1,   u8_fifty  = 50, u8_min  = 0,           u8_max = 255;
1585
        const short   s16_zero = 0,   s16_one = 1,   s16_fifty = 50, s16_min = -32768,      s16_max = 32767;
1586
        const ImU16   u16_zero = 0,   u16_one = 1,   u16_fifty = 50, u16_min = 0,           u16_max = 65535;
1587
        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;
1588
        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;
1589
        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;
1590
        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;
1591
        const float   f32_zero = 0.f, f32_one = 1.f, f32_lo_a = -10000000000.0f, f32_hi_a = +10000000000.0f;
1592
        const double  f64_zero = 0.,  f64_one = 1.,  f64_lo_a = -1000000000000000.0, f64_hi_a = +1000000000000000.0;
1593
1594
        // State
1595
        static char   s8_v  = 127;
1596
        static ImU8   u8_v  = 255;
1597
        static short  s16_v = 32767;
1598
        static ImU16  u16_v = 65535;
1599
        static ImS32  s32_v = -1;
1600
        static ImU32  u32_v = (ImU32)-1;
1601
        static ImS64  s64_v = -1;
1602
        static ImU64  u64_v = (ImU64)-1;
1603
        static float  f32_v = 0.123f;
1604
        static double f64_v = 90000.01234567890123456789;
1605
1606
        const float drag_speed = 0.2f;
1607
        static bool drag_clamp = false;
1608
        IMGUI_DEMO_MARKER("Widgets/Data Types/Drags");
1609
        ImGui::SeparatorText("Drags");
1610
        ImGui::Checkbox("Clamp integers to 0..50", &drag_clamp);
1611
        ImGui::SameLine(); HelpMarker(
1612
            "As with every widget in dear imgui, we never modify values unless there is a user interaction.\n"
1613
            "You can override the clamping limits by using Ctrl+Click to input a value.");
1614
        ImGui::DragScalar("drag s8",        ImGuiDataType_S8,     &s8_v,  drag_speed, drag_clamp ? &s8_zero  : NULL, drag_clamp ? &s8_fifty  : NULL);
1615
        ImGui::DragScalar("drag u8",        ImGuiDataType_U8,     &u8_v,  drag_speed, drag_clamp ? &u8_zero  : NULL, drag_clamp ? &u8_fifty  : NULL, "%u ms");
1616
        ImGui::DragScalar("drag s16",       ImGuiDataType_S16,    &s16_v, drag_speed, drag_clamp ? &s16_zero : NULL, drag_clamp ? &s16_fifty : NULL);
1617
        ImGui::DragScalar("drag u16",       ImGuiDataType_U16,    &u16_v, drag_speed, drag_clamp ? &u16_zero : NULL, drag_clamp ? &u16_fifty : NULL, "%u ms");
1618
        ImGui::DragScalar("drag s32",       ImGuiDataType_S32,    &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL);
1619
        ImGui::DragScalar("drag s32 hex",   ImGuiDataType_S32,    &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL, "0x%08X");
1620
        ImGui::DragScalar("drag u32",       ImGuiDataType_U32,    &u32_v, drag_speed, drag_clamp ? &u32_zero : NULL, drag_clamp ? &u32_fifty : NULL, "%u ms");
1621
        ImGui::DragScalar("drag s64",       ImGuiDataType_S64,    &s64_v, drag_speed, drag_clamp ? &s64_zero : NULL, drag_clamp ? &s64_fifty : NULL);
1622
        ImGui::DragScalar("drag u64",       ImGuiDataType_U64,    &u64_v, drag_speed, drag_clamp ? &u64_zero : NULL, drag_clamp ? &u64_fifty : NULL);
1623
        ImGui::DragScalar("drag float",     ImGuiDataType_Float,  &f32_v, 0.005f,  &f32_zero, &f32_one, "%f");
1624
        ImGui::DragScalar("drag float log", ImGuiDataType_Float,  &f32_v, 0.005f,  &f32_zero, &f32_one, "%f", ImGuiSliderFlags_Logarithmic);
1625
        ImGui::DragScalar("drag double",    ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, NULL,     "%.10f grams");
1626
        ImGui::DragScalar("drag double log",ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", ImGuiSliderFlags_Logarithmic);
1627
1628
        IMGUI_DEMO_MARKER("Widgets/Data Types/Sliders");
1629
        ImGui::SeparatorText("Sliders");
1630
        ImGui::SliderScalar("slider s8 full",       ImGuiDataType_S8,     &s8_v,  &s8_min,   &s8_max,   "%d");
1631
        ImGui::SliderScalar("slider u8 full",       ImGuiDataType_U8,     &u8_v,  &u8_min,   &u8_max,   "%u");
1632
        ImGui::SliderScalar("slider s16 full",      ImGuiDataType_S16,    &s16_v, &s16_min,  &s16_max,  "%d");
1633
        ImGui::SliderScalar("slider u16 full",      ImGuiDataType_U16,    &u16_v, &u16_min,  &u16_max,  "%u");
1634
        ImGui::SliderScalar("slider s32 low",       ImGuiDataType_S32,    &s32_v, &s32_zero, &s32_fifty,"%d");
1635
        ImGui::SliderScalar("slider s32 high",      ImGuiDataType_S32,    &s32_v, &s32_hi_a, &s32_hi_b, "%d");
1636
        ImGui::SliderScalar("slider s32 full",      ImGuiDataType_S32,    &s32_v, &s32_min,  &s32_max,  "%d");
1637
        ImGui::SliderScalar("slider s32 hex",       ImGuiDataType_S32,    &s32_v, &s32_zero, &s32_fifty, "0x%04X");
1638
        ImGui::SliderScalar("slider u32 low",       ImGuiDataType_U32,    &u32_v, &u32_zero, &u32_fifty,"%u");
1639
        ImGui::SliderScalar("slider u32 high",      ImGuiDataType_U32,    &u32_v, &u32_hi_a, &u32_hi_b, "%u");
1640
        ImGui::SliderScalar("slider u32 full",      ImGuiDataType_U32,    &u32_v, &u32_min,  &u32_max,  "%u");
1641
        ImGui::SliderScalar("slider s64 low",       ImGuiDataType_S64,    &s64_v, &s64_zero, &s64_fifty,"%" PRId64);
1642
        ImGui::SliderScalar("slider s64 high",      ImGuiDataType_S64,    &s64_v, &s64_hi_a, &s64_hi_b, "%" PRId64);
1643
        ImGui::SliderScalar("slider s64 full",      ImGuiDataType_S64,    &s64_v, &s64_min,  &s64_max,  "%" PRId64);
1644
        ImGui::SliderScalar("slider u64 low",       ImGuiDataType_U64,    &u64_v, &u64_zero, &u64_fifty,"%" PRIu64 " ms");
1645
        ImGui::SliderScalar("slider u64 high",      ImGuiDataType_U64,    &u64_v, &u64_hi_a, &u64_hi_b, "%" PRIu64 " ms");
1646
        ImGui::SliderScalar("slider u64 full",      ImGuiDataType_U64,    &u64_v, &u64_min,  &u64_max,  "%" PRIu64 " ms");
1647
        ImGui::SliderScalar("slider float low",     ImGuiDataType_Float,  &f32_v, &f32_zero, &f32_one);
1648
        ImGui::SliderScalar("slider float low log", ImGuiDataType_Float,  &f32_v, &f32_zero, &f32_one,  "%.10f", ImGuiSliderFlags_Logarithmic);
1649
        ImGui::SliderScalar("slider float high",    ImGuiDataType_Float,  &f32_v, &f32_lo_a, &f32_hi_a, "%e");
1650
        ImGui::SliderScalar("slider double low",    ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one,  "%.10f grams");
1651
        ImGui::SliderScalar("slider double low log",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one,  "%.10f", ImGuiSliderFlags_Logarithmic);
1652
        ImGui::SliderScalar("slider double high",   ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams");
1653
1654
        ImGui::SeparatorText("Sliders (reverse)");
1655
        ImGui::SliderScalar("slider s8 reverse",    ImGuiDataType_S8,   &s8_v,  &s8_max,    &s8_min,   "%d");
1656
        ImGui::SliderScalar("slider u8 reverse",    ImGuiDataType_U8,   &u8_v,  &u8_max,    &u8_min,   "%u");
1657
        ImGui::SliderScalar("slider s32 reverse",   ImGuiDataType_S32,  &s32_v, &s32_fifty, &s32_zero, "%d");
1658
        ImGui::SliderScalar("slider u32 reverse",   ImGuiDataType_U32,  &u32_v, &u32_fifty, &u32_zero, "%u");
1659
        ImGui::SliderScalar("slider s64 reverse",   ImGuiDataType_S64,  &s64_v, &s64_fifty, &s64_zero, "%" PRId64);
1660
        ImGui::SliderScalar("slider u64 reverse",   ImGuiDataType_U64,  &u64_v, &u64_fifty, &u64_zero, "%" PRIu64 " ms");
1661
1662
        IMGUI_DEMO_MARKER("Widgets/Data Types/Inputs");
1663
        static bool inputs_step = true;
1664
        static ImGuiInputTextFlags flags = ImGuiInputTextFlags_None;
1665
        ImGui::SeparatorText("Inputs");
1666
        ImGui::Checkbox("Show step buttons", &inputs_step);
1667
        ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly);
1668
        ImGui::CheckboxFlags("ImGuiInputTextFlags_ParseEmptyRefVal", &flags, ImGuiInputTextFlags_ParseEmptyRefVal);
1669
        ImGui::CheckboxFlags("ImGuiInputTextFlags_DisplayEmptyRefVal", &flags, ImGuiInputTextFlags_DisplayEmptyRefVal);
1670
        ImGui::InputScalar("input s8",      ImGuiDataType_S8,     &s8_v,  inputs_step ? &s8_one  : NULL, NULL, "%d", flags);
1671
        ImGui::InputScalar("input u8",      ImGuiDataType_U8,     &u8_v,  inputs_step ? &u8_one  : NULL, NULL, "%u", flags);
1672
        ImGui::InputScalar("input s16",     ImGuiDataType_S16,    &s16_v, inputs_step ? &s16_one : NULL, NULL, "%d", flags);
1673
        ImGui::InputScalar("input u16",     ImGuiDataType_U16,    &u16_v, inputs_step ? &u16_one : NULL, NULL, "%u", flags);
1674
        ImGui::InputScalar("input s32",     ImGuiDataType_S32,    &s32_v, inputs_step ? &s32_one : NULL, NULL, "%d", flags);
1675
        ImGui::InputScalar("input s32 hex", ImGuiDataType_S32,    &s32_v, inputs_step ? &s32_one : NULL, NULL, "%04X", flags);
1676
        ImGui::InputScalar("input u32",     ImGuiDataType_U32,    &u32_v, inputs_step ? &u32_one : NULL, NULL, "%u", flags);
1677
        ImGui::InputScalar("input u32 hex", ImGuiDataType_U32,    &u32_v, inputs_step ? &u32_one : NULL, NULL, "%08X", flags);
1678
        ImGui::InputScalar("input s64",     ImGuiDataType_S64,    &s64_v, inputs_step ? &s64_one : NULL, NULL, NULL, flags);
1679
        ImGui::InputScalar("input u64",     ImGuiDataType_U64,    &u64_v, inputs_step ? &u64_one : NULL, NULL, NULL, flags);
1680
        ImGui::InputScalar("input float",   ImGuiDataType_Float,  &f32_v, inputs_step ? &f32_one : NULL, NULL, NULL, flags);
1681
        ImGui::InputScalar("input double",  ImGuiDataType_Double, &f64_v, inputs_step ? &f64_one : NULL, NULL, NULL, flags);
1682
1683
        ImGui::TreePop();
1684
    }
1685
}
1686
1687
//-----------------------------------------------------------------------------
1688
// [SECTION] DemoWindowWidgetsDisableBlocks()
1689
//-----------------------------------------------------------------------------
1690
1691
static void DemoWindowWidgetsDisableBlocks(ImGuiDemoWindowData* demo_data)
1692
{
1693
    if (ImGui::TreeNode("Disable Blocks"))
1694
    {
1695
        IMGUI_DEMO_MARKER("Widgets/Disable Blocks");
1696
        ImGui::Checkbox("Disable entire section above", &demo_data->DisableSections);
1697
        ImGui::SameLine(); HelpMarker("Demonstrate using BeginDisabled()/EndDisabled() across other sections.");
1698
        ImGui::TreePop();
1699
    }
1700
}
1701
1702
//-----------------------------------------------------------------------------
1703
// [SECTION] DemoWindowWidgetsDragAndDrop()
1704
//-----------------------------------------------------------------------------
1705
1706
static void DemoWindowWidgetsDragAndDrop()
1707
{
1708
    if (ImGui::TreeNode("Drag and Drop"))
1709
    {
1710
        IMGUI_DEMO_MARKER("Widgets/Drag and drop");
1711
        if (ImGui::TreeNode("Drag and drop in standard widgets"))
1712
        {
1713
            IMGUI_DEMO_MARKER("Widgets/Drag and drop/Standard widgets");
1714
            // ColorEdit widgets automatically act as drag source and drag target.
1715
            // They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F
1716
            // to allow your own widgets to use colors in their drag and drop interaction.
1717
            // Also see 'Demo->Widgets->Color/Picker Widgets->Palette' demo.
1718
            HelpMarker("You can drag from the color squares.");
1719
            static float col1[3] = { 1.0f, 0.0f, 0.2f };
1720
            static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
1721
            ImGui::ColorEdit3("color 1", col1);
1722
            ImGui::ColorEdit4("color 2", col2);
1723
            ImGui::TreePop();
1724
        }
1725
1726
        if (ImGui::TreeNode("Drag and drop to copy/swap items"))
1727
        {
1728
            IMGUI_DEMO_MARKER("Widgets/Drag and drop/Copy-swap items");
1729
            enum Mode
1730
            {
1731
                Mode_Copy,
1732
                Mode_Move,
1733
                Mode_Swap
1734
            };
1735
            static int mode = 0;
1736
            if (ImGui::RadioButton("Copy", mode == Mode_Copy)) { mode = Mode_Copy; } ImGui::SameLine();
1737
            if (ImGui::RadioButton("Move", mode == Mode_Move)) { mode = Mode_Move; } ImGui::SameLine();
1738
            if (ImGui::RadioButton("Swap", mode == Mode_Swap)) { mode = Mode_Swap; }
1739
            static const char* names[9] =
1740
            {
1741
                "Bobby", "Beatrice", "Betty",
1742
                "Brianna", "Barry", "Bernard",
1743
                "Bibi", "Blaine", "Bryn"
1744
            };
1745
            for (int n = 0; n < IM_COUNTOF(names); n++)
1746
            {
1747
                ImGui::PushID(n);
1748
                if ((n % 3) != 0)
1749
                    ImGui::SameLine();
1750
                ImGui::Button(names[n], ImVec2(60, 60));
1751
1752
                // Our buttons are both drag sources and drag targets here!
1753
                if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None))
1754
                {
1755
                    // Set payload to carry the index of our item (could be anything)
1756
                    ImGui::SetDragDropPayload("DND_DEMO_CELL", &n, sizeof(int));
1757
1758
                    // Display preview (could be anything, e.g. when dragging an image we could decide to display
1759
                    // the filename and a small preview of the image, etc.)
1760
                    if (mode == Mode_Copy) { ImGui::Text("Copy %s", names[n]); }
1761
                    if (mode == Mode_Move) { ImGui::Text("Move %s", names[n]); }
1762
                    if (mode == Mode_Swap) { ImGui::Text("Swap %s", names[n]); }
1763
                    ImGui::EndDragDropSource();
1764
                }
1765
                if (ImGui::BeginDragDropTarget())
1766
                {
1767
                    if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DND_DEMO_CELL"))
1768
                    {
1769
                        IM_ASSERT(payload->DataSize == sizeof(int));
1770
                        int payload_n = *(const int*)payload->Data;
1771
                        if (mode == Mode_Copy)
1772
                        {
1773
                            names[n] = names[payload_n];
1774
                        }
1775
                        if (mode == Mode_Move)
1776
                        {
1777
                            names[n] = names[payload_n];
1778
                            names[payload_n] = "";
1779
                        }
1780
                        if (mode == Mode_Swap)
1781
                        {
1782
                            const char* tmp = names[n];
1783
                            names[n] = names[payload_n];
1784
                            names[payload_n] = tmp;
1785
                        }
1786
                    }
1787
                    ImGui::EndDragDropTarget();
1788
                }
1789
                ImGui::PopID();
1790
            }
1791
            ImGui::TreePop();
1792
        }
1793
1794
        if (ImGui::TreeNode("Drag to reorder items (simple)"))
1795
        {
1796
            IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Drag to reorder items (simple)");
1797
            // FIXME: there is temporary (usually single-frame) ID Conflict during reordering as a same item may be submitting twice.
1798
            // This code was always slightly faulty but in a way which was not easily noticeable.
1799
            // Until we fix this, enable ImGuiItemFlags_AllowDuplicateId to disable detecting the issue.
1800
            ImGui::PushItemFlag(ImGuiItemFlags_AllowDuplicateId, true);
1801
1802
            // Simple reordering
1803
            HelpMarker(
1804
                "We don't use the drag and drop api at all here! "
1805
                "Instead we query when the item is held but not hovered, and order items accordingly.");
1806
            static const char* item_names[] = { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" };
1807
            for (int n = 0; n < IM_COUNTOF(item_names); n++)
1808
            {
1809
                const char* item = item_names[n];
1810
                ImGui::Selectable(item);
1811
1812
                if (ImGui::IsItemActive() && !ImGui::IsItemHovered())
1813
                {
1814
                    int n_next = n + (ImGui::GetMouseDragDelta(0).y < 0.f ? -1 : 1);
1815
                    if (n_next >= 0 && n_next < IM_COUNTOF(item_names))
1816
                    {
1817
                        item_names[n] = item_names[n_next];
1818
                        item_names[n_next] = item;
1819
                        ImGui::ResetMouseDragDelta();
1820
                    }
1821
                }
1822
            }
1823
1824
            ImGui::PopItemFlag();
1825
            ImGui::TreePop();
1826
        }
1827
1828
        if (ImGui::TreeNode("Tooltip at target location"))
1829
        {
1830
            IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Tooltip at target location");
1831
            for (int n = 0; n < 2; n++)
1832
            {
1833
                // Drop targets
1834
                ImGui::Button(n ? "drop here##1" : "drop here##0");
1835
                if (ImGui::BeginDragDropTarget())
1836
                {
1837
                    ImGuiDragDropFlags drop_target_flags = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoPreviewTooltip;
1838
                    if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, drop_target_flags))
1839
                    {
1840
                        IM_UNUSED(payload);
1841
                        ImGui::SetMouseCursor(ImGuiMouseCursor_NotAllowed);
1842
                        ImGui::SetTooltip("Cannot drop here!");
1843
                    }
1844
                    ImGui::EndDragDropTarget();
1845
                }
1846
1847
                // Drop source
1848
                static ImVec4 col4 = { 1.0f, 0.0f, 0.2f, 1.0f };
1849
                if (n == 0)
1850
                    ImGui::ColorButton("drag me", col4);
1851
1852
            }
1853
            ImGui::TreePop();
1854
        }
1855
1856
        ImGui::TreePop();
1857
    }
1858
}
1859
1860
//-----------------------------------------------------------------------------
1861
// [SECTION] DemoWindowWidgetsDragsAndSliders()
1862
//-----------------------------------------------------------------------------
1863
1864
static void DemoWindowWidgetsDragsAndSliders()
1865
{
1866
    if (ImGui::TreeNode("Drag/Slider Flags"))
1867
    {
1868
        IMGUI_DEMO_MARKER("Widgets/Drag and Slider Flags");
1869
        // Demonstrate using advanced flags for DragXXX and SliderXXX functions. Note that the flags are the same!
1870
        static ImGuiSliderFlags flags = ImGuiSliderFlags_None;
1871
        ImGui::CheckboxFlags("ImGuiSliderFlags_AlwaysClamp", &flags, ImGuiSliderFlags_AlwaysClamp);
1872
        ImGui::CheckboxFlags("ImGuiSliderFlags_ClampOnInput", &flags, ImGuiSliderFlags_ClampOnInput);
1873
        ImGui::SameLine(); HelpMarker("Clamp value to min/max bounds when input manually with Ctrl+Click. By default Ctrl+Click allows going out of bounds.");
1874
        ImGui::CheckboxFlags("ImGuiSliderFlags_ClampZeroRange", &flags, ImGuiSliderFlags_ClampZeroRange);
1875
        ImGui::SameLine(); HelpMarker("Clamp even if min==max==0.0f. Otherwise DragXXX functions don't clamp.");
1876
        ImGui::CheckboxFlags("ImGuiSliderFlags_Logarithmic", &flags, ImGuiSliderFlags_Logarithmic);
1877
        ImGui::SameLine(); HelpMarker("Enable logarithmic editing (more precision for small values).");
1878
        ImGui::CheckboxFlags("ImGuiSliderFlags_NoRoundToFormat", &flags, ImGuiSliderFlags_NoRoundToFormat);
1879
        ImGui::SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits).");
1880
        ImGui::CheckboxFlags("ImGuiSliderFlags_NoInput", &flags, ImGuiSliderFlags_NoInput);
1881
        ImGui::SameLine(); HelpMarker("Disable Ctrl+Click or Enter key allowing to input text directly into the widget.");
1882
        ImGui::CheckboxFlags("ImGuiSliderFlags_NoSpeedTweaks", &flags, ImGuiSliderFlags_NoSpeedTweaks);
1883
        ImGui::SameLine(); HelpMarker("Disable keyboard modifiers altering tweak speed. Useful if you want to alter tweak speed yourself based on your own logic.");
1884
        ImGui::CheckboxFlags("ImGuiSliderFlags_WrapAround", &flags, ImGuiSliderFlags_WrapAround);
1885
        ImGui::SameLine(); HelpMarker("Enable wrapping around from max to min and from min to max (only supported by DragXXX() functions)");
1886
        ImGui::CheckboxFlags("ImGuiSliderFlags_ColorMarkers", &flags, ImGuiSliderFlags_ColorMarkers);
1887
1888
        // Drags
1889
        static float drag_f = 0.5f;
1890
        static float drag_f4[4];
1891
        static int drag_i = 50;
1892
        ImGui::Text("Underlying float value: %f", drag_f);
1893
        ImGui::DragFloat("DragFloat (0 -> 1)", &drag_f, 0.005f, 0.0f, 1.0f, "%.3f", flags);
1894
        ImGui::DragFloat("DragFloat (0 -> +inf)", &drag_f, 0.005f, 0.0f, FLT_MAX, "%.3f", flags);
1895
        ImGui::DragFloat("DragFloat (-inf -> 1)", &drag_f, 0.005f, -FLT_MAX, 1.0f, "%.3f", flags);
1896
        ImGui::DragFloat("DragFloat (-inf -> +inf)", &drag_f, 0.005f, -FLT_MAX, +FLT_MAX, "%.3f", flags);
1897
        //ImGui::DragFloat("DragFloat (0 -> 0)", &drag_f, 0.005f, 0.0f, 0.0f, "%.3f", flags);           // To test ClampZeroRange
1898
        //ImGui::DragFloat("DragFloat (100 -> 100)", &drag_f, 0.005f, 100.0f, 100.0f, "%.3f", flags);
1899
        ImGui::DragInt("DragInt (0 -> 100)", &drag_i, 0.5f, 0, 100, "%d", flags);
1900
        ImGui::DragFloat4("DragFloat4 (0 -> 1)", drag_f4, 0.005f, 0.0f, 1.0f, "%.3f", flags); // Multi-component item, mostly here to document the effect of ImGuiSliderFlags_ColorMarkers.
1901
1902
        // Sliders
1903
        static float slider_f = 0.5f;
1904
        static float slider_f4[4];
1905
        static int slider_i = 50;
1906
        const ImGuiSliderFlags flags_for_sliders = (flags & ~ImGuiSliderFlags_WrapAround);
1907
        ImGui::Text("Underlying float value: %f", slider_f);
1908
        ImGui::SliderFloat("SliderFloat (0 -> 1)", &slider_f, 0.0f, 1.0f, "%.3f", flags_for_sliders);
1909
        ImGui::SliderInt("SliderInt (0 -> 100)", &slider_i, 0, 100, "%d", flags_for_sliders);
1910
        ImGui::SliderFloat4("SliderFloat4 (0 -> 1)", slider_f4, 0.0f, 1.0f, "%.3f", flags); // Multi-component item, mostly here to document the effect of ImGuiSliderFlags_ColorMarkers.
1911
1912
        ImGui::TreePop();
1913
    }
1914
}
1915
1916
//-----------------------------------------------------------------------------
1917
// [SECTION] DemoWindowWidgetsFonts()
1918
//-----------------------------------------------------------------------------
1919
1920
static void DemoWindowWidgetsFonts()
1921
{
1922
    if (ImGui::TreeNode("Fonts"))
1923
    {
1924
        IMGUI_DEMO_MARKER("Widgets/Fonts");
1925
        ImFontAtlas* atlas = ImGui::GetIO().Fonts;
1926
        ImGui::ShowFontAtlas(atlas);
1927
        // FIXME-NEWATLAS: Provide a demo to add/create a procedural font?
1928
        ImGui::TreePop();
1929
    }
1930
}
1931
1932
//-----------------------------------------------------------------------------
1933
// [SECTION] DemoWindowWidgetsImages()
1934
//-----------------------------------------------------------------------------
1935
1936
static void DemoWindowWidgetsImages()
1937
{
1938
    if (ImGui::TreeNode("Images"))
1939
    {
1940
        IMGUI_DEMO_MARKER("Widgets/Images");
1941
        ImGuiIO& io = ImGui::GetIO();
1942
        ImGui::TextWrapped(
1943
            "Below we are displaying the font texture (which is the only texture we have access to in this demo). "
1944
            "Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. "
1945
            "Hover the texture for a zoomed view!");
1946
1947
        // Below we are displaying the font texture because it is the only texture we have access to inside the demo!
1948
        // Read description about ImTextureID/ImTextureRef and FAQ for details about texture identifiers.
1949
        // If you use one of the default imgui_impl_XXXX.cpp rendering backend, they all have comments at the top
1950
        // of their respective source file to specify what they are using as texture identifier, for example:
1951
        // - The imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer.
1952
        // - The imgui_impl_opengl3.cpp renderer expect a GLuint OpenGL texture identifier, etc.
1953
        // So with the DirectX11 backend, you call ImGui::Image() with a 'ID3D11ShaderResourceView*' cast to ImTextureID.
1954
        // - If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers
1955
        //   to ImGui::Image(), and gather width/height through your own functions, etc.
1956
        // - You can use ShowMetricsWindow() to inspect the draw data that are being passed to your renderer,
1957
        //   it will help you debug issues if you are confused about it.
1958
        // - Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage().
1959
        // - Read https://github.com/ocornut/imgui/blob/master/docs/FAQ.md
1960
        // - Read https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
1961
1962
        // Grab the current texture identifier used by the font atlas.
1963
        ImFontAtlas* atlas = io.Fonts;
1964
        ImTextureRef my_tex_id = atlas->TexRef;
1965
        float my_tex_w = (float)atlas->TexData->Width; // Regular user code should never have to care about TexData-> fields, but since we want to display the entire texture here, we pull Width/Height from it.
1966
        float my_tex_h = (float)atlas->TexData->Height;
1967
        ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h);
1968
1969
        // Basic drawing
1970
        ImGui::SeparatorText("Image()/ImageWithBg() function");
1971
        ImVec2 uv_min = ImVec2(0.0f, 0.0f); // Top-left
1972
        ImVec2 uv_max = ImVec2(1.0f, 1.0f); // Lower-right
1973
        ImGui::PushStyleVar(ImGuiStyleVar_ImageBorderSize, IM_MAX(1.0f, ImGui::GetStyle().ImageBorderSize));
1974
        ImGui::ImageWithBg(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, ImVec4(0.0f, 0.0f, 0.0f, 1.0f));
1975
        ImGui::PopStyleVar();
1976
1977
        // Fancy widget
1978
        ImGui::SeparatorText("Interactive Image Viewer");
1979
        static ExampleImageViewerData image_viewer;
1980
        ImVec2 canvas_size(ImGui::GetContentRegionAvail().x, my_tex_h * 2.0f);
1981
        ExampleImageViewer_DrawOptions(&image_viewer);
1982
        ExampleImageViewer_DrawCanvas(&image_viewer, canvas_size, my_tex_id, (int)my_tex_w, (int)my_tex_h);
1983
1984
        IMGUI_DEMO_MARKER("Widgets/Images/Textured buttons");
1985
        ImGui::SeparatorText("Textured Buttons");
1986
        ImGui::TextWrapped("And now some textured buttons..");
1987
        static int pressed_count = 0;
1988
        for (int i = 0; i < 8; i++)
1989
        {
1990
            // UV coordinates are often (0.0f, 0.0f) and (1.0f, 1.0f) to display an entire textures.
1991
            // Here are trying to display only a 32x32 pixels area of the texture, hence the UV computation.
1992
            // Read about UV coordinates here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
1993
            ImGui::PushID(i);
1994
            if (i > 0)
1995
                ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(i - 1.0f, i - 1.0f));
1996
            ImVec2 size = ImVec2(32.0f, 32.0f);                         // Size of the image we want to make visible
1997
            ImVec2 uv0 = ImVec2(0.0f, 0.0f);                            // UV coordinates for lower-left
1998
            ImVec2 uv1 = ImVec2(32.0f / my_tex_w, 32.0f / my_tex_h);    // UV coordinates for (32,32) in our texture
1999
            ImVec4 bg_col = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);             // Black background
2000
            ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);           // No tint
2001
            if (ImGui::ImageButton("", my_tex_id, size, uv0, uv1, bg_col, tint_col))
2002
                pressed_count += 1;
2003
            if (i > 0)
2004
                ImGui::PopStyleVar();
2005
            ImGui::PopID();
2006
            ImGui::SameLine();
2007
        }
2008
        ImGui::NewLine();
2009
        ImGui::Text("Pressed %d times.", pressed_count);
2010
        ImGui::TreePop();
2011
    }
2012
}
2013
2014
//-----------------------------------------------------------------------------
2015
// [SECTION] DemoWindowWidgetsListBoxes()
2016
//-----------------------------------------------------------------------------
2017
2018
static void DemoWindowWidgetsListBoxes()
2019
{
2020
    if (ImGui::TreeNode("List Boxes"))
2021
    {
2022
        IMGUI_DEMO_MARKER("Widgets/List Boxes");
2023
        // BeginListBox() is essentially a thin wrapper to using BeginChild()/EndChild()
2024
        // using the ImGuiChildFlags_FrameStyle flag for stylistic changes + displaying a label.
2025
        // You may be tempted to simply use BeginChild() directly. However note that BeginChild() requires EndChild()
2026
        // to always be called (inconsistent with BeginListBox()/EndListBox()).
2027
2028
        // Using the generic BeginListBox() API, you have full control over how to display the combo contents.
2029
        // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
2030
        // stored in the object itself, etc.)
2031
        const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" };
2032
        static int item_selected_idx = 0; // Here we store our selected data as an index.
2033
2034
        static bool item_highlight = false;
2035
        int item_highlighted_idx = -1; // Here we store our highlighted data as an index.
2036
        ImGui::Checkbox("Highlight hovered item in second listbox", &item_highlight);
2037
2038
        if (ImGui::BeginListBox("listbox 1"))
2039
        {
2040
            for (int n = 0; n < IM_COUNTOF(items); n++)
2041
            {
2042
                const bool is_selected = (item_selected_idx == n);
2043
                if (ImGui::Selectable(items[n], is_selected))
2044
                    item_selected_idx = n;
2045
2046
                if (item_highlight && ImGui::IsItemHovered())
2047
                    item_highlighted_idx = n;
2048
2049
                // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
2050
                if (is_selected)
2051
                    ImGui::SetItemDefaultFocus();
2052
            }
2053
            ImGui::EndListBox();
2054
        }
2055
        ImGui::SameLine(); HelpMarker("Here we are sharing selection state between both boxes.");
2056
2057
        // Custom size: use all width, 5 items tall
2058
        ImGui::Text("Full-width:");
2059
        if (ImGui::BeginListBox("##listbox 2", ImVec2(-FLT_MIN, 5 * ImGui::GetTextLineHeightWithSpacing())))
2060
        {
2061
            for (int n = 0; n < IM_COUNTOF(items); n++)
2062
            {
2063
                bool is_selected = (item_selected_idx == n);
2064
                ImGuiSelectableFlags flags = (item_highlighted_idx == n) ? ImGuiSelectableFlags_Highlight : 0;
2065
                if (ImGui::Selectable(items[n], is_selected, flags))
2066
                    item_selected_idx = n;
2067
2068
                // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
2069
                if (is_selected)
2070
                    ImGui::SetItemDefaultFocus();
2071
            }
2072
            ImGui::EndListBox();
2073
        }
2074
2075
        ImGui::TreePop();
2076
    }
2077
}
2078
2079
//-----------------------------------------------------------------------------
2080
// [SECTION] DemoWindowWidgetsMultiComponents()
2081
//-----------------------------------------------------------------------------
2082
2083
static void DemoWindowWidgetsMultiComponents()
2084
{
2085
    if (ImGui::TreeNode("Multi-component Widgets"))
2086
    {
2087
        IMGUI_DEMO_MARKER("Widgets/Multi-component Widgets");
2088
        static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f };
2089
        static int vec4i[4] = { 1, 5, 100, 255 };
2090
2091
        static ImGuiSliderFlags flags = 0;
2092
        ImGui::CheckboxFlags("ImGuiSliderFlags_ColorMarkers", &flags, ImGuiSliderFlags_ColorMarkers); // Only passing this to Drag/Sliders
2093
2094
        ImGui::SeparatorText("2-wide");
2095
        ImGui::InputFloat2("input float2", vec4f);
2096
        ImGui::InputInt2("input int2", vec4i);
2097
        ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f, NULL, flags);
2098
        ImGui::DragInt2("drag int2", vec4i, 1, 0, 255, NULL, flags);
2099
        ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f, NULL, flags);
2100
        ImGui::SliderInt2("slider int2", vec4i, 0, 255, NULL, flags);
2101
2102
        ImGui::SeparatorText("3-wide");
2103
        ImGui::InputFloat3("input float3", vec4f);
2104
        ImGui::InputInt3("input int3", vec4i);
2105
        ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f, NULL, flags);
2106
        ImGui::DragInt3("drag int3", vec4i, 1, 0, 255, NULL, flags);
2107
        ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f, NULL, flags);
2108
        ImGui::SliderInt3("slider int3", vec4i, 0, 255, NULL, flags);
2109
2110
        ImGui::SeparatorText("4-wide");
2111
        ImGui::InputFloat4("input float4", vec4f);
2112
        ImGui::InputInt4("input int4", vec4i);
2113
        ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f, NULL, flags);
2114
        ImGui::DragInt4("drag int4", vec4i, 1, 0, 255, NULL, flags);
2115
        ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f, NULL, flags);
2116
        ImGui::SliderInt4("slider int4", vec4i, 0, 255, NULL, flags);
2117
2118
        ImGui::SeparatorText("Ranges");
2119
        static float begin = 10, end = 90;
2120
        static int begin_i = 100, end_i = 1000;
2121
        ImGui::DragFloatRange2("range float", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%", ImGuiSliderFlags_AlwaysClamp);
2122
        ImGui::DragIntRange2("range int", &begin_i, &end_i, 5, 0, 1000, "Min: %d units", "Max: %d units");
2123
        ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %d units", "Max: %d units");
2124
2125
        ImGui::TreePop();
2126
    }
2127
}
2128
2129
//-----------------------------------------------------------------------------
2130
// [SECTION] DemoWindowWidgetsPlotting()
2131
//-----------------------------------------------------------------------------
2132
2133
static void DemoWindowWidgetsPlotting()
2134
{
2135
    // Plot/Graph widgets are not very good.
2136
// Consider using a third-party library such as ImPlot: https://github.com/epezent/implot
2137
// (see others https://github.com/ocornut/imgui/wiki/Useful-Extensions)
2138
    if (ImGui::TreeNode("Plotting"))
2139
    {
2140
        IMGUI_DEMO_MARKER("Widgets/Plotting");
2141
        ImGui::Text("Need better plotting and graphing? Consider using ImPlot:");
2142
        ImGui::TextLinkOpenURL("https://github.com/epezent/implot");
2143
        ImGui::Separator();
2144
2145
        static bool animate = true;
2146
        ImGui::Checkbox("Animate", &animate);
2147
2148
        // Plot as lines and plot as histogram
2149
        static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
2150
        ImGui::PlotLines("Frame Times", arr, IM_COUNTOF(arr));
2151
        ImGui::PlotHistogram("Histogram", arr, IM_COUNTOF(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0, 80.0f));
2152
        //ImGui::SameLine(); HelpMarker("Consider using ImPlot instead!");
2153
2154
        // Fill an array of contiguous float values to plot
2155
        // Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float
2156
        // and the sizeof() of your structure in the "stride" parameter.
2157
        static float values[90] = {};
2158
        static int values_offset = 0;
2159
        static double refresh_time = 0.0;
2160
        if (!animate || refresh_time == 0.0)
2161
            refresh_time = ImGui::GetTime();
2162
        while (refresh_time < ImGui::GetTime()) // Create data at fixed 60 Hz rate for the demo
2163
        {
2164
            static float phase = 0.0f;
2165
            values[values_offset] = cosf(phase);
2166
            values_offset = (values_offset + 1) % IM_COUNTOF(values);
2167
            phase += 0.10f * values_offset;
2168
            refresh_time += 1.0f / 60.0f;
2169
        }
2170
2171
        // Plots can display overlay texts
2172
        // (in this example, we will display an average value)
2173
        {
2174
            float average = 0.0f;
2175
            for (int n = 0; n < IM_COUNTOF(values); n++)
2176
                average += values[n];
2177
            average /= (float)IM_COUNTOF(values);
2178
            char overlay[32];
2179
            sprintf(overlay, "avg %f", average);
2180
            ImGui::PlotLines("Lines", values, IM_COUNTOF(values), values_offset, overlay, -1.0f, 1.0f, ImVec2(0, 80.0f));
2181
        }
2182
2183
        // Use functions to generate output
2184
        // FIXME: This is actually VERY awkward because current plot API only pass in indices.
2185
        // We probably want an API passing floats and user provide sample rate/count.
2186
        struct Funcs
2187
        {
2188
            static float Sin(void*, int i) { return sinf(i * 0.1f); }
2189
            static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; }
2190
        };
2191
        static int func_type = 0, display_count = 70;
2192
        ImGui::SeparatorText("Functions");
2193
        ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
2194
        ImGui::Combo("func", &func_type, "Sin\0Saw\0");
2195
        ImGui::SameLine();
2196
        ImGui::SliderInt("Sample count", &display_count, 1, 400);
2197
        float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw;
2198
        ImGui::PlotLines("Lines##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
2199
        ImGui::PlotHistogram("Histogram##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
2200
2201
        ImGui::TreePop();
2202
    }
2203
}
2204
2205
//-----------------------------------------------------------------------------
2206
// [SECTION] DemoWindowWidgetsProgressBars()
2207
//-----------------------------------------------------------------------------
2208
2209
static void DemoWindowWidgetsProgressBars()
2210
{
2211
    if (ImGui::TreeNode("Progress Bars"))
2212
    {
2213
        IMGUI_DEMO_MARKER("Widgets/Progress Bars");
2214
        // Animate a simple progress bar
2215
        static float progress_accum = 0.0f, progress_dir = 1.0f;
2216
        progress_accum += progress_dir * 0.4f * ImGui::GetIO().DeltaTime;
2217
        if (progress_accum >= +1.1f) { progress_accum = +1.1f; progress_dir *= -1.0f; }
2218
        if (progress_accum <= -0.1f) { progress_accum = -0.1f; progress_dir *= -1.0f; }
2219
2220
        const float progress = IM_CLAMP(progress_accum, 0.0f, 1.0f);
2221
2222
        // Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width,
2223
        // or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth.
2224
        ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f));
2225
        ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
2226
        ImGui::Text("Progress Bar");
2227
2228
        char buf[32];
2229
        sprintf(buf, "%d/%d", (int)(progress * 1753), 1753);
2230
        ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), buf);
2231
2232
        // Pass an animated negative value, e.g. -1.0f * (float)ImGui::GetTime() is the recommended value.
2233
        // Adjust the factor if you want to adjust the animation speed.
2234
        ImGui::ProgressBar(-1.0f * (float)ImGui::GetTime(), ImVec2(0.0f, 0.0f), "Searching..");
2235
        ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
2236
        ImGui::Text("Indeterminate");
2237
2238
        ImGui::TreePop();
2239
    }
2240
}
2241
2242
//-----------------------------------------------------------------------------
2243
// [SECTION] DemoWindowWidgetsQueryingStatuses()
2244
//-----------------------------------------------------------------------------
2245
2246
static void DemoWindowWidgetsQueryingStatuses()
2247
{
2248
    if (ImGui::TreeNode("Querying Item Status (Edited/Active/Hovered etc.)"))
2249
    {
2250
        IMGUI_DEMO_MARKER("Widgets/Querying Item Status (Edited,Active,Hovered etc.)");
2251
        // Select an item type
2252
        const char* item_names[] =
2253
        {
2254
            "Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputTextMultiline", "InputFloat",
2255
            "InputFloat3", "ColorEdit4", "Selectable", "MenuItem", "TreeNode", "TreeNode (w/ double-click)", "Combo", "ListBox"
2256
        };
2257
        static int item_type = 4;
2258
        static bool item_disabled = false;
2259
        ImGui::Combo("Item Type", &item_type, item_names, IM_COUNTOF(item_names), IM_COUNTOF(item_names));
2260
        ImGui::SameLine();
2261
        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().");
2262
        ImGui::Checkbox("Item Disabled", &item_disabled);
2263
2264
        // Submit selected items so we can query their status in the code following it.
2265
        bool ret = false;
2266
        static bool b = false;
2267
        static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f };
2268
        static char str[16] = {};
2269
        if (item_disabled)
2270
            ImGui::BeginDisabled(true);
2271
        if (item_type == 0) { ImGui::Text("ITEM: Text"); }                                              // Testing text items with no identifier/interaction
2272
        if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); }                                    // Testing button
2273
        if (item_type == 2) { ImGui::PushItemFlag(ImGuiItemFlags_ButtonRepeat, true); ret = ImGui::Button("ITEM: Button"); ImGui::PopItemFlag(); } // Testing button (with repeater)
2274
        if (item_type == 3) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); }                            // Testing checkbox
2275
        if (item_type == 4) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); }   // Testing basic item
2276
        if (item_type == 5) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_COUNTOF(str)); }  // Testing input text (which handles tabbing)
2277
        if (item_type == 6) { ret = ImGui::InputTextMultiline("ITEM: InputTextMultiline", &str[0], IM_COUNTOF(str)); } // Testing input text (which uses a child window)
2278
        if (item_type == 7) { ret = ImGui::InputFloat("ITEM: InputFloat", col4f, 1.0f); }               // Testing +/- buttons on scalar input
2279
        if (item_type == 8) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); }                   // Testing multi-component items (IsItemXXX flags are reported merged)
2280
        if (item_type == 9) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); }                     // Testing multi-component items (IsItemXXX flags are reported merged)
2281
        if (item_type == 10) { ret = ImGui::Selectable("ITEM: Selectable"); }                            // Testing selectable item
2282
        if (item_type == 11) { ret = ImGui::MenuItem("ITEM: MenuItem"); }                                // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy)
2283
        if (item_type == 12) { ret = ImGui::TreeNode("ITEM: TreeNode"); if (ret) ImGui::TreePop(); }     // Testing tree node
2284
        if (item_type == 13) { ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy.
2285
        if (item_type == 14) { const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::Combo("ITEM: Combo", &current, items, IM_COUNTOF(items)); }
2286
        if (item_type == 15) { const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", &current, items, IM_COUNTOF(items), IM_COUNTOF(items)); }
2287
2288
        bool hovered_delay_none = ImGui::IsItemHovered();
2289
        bool hovered_delay_stationary = ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary);
2290
        bool hovered_delay_short = ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort);
2291
        bool hovered_delay_normal = ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal);
2292
        bool hovered_delay_tooltip = ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip); // = Normal + Stationary
2293
2294
        // Display the values of IsItemHovered() and other common item state functions.
2295
        // Note that the ImGuiHoveredFlags_XXX flags can be combined.
2296
        // Because BulletText is an item itself and that would affect the output of IsItemXXX functions,
2297
        // we query every state in a single call to avoid storing them and to simplify the code.
2298
        ImGui::BulletText(
2299
            "Return value = %d\n"
2300
            "IsItemFocused() = %d\n"
2301
            "IsItemHovered() = %d\n"
2302
            "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n"
2303
            "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n"
2304
            "IsItemHovered(_AllowWhenOverlappedByItem) = %d\n"
2305
            "IsItemHovered(_AllowWhenOverlappedByWindow) = %d\n"
2306
            "IsItemHovered(_AllowWhenDisabled) = %d\n"
2307
            "IsItemHovered(_RectOnly) = %d\n"
2308
            "IsItemActive() = %d\n"
2309
            "IsItemEdited() = %d\n"
2310
            "IsItemActivated() = %d\n"
2311
            "IsItemDeactivated() = %d\n"
2312
            "IsItemDeactivatedAfterEdit() = %d\n"
2313
            "IsItemVisible() = %d\n"
2314
            "IsItemClicked() = %d\n"
2315
            "IsItemToggledOpen() = %d\n"
2316
            "GetItemRectMin() = (%.1f, %.1f)\n"
2317
            "GetItemRectMax() = (%.1f, %.1f)\n"
2318
            "GetItemRectSize() = (%.1f, %.1f)",
2319
            ret,
2320
            ImGui::IsItemFocused(),
2321
            ImGui::IsItemHovered(),
2322
            ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2323
            ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
2324
            ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlappedByItem),
2325
            ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlappedByWindow),
2326
            ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled),
2327
            ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly),
2328
            ImGui::IsItemActive(),
2329
            ImGui::IsItemEdited(),
2330
            ImGui::IsItemActivated(),
2331
            ImGui::IsItemDeactivated(),
2332
            ImGui::IsItemDeactivatedAfterEdit(),
2333
            ImGui::IsItemVisible(),
2334
            ImGui::IsItemClicked(),
2335
            ImGui::IsItemToggledOpen(),
2336
            ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y,
2337
            ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y,
2338
            ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y
2339
        );
2340
        ImGui::BulletText(
2341
            "with Hovering Delay or Stationary test:\n"
2342
            "IsItemHovered() = %d\n"
2343
            "IsItemHovered(_Stationary) = %d\n"
2344
            "IsItemHovered(_DelayShort) = %d\n"
2345
            "IsItemHovered(_DelayNormal) = %d\n"
2346
            "IsItemHovered(_Tooltip) = %d",
2347
            hovered_delay_none, hovered_delay_stationary, hovered_delay_short, hovered_delay_normal, hovered_delay_tooltip);
2348
2349
        if (item_disabled)
2350
            ImGui::EndDisabled();
2351
2352
        char buf[1] = "";
2353
        ImGui::InputText("unused", buf, IM_COUNTOF(buf), ImGuiInputTextFlags_ReadOnly);
2354
        ImGui::SameLine();
2355
        HelpMarker("This widget is only here to be able to tab-out of the widgets above and see e.g. Deactivated() status.");
2356
2357
        ImGui::TreePop();
2358
    }
2359
2360
    if (ImGui::TreeNode("Querying Window Status (Focused/Hovered etc.)"))
2361
    {
2362
        IMGUI_DEMO_MARKER("Widgets/Querying Window Status (Focused,Hovered etc.)");
2363
        static bool embed_all_inside_a_child_window = false;
2364
        ImGui::Checkbox("Embed everything inside a child window for testing _RootWindow flag.", &embed_all_inside_a_child_window);
2365
        if (embed_all_inside_a_child_window)
2366
            ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20.0f), ImGuiChildFlags_Borders);
2367
2368
        // Testing IsWindowFocused() function with its various flags.
2369
        ImGui::BulletText(
2370
            "IsWindowFocused() = %d\n"
2371
            "IsWindowFocused(_ChildWindows) = %d\n"
2372
            "IsWindowFocused(_ChildWindows|_NoPopupHierarchy) = %d\n"
2373
            "IsWindowFocused(_ChildWindows|_DockHierarchy) = %d\n"
2374
            "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n"
2375
            "IsWindowFocused(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n"
2376
            "IsWindowFocused(_ChildWindows|_RootWindow|_DockHierarchy) = %d\n"
2377
            "IsWindowFocused(_RootWindow) = %d\n"
2378
            "IsWindowFocused(_RootWindow|_NoPopupHierarchy) = %d\n"
2379
            "IsWindowFocused(_RootWindow|_DockHierarchy) = %d\n"
2380
            "IsWindowFocused(_AnyWindow) = %d\n",
2381
            ImGui::IsWindowFocused(),
2382
            ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows),
2383
            ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_NoPopupHierarchy),
2384
            ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_DockHierarchy),
2385
            ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow),
2386
            ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy),
2387
            ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_DockHierarchy),
2388
            ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow),
2389
            ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy),
2390
            ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_DockHierarchy),
2391
            ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow));
2392
2393
        // Testing IsWindowHovered() function with its various flags.
2394
        ImGui::BulletText(
2395
            "IsWindowHovered() = %d\n"
2396
            "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n"
2397
            "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n"
2398
            "IsWindowHovered(_ChildWindows) = %d\n"
2399
            "IsWindowHovered(_ChildWindows|_NoPopupHierarchy) = %d\n"
2400
            "IsWindowHovered(_ChildWindows|_DockHierarchy) = %d\n"
2401
            "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n"
2402
            "IsWindowHovered(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n"
2403
            "IsWindowHovered(_ChildWindows|_RootWindow|_DockHierarchy) = %d\n"
2404
            "IsWindowHovered(_RootWindow) = %d\n"
2405
            "IsWindowHovered(_RootWindow|_NoPopupHierarchy) = %d\n"
2406
            "IsWindowHovered(_RootWindow|_DockHierarchy) = %d\n"
2407
            "IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n"
2408
            "IsWindowHovered(_AnyWindow) = %d\n"
2409
            "IsWindowHovered(_Stationary) = %d\n",
2410
            ImGui::IsWindowHovered(),
2411
            ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2412
            ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
2413
            ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows),
2414
            ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy),
2415
            ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_DockHierarchy),
2416
            ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow),
2417
            ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy),
2418
            ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_DockHierarchy),
2419
            ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow),
2420
            ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy),
2421
            ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_DockHierarchy),
2422
            ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2423
            ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow),
2424
            ImGui::IsWindowHovered(ImGuiHoveredFlags_Stationary));
2425
2426
        ImGui::BeginChild("child", ImVec2(0, 50), ImGuiChildFlags_Borders);
2427
        ImGui::Text("This is another child window for testing the _ChildWindows flag.");
2428
        ImGui::EndChild();
2429
        if (embed_all_inside_a_child_window)
2430
            ImGui::EndChild();
2431
2432
        // Calling IsItemHovered() after begin returns the hovered status of the title bar.
2433
        // This is useful in particular if you want to create a context menu associated to the title bar of a window.
2434
        // This will also work when docked into a Tab (the Tab replace the Title Bar and guarantee the same properties).
2435
        static bool test_window = false;
2436
        ImGui::Checkbox("Hovered/Active tests after Begin() for title bar testing", &test_window);
2437
        if (test_window)
2438
        {
2439
            // FIXME-DOCK: This window cannot be docked within the ImGui Demo window, this will cause a feedback loop and get them stuck.
2440
            // Could we fix this through an ImGuiWindowClass feature? Or an API call to tag our parent as "don't skip items"?
2441
            ImGui::Begin("Title bar Hovered/Active tests", &test_window);
2442
            if (ImGui::BeginPopupContextItem()) // <-- This is using IsItemHovered()
2443
            {
2444
                if (ImGui::MenuItem("Close")) { test_window = false; }
2445
                ImGui::EndPopup();
2446
            }
2447
            ImGui::Text(
2448
                "IsItemHovered() after begin = %d (== is title bar hovered)\n"
2449
                "IsItemActive() after begin = %d (== is window being clicked/moved)\n",
2450
                ImGui::IsItemHovered(), ImGui::IsItemActive());
2451
            ImGui::End();
2452
        }
2453
2454
        ImGui::TreePop();
2455
    }
2456
}
2457
2458
//-----------------------------------------------------------------------------
2459
// [SECTION] DemoWindowWidgetsSelectables()
2460
//-----------------------------------------------------------------------------
2461
2462
static void DemoWindowWidgetsSelectables()
2463
{
2464
    //ImGui::SetNextItemOpen(true, ImGuiCond_Once);
2465
    if (ImGui::TreeNode("Selectables"))
2466
    {
2467
        IMGUI_DEMO_MARKER("Widgets/Selectables");
2468
        // Selectable() has 2 overloads:
2469
        // - The one taking "bool selected" as a read-only selection information.
2470
        //   When Selectable() has been clicked it returns true and you can alter selection state accordingly.
2471
        // - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases)
2472
        // The earlier is more flexible, as in real application your selection may be stored in many different ways
2473
        // and not necessarily inside a bool value (e.g. in flags within objects, as an external list, etc).
2474
        IMGUI_DEMO_MARKER("Widgets/Selectables/Basic");
2475
        if (ImGui::TreeNode("Basic"))
2476
        {
2477
            static bool selection[5] = { false, true, false, false };
2478
            ImGui::Selectable("1. I am selectable", &selection[0]);
2479
            ImGui::Selectable("2. I am selectable", &selection[1]);
2480
            ImGui::Selectable("3. I am selectable", &selection[2]);
2481
            if (ImGui::Selectable("4. I am double clickable", selection[3], ImGuiSelectableFlags_AllowDoubleClick))
2482
                if (ImGui::IsMouseDoubleClicked(0))
2483
                    selection[3] = !selection[3];
2484
            ImGui::TreePop();
2485
        }
2486
2487
        IMGUI_DEMO_MARKER("Widgets/Selectables/Rendering more items on the same line");
2488
        if (ImGui::TreeNode("Multiple items on the same line"))
2489
        {
2490
            IMGUI_DEMO_MARKER("Widgets/Selectables/Multiple items on the same line");
2491
            // - Using SetNextItemAllowOverlap()
2492
            // - Using the Selectable() override that takes "bool* p_selected" parameter, the bool value is toggled automatically.
2493
            {
2494
                static bool selected[3] = {};
2495
                ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("main.c", &selected[0]); ImGui::SameLine(); ImGui::SmallButton("Link 1");
2496
                ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("hello.cpp", &selected[1]); ImGui::SameLine(); ImGui::SmallButton("Link 2");
2497
                ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("hello.h", &selected[2]); ImGui::SameLine(); ImGui::SmallButton("Link 3");
2498
            }
2499
2500
            // (2)
2501
            // - Using ImGuiSelectableFlags_AllowOverlap is a shortcut for calling SetNextItemAllowOverlap()
2502
            // - No visible label, display contents inside the selectable bounds.
2503
            // - We don't maintain actual selection in this example to keep things simple.
2504
            ImGui::Spacing();
2505
            {
2506
                static bool checked[5] = {};
2507
                static int selected_n = 0;
2508
                const float color_marker_w = ImGui::CalcTextSize("x").x;
2509
                for (int n = 0; n < 5; n++)
2510
                {
2511
                    ImGui::PushID(n);
2512
                    ImGui::AlignTextToFramePadding();
2513
                    if (ImGui::Selectable("##selectable", selected_n == n, ImGuiSelectableFlags_AllowOverlap))
2514
                        selected_n = n;
2515
                    ImGui::SameLine(0, 0);
2516
                    ImGui::Checkbox("##check", &checked[n]);
2517
                    ImGui::SameLine();
2518
                    ImVec4 color((n & 1) ? 1.0f : 0.2f, (n & 2) ? 1.0f : 0.2f, 0.2f, 1.0f);
2519
                    ImGui::ColorButton("##color", color, ImGuiColorEditFlags_NoTooltip, ImVec2(color_marker_w, 0));
2520
                    ImGui::SameLine();
2521
                    ImGui::Text("Some label");
2522
                    ImGui::PopID();
2523
                }
2524
            }
2525
2526
            ImGui::TreePop();
2527
        }
2528
2529
        if (ImGui::TreeNode("In Tables"))
2530
        {
2531
            IMGUI_DEMO_MARKER("Widgets/Selectables/In Tables");
2532
            static bool selected[10] = {};
2533
2534
            if (ImGui::BeginTable("split1", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders))
2535
            {
2536
                for (int i = 0; i < 10; i++)
2537
                {
2538
                    char label[32];
2539
                    sprintf(label, "Item %d", i);
2540
                    ImGui::TableNextColumn();
2541
                    ImGui::Selectable(label, &selected[i]); // FIXME-TABLE: Selection overlap
2542
                }
2543
                ImGui::EndTable();
2544
            }
2545
            ImGui::Spacing();
2546
            if (ImGui::BeginTable("split2", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders))
2547
            {
2548
                for (int i = 0; i < 10; i++)
2549
                {
2550
                    char label[32];
2551
                    sprintf(label, "Item %d", i);
2552
                    ImGui::TableNextRow();
2553
                    ImGui::TableNextColumn();
2554
                    ImGui::Selectable(label, &selected[i], ImGuiSelectableFlags_SpanAllColumns);
2555
                    ImGui::TableNextColumn();
2556
                    ImGui::Text("Some other contents");
2557
                    ImGui::TableNextColumn();
2558
                    ImGui::Text("123456");
2559
                }
2560
                ImGui::EndTable();
2561
            }
2562
            ImGui::TreePop();
2563
        }
2564
2565
        if (ImGui::TreeNode("Grid"))
2566
        {
2567
            IMGUI_DEMO_MARKER("Widgets/Selectables/Grid");
2568
            static char selected[4][4] = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } };
2569
2570
            // Add in a bit of silly fun...
2571
            const float time = (float)ImGui::GetTime();
2572
            const bool winning_state = memchr(selected, 0, sizeof(selected)) == NULL; // If all cells are selected...
2573
            if (winning_state)
2574
                ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f + 0.5f * cosf(time * 2.0f), 0.5f + 0.5f * sinf(time * 3.0f)));
2575
2576
            const float size = ImGui::CalcTextSize("Sailor").x;
2577
            for (int y = 0; y < 4; y++)
2578
                for (int x = 0; x < 4; x++)
2579
                {
2580
                    if (x > 0)
2581
                        ImGui::SameLine();
2582
                    ImGui::PushID(y * 4 + x);
2583
                    if (ImGui::Selectable("Sailor", selected[y][x] != 0, 0, ImVec2(size, size)))
2584
                    {
2585
                        // Toggle clicked cell + toggle neighbors
2586
                        selected[y][x] ^= 1;
2587
                        if (x > 0) { selected[y][x - 1] ^= 1; }
2588
                        if (x < 3) { selected[y][x + 1] ^= 1; }
2589
                        if (y > 0) { selected[y - 1][x] ^= 1; }
2590
                        if (y < 3) { selected[y + 1][x] ^= 1; }
2591
                    }
2592
                    ImGui::PopID();
2593
                }
2594
2595
            if (winning_state)
2596
                ImGui::PopStyleVar();
2597
            ImGui::TreePop();
2598
        }
2599
        if (ImGui::TreeNode("Alignment"))
2600
        {
2601
            IMGUI_DEMO_MARKER("Widgets/Selectables/Alignment");
2602
            HelpMarker(
2603
                "By default, Selectables uses style.SelectableTextAlign but it can be overridden on a per-item "
2604
                "basis using PushStyleVar(). You'll probably want to always keep your default situation to "
2605
                "left-align otherwise it becomes difficult to layout multiple items on a same line");
2606
2607
            static bool selected[3 * 3] = { true, false, true, false, true, false, true, false, true };
2608
            const float size = ImGui::CalcTextSize("(1.0,1.0)").x;
2609
            for (int y = 0; y < 3; y++)
2610
            {
2611
                for (int x = 0; x < 3; x++)
2612
                {
2613
                    ImVec2 alignment = ImVec2((float)x / 2.0f, (float)y / 2.0f);
2614
                    char name[32];
2615
                    sprintf(name, "(%.1f,%.1f)", alignment.x, alignment.y);
2616
                    if (x > 0) ImGui::SameLine();
2617
                    ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, alignment);
2618
                    ImGui::Selectable(name, &selected[3 * y + x], ImGuiSelectableFlags_None, ImVec2(size, size));
2619
                    ImGui::PopStyleVar();
2620
                }
2621
            }
2622
            ImGui::TreePop();
2623
        }
2624
        ImGui::TreePop();
2625
    }
2626
}
2627
2628
//-----------------------------------------------------------------------------
2629
// [SECTION] DemoWindowWidgetsSelectionAndMultiSelect()
2630
//-----------------------------------------------------------------------------
2631
// Multi-selection demos
2632
// Also read: https://github.com/ocornut/imgui/wiki/Multi-Select
2633
//-----------------------------------------------------------------------------
2634
2635
static const char* ExampleNames[] =
2636
{
2637
    "Artichoke", "Arugula", "Asparagus", "Avocado", "Bamboo Shoots", "Bean Sprouts", "Beans", "Beet", "Belgian Endive", "Bell Pepper",
2638
    "Bitter Gourd", "Bok Choy", "Broccoli", "Brussels Sprouts", "Burdock Root", "Cabbage", "Calabash", "Capers", "Carrot", "Cassava",
2639
    "Cauliflower", "Celery", "Celery Root", "Celcuce", "Chayote", "Chinese Broccoli", "Corn", "Cucumber"
2640
};
2641
2642
// Extra functions to add deletion support to ImGuiSelectionBasicStorage
2643
struct ExampleSelectionWithDeletion : ImGuiSelectionBasicStorage
2644
{
2645
    // Find which item should be Focused after deletion.
2646
    // Call _before_ item submission. Return an index in the before-deletion item list, your item loop should call SetKeyboardFocusHere() on it.
2647
    // The subsequent ApplyDeletionPostLoop() code will use it to apply Selection.
2648
    // - We cannot provide this logic in core Dear ImGui because we don't have access to selection data.
2649
    // - We don't actually manipulate the ImVector<> here, only in ApplyDeletionPostLoop(), but using similar API for consistency and flexibility.
2650
    // - 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.
2651
    // FIXME-MULTISELECT: Doesn't take account of the possibility focus target will be moved during deletion. Need refocus or scroll offset.
2652
    int ApplyDeletionPreLoop(ImGuiMultiSelectIO* ms_io, int items_count)
2653
    {
2654
        if (Size == 0)
2655
            return -1;
2656
2657
        // If focused item is not selected...
2658
        const int focused_idx = (int)ms_io->NavIdItem;  // Index of currently focused item
2659
        if (ms_io->NavIdSelected == false)  // This is merely a shortcut, == Contains(adapter->IndexToStorage(items, focused_idx))
2660
        {
2661
            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.
2662
            return focused_idx;             // Request to focus same item after deletion.
2663
        }
2664
2665
        // If focused item is selected: land on first unselected item after focused item.
2666
        for (int idx = focused_idx + 1; idx < items_count; idx++)
2667
            if (!Contains(GetStorageIdFromIndex(idx)))
2668
                return idx;
2669
2670
        // If focused item is selected: otherwise return last unselected item before focused item.
2671
        for (int idx = IM_MIN(focused_idx, items_count) - 1; idx >= 0; idx--)
2672
            if (!Contains(GetStorageIdFromIndex(idx)))
2673
                return idx;
2674
2675
        return -1;
2676
    }
2677
2678
    // Rewrite item list (delete items) + update selection.
2679
    // - Call after EndMultiSelect()
2680
    // - We cannot provide this logic in core Dear ImGui because we don't have access to your items, nor to selection data.
2681
    template<typename ITEM_TYPE>
2682
    void ApplyDeletionPostLoop(ImGuiMultiSelectIO* ms_io, ImVector<ITEM_TYPE>& items, int item_curr_idx_to_select)
2683
    {
2684
        // Rewrite item list (delete items) + convert old selection index (before deletion) to new selection index (after selection).
2685
        // If NavId was not part of selection, we will stay on same item.
2686
        ImVector<ITEM_TYPE> new_items;
2687
        new_items.reserve(items.Size - Size);
2688
        int item_next_idx_to_select = -1;
2689
        for (int idx = 0; idx < items.Size; idx++)
2690
        {
2691
            if (!Contains(GetStorageIdFromIndex(idx)))
2692
                new_items.push_back(items[idx]);
2693
            if (item_curr_idx_to_select == idx)
2694
                item_next_idx_to_select = new_items.Size - 1;
2695
        }
2696
        items.swap(new_items);
2697
2698
        // Update selection
2699
        Clear();
2700
        if (item_next_idx_to_select != -1 && ms_io->NavIdSelected)
2701
            SetItemSelected(GetStorageIdFromIndex(item_next_idx_to_select), true);
2702
    }
2703
};
2704
2705
// Example: Implement dual list box storage and interface
2706
struct ExampleDualListBox
2707
{
2708
    ImVector<ImGuiID>           Items[2];               // ID is index into ExampleName[]
2709
    ImGuiSelectionBasicStorage  Selections[2];          // Store ExampleItemId into selection
2710
    bool                        OptKeepSorted = true;
2711
2712
    void MoveAll(int src, int dst)
2713
    {
2714
        IM_ASSERT((src == 0 && dst == 1) || (src == 1 && dst == 0));
2715
        for (ImGuiID item_id : Items[src])
2716
            Items[dst].push_back(item_id);
2717
        Items[src].clear();
2718
        SortItems(dst);
2719
        Selections[src].Swap(Selections[dst]);
2720
        Selections[src].Clear();
2721
    }
2722
    void MoveSelected(int src, int dst)
2723
    {
2724
        for (int src_n = 0; src_n < Items[src].Size; src_n++)
2725
        {
2726
            ImGuiID item_id = Items[src][src_n];
2727
            if (!Selections[src].Contains(item_id))
2728
                continue;
2729
            Items[src].erase(&Items[src][src_n]); // FIXME-OPT: Could be implemented more optimally (rebuild src items and swap)
2730
            Items[dst].push_back(item_id);
2731
            src_n--;
2732
        }
2733
        if (OptKeepSorted)
2734
            SortItems(dst);
2735
        Selections[src].Swap(Selections[dst]);
2736
        Selections[src].Clear();
2737
    }
2738
    void ApplySelectionRequests(ImGuiMultiSelectIO* ms_io, int side)
2739
    {
2740
        // In this example we store item id in selection (instead of item index)
2741
        Selections[side].UserData = Items[side].Data;
2742
        Selections[side].AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { ImGuiID* items = (ImGuiID*)self->UserData; return items[idx]; };
2743
        Selections[side].ApplyRequests(ms_io);
2744
    }
2745
    static int IMGUI_CDECL CompareItemsByValue(const void* lhs, const void* rhs)
2746
    {
2747
        const int* a = (const int*)lhs;
2748
        const int* b = (const int*)rhs;
2749
        return *a - *b;
2750
    }
2751
    void SortItems(int n)
2752
    {
2753
        qsort(Items[n].Data, (size_t)Items[n].Size, sizeof(Items[n][0]), CompareItemsByValue);
2754
    }
2755
    void Show()
2756
    {
2757
        //if (ImGui::Checkbox("Sorted", &OptKeepSorted) && OptKeepSorted) { SortItems(0); SortItems(1); }
2758
        if (ImGui::BeginTable("split", 3, ImGuiTableFlags_None))
2759
        {
2760
            ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch);    // Left side
2761
            ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed);      // Buttons
2762
            ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch);    // Right side
2763
            ImGui::TableNextRow();
2764
2765
            int request_move_selected = -1;
2766
            int request_move_all = -1;
2767
            float child_height_0 = 0.0f;
2768
            for (int side = 0; side < 2; side++)
2769
            {
2770
                // FIXME-MULTISELECT: Dual List Box: Add context menus
2771
                // FIXME-NAV: Using ImGuiWindowFlags_NavFlattened exhibit many issues.
2772
                ImVector<ImGuiID>& items = Items[side];
2773
                ImGuiSelectionBasicStorage& selection = Selections[side];
2774
2775
                ImGui::TableSetColumnIndex((side == 0) ? 0 : 2);
2776
                ImGui::Text("%s (%d)", (side == 0) ? "Available" : "Basket", items.Size);
2777
2778
                // Submit scrolling range to avoid glitches on moving/deletion
2779
                const float items_height = ImGui::GetTextLineHeightWithSpacing();
2780
                ImGui::SetNextWindowContentSize(ImVec2(0.0f, items.Size * items_height));
2781
2782
                bool child_visible;
2783
                if (side == 0)
2784
                {
2785
                    // Left child is resizable
2786
                    ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetFrameHeightWithSpacing() * 4), ImVec2(FLT_MAX, FLT_MAX));
2787
                    child_visible = ImGui::BeginChild("0", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY);
2788
                    child_height_0 = ImGui::GetWindowSize().y;
2789
                }
2790
                else
2791
                {
2792
                    // Right child use same height as left one
2793
                    child_visible = ImGui::BeginChild("1", ImVec2(-FLT_MIN, child_height_0), ImGuiChildFlags_FrameStyle);
2794
                }
2795
                if (child_visible)
2796
                {
2797
                    ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_BoxSelect1d;
2798
                    ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size);
2799
                    ApplySelectionRequests(ms_io, side);
2800
2801
                    for (int item_n = 0; item_n < items.Size; item_n++)
2802
                    {
2803
                        ImGuiID item_id = items[item_n];
2804
                        bool item_is_selected = selection.Contains(item_id);
2805
                        ImGui::SetNextItemSelectionUserData(item_n);
2806
                        ImGui::Selectable(ExampleNames[item_id], item_is_selected, ImGuiSelectableFlags_AllowDoubleClick);
2807
                        if (ImGui::IsItemFocused())
2808
                        {
2809
                            // FIXME-MULTISELECT: Dual List Box: Transfer focus
2810
                            if (ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_KeypadEnter))
2811
                                request_move_selected = side;
2812
                            if (ImGui::IsMouseDoubleClicked(0)) // FIXME-MULTISELECT: Double-click on multi-selection?
2813
                                request_move_selected = side;
2814
                        }
2815
                    }
2816
2817
                    ms_io = ImGui::EndMultiSelect();
2818
                    ApplySelectionRequests(ms_io, side);
2819
                }
2820
                ImGui::EndChild();
2821
            }
2822
2823
            // Buttons columns
2824
            ImGui::TableSetColumnIndex(1);
2825
            ImGui::NewLine();
2826
            //ImVec2 button_sz = { ImGui::CalcTextSize(">>").x + ImGui::GetStyle().FramePadding.x * 2.0f, ImGui::GetFrameHeight() + padding.y * 2.0f };
2827
            ImVec2 button_sz = { ImGui::GetFrameHeight(), ImGui::GetFrameHeight() };
2828
2829
            // (Using BeginDisabled()/EndDisabled() works but feels distracting given how it is currently visualized)
2830
            if (ImGui::Button(">>", button_sz))
2831
                request_move_all = 0;
2832
            if (ImGui::Button(">", button_sz))
2833
                request_move_selected = 0;
2834
            if (ImGui::Button("<", button_sz))
2835
                request_move_selected = 1;
2836
            if (ImGui::Button("<<", button_sz))
2837
                request_move_all = 1;
2838
2839
            // Process requests
2840
            if (request_move_all != -1)
2841
                MoveAll(request_move_all, request_move_all ^ 1);
2842
            if (request_move_selected != -1)
2843
                MoveSelected(request_move_selected, request_move_selected ^ 1);
2844
2845
            // FIXME-MULTISELECT: Support action from outside
2846
            /*
2847
            if (OptKeepSorted == false)
2848
            {
2849
                ImGui::NewLine();
2850
                if (ImGui::ArrowButton("MoveUp", ImGuiDir_Up)) {}
2851
                if (ImGui::ArrowButton("MoveDown", ImGuiDir_Down)) {}
2852
            }
2853
            */
2854
2855
            ImGui::EndTable();
2856
        }
2857
    }
2858
};
2859
2860
static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_data)
2861
{
2862
    if (ImGui::TreeNode("Selection State & Multi-Select"))
2863
    {
2864
        IMGUI_DEMO_MARKER("Widgets/Selection State & Multi-Select");
2865
        HelpMarker("Selections can be built using Selectable(), TreeNode() or other widgets. Selection state is owned by application code/data.");
2866
2867
        ImGui::BulletText("Wiki page:");
2868
        ImGui::SameLine();
2869
        ImGui::TextLinkOpenURL("imgui/wiki/Multi-Select", "https://github.com/ocornut/imgui/wiki/Multi-Select");
2870
2871
        // Without any fancy API: manage single-selection yourself.
2872
        if (ImGui::TreeNode("Single-Select"))
2873
        {
2874
            IMGUI_DEMO_MARKER("Widgets/Selection State/Single-Select");
2875
            static int selected = -1;
2876
            for (int n = 0; n < 5; n++)
2877
            {
2878
                char buf[32];
2879
                sprintf(buf, "Object %d", n);
2880
                if (ImGui::Selectable(buf, selected == n))
2881
                    selected = n;
2882
            }
2883
            ImGui::TreePop();
2884
        }
2885
2886
        // Demonstrate implementation a most-basic form of multi-selection manually
2887
        // This doesn't support the Shift modifier which requires BeginMultiSelect()!
2888
        if (ImGui::TreeNode("Multi-Select (manual/simplified, without BeginMultiSelect)"))
2889
        {
2890
            IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (manual/simplified, without BeginMultiSelect)");
2891
            HelpMarker("Hold Ctrl and Click to select multiple items.");
2892
            static bool selection[5] = { false, false, false, false, false };
2893
            for (int n = 0; n < 5; n++)
2894
            {
2895
                char buf[32];
2896
                sprintf(buf, "Object %d", n);
2897
                if (ImGui::Selectable(buf, selection[n]))
2898
                {
2899
                    if (!ImGui::GetIO().KeyCtrl) // Clear selection when Ctrl is not held
2900
                        memset(selection, 0, sizeof(selection));
2901
                    selection[n] ^= 1; // Toggle current item
2902
                }
2903
            }
2904
            ImGui::TreePop();
2905
        }
2906
2907
        // Demonstrate handling proper multi-selection using the BeginMultiSelect/EndMultiSelect API.
2908
        // Shift+Click w/ Ctrl and other standard features are supported.
2909
        // We use the ImGuiSelectionBasicStorage helper which you may freely reimplement.
2910
        if (ImGui::TreeNode("Multi-Select"))
2911
        {
2912
            IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select");
2913
            ImGui::Text("Supported features:");
2914
            ImGui::BulletText("Keyboard navigation (arrows, page up/down, home/end, space).");
2915
            ImGui::BulletText("Ctrl modifier to preserve and toggle selection.");
2916
            ImGui::BulletText("Shift modifier for range selection.");
2917
            ImGui::BulletText("Ctrl+A to select all.");
2918
            ImGui::BulletText("Escape to clear selection.");
2919
            ImGui::BulletText("Click and drag to box-select.");
2920
            ImGui::Text("Tip: Use 'Demo->Tools->Debug Log->Selection' to see selection requests as they happen.");
2921
2922
            // Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection
2923
            const int ITEMS_COUNT = 50;
2924
            static ImGuiSelectionBasicStorage selection;
2925
            ImGui::Text("Selection: %d/%d", selection.Size, ITEMS_COUNT);
2926
2927
            // The BeginChild() has no purpose for selection logic, other that offering a scrolling region.
2928
            if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
2929
            {
2930
                ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
2931
                ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT);
2932
                selection.ApplyRequests(ms_io);
2933
2934
                for (int n = 0; n < ITEMS_COUNT; n++)
2935
                {
2936
                    char label[64];
2937
                    sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_COUNTOF(ExampleNames)]);
2938
                    bool item_is_selected = selection.Contains((ImGuiID)n);
2939
                    ImGui::SetNextItemSelectionUserData(n);
2940
                    ImGui::Selectable(label, item_is_selected);
2941
                }
2942
2943
                ms_io = ImGui::EndMultiSelect();
2944
                selection.ApplyRequests(ms_io);
2945
            }
2946
            ImGui::EndChild();
2947
            ImGui::TreePop();
2948
        }
2949
2950
        // Demonstrate using the clipper with BeginMultiSelect()/EndMultiSelect()
2951
        if (ImGui::TreeNode("Multi-Select (with clipper)"))
2952
        {
2953
            IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (with clipper)");
2954
            // Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection
2955
            static ImGuiSelectionBasicStorage selection;
2956
2957
            ImGui::Text("Added features:");
2958
            ImGui::BulletText("Using ImGuiListClipper.");
2959
2960
            const int ITEMS_COUNT = 10000;
2961
            ImGui::Text("Selection: %d/%d", selection.Size, ITEMS_COUNT);
2962
            if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
2963
            {
2964
                ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
2965
                ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT);
2966
                selection.ApplyRequests(ms_io);
2967
2968
                ImGuiListClipper clipper;
2969
                clipper.Begin(ITEMS_COUNT);
2970
                if (ms_io->RangeSrcItem != -1)
2971
                    clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped.
2972
                while (clipper.Step())
2973
                {
2974
                    for (int n = clipper.DisplayStart; n < clipper.DisplayEnd; n++)
2975
                    {
2976
                        char label[64];
2977
                        sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_COUNTOF(ExampleNames)]);
2978
                        bool item_is_selected = selection.Contains((ImGuiID)n);
2979
                        ImGui::SetNextItemSelectionUserData(n);
2980
                        ImGui::Selectable(label, item_is_selected);
2981
                    }
2982
                }
2983
2984
                ms_io = ImGui::EndMultiSelect();
2985
                selection.ApplyRequests(ms_io);
2986
            }
2987
            ImGui::EndChild();
2988
            ImGui::TreePop();
2989
        }
2990
2991
        // Demonstrate dynamic item list + deletion support using the BeginMultiSelect/EndMultiSelect API.
2992
        // In order to support Deletion without any glitches you need to:
2993
        // - (1) If items are submitted in their own scrolling area, submit contents size SetNextWindowContentSize() ahead of time to prevent one-frame readjustment of scrolling.
2994
        // - (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.
2995
        // - (3) BeginXXXX process
2996
        // - (4) Focus process
2997
        // - (5) EndXXXX process
2998
        if (ImGui::TreeNode("Multi-Select (with deletion)"))
2999
        {
3000
            IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (with deletion)");
3001
            // Storing items data separately from selection data.
3002
            // (you may decide to store selection data inside your item (aka intrusive storage) if you don't need multiple views over same items)
3003
            // Use a custom selection.Adapter: store item identifier in Selection (instead of index)
3004
            static ImVector<ImGuiID> items;
3005
            static ExampleSelectionWithDeletion selection;
3006
            selection.UserData = (void*)&items;
3007
            selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { ImVector<ImGuiID>* p_items = (ImVector<ImGuiID>*)self->UserData; return (*p_items)[idx]; }; // Index -> ID
3008
3009
            ImGui::Text("Added features:");
3010
            ImGui::BulletText("Dynamic list with Delete key support.");
3011
            ImGui::Text("Selection size: %d/%d", selection.Size, items.Size);
3012
3013
            // Initialize default list with 50 items + button to add/remove items.
3014
            static ImGuiID items_next_id = 0;
3015
            if (items_next_id == 0)
3016
                for (ImGuiID n = 0; n < 50; n++)
3017
                    items.push_back(items_next_id++);
3018
            if (ImGui::SmallButton("Add 20 items"))     { for (int n = 0; n < 20; n++) { items.push_back(items_next_id++); } }
3019
            ImGui::SameLine();
3020
            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(); } }
3021
3022
            // (1) Extra to support deletion: Submit scrolling range to avoid glitches on deletion
3023
            const float items_height = ImGui::GetTextLineHeightWithSpacing();
3024
            ImGui::SetNextWindowContentSize(ImVec2(0.0f, items.Size * items_height));
3025
3026
            if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
3027
            {
3028
                ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
3029
                ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size);
3030
                selection.ApplyRequests(ms_io);
3031
3032
                const bool want_delete = ImGui::Shortcut(ImGuiKey_Delete, ImGuiInputFlags_Repeat) && (selection.Size > 0);
3033
                const int item_curr_idx_to_focus = want_delete ? selection.ApplyDeletionPreLoop(ms_io, items.Size) : -1;
3034
3035
                for (int n = 0; n < items.Size; n++)
3036
                {
3037
                    const ImGuiID item_id = items[n];
3038
                    char label[64];
3039
                    sprintf(label, "Object %05u: %s", item_id, ExampleNames[item_id % IM_COUNTOF(ExampleNames)]);
3040
3041
                    bool item_is_selected = selection.Contains(item_id);
3042
                    ImGui::SetNextItemSelectionUserData(n);
3043
                    ImGui::Selectable(label, item_is_selected);
3044
                    if (item_curr_idx_to_focus == n)
3045
                        ImGui::SetKeyboardFocusHere(-1);
3046
                }
3047
3048
                // Apply multi-select requests
3049
                ms_io = ImGui::EndMultiSelect();
3050
                selection.ApplyRequests(ms_io);
3051
                if (want_delete)
3052
                    selection.ApplyDeletionPostLoop(ms_io, items, item_curr_idx_to_focus);
3053
            }
3054
            ImGui::EndChild();
3055
            ImGui::TreePop();
3056
        }
3057
3058
        // Implement a Dual List Box (#6648)
3059
        if (ImGui::TreeNode("Multi-Select (dual list box)"))
3060
        {
3061
            IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (dual list box)");
3062
            // Init default state
3063
            static ExampleDualListBox dlb;
3064
            if (dlb.Items[0].Size == 0 && dlb.Items[1].Size == 0)
3065
                for (int item_id = 0; item_id < IM_COUNTOF(ExampleNames); item_id++)
3066
                    dlb.Items[0].push_back((ImGuiID)item_id);
3067
3068
            // Show
3069
            dlb.Show();
3070
3071
            ImGui::TreePop();
3072
        }
3073
3074
        // Demonstrate using the clipper with BeginMultiSelect()/EndMultiSelect()
3075
        if (ImGui::TreeNode("Multi-Select (in a table)"))
3076
        {
3077
            IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (in a table)");
3078
            static ImGuiSelectionBasicStorage selection;
3079
3080
            const int ITEMS_COUNT = 10000;
3081
            ImGui::Text("Selection: %d/%d", selection.Size, ITEMS_COUNT);
3082
            if (ImGui::BeginTable("##Basket", 2, ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter, ImVec2(0.0f, ImGui::GetFontSize() * 20)))
3083
            {
3084
                ImGui::TableSetupColumn("Object");
3085
                ImGui::TableSetupColumn("Action");
3086
                ImGui::TableSetupScrollFreeze(0, 1);
3087
                ImGui::TableHeadersRow();
3088
3089
                ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
3090
                ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT);
3091
                selection.ApplyRequests(ms_io);
3092
3093
                ImGuiListClipper clipper;
3094
                clipper.Begin(ITEMS_COUNT);
3095
                if (ms_io->RangeSrcItem != -1)
3096
                    clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped.
3097
                while (clipper.Step())
3098
                {
3099
                    for (int n = clipper.DisplayStart; n < clipper.DisplayEnd; n++)
3100
                    {
3101
                        ImGui::TableNextRow();
3102
                        ImGui::TableNextColumn();
3103
                        ImGui::PushID(n);
3104
                        char label[64];
3105
                        sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_COUNTOF(ExampleNames)]);
3106
                        bool item_is_selected = selection.Contains((ImGuiID)n);
3107
                        ImGui::SetNextItemSelectionUserData(n);
3108
                        ImGui::Selectable(label, item_is_selected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap);
3109
                        ImGui::TableNextColumn();
3110
                        ImGui::SmallButton("hello");
3111
                        ImGui::PopID();
3112
                    }
3113
                }
3114
3115
                ms_io = ImGui::EndMultiSelect();
3116
                selection.ApplyRequests(ms_io);
3117
                ImGui::EndTable();
3118
            }
3119
            ImGui::TreePop();
3120
        }
3121
3122
        if (ImGui::TreeNode("Multi-Select (checkboxes)"))
3123
        {
3124
            IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (checkboxes)");
3125
            ImGui::Text("In a list of checkboxes (not selectable):");
3126
            ImGui::BulletText("Using _NoAutoSelect + _NoAutoClear flags.");
3127
            ImGui::BulletText("Shift+Click to check multiple boxes.");
3128
            ImGui::BulletText("Shift+Keyboard to copy current value to other boxes.");
3129
3130
            // If you have an array of checkboxes, you may want to use NoAutoSelect + NoAutoClear and the ImGuiSelectionExternalStorage helper.
3131
            static bool items[20] = {};
3132
            static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_NoAutoSelect | ImGuiMultiSelectFlags_NoAutoClear | ImGuiMultiSelectFlags_ClearOnEscape;
3133
            ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoSelect", &flags, ImGuiMultiSelectFlags_NoAutoSelect);
3134
            ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoClear", &flags, ImGuiMultiSelectFlags_NoAutoClear);
3135
            ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect2d", &flags, ImGuiMultiSelectFlags_BoxSelect2d); // Cannot use ImGuiMultiSelectFlags_BoxSelect1d as checkboxes are varying width.
3136
3137
            if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeY))
3138
            {
3139
                ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, -1, IM_COUNTOF(items));
3140
                ImGuiSelectionExternalStorage storage_wrapper;
3141
                storage_wrapper.UserData = (void*)items;
3142
                storage_wrapper.AdapterSetItemSelected = [](ImGuiSelectionExternalStorage* self, int n, bool selected) { bool* array = (bool*)self->UserData; array[n] = selected; };
3143
                storage_wrapper.ApplyRequests(ms_io);
3144
                for (int n = 0; n < 20; n++)
3145
                {
3146
                    char label[32];
3147
                    sprintf(label, "Item %d", n);
3148
                    ImGui::SetNextItemSelectionUserData(n);
3149
                    ImGui::Checkbox(label, &items[n]);
3150
                }
3151
                ms_io = ImGui::EndMultiSelect();
3152
                storage_wrapper.ApplyRequests(ms_io);
3153
            }
3154
            ImGui::EndChild();
3155
3156
            ImGui::TreePop();
3157
        }
3158
3159
        // Demonstrate individual selection scopes in same window
3160
        if (ImGui::TreeNode("Multi-Select (multiple scopes)"))
3161
        {
3162
            IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (multiple scopes)");
3163
            // Use default select: Pass index to SetNextItemSelectionUserData(), store index in Selection
3164
            const int SCOPES_COUNT = 3;
3165
            const int ITEMS_COUNT = 8; // Per scope
3166
            static ImGuiSelectionBasicStorage selections_data[SCOPES_COUNT];
3167
3168
            // Use ImGuiMultiSelectFlags_ScopeRect to not affect other selections in same window.
3169
            static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ScopeRect | ImGuiMultiSelectFlags_ClearOnEscape;// | ImGuiMultiSelectFlags_ClearOnClickVoid;
3170
            if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeWindow", &flags, ImGuiMultiSelectFlags_ScopeWindow) && (flags & ImGuiMultiSelectFlags_ScopeWindow))
3171
                flags &= ~ImGuiMultiSelectFlags_ScopeRect;
3172
            if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeRect", &flags, ImGuiMultiSelectFlags_ScopeRect) && (flags & ImGuiMultiSelectFlags_ScopeRect))
3173
                flags &= ~ImGuiMultiSelectFlags_ScopeWindow;
3174
            ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnClickVoid", &flags, ImGuiMultiSelectFlags_ClearOnClickVoid);
3175
            ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect1d", &flags, ImGuiMultiSelectFlags_BoxSelect1d);
3176
3177
            for (int selection_scope_n = 0; selection_scope_n < SCOPES_COUNT; selection_scope_n++)
3178
            {
3179
                ImGui::PushID(selection_scope_n);
3180
                ImGuiSelectionBasicStorage* selection = &selections_data[selection_scope_n];
3181
                ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection->Size, ITEMS_COUNT);
3182
                selection->ApplyRequests(ms_io);
3183
3184
                ImGui::SeparatorText("Selection scope");
3185
                ImGui::Text("Selection size: %d/%d", selection->Size, ITEMS_COUNT);
3186
3187
                for (int n = 0; n < ITEMS_COUNT; n++)
3188
                {
3189
                    char label[64];
3190
                    sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_COUNTOF(ExampleNames)]);
3191
                    bool item_is_selected = selection->Contains((ImGuiID)n);
3192
                    ImGui::SetNextItemSelectionUserData(n);
3193
                    ImGui::Selectable(label, item_is_selected);
3194
                }
3195
3196
                // Apply multi-select requests
3197
                ms_io = ImGui::EndMultiSelect();
3198
                selection->ApplyRequests(ms_io);
3199
                ImGui::PopID();
3200
            }
3201
            ImGui::TreePop();
3202
        }
3203
3204
        // See ShowExampleAppAssetsBrowser()
3205
        if (ImGui::TreeNode("Multi-Select (tiled assets browser)"))
3206
        {
3207
            ImGui::Checkbox("Assets Browser", &demo_data->ShowAppAssetsBrowser);
3208
            ImGui::Text("(also access from 'Examples->Assets Browser' in menu)");
3209
            ImGui::TreePop();
3210
        }
3211
3212
        // Demonstrate supporting multiple-selection in a tree.
3213
        // - We don't use linear indices for selection user data, but our ExampleTreeNode* pointer directly!
3214
        //   This showcase how SetNextItemSelectionUserData() never assume indices!
3215
        // - The difficulty here is to "interpolate" from RangeSrcItem to RangeDstItem in the SetAll/SetRange request.
3216
        //   We want this interpolation to match what the user sees: in visible order, skipping closed nodes.
3217
        //   This is implemented by our TreeGetNextNodeInVisibleOrder() user-space helper.
3218
        // - Important: In a real codebase aiming to implement full-featured selectable tree with custom filtering, you
3219
        //   are more likely to build an array mapping sequential indices to visible tree nodes, since your
3220
        //   filtering/search + clipping process will benefit from it. Having this will make this interpolation much easier.
3221
        // - Consider this a prototype: we are working toward simplifying some of it.
3222
        if (ImGui::TreeNode("Multi-Select (trees)"))
3223
        {
3224
            IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (trees)");
3225
            HelpMarker(
3226
                "This is rather advanced and experimental. If you are getting started with multi-select, "
3227
                "please don't start by looking at how to use it for a tree!\n\n"
3228
                "Future versions will try to simplify and formalize some of this.");
3229
3230
            struct ExampleTreeFuncs
3231
            {
3232
                static void DrawNode(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection)
3233
                {
3234
                    ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;
3235
                    tree_node_flags |= ImGuiTreeNodeFlags_NavLeftJumpsToParent; // Enable pressing left to jump to parent
3236
                    if (node->Childs.Size == 0)
3237
                        tree_node_flags |= ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_Leaf;
3238
                    if (selection->Contains((ImGuiID)node->UID))
3239
                        tree_node_flags |= ImGuiTreeNodeFlags_Selected;
3240
3241
                    // Using SetNextItemStorageID() to specify storage id, so we can easily peek into
3242
                    // the storage holding open/close stage, using our TreeNodeGetOpen/TreeNodeSetOpen() functions.
3243
                    ImGui::SetNextItemSelectionUserData((ImGuiSelectionUserData)(intptr_t)node);
3244
                    ImGui::SetNextItemStorageID((ImGuiID)node->UID);
3245
                    if (ImGui::TreeNodeEx(node->Name, tree_node_flags))
3246
                    {
3247
                        for (ExampleTreeNode* child : node->Childs)
3248
                            DrawNode(child, selection);
3249
                        ImGui::TreePop();
3250
                    }
3251
                    else if (ImGui::IsItemToggledOpen())
3252
                    {
3253
                        TreeCloseAndUnselectChildNodes(node, selection);
3254
                    }
3255
                }
3256
3257
                // When closing a node: 1) close and unselect all child nodes, 2) select parent if any child was selected.
3258
                // FIXME: This is currently handled by user logic but I'm hoping to eventually provide tree node
3259
                // features to do this automatically, e.g. a ImGuiTreeNodeFlags_AutoCloseChildNodes etc.
3260
                static int TreeCloseAndUnselectChildNodes(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection, int depth = 0)
3261
                {
3262
                    // Recursive close (the test for depth == 0 is because we call this on a node that was just closed!)
3263
                    int unselected_count = selection->Contains((ImGuiID)node->UID) ? 1 : 0;
3264
                    if (depth == 0 || ImGui::TreeNodeGetOpen((ImGuiID)node->UID))
3265
                    {
3266
                        for (ExampleTreeNode* child : node->Childs)
3267
                            unselected_count += TreeCloseAndUnselectChildNodes(child, selection, depth + 1);
3268
                        ImGui::TreeNodeSetOpen((ImGuiID)node->UID, false);
3269
                    }
3270
3271
                    // Select root node if any of its child was selected, otherwise unselect
3272
                    selection->SetItemSelected((ImGuiID)node->UID, (depth == 0 && unselected_count > 0));
3273
                    return unselected_count;
3274
                }
3275
3276
                // Apply multi-selection requests
3277
                static void ApplySelectionRequests(ImGuiMultiSelectIO* ms_io, ExampleTreeNode* tree, ImGuiSelectionBasicStorage* selection)
3278
                {
3279
                    for (ImGuiSelectionRequest& req : ms_io->Requests)
3280
                    {
3281
                        if (req.Type == ImGuiSelectionRequestType_SetAll)
3282
                        {
3283
                            if (req.Selected)
3284
                                TreeSetAllInOpenNodes(tree, selection, req.Selected);
3285
                            else
3286
                                selection->Clear();
3287
                        }
3288
                        else if (req.Type == ImGuiSelectionRequestType_SetRange)
3289
                        {
3290
                            ExampleTreeNode* first_node = (ExampleTreeNode*)(intptr_t)req.RangeFirstItem;
3291
                            ExampleTreeNode* last_node = (ExampleTreeNode*)(intptr_t)req.RangeLastItem;
3292
                            for (ExampleTreeNode* node = first_node; node != NULL; node = TreeGetNextNodeInVisibleOrder(node, last_node))
3293
                                selection->SetItemSelected((ImGuiID)node->UID, req.Selected);
3294
                        }
3295
                    }
3296
                }
3297
3298
                static void TreeSetAllInOpenNodes(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection, bool selected)
3299
                {
3300
                    if (node->Parent != NULL) // Root node isn't visible nor selectable in our scheme
3301
                        selection->SetItemSelected((ImGuiID)node->UID, selected);
3302
                    if (node->Parent == NULL || ImGui::TreeNodeGetOpen((ImGuiID)node->UID))
3303
                        for (ExampleTreeNode* child : node->Childs)
3304
                            TreeSetAllInOpenNodes(child, selection, selected);
3305
                }
3306
3307
                // Interpolate in *user-visible order* AND only *over opened nodes*.
3308
                // If you have a sequential mapping tables (e.g. generated after a filter/search pass) this would be simpler.
3309
                // Here the tricks are that:
3310
                // - we store/maintain ExampleTreeNode::IndexInParent which allows implementing a linear iterator easily, without searches, without recursion.
3311
                //   this could be replaced by a search in parent, aka 'int index_in_parent = curr_node->Parent->Childs.find_index(curr_node)'
3312
                //   which would only be called when crossing from child to a parent, aka not too much.
3313
                // - we call SetNextItemStorageID() before our TreeNode() calls with an ID which doesn't relate to UI stack,
3314
                //   making it easier to call TreeNodeGetOpen()/TreeNodeSetOpen() from any location.
3315
                static ExampleTreeNode* TreeGetNextNodeInVisibleOrder(ExampleTreeNode* curr_node, ExampleTreeNode* last_node)
3316
                {
3317
                    // Reached last node
3318
                    if (curr_node == last_node)
3319
                        return NULL;
3320
3321
                    // Recurse into childs. Query storage to tell if the node is open.
3322
                    if (curr_node->Childs.Size > 0 && ImGui::TreeNodeGetOpen((ImGuiID)curr_node->UID))
3323
                        return curr_node->Childs[0];
3324
3325
                    // Next sibling, then into our own parent
3326
                    while (curr_node->Parent != NULL)
3327
                    {
3328
                        if (curr_node->IndexInParent + 1 < curr_node->Parent->Childs.Size)
3329
                            return curr_node->Parent->Childs[curr_node->IndexInParent + 1];
3330
                        curr_node = curr_node->Parent;
3331
                    }
3332
                    return NULL;
3333
                }
3334
3335
            }; // ExampleTreeFuncs
3336
3337
            static ImGuiSelectionBasicStorage selection;
3338
            if (demo_data->DemoTree == NULL)
3339
                demo_data->DemoTree = ExampleTree_CreateDemoTree(); // Create tree once
3340
            ImGui::Text("Selection size: %d", selection.Size);
3341
3342
            if (ImGui::BeginChild("##Tree", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
3343
            {
3344
                ExampleTreeNode* tree = demo_data->DemoTree;
3345
                ImGuiMultiSelectFlags ms_flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect2d;
3346
                ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(ms_flags, selection.Size, -1);
3347
                ExampleTreeFuncs::ApplySelectionRequests(ms_io, tree, &selection);
3348
                for (ExampleTreeNode* node : tree->Childs)
3349
                    ExampleTreeFuncs::DrawNode(node, &selection);
3350
                ms_io = ImGui::EndMultiSelect();
3351
                ExampleTreeFuncs::ApplySelectionRequests(ms_io, tree, &selection);
3352
            }
3353
            ImGui::EndChild();
3354
3355
            ImGui::TreePop();
3356
        }
3357
3358
        // Advanced demonstration of BeginMultiSelect()
3359
        // - Showcase clipping.
3360
        // - Showcase deletion.
3361
        // - Showcase basic drag and drop.
3362
        // - Showcase TreeNode variant (note that tree node don't expand in the demo: supporting expanding tree nodes + clipping a separate thing).
3363
        // - Showcase using inside a table.
3364
        //ImGui::SetNextItemOpen(true, ImGuiCond_Once);
3365
        if (ImGui::TreeNode("Multi-Select (advanced)"))
3366
        {
3367
            IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (advanced)");
3368
            // Options
3369
            enum WidgetType { WidgetType_Selectable, WidgetType_TreeNode };
3370
            static bool use_clipper = true;
3371
            static bool use_deletion = true;
3372
            static bool use_drag_drop = true;
3373
            static bool show_in_table = false;
3374
            static bool show_color_button = true;
3375
            static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
3376
            static WidgetType widget_type = WidgetType_Selectable;
3377
3378
            if (ImGui::TreeNode("Options"))
3379
            {
3380
                if (ImGui::RadioButton("Selectables", widget_type == WidgetType_Selectable)) { widget_type = WidgetType_Selectable; }
3381
                ImGui::SameLine();
3382
                if (ImGui::RadioButton("Tree nodes", widget_type == WidgetType_TreeNode)) { widget_type = WidgetType_TreeNode; }
3383
                ImGui::SameLine();
3384
                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.");
3385
                ImGui::Checkbox("Enable clipper", &use_clipper);
3386
                ImGui::Checkbox("Enable deletion", &use_deletion);
3387
                ImGui::Checkbox("Enable drag & drop", &use_drag_drop);
3388
                ImGui::Checkbox("Show in a table", &show_in_table);
3389
                ImGui::Checkbox("Show color button", &show_color_button);
3390
                ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SingleSelect", &flags, ImGuiMultiSelectFlags_SingleSelect);
3391
                ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoSelectAll", &flags, ImGuiMultiSelectFlags_NoSelectAll);
3392
                ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoRangeSelect", &flags, ImGuiMultiSelectFlags_NoRangeSelect);
3393
                ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoSelect", &flags, ImGuiMultiSelectFlags_NoAutoSelect);
3394
                ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoClear", &flags, ImGuiMultiSelectFlags_NoAutoClear);
3395
                ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoClearOnReselect", &flags, ImGuiMultiSelectFlags_NoAutoClearOnReselect);
3396
                ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoSelectOnRightClick", &flags, ImGuiMultiSelectFlags_NoSelectOnRightClick);
3397
                ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect1d", &flags, ImGuiMultiSelectFlags_BoxSelect1d);
3398
                ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect2d", &flags, ImGuiMultiSelectFlags_BoxSelect2d);
3399
                ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelectNoScroll", &flags, ImGuiMultiSelectFlags_BoxSelectNoScroll);
3400
                ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnEscape", &flags, ImGuiMultiSelectFlags_ClearOnEscape);
3401
                ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnClickVoid", &flags, ImGuiMultiSelectFlags_ClearOnClickVoid);
3402
                if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeWindow", &flags, ImGuiMultiSelectFlags_ScopeWindow) && (flags & ImGuiMultiSelectFlags_ScopeWindow))
3403
                    flags &= ~ImGuiMultiSelectFlags_ScopeRect;
3404
                if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeRect", &flags, ImGuiMultiSelectFlags_ScopeRect) && (flags & ImGuiMultiSelectFlags_ScopeRect))
3405
                    flags &= ~ImGuiMultiSelectFlags_ScopeWindow;
3406
                if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SelectOnAuto", &flags, ImGuiMultiSelectFlags_SelectOnAuto))
3407
                    flags &= ~(ImGuiMultiSelectFlags_SelectOnMask_ ^ ImGuiMultiSelectFlags_SelectOnAuto);
3408
                ImGui::SameLine(); HelpMarker("Apply selection on mouse down when clicking on unselected item, on mouse up when clicking on selected item. (Default)");
3409
                if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SelectOnClickAlways", &flags, ImGuiMultiSelectFlags_SelectOnClickAlways))
3410
                    flags &= ~(ImGuiMultiSelectFlags_SelectOnMask_ ^ ImGuiMultiSelectFlags_SelectOnClickAlways);
3411
                ImGui::SameLine(); HelpMarker("Prevents Drag and Drop from being used on multi-selection, but allows e.g. BoxSelect to always reselect even when clicking inside an existing selection. (Excel style behavior)");
3412
                if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SelectOnClickRelease", &flags, ImGuiMultiSelectFlags_SelectOnClickRelease))
3413
                    flags &= ~(ImGuiMultiSelectFlags_SelectOnMask_ ^ ImGuiMultiSelectFlags_SelectOnClickRelease);
3414
                ImGui::SameLine(); HelpMarker("Allow dragging an unselected item without altering selection.");
3415
                ImGui::TreePop();
3416
            }
3417
3418
            // Initialize default list with 1000 items.
3419
            // Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection
3420
            static ImVector<int> items;
3421
            static int items_next_id = 0;
3422
            if (items_next_id == 0) { for (int n = 0; n < 1000; n++) { items.push_back(items_next_id++); } }
3423
            static ExampleSelectionWithDeletion selection;
3424
            static bool request_deletion_from_menu = false; // Queue deletion triggered from context menu
3425
3426
            ImGui::Text("Selection size: %d/%d", selection.Size, items.Size);
3427
3428
            const float items_height = (widget_type == WidgetType_TreeNode) ? ImGui::GetTextLineHeight() : ImGui::GetTextLineHeightWithSpacing();
3429
            ImGui::SetNextWindowContentSize(ImVec2(0.0f, items.Size * items_height));
3430
            if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
3431
            {
3432
                ImVec2 color_button_sz(ImGui::GetFontSize(), ImGui::GetFontSize());
3433
                if (widget_type == WidgetType_TreeNode)
3434
                    ImGui::PushStyleVarY(ImGuiStyleVar_ItemSpacing, 0.0f);
3435
3436
                ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size);
3437
                selection.ApplyRequests(ms_io);
3438
3439
                const bool want_delete = (ImGui::Shortcut(ImGuiKey_Delete, ImGuiInputFlags_Repeat) && (selection.Size > 0)) || request_deletion_from_menu;
3440
                const int item_curr_idx_to_focus = want_delete ? selection.ApplyDeletionPreLoop(ms_io, items.Size) : -1;
3441
                request_deletion_from_menu = false;
3442
3443
                if (show_in_table)
3444
                {
3445
                    if (widget_type == WidgetType_TreeNode)
3446
                        ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(0.0f, 0.0f));
3447
                    ImGui::BeginTable("##Split", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_NoPadOuterX);
3448
                    ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 0.70f);
3449
                    ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 0.30f);
3450
                    //ImGui::PushStyleVarY(ImGuiStyleVar_ItemSpacing, 0.0f);
3451
                }
3452
3453
                ImGuiListClipper clipper;
3454
                if (use_clipper)
3455
                {
3456
                    clipper.Begin(items.Size);
3457
                    if (item_curr_idx_to_focus != -1)
3458
                        clipper.IncludeItemByIndex(item_curr_idx_to_focus); // Ensure focused item is not clipped.
3459
                    if (ms_io->RangeSrcItem != -1)
3460
                        clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped.
3461
                }
3462
3463
                while (!use_clipper || clipper.Step())
3464
                {
3465
                    const int item_begin = use_clipper ? clipper.DisplayStart : 0;
3466
                    const int item_end = use_clipper ? clipper.DisplayEnd : items.Size;
3467
                    for (int n = item_begin; n < item_end; n++)
3468
                    {
3469
                        if (show_in_table)
3470
                            ImGui::TableNextColumn();
3471
3472
                        const int item_id = items[n];
3473
                        const char* item_category = ExampleNames[item_id % IM_COUNTOF(ExampleNames)];
3474
                        char label[64];
3475
                        sprintf(label, "Object %05d: %s", item_id, item_category);
3476
3477
                        // IMPORTANT: for deletion refocus to work we need object ID to be stable,
3478
                        // aka not depend on their index in the list. Here we use our persistent item_id
3479
                        // instead of index to build a unique ID that will persist.
3480
                        // (If we used PushID(index) instead, focus wouldn't be restored correctly after deletion).
3481
                        ImGui::PushID(item_id);
3482
3483
                        // Emit a color button, to test that Shift+LeftArrow landing on an item that is not part
3484
                        // of the selection scope doesn't erroneously alter our selection.
3485
                        if (show_color_button)
3486
                        {
3487
                            ImU32 dummy_col = (ImU32)((unsigned int)n * 0xC250B74B) | IM_COL32_A_MASK;
3488
                            ImGui::ColorButton("##", ImColor(dummy_col), ImGuiColorEditFlags_NoTooltip, color_button_sz);
3489
                            ImGui::SameLine();
3490
                        }
3491
3492
                        // Submit item
3493
                        bool item_is_selected = selection.Contains((ImGuiID)n);
3494
                        bool item_is_open = false;
3495
                        ImGui::SetNextItemSelectionUserData(n);
3496
                        if (widget_type == WidgetType_Selectable)
3497
                        {
3498
                            ImGui::Selectable(label, item_is_selected, ImGuiSelectableFlags_None);
3499
                        }
3500
                        else if (widget_type == WidgetType_TreeNode)
3501
                        {
3502
                            ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;
3503
                            if (item_is_selected)
3504
                                tree_node_flags |= ImGuiTreeNodeFlags_Selected;
3505
                            item_is_open = ImGui::TreeNodeEx(label, tree_node_flags);
3506
                        }
3507
3508
                        // Focus (for after deletion)
3509
                        if (item_curr_idx_to_focus == n)
3510
                            ImGui::SetKeyboardFocusHere(-1);
3511
3512
                        // Drag and Drop
3513
                        if (use_drag_drop && ImGui::BeginDragDropSource())
3514
                        {
3515
                            // Create payload with full selection OR single unselected item.
3516
                            // (the later is only possible when using ImGuiMultiSelectFlags_SelectOnClickRelease)
3517
                            if (ImGui::GetDragDropPayload() == NULL)
3518
                            {
3519
                                ImVector<int> payload_items;
3520
                                void* it = NULL;
3521
                                ImGuiID id = 0;
3522
                                if (!item_is_selected)
3523
                                    payload_items.push_back(item_id);
3524
                                else
3525
                                    while (selection.GetNextSelectedItem(&it, &id))
3526
                                        payload_items.push_back((int)id);
3527
                                ImGui::SetDragDropPayload("MULTISELECT_DEMO_ITEMS", payload_items.Data, (size_t)payload_items.size_in_bytes());
3528
                            }
3529
3530
                            // Display payload content in tooltip
3531
                            const ImGuiPayload* payload = ImGui::GetDragDropPayload();
3532
                            const int* payload_items = (int*)payload->Data;
3533
                            const int payload_count = (int)payload->DataSize / (int)sizeof(int);
3534
                            if (payload_count == 1)
3535
                                ImGui::Text("Object %05d: %s", payload_items[0], ExampleNames[payload_items[0] % IM_COUNTOF(ExampleNames)]);
3536
                            else
3537
                                ImGui::Text("Dragging %d objects", payload_count);
3538
3539
                            ImGui::EndDragDropSource();
3540
                        }
3541
3542
                        if (widget_type == WidgetType_TreeNode && item_is_open)
3543
                            ImGui::TreePop();
3544
3545
                        // Right-click: context menu
3546
                        if (ImGui::BeginPopupContextItem())
3547
                        {
3548
                            ImGui::BeginDisabled(!use_deletion || selection.Size == 0);
3549
                            sprintf(label, "Delete %d item(s)###DeleteSelected", selection.Size);
3550
                            if (ImGui::Selectable(label))
3551
                                request_deletion_from_menu = true;
3552
                            ImGui::EndDisabled();
3553
                            ImGui::Selectable("Close");
3554
                            ImGui::EndPopup();
3555
                        }
3556
3557
                        // Demo content within a table
3558
                        if (show_in_table)
3559
                        {
3560
                            ImGui::TableNextColumn();
3561
                            ImGui::SetNextItemWidth(-FLT_MIN);
3562
                            ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
3563
                            ImGui::InputText("##NoLabel", (char*)(void*)item_category, strlen(item_category), ImGuiInputTextFlags_ReadOnly);
3564
                            ImGui::PopStyleVar();
3565
                        }
3566
3567
                        ImGui::PopID();
3568
                    }
3569
                    if (!use_clipper)
3570
                        break;
3571
                }
3572
3573
                if (show_in_table)
3574
                {
3575
                    ImGui::EndTable();
3576
                    if (widget_type == WidgetType_TreeNode)
3577
                        ImGui::PopStyleVar();
3578
                }
3579
3580
                // Apply multi-select requests
3581
                ms_io = ImGui::EndMultiSelect();
3582
                selection.ApplyRequests(ms_io);
3583
                if (want_delete)
3584
                    selection.ApplyDeletionPostLoop(ms_io, items, item_curr_idx_to_focus);
3585
3586
                if (widget_type == WidgetType_TreeNode)
3587
                    ImGui::PopStyleVar();
3588
            }
3589
            ImGui::EndChild();
3590
            ImGui::TreePop();
3591
        }
3592
        ImGui::TreePop();
3593
    }
3594
}
3595
3596
//-----------------------------------------------------------------------------
3597
// [SECTION] DemoWindowWidgetsTabs()
3598
//-----------------------------------------------------------------------------
3599
3600
static void EditTabBarFittingPolicyFlags(ImGuiTabBarFlags* p_flags)
3601
{
3602
    if ((*p_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0)
3603
        *p_flags |= ImGuiTabBarFlags_FittingPolicyDefault_;
3604
    if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyMixed", p_flags, ImGuiTabBarFlags_FittingPolicyMixed))
3605
        *p_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyMixed);
3606
    if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyShrink", p_flags, ImGuiTabBarFlags_FittingPolicyShrink))
3607
        *p_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyShrink);
3608
    if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", p_flags, ImGuiTabBarFlags_FittingPolicyScroll))
3609
        *p_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll);
3610
}
3611
3612
static void DemoWindowWidgetsTabs()
3613
{
3614
    if (ImGui::TreeNode("Tabs"))
3615
    {
3616
        IMGUI_DEMO_MARKER("Widgets/Tabs");
3617
        if (ImGui::TreeNode("Basic"))
3618
        {
3619
            IMGUI_DEMO_MARKER("Widgets/Tabs/Basic");
3620
            ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None;
3621
            if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
3622
            {
3623
                if (ImGui::BeginTabItem("Avocado"))
3624
                {
3625
                    ImGui::Text("This is the Avocado tab!\nblah blah blah blah blah");
3626
                    ImGui::EndTabItem();
3627
                }
3628
                if (ImGui::BeginTabItem("Broccoli"))
3629
                {
3630
                    ImGui::Text("This is the Broccoli tab!\nblah blah blah blah blah");
3631
                    ImGui::EndTabItem();
3632
                }
3633
                if (ImGui::BeginTabItem("Cucumber"))
3634
                {
3635
                    ImGui::Text("This is the Cucumber tab!\nblah blah blah blah blah");
3636
                    ImGui::EndTabItem();
3637
                }
3638
                ImGui::EndTabBar();
3639
            }
3640
            ImGui::Separator();
3641
            ImGui::TreePop();
3642
        }
3643
3644
        if (ImGui::TreeNode("Advanced & Close Button"))
3645
        {
3646
            IMGUI_DEMO_MARKER("Widgets/Tabs/Advanced & Close Button");
3647
            // Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0).
3648
            static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable;
3649
            ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", &tab_bar_flags, ImGuiTabBarFlags_Reorderable);
3650
            ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", &tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs);
3651
            ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton);
3652
            ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", &tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton);
3653
            ImGui::CheckboxFlags("ImGuiTabBarFlags_DrawSelectedOverline", &tab_bar_flags, ImGuiTabBarFlags_DrawSelectedOverline);
3654
            EditTabBarFittingPolicyFlags(&tab_bar_flags);
3655
3656
            // Tab Bar
3657
            ImGui::AlignTextToFramePadding();
3658
            ImGui::Text("Opened:");
3659
            const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" };
3660
            static bool opened[4] = { true, true, true, true }; // Persistent user state
3661
            for (int n = 0; n < IM_COUNTOF(opened); n++)
3662
            {
3663
                ImGui::SameLine();
3664
                ImGui::Checkbox(names[n], &opened[n]);
3665
            }
3666
3667
            // Passing a bool* to BeginTabItem() is similar to passing one to Begin():
3668
            // the underlying bool will be set to false when the tab is closed.
3669
            if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
3670
            {
3671
                for (int n = 0; n < IM_COUNTOF(opened); n++)
3672
                    if (opened[n] && ImGui::BeginTabItem(names[n], &opened[n], ImGuiTabItemFlags_None))
3673
                    {
3674
                        ImGui::Text("This is the %s tab!", names[n]);
3675
                        if (n & 1)
3676
                            ImGui::Text("I am an odd tab.");
3677
                        ImGui::EndTabItem();
3678
                    }
3679
                ImGui::EndTabBar();
3680
            }
3681
            ImGui::Separator();
3682
            ImGui::TreePop();
3683
        }
3684
3685
        if (ImGui::TreeNode("TabItemButton & Leading/Trailing flags"))
3686
        {
3687
            IMGUI_DEMO_MARKER("Widgets/Tabs/TabItemButton & Leading-Trailing flags");
3688
            static ImVector<int> active_tabs;
3689
            static int next_tab_id = 0;
3690
            if (next_tab_id == 0) // Initialize with some default tabs
3691
                for (int i = 0; i < 3; i++)
3692
                    active_tabs.push_back(next_tab_id++);
3693
3694
            // TabItemButton() and Leading/Trailing flags are distinct features which we will demo together.
3695
            // (It is possible to submit regular tabs with Leading/Trailing flags, or TabItemButton tabs without Leading/Trailing flags...
3696
            // but they tend to make more sense together)
3697
            static bool show_leading_button = true;
3698
            static bool show_trailing_button = true;
3699
            ImGui::Checkbox("Show Leading TabItemButton()", &show_leading_button);
3700
            ImGui::Checkbox("Show Trailing TabItemButton()", &show_trailing_button);
3701
3702
            // Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs
3703
            static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_FittingPolicyShrink;
3704
            EditTabBarFittingPolicyFlags(&tab_bar_flags);
3705
3706
            if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
3707
            {
3708
                // Demo a Leading TabItemButton(): click the "?" button to open a menu
3709
                if (show_leading_button)
3710
                    if (ImGui::TabItemButton("?", ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_NoTooltip))
3711
                        ImGui::OpenPopup("MyHelpMenu");
3712
                if (ImGui::BeginPopup("MyHelpMenu"))
3713
                {
3714
                    ImGui::Selectable("Hello!");
3715
                    ImGui::EndPopup();
3716
                }
3717
3718
                // Demo Trailing Tabs: click the "+" button to add a new tab.
3719
                // (In your app you may want to use a font icon instead of the "+")
3720
                // We submit it before the regular tabs, but thanks to the ImGuiTabItemFlags_Trailing flag it will always appear at the end.
3721
                if (show_trailing_button)
3722
                    if (ImGui::TabItemButton("+", ImGuiTabItemFlags_Trailing | ImGuiTabItemFlags_NoTooltip))
3723
                        active_tabs.push_back(next_tab_id++); // Add new tab
3724
3725
                // Submit our regular tabs
3726
                for (int n = 0; n < active_tabs.Size; )
3727
                {
3728
                    bool open = true;
3729
                    char name[16];
3730
                    snprintf(name, IM_COUNTOF(name), "%04d", active_tabs[n]);
3731
                    if (ImGui::BeginTabItem(name, &open, ImGuiTabItemFlags_None))
3732
                    {
3733
                        ImGui::Text("This is the %s tab!", name);
3734
                        ImGui::EndTabItem();
3735
                    }
3736
3737
                    if (!open)
3738
                        active_tabs.erase(active_tabs.Data + n);
3739
                    else
3740
                        n++;
3741
                }
3742
3743
                ImGui::EndTabBar();
3744
            }
3745
            ImGui::Separator();
3746
            ImGui::TreePop();
3747
        }
3748
        ImGui::TreePop();
3749
    }
3750
}
3751
3752
//-----------------------------------------------------------------------------
3753
// [SECTION] DemoWindowWidgetsText()
3754
//-----------------------------------------------------------------------------
3755
3756
static void DemoWindowWidgetsText()
3757
{
3758
    if (ImGui::TreeNode("Text"))
3759
    {
3760
        IMGUI_DEMO_MARKER("Widgets/Text");
3761
        if (ImGui::TreeNode("Colorful Text"))
3762
        {
3763
            IMGUI_DEMO_MARKER("Widgets/Text/Colored Text");
3764
            // Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility.
3765
            ImGui::TextColored(ImVec4(1.0f, 0.0f, 1.0f, 1.0f), "Pink");
3766
            ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Yellow");
3767
            ImGui::TextDisabled("Disabled");
3768
            ImGui::SameLine(); HelpMarker("The TextDisabled color is stored in ImGuiStyle.");
3769
            ImGui::TreePop();
3770
        }
3771
3772
        if (ImGui::TreeNode("Font Size"))
3773
        {
3774
            IMGUI_DEMO_MARKER("Widgets/Text/Font Size");
3775
            ImGuiStyle& style = ImGui::GetStyle();
3776
            const float global_scale = style.FontScaleMain * style.FontScaleDpi;
3777
            ImGui::Text("style.FontScaleMain = %0.2f", style.FontScaleMain);
3778
            ImGui::Text("style.FontScaleDpi = %0.2f", style.FontScaleDpi);
3779
            ImGui::Text("global_scale = ~%0.2f", global_scale); // This is not technically accurate as internal scales may apply, but conceptually let's pretend it is.
3780
            ImGui::Text("FontSize = %0.2f", ImGui::GetFontSize());
3781
3782
            ImGui::SeparatorText("");
3783
            static float custom_size = 16.0f;
3784
            ImGui::SliderFloat("custom_size", &custom_size, 10.0f, 100.0f, "%.0f");
3785
            ImGui::Text("ImGui::PushFont(nullptr, custom_size);");
3786
            ImGui::PushFont(NULL, custom_size);
3787
            ImGui::Text("FontSize = %.2f (== %.2f * global_scale)", ImGui::GetFontSize(), custom_size);
3788
            ImGui::PopFont();
3789
3790
            ImGui::SeparatorText("");
3791
            static float custom_scale = 1.0f;
3792
            ImGui::SliderFloat("custom_scale", &custom_scale, 0.5f, 4.0f, "%.2f");
3793
            ImGui::Text("ImGui::PushFont(nullptr, style.FontSizeBase * custom_scale);");
3794
            ImGui::PushFont(NULL, style.FontSizeBase * custom_scale);
3795
            ImGui::Text("FontSize = %.2f (== style.FontSizeBase * %.2f * global_scale)", ImGui::GetFontSize(), custom_scale);
3796
            ImGui::PopFont();
3797
3798
            ImGui::SeparatorText("");
3799
            for (float scaling = 0.5f; scaling <= 4.0f; scaling += 0.5f)
3800
            {
3801
                ImGui::PushFont(NULL, style.FontSizeBase * scaling);
3802
                ImGui::Text("FontSize = %.2f (== style.FontSizeBase * %.2f * global_scale)", ImGui::GetFontSize(), scaling);
3803
                ImGui::PopFont();
3804
            }
3805
3806
            ImGui::TreePop();
3807
        }
3808
3809
        if (ImGui::TreeNode("Word Wrapping"))
3810
        {
3811
            IMGUI_DEMO_MARKER("Widgets/Text/Word Wrapping");
3812
            // Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility.
3813
            ImGui::TextWrapped(
3814
                "This text should automatically wrap on the edge of the window. The current implementation "
3815
                "for text wrapping follows simple rules suitable for English and possibly other languages.");
3816
            ImGui::Spacing();
3817
3818
            static float wrap_width = 200.0f;
3819
            ImGui::SliderFloat("Wrap width", &wrap_width, -20, 600, "%.0f");
3820
3821
            ImDrawList* draw_list = ImGui::GetWindowDrawList();
3822
            for (int n = 0; n < 2; n++)
3823
            {
3824
                ImGui::Text("Test paragraph %d:", n);
3825
                ImVec2 pos = ImGui::GetCursorScreenPos();
3826
                ImVec2 marker_min = ImVec2(pos.x + wrap_width, pos.y);
3827
                ImVec2 marker_max = ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight());
3828
                ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width);
3829
                if (n == 0)
3830
                    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);
3831
                else
3832
                    ImGui::Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee   ffffffff. gggggggg!hhhhhhhh");
3833
3834
                // Draw actual text bounding box, following by marker of our expected limit (should not overlap!)
3835
                draw_list->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 255, 0, 255));
3836
                draw_list->AddRectFilled(marker_min, marker_max, IM_COL32(255, 0, 255, 255));
3837
                ImGui::PopTextWrapPos();
3838
            }
3839
3840
            ImGui::TreePop();
3841
        }
3842
3843
        if (ImGui::TreeNode("UTF-8 Text"))
3844
        {
3845
            IMGUI_DEMO_MARKER("Widgets/Text/UTF-8 Text");
3846
            // UTF-8 test with Japanese characters
3847
            // (Needs a suitable font? Try "Google Noto" or "Arial Unicode". See docs/FONTS.md for details.)
3848
            // - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8
3849
            // - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. in Visual Studio, you
3850
            //   can save your source files as 'UTF-8 without signature').
3851
            // - FOR THIS DEMO FILE ONLY, BECAUSE WE WANT TO SUPPORT OLD COMPILERS, WE ARE *NOT* INCLUDING RAW UTF-8
3852
            //   CHARACTERS IN THIS SOURCE FILE. Instead we are encoding a few strings with hexadecimal constants.
3853
            //   Don't do this in your application! Please use u8"text in any language" in your application!
3854
            // Note that characters values are preserved even by InputText() if the font cannot be displayed,
3855
            // so you can safely copy & paste garbled characters into another application.
3856
            ImGui::TextWrapped(
3857
                "CJK text will only appear if the font was loaded with the appropriate CJK character ranges. "
3858
                "Call io.Fonts->AddFontFromFileTTF() manually to load extra character ranges. "
3859
                "Read docs/FONTS.md for details.");
3860
            ImGui::Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)");
3861
            ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)");
3862
            static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e";
3863
            //static char buf[32] = u8"NIHONGO"; // <- this is how you would write it with C++11, using real kanjis
3864
            ImGui::InputText("UTF-8 input", buf, IM_COUNTOF(buf));
3865
            ImGui::TreePop();
3866
        }
3867
        ImGui::TreePop();
3868
    }
3869
}
3870
3871
//-----------------------------------------------------------------------------
3872
// [SECTION] DemoWindowWidgetsTextFilter()
3873
//-----------------------------------------------------------------------------
3874
3875
static void DemoWindowWidgetsTextFilter()
3876
{
3877
    if (ImGui::TreeNode("Text Filter"))
3878
    {
3879
        IMGUI_DEMO_MARKER("Widgets/Text Filter");
3880
        // Helper class to easy setup a text filter.
3881
        // You may want to implement a more feature-full filtering scheme in your own application.
3882
        HelpMarker("Not a widget per-se, but ImGuiTextFilter is a helper to perform simple filtering on text strings.");
3883
        static ImGuiTextFilter filter;
3884
        ImGui::Text("Filter usage:\n"
3885
            "  \"\"         display all lines\n"
3886
            "  \"xxx\"      display lines containing \"xxx\"\n"
3887
            "  \"xxx,yyy\"  display lines containing \"xxx\" or \"yyy\"\n"
3888
            "  \"-xxx\"     hide lines containing \"xxx\"");
3889
        filter.Draw();
3890
        const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" };
3891
        for (int i = 0; i < IM_COUNTOF(lines); i++)
3892
            if (filter.PassFilter(lines[i]))
3893
                ImGui::BulletText("%s", lines[i]);
3894
        ImGui::TreePop();
3895
    }
3896
}
3897
3898
//-----------------------------------------------------------------------------
3899
// [SECTION] DemoWindowWidgetsTextInput()
3900
//-----------------------------------------------------------------------------
3901
3902
static void DemoWindowWidgetsTextInput()
3903
{
3904
    // To wire InputText() with std::string or any other custom string type,
3905
    // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file.
3906
    if (ImGui::TreeNode("Text Input"))
3907
    {
3908
        IMGUI_DEMO_MARKER("Widgets/Text Input");
3909
        if (ImGui::TreeNode("Multi-line Text Input"))
3910
        {
3911
            IMGUI_DEMO_MARKER("Widgets/Text Input/Multi-line Text Input");
3912
            // WE ARE USING A FIXED-SIZE BUFFER FOR SIMPLICITY HERE.
3913
            // If you want to use InputText() with std::string or any custom dynamic string type:
3914
            // - For std::string: use the wrapper in misc/cpp/imgui_stdlib.h/.cpp
3915
            // - Otherwise, see the 'Dear ImGui Demo->Widgets->Text Input->Resize Callback' for using ImGuiInputTextFlags_CallbackResize.
3916
            static char text[1024 * 16] =
3917
                "/*\n"
3918
                " The Pentium F00F bug, shorthand for F0 0F C7 C8,\n"
3919
                " the hexadecimal encoding of one offending instruction,\n"
3920
                " more formally, the invalid operand with locked CMPXCHG8B\n"
3921
                " instruction bug, is a design flaw in the majority of\n"
3922
                " Intel Pentium, Pentium MMX, and Pentium OverDrive\n"
3923
                " processors (all in the P5 microarchitecture).\n"
3924
                "*/\n\n"
3925
                "label:\n"
3926
                "\tlock cmpxchg8b eax\n";
3927
3928
            static ImGuiInputTextFlags flags = ImGuiInputTextFlags_AllowTabInput;
3929
            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)");
3930
            ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly);
3931
            ImGui::CheckboxFlags("ImGuiInputTextFlags_WordWrap", &flags, ImGuiInputTextFlags_WordWrap);
3932
            ImGui::SameLine(); HelpMarker("Feature is currently in Beta. Please read comments in imgui.h");
3933
            ImGui::CheckboxFlags("ImGuiInputTextFlags_AllowTabInput", &flags, ImGuiInputTextFlags_AllowTabInput);
3934
            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.");
3935
            ImGui::CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", &flags, ImGuiInputTextFlags_CtrlEnterForNewLine);
3936
            ImGui::InputTextMultiline("##source", text, IM_COUNTOF(text), ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16), flags);
3937
            ImGui::TreePop();
3938
        }
3939
3940
        if (ImGui::TreeNode("Filtered Text Input"))
3941
        {
3942
            IMGUI_DEMO_MARKER("Widgets/Text Input/Filtered Text Input");
3943
            struct TextFilters
3944
            {
3945
                // Modify character input by altering 'data->Eventchar' (ImGuiInputTextFlags_CallbackCharFilter callback)
3946
                static int FilterCasingSwap(ImGuiInputTextCallbackData* data)
3947
                {
3948
                    if (data->EventChar >= 'a' && data->EventChar <= 'z') { data->EventChar -= 'a' - 'A'; } // Lowercase becomes uppercase
3949
                    else if (data->EventChar >= 'A' && data->EventChar <= 'Z') { data->EventChar += 'a' - 'A'; } // Uppercase becomes lowercase
3950
                    return 0;
3951
                }
3952
3953
                // Return 0 (pass) if the character is 'i' or 'm' or 'g' or 'u' or 'i', otherwise return 1 (filter out)
3954
                static int FilterImGuiLetters(ImGuiInputTextCallbackData* data)
3955
                {
3956
                    if (data->EventChar < 256 && strchr("imgui", (char)data->EventChar))
3957
                        return 0;
3958
                    return 1;
3959
                }
3960
            };
3961
3962
            static char buf1[32] = ""; ImGui::InputText("default", buf1, IM_COUNTOF(buf1));
3963
            static char buf2[32] = ""; ImGui::InputText("decimal", buf2, IM_COUNTOF(buf2), ImGuiInputTextFlags_CharsDecimal);
3964
            static char buf3[32] = ""; ImGui::InputText("hexadecimal", buf3, IM_COUNTOF(buf3), ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase);
3965
            static char buf4[32] = ""; ImGui::InputText("uppercase", buf4, IM_COUNTOF(buf4), ImGuiInputTextFlags_CharsUppercase);
3966
            static char buf5[32] = ""; ImGui::InputText("no blank", buf5, IM_COUNTOF(buf5), ImGuiInputTextFlags_CharsNoBlank);
3967
            static char buf6[32] = ""; ImGui::InputText("casing swap", buf6, IM_COUNTOF(buf6), ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterCasingSwap); // Use CharFilter callback to replace characters.
3968
            static char buf7[32] = ""; ImGui::InputText("\"imgui\"", buf7, IM_COUNTOF(buf7), ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters); // Use CharFilter callback to disable some characters.
3969
            ImGui::TreePop();
3970
        }
3971
3972
        if (ImGui::TreeNode("Password Input"))
3973
        {
3974
            IMGUI_DEMO_MARKER("Widgets/Text Input/Password input");
3975
            static char password[64] = "password123";
3976
            ImGui::InputText("password", password, IM_COUNTOF(password), ImGuiInputTextFlags_Password);
3977
            ImGui::SameLine(); HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n");
3978
            ImGui::InputTextWithHint("password (w/ hint)", "<password>", password, IM_COUNTOF(password), ImGuiInputTextFlags_Password);
3979
            ImGui::InputText("password (clear)", password, IM_COUNTOF(password));
3980
            ImGui::TreePop();
3981
        }
3982
3983
        if (ImGui::TreeNode("Completion, History, Edit Callbacks"))
3984
        {
3985
            IMGUI_DEMO_MARKER("Widgets/Text Input/Completion, History, Edit Callbacks");
3986
            struct Funcs
3987
            {
3988
                static int MyCallback(ImGuiInputTextCallbackData* data)
3989
                {
3990
                    if (data->EventFlag == ImGuiInputTextFlags_CallbackCompletion)
3991
                    {
3992
                        data->InsertChars(data->CursorPos, "..");
3993
                    }
3994
                    else if (data->EventFlag == ImGuiInputTextFlags_CallbackHistory)
3995
                    {
3996
                        if (data->EventKey == ImGuiKey_UpArrow)
3997
                        {
3998
                            data->DeleteChars(0, data->BufTextLen);
3999
                            data->InsertChars(0, "Pressed Up!");
4000
                            data->SelectAll();
4001
                        }
4002
                        else if (data->EventKey == ImGuiKey_DownArrow)
4003
                        {
4004
                            data->DeleteChars(0, data->BufTextLen);
4005
                            data->InsertChars(0, "Pressed Down!");
4006
                            data->SelectAll();
4007
                        }
4008
                    }
4009
                    else if (data->EventFlag == ImGuiInputTextFlags_CallbackEdit)
4010
                    {
4011
                        // Toggle casing of first character
4012
                        char c = data->Buf[0];
4013
                        if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) data->Buf[0] ^= 32;
4014
                        data->BufDirty = true;
4015
4016
                        // Increment a counter
4017
                        int* p_int = (int*)data->UserData;
4018
                        *p_int = *p_int + 1;
4019
                    }
4020
                    return 0;
4021
                }
4022
            };
4023
            static char buf1[64];
4024
            ImGui::InputText("Completion", buf1, IM_COUNTOF(buf1), ImGuiInputTextFlags_CallbackCompletion, Funcs::MyCallback);
4025
            ImGui::SameLine(); HelpMarker(
4026
                "Here we append \"..\" each time Tab is pressed. "
4027
                "See 'Examples>Console' for a more meaningful demonstration of using this callback.");
4028
4029
            static char buf2[64];
4030
            ImGui::InputText("History", buf2, IM_COUNTOF(buf2), ImGuiInputTextFlags_CallbackHistory, Funcs::MyCallback);
4031
            ImGui::SameLine(); HelpMarker(
4032
                "Here we replace and select text each time Up/Down are pressed. "
4033
                "See 'Examples>Console' for a more meaningful demonstration of using this callback.");
4034
4035
            static char buf3[64];
4036
            static int edit_count = 0;
4037
            ImGui::InputText("Edit", buf3, IM_COUNTOF(buf3), ImGuiInputTextFlags_CallbackEdit, Funcs::MyCallback, (void*)&edit_count);
4038
            ImGui::SameLine(); HelpMarker(
4039
                "Here we toggle the casing of the first character on every edit + count edits.");
4040
            ImGui::SameLine(); ImGui::Text("(%d)", edit_count);
4041
4042
            ImGui::TreePop();
4043
        }
4044
4045
        if (ImGui::TreeNode("Resize Callback"))
4046
        {
4047
            IMGUI_DEMO_MARKER("Widgets/Text Input/Resize Callback");
4048
            // To wire InputText() with std::string or any other custom string type,
4049
            // you can use the ImGuiInputTextFlags_CallbackResize flag + create a custom ImGui::InputText() wrapper
4050
            // using your preferred type. See misc/cpp/imgui_stdlib.h for an implementation of this using std::string.
4051
            HelpMarker(
4052
                "Using ImGuiInputTextFlags_CallbackResize to wire your custom string type to InputText().\n\n"
4053
                "See misc/cpp/imgui_stdlib.h for an implementation of this for std::string.");
4054
            struct Funcs
4055
            {
4056
                static int MyResizeCallback(ImGuiInputTextCallbackData* data)
4057
                {
4058
                    if (data->EventFlag == ImGuiInputTextFlags_CallbackResize)
4059
                    {
4060
                        ImVector<char>* my_str = (ImVector<char>*)data->UserData;
4061
                        IM_ASSERT(my_str->begin() == data->Buf);
4062
                        my_str->resize(data->BufSize); // NB: On resizing calls, generally data->BufSize == data->BufTextLen + 1
4063
                        data->Buf = my_str->begin();
4064
                    }
4065
                    return 0;
4066
                }
4067
4068
                // Note: Because ImGui:: is a namespace you would typically add your own function into the namespace.
4069
                // For example, you code may declare a function 'ImGui::InputText(const char* label, MyString* my_str)'
4070
                static bool MyInputTextMultiline(const char* label, ImVector<char>* my_str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0)
4071
                {
4072
                    IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
4073
                    return ImGui::InputTextMultiline(label, my_str->begin(), (size_t)my_str->size(), size, flags | ImGuiInputTextFlags_CallbackResize, Funcs::MyResizeCallback, (void*)my_str);
4074
                }
4075
            };
4076
4077
            // For this demo we are using ImVector as a string container.
4078
            // Note that because we need to store a terminating zero character, our size/capacity are 1 more
4079
            // than usually reported by a typical string class.
4080
            static ImGuiInputTextFlags flags = ImGuiInputTextFlags_None;
4081
            ImGui::CheckboxFlags("ImGuiInputTextFlags_WordWrap", &flags, ImGuiInputTextFlags_WordWrap);
4082
4083
            static ImVector<char> my_str;
4084
            if (my_str.empty())
4085
                my_str.push_back(0);
4086
            Funcs::MyInputTextMultiline("##MyStr", &my_str, ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16), flags);
4087
            ImGui::Text("Data: %p\nSize: %d\nCapacity: %d", (void*)my_str.begin(), my_str.size(), my_str.capacity());
4088
            ImGui::TreePop();
4089
        }
4090
4091
        if (ImGui::TreeNode("Eliding, Alignment"))
4092
        {
4093
            IMGUI_DEMO_MARKER("Widgets/Text Input/Eliding, Alignment");
4094
            static char buf1[128] = "/path/to/some/folder/with/long/filename.cpp";
4095
            static ImGuiInputTextFlags flags = ImGuiInputTextFlags_ElideLeft;
4096
            ImGui::CheckboxFlags("ImGuiInputTextFlags_ElideLeft", &flags, ImGuiInputTextFlags_ElideLeft);
4097
            ImGui::InputText("Path", buf1, IM_COUNTOF(buf1), flags);
4098
            ImGui::TreePop();
4099
        }
4100
4101
        if (ImGui::TreeNode("Miscellaneous"))
4102
        {
4103
            IMGUI_DEMO_MARKER("Widgets/Text Input/Miscellaneous");
4104
            static char buf1[16];
4105
            static ImGuiInputTextFlags flags = ImGuiInputTextFlags_EscapeClearsAll;
4106
            ImGui::CheckboxFlags("ImGuiInputTextFlags_EscapeClearsAll", &flags, ImGuiInputTextFlags_EscapeClearsAll);
4107
            ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly);
4108
            ImGui::CheckboxFlags("ImGuiInputTextFlags_NoUndoRedo", &flags, ImGuiInputTextFlags_NoUndoRedo);
4109
            ImGui::InputText("Hello", buf1, IM_COUNTOF(buf1), flags);
4110
            ImGui::TreePop();
4111
        }
4112
4113
        ImGui::TreePop();
4114
    }
4115
4116
}
4117
4118
//-----------------------------------------------------------------------------
4119
// [SECTION] DemoWindowWidgetsTooltips()
4120
//-----------------------------------------------------------------------------
4121
4122
static void DemoWindowWidgetsTooltips()
4123
{
4124
    if (ImGui::TreeNode("Tooltips"))
4125
    {
4126
        IMGUI_DEMO_MARKER("Widgets/Tooltips");
4127
        // Tooltips are windows following the mouse. They do not take focus away.
4128
        ImGui::SeparatorText("General");
4129
4130
        // Typical use cases:
4131
        // - Short-form (text only):      SetItemTooltip("Hello");
4132
        // - Short-form (any contents):   if (BeginItemTooltip()) { Text("Hello"); EndTooltip(); }
4133
4134
        // - Full-form (text only):       if (IsItemHovered(...)) { SetTooltip("Hello"); }
4135
        // - Full-form (any contents):    if (IsItemHovered(...) && BeginTooltip()) { Text("Hello"); EndTooltip(); }
4136
4137
        HelpMarker(
4138
            "Tooltip are typically created by using a IsItemHovered() + SetTooltip() sequence.\n\n"
4139
            "We provide a helper SetItemTooltip() function to perform the two with standards flags.");
4140
4141
        ImVec2 sz = ImVec2(-FLT_MIN, 0.0f);
4142
4143
        ImGui::Button("Basic", sz);
4144
        ImGui::SetItemTooltip("I am a tooltip");
4145
4146
        ImGui::Button("Fancy", sz);
4147
        if (ImGui::BeginItemTooltip())
4148
        {
4149
            ImGui::Text("I am a fancy tooltip");
4150
            static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
4151
            ImGui::PlotLines("Curve", arr, IM_COUNTOF(arr));
4152
            ImGui::Text("Sin(time) = %f", sinf((float)ImGui::GetTime()));
4153
            ImGui::EndTooltip();
4154
        }
4155
4156
        ImGui::SeparatorText("Always On");
4157
4158
        // Showcase NOT relying on a IsItemHovered() to emit a tooltip.
4159
        // Here the tooltip is always emitted when 'always_on == true'.
4160
        static int always_on = 0;
4161
        ImGui::RadioButton("Off", &always_on, 0);
4162
        ImGui::SameLine();
4163
        ImGui::RadioButton("Always On (Simple)", &always_on, 1);
4164
        ImGui::SameLine();
4165
        ImGui::RadioButton("Always On (Advanced)", &always_on, 2);
4166
        if (always_on == 1)
4167
            ImGui::SetTooltip("I am following you around.");
4168
        else if (always_on == 2 && ImGui::BeginTooltip())
4169
        {
4170
            ImGui::ProgressBar(sinf((float)ImGui::GetTime()) * 0.5f + 0.5f, ImVec2(ImGui::GetFontSize() * 25, 0.0f));
4171
            ImGui::EndTooltip();
4172
        }
4173
4174
        ImGui::SeparatorText("Custom");
4175
4176
        HelpMarker(
4177
            "Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() is the preferred way to standardize "
4178
            "tooltip activation details across your application. You may however decide to use custom "
4179
            "flags for a specific tooltip instance.");
4180
4181
        // The following examples are passed for documentation purpose but may not be useful to most users.
4182
        // Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() will pull ImGuiHoveredFlags flags values from
4183
        // 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' depending on whether mouse or keyboard/gamepad is being used.
4184
        // With default settings, ImGuiHoveredFlags_ForTooltip is equivalent to ImGuiHoveredFlags_DelayShort + ImGuiHoveredFlags_Stationary.
4185
        ImGui::Button("Manual", sz);
4186
        if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip))
4187
            ImGui::SetTooltip("I am a manually emitted tooltip.");
4188
4189
        ImGui::Button("DelayNone", sz);
4190
        if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNone))
4191
            ImGui::SetTooltip("I am a tooltip with no delay.");
4192
4193
        ImGui::Button("DelayShort", sz);
4194
        if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort | ImGuiHoveredFlags_NoSharedDelay))
4195
            ImGui::SetTooltip("I am a tooltip with a short delay (%0.2f sec).", ImGui::GetStyle().HoverDelayShort);
4196
4197
        ImGui::Button("DelayLong", sz);
4198
        if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal | ImGuiHoveredFlags_NoSharedDelay))
4199
            ImGui::SetTooltip("I am a tooltip with a long delay (%0.2f sec).", ImGui::GetStyle().HoverDelayNormal);
4200
4201
        ImGui::Button("Stationary", sz);
4202
        if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary))
4203
            ImGui::SetTooltip("I am a tooltip requiring mouse to be stationary before activating.");
4204
4205
        // Using ImGuiHoveredFlags_ForTooltip will pull flags from 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav',
4206
        // which default value include the ImGuiHoveredFlags_AllowWhenDisabled flag.
4207
        ImGui::BeginDisabled();
4208
        ImGui::Button("Disabled item", sz);
4209
        if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip))
4210
            ImGui::SetTooltip("I am a tooltip for a disabled item.");
4211
        ImGui::EndDisabled();
4212
4213
        ImGui::TreePop();
4214
    }
4215
}
4216
4217
//-----------------------------------------------------------------------------
4218
// [SECTION] DemoWindowWidgetsTreeNodes()
4219
//-----------------------------------------------------------------------------
4220
4221
static void DemoWindowWidgetsTreeNodes()
4222
{
4223
    if (ImGui::TreeNode("Tree Nodes"))
4224
    {
4225
        IMGUI_DEMO_MARKER("Widgets/Tree Nodes");
4226
        // See see "Examples -> Property Editor" (ShowExampleAppPropertyEditor() function) for a fancier, data-driven tree.
4227
        if (ImGui::TreeNode("Basic Trees"))
4228
        {
4229
            IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Basic Trees");
4230
            for (int i = 0; i < 5; i++)
4231
            {
4232
                // Use SetNextItemOpen() so set the default state of a node to be open. We could
4233
                // also use TreeNodeEx() with the ImGuiTreeNodeFlags_DefaultOpen flag to achieve the same thing!
4234
                if (i == 0)
4235
                    ImGui::SetNextItemOpen(true, ImGuiCond_Once);
4236
4237
                // Here we use PushID() to generate a unique base ID, and then the "" used as TreeNode id won't conflict.
4238
                // An alternative to using 'PushID() + TreeNode("", ...)' to generate a unique ID is to use 'TreeNode((void*)(intptr_t)i, ...)',
4239
                // aka generate a dummy pointer-sized value to be hashed. The demo below uses that technique. Both are fine.
4240
                ImGui::PushID(i);
4241
                if (ImGui::TreeNode("", "Child %d", i))
4242
                {
4243
                    ImGui::Text("blah blah");
4244
                    ImGui::SameLine();
4245
                    if (ImGui::SmallButton("button")) {}
4246
                    ImGui::TreePop();
4247
                }
4248
                ImGui::PopID();
4249
            }
4250
            ImGui::TreePop();
4251
        }
4252
4253
        if (ImGui::TreeNode("Hierarchy Lines"))
4254
        {
4255
            IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Hierarchy Lines");
4256
            static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DefaultOpen;
4257
            HelpMarker("Default option for DrawLinesXXX is stored in style.TreeLinesFlags");
4258
            ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesNone", &base_flags, ImGuiTreeNodeFlags_DrawLinesNone);
4259
            ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesFull", &base_flags, ImGuiTreeNodeFlags_DrawLinesFull);
4260
            ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesToNodes", &base_flags, ImGuiTreeNodeFlags_DrawLinesToNodes);
4261
4262
            if (ImGui::TreeNodeEx("Parent", base_flags))
4263
            {
4264
                if (ImGui::TreeNodeEx("Child 1", base_flags))
4265
                {
4266
                    ImGui::Button("Button for Child 1");
4267
                    ImGui::TreePop();
4268
                }
4269
                if (ImGui::TreeNodeEx("Child 2", base_flags))
4270
                {
4271
                    ImGui::Button("Button for Child 2");
4272
                    ImGui::TreePop();
4273
                }
4274
                ImGui::Text("Remaining contents");
4275
                ImGui::Text("Remaining contents");
4276
                ImGui::TreePop();
4277
            }
4278
4279
            ImGui::TreePop();
4280
        }
4281
4282
        if (ImGui::TreeNode("Clipping Large Trees"))
4283
        {
4284
            IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Clipping Large Trees");
4285
            ImGui::TextWrapped(
4286
                "- Using ImGuiListClipper with trees is a less easy than on arrays or grids.\n"
4287
                "- Refer to 'Demo->Examples->Property Editor' for an example of how to do that.\n"
4288
                "- Discuss in #3823");
4289
            ImGui::TreePop();
4290
        }
4291
4292
        if (ImGui::TreeNode("Selectable Nodes"))
4293
        {
4294
            IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Selectable Nodes");
4295
            HelpMarker(
4296
                "Manually implemented selectable nodes.\n"
4297
                "Click to select, Ctrl+Click to toggle, click on arrows or double-click to open.\n\n"
4298
                "You may also use the multi-select API (see 'Demo->Widgets->Selection State & Multi-Select') for more advanced multi-selection features.");
4299
4300
            // Hold in 'selection_mask' a simple representation of what may be user-side selection state.
4301
            // - You may retain selection state inside or outside your objects in whatever format you see fit.
4302
            //   You may use ImGuiSelectionBasicStorage which is conceptually close to a set<> of identifiers.
4303
            // - We record which node was clicked and then apply selection at the end of the loop.
4304
            // - This is a manual and simplified reimplementation of multi-selection, which the full
4305
            //   BeginMultiSelect() API implements better, but which is not trivial to wire for trees.
4306
            static int selection_mask = 0x00;
4307
            int node_clicked_idx = -1;
4308
            for (int node_n = 0; node_n < 6; node_n++)
4309
            {
4310
                // Disable the default "open on single-click behavior" + set Selected flag according to our selection.
4311
                // To alter selection we use if 'IsItemClicked() && !IsItemToggledOpen()', so clicking on an arrow doesn't alter selection.
4312
                // In a BeginMultiSelect()/EndMultiSelect() we could use IsItemToggledSelection() but here we reimplement and use our own logic.
4313
                ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth;
4314
                if (selection_mask & (1 << node_n))
4315
                    flags |= ImGuiTreeNodeFlags_Selected;
4316
4317
                bool is_open = ImGui::TreeNodeEx((void*)(intptr_t)node_n, flags, "Selectable Node %d", node_n);
4318
                if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen())
4319
                    node_clicked_idx = node_n;
4320
                if (is_open)
4321
                {
4322
                    ImGui::BulletText("<Node contents here>");
4323
                    ImGui::TreePop();
4324
                }
4325
            }
4326
            if (node_clicked_idx != -1)
4327
            {
4328
                // Update selection state (process outside of tree loop to avoid visual inconsistencies during the clicking frame)
4329
                if (ImGui::GetIO().KeyCtrl)
4330
                    selection_mask ^= (1 << node_clicked_idx);          // Ctrl+Click to toggle
4331
                else //if (!(selection_mask & (1 << node_clicked_idx))) // Depending on selection behavior you want, may want to preserve selection when clicking on item that is part of the selection
4332
                    selection_mask = (1 << node_clicked_idx);           // Click to single-select
4333
            }
4334
            ImGui::TreePop();
4335
        }
4336
4337
        if (ImGui::TreeNode("Advanced"))
4338
        {
4339
            IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Advanced");
4340
            static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth;
4341
            static bool align_label_with_current_x_position = false;
4342
            static bool use_drag_and_drop = false;
4343
            ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnArrow", &base_flags, ImGuiTreeNodeFlags_OpenOnArrow);
4344
            ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", &base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick);
4345
            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.");
4346
            ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &base_flags, ImGuiTreeNodeFlags_SpanFullWidth);
4347
            ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanLabelWidth", &base_flags, ImGuiTreeNodeFlags_SpanLabelWidth); ImGui::SameLine(); HelpMarker("Reduce hit area to the text label and a bit of margin.");
4348
            ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &base_flags, ImGuiTreeNodeFlags_SpanAllColumns); ImGui::SameLine(); HelpMarker("For use in Tables only.");
4349
            ImGui::CheckboxFlags("ImGuiTreeNodeFlags_AllowOverlap", &base_flags, ImGuiTreeNodeFlags_AllowOverlap);
4350
            ImGui::CheckboxFlags("ImGuiTreeNodeFlags_Framed", &base_flags, ImGuiTreeNodeFlags_Framed); ImGui::SameLine(); HelpMarker("Draw frame with background (e.g. for CollapsingHeader)");
4351
            ImGui::CheckboxFlags("ImGuiTreeNodeFlags_FramePadding", &base_flags, ImGuiTreeNodeFlags_FramePadding);
4352
            ImGui::CheckboxFlags("ImGuiTreeNodeFlags_NavLeftJumpsToParent", &base_flags, ImGuiTreeNodeFlags_NavLeftJumpsToParent);
4353
4354
            HelpMarker("Default option for DrawLinesXXX is stored in style.TreeLinesFlags");
4355
            ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesNone", &base_flags, ImGuiTreeNodeFlags_DrawLinesNone);
4356
            ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesFull", &base_flags, ImGuiTreeNodeFlags_DrawLinesFull);
4357
            ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesToNodes", &base_flags, ImGuiTreeNodeFlags_DrawLinesToNodes);
4358
4359
            ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position);
4360
            ImGui::Checkbox("Make Tree Nodes as drag & drop sources", &use_drag_and_drop);
4361
            if (align_label_with_current_x_position)
4362
                ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing());
4363
4364
            for (int node_n = 0; node_n < 6; node_n++)
4365
            {
4366
                ImGuiTreeNodeFlags node_flags = base_flags;
4367
                if (node_n < 3)
4368
                {
4369
                    // Items 0..2 are Tree Node
4370
                    bool is_open = ImGui::TreeNodeEx((void*)(intptr_t)node_n, node_flags, "Selectable Node %d", node_n);
4371
                    if (use_drag_and_drop && ImGui::BeginDragDropSource())
4372
                    {
4373
                        ImGui::SetDragDropPayload("MY_TREENODE_PAYLOAD_TYPE", NULL, 0);
4374
                        ImGui::Text("This is a drag and drop source");
4375
                        ImGui::EndDragDropSource();
4376
                    }
4377
                    if (node_n == 2 && (base_flags & ImGuiTreeNodeFlags_SpanLabelWidth))
4378
                    {
4379
                        // Item 2 has an additional inline button to help demonstrate SpanLabelWidth.
4380
                        ImGui::SameLine();
4381
                        if (ImGui::SmallButton("button")) {}
4382
                    }
4383
                    if (is_open)
4384
                    {
4385
                        ImGui::BulletText("Blah blah\nBlah Blah");
4386
                        ImGui::SameLine();
4387
                        ImGui::SmallButton("Button");
4388
                        ImGui::TreePop();
4389
                    }
4390
                }
4391
                else
4392
                {
4393
                    // Items 3..5 are Tree Leaves
4394
                    // The only reason we use TreeNode at all is to allow selection of the leaf. Otherwise we can
4395
                    // use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text().
4396
                    node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet
4397
                    ImGui::TreeNodeEx((void*)(intptr_t)node_n, node_flags, "Selectable Leaf %d", node_n);
4398
                    if (use_drag_and_drop && ImGui::BeginDragDropSource())
4399
                    {
4400
                        ImGui::SetDragDropPayload("MY_TREENODE_PAYLOAD_TYPE", NULL, 0);
4401
                        ImGui::Text("This is a drag and drop source");
4402
                        ImGui::EndDragDropSource();
4403
                    }
4404
                }
4405
            }
4406
            if (align_label_with_current_x_position)
4407
                ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing());
4408
            ImGui::TreePop();
4409
        }
4410
        ImGui::TreePop();
4411
    }
4412
}
4413
4414
//-----------------------------------------------------------------------------
4415
// [SECTION] DemoWindowWidgetsVerticalSliders()
4416
//-----------------------------------------------------------------------------
4417
4418
static void DemoWindowWidgetsVerticalSliders()
4419
{
4420
    if (ImGui::TreeNode("Vertical Sliders"))
4421
    {
4422
        IMGUI_DEMO_MARKER("Widgets/Vertical Sliders");
4423
        const float spacing = 4;
4424
        ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
4425
4426
        static int int_value = 0;
4427
        ImGui::VSliderInt("##int", ImVec2(18, 160), &int_value, 0, 5);
4428
        ImGui::SameLine();
4429
4430
        static float values[7] = { 0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f };
4431
        ImGui::PushID("set1");
4432
        for (int i = 0; i < 7; i++)
4433
        {
4434
            if (i > 0) ImGui::SameLine();
4435
            ImGui::PushID(i);
4436
            ImGui::PushStyleColor(ImGuiCol_FrameBg, (ImVec4)ImColor::HSV(i / 7.0f, 0.5f, 0.5f));
4437
            ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.5f));
4438
            ImGui::PushStyleColor(ImGuiCol_FrameBgActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.5f));
4439
            ImGui::PushStyleColor(ImGuiCol_SliderGrab, (ImVec4)ImColor::HSV(i / 7.0f, 0.9f, 0.9f));
4440
            ImGui::VSliderFloat("##v", ImVec2(18, 160), &values[i], 0.0f, 1.0f, "");
4441
            if (ImGui::IsItemActive() || ImGui::IsItemHovered())
4442
                ImGui::SetTooltip("%.3f", values[i]);
4443
            ImGui::PopStyleColor(4);
4444
            ImGui::PopID();
4445
        }
4446
        ImGui::PopID();
4447
4448
        ImGui::SameLine();
4449
        ImGui::PushID("set2");
4450
        static float values2[4] = { 0.20f, 0.80f, 0.40f, 0.25f };
4451
        const int rows = 3;
4452
        const ImVec2 small_slider_size(18, (float)(int)((160.0f - (rows - 1) * spacing) / rows));
4453
        for (int nx = 0; nx < 4; nx++)
4454
        {
4455
            if (nx > 0) ImGui::SameLine();
4456
            ImGui::BeginGroup();
4457
            for (int ny = 0; ny < rows; ny++)
4458
            {
4459
                ImGui::PushID(nx * rows + ny);
4460
                ImGui::VSliderFloat("##v", small_slider_size, &values2[nx], 0.0f, 1.0f, "");
4461
                if (ImGui::IsItemActive() || ImGui::IsItemHovered())
4462
                    ImGui::SetTooltip("%.3f", values2[nx]);
4463
                ImGui::PopID();
4464
            }
4465
            ImGui::EndGroup();
4466
        }
4467
        ImGui::PopID();
4468
4469
        ImGui::SameLine();
4470
        ImGui::PushID("set3");
4471
        for (int i = 0; i < 4; i++)
4472
        {
4473
            if (i > 0) ImGui::SameLine();
4474
            ImGui::PushID(i);
4475
            ImGui::PushStyleVar(ImGuiStyleVar_GrabMinSize, 40);
4476
            ImGui::VSliderFloat("##v", ImVec2(40, 160), &values[i], 0.0f, 1.0f, "%.2f\nsec");
4477
            ImGui::PopStyleVar();
4478
            ImGui::PopID();
4479
        }
4480
        ImGui::PopID();
4481
        ImGui::PopStyleVar();
4482
        ImGui::TreePop();
4483
    }
4484
}
4485
4486
//-----------------------------------------------------------------------------
4487
// [SECTION] DemoWindowWidgets()
4488
//-----------------------------------------------------------------------------
4489
4490
static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data)
4491
{
4492
    //ImGui::SetNextItemOpen(true, ImGuiCond_Once);
4493
    if (!ImGui::CollapsingHeader("Widgets"))
4494
        return;
4495
    // IMGUI_DEMO_MARKER("Widgets");
4496
4497
    const bool disable_all = demo_data->DisableSections; // The Checkbox for that is inside the "Disabled" section at the bottom
4498
    if (disable_all)
4499
        ImGui::BeginDisabled();
4500
4501
    DemoWindowWidgetsBasic();
4502
    DemoWindowWidgetsBullets();
4503
    DemoWindowWidgetsCollapsingHeaders();
4504
    DemoWindowWidgetsComboBoxes();
4505
    DemoWindowWidgetsColorAndPickers();
4506
    DemoWindowWidgetsDataTypes();
4507
4508
    if (disable_all)
4509
        ImGui::EndDisabled();
4510
    DemoWindowWidgetsDisableBlocks(demo_data);
4511
    if (disable_all)
4512
        ImGui::BeginDisabled();
4513
4514
    DemoWindowWidgetsDragAndDrop();
4515
    DemoWindowWidgetsDragsAndSliders();
4516
    DemoWindowWidgetsFonts();
4517
    DemoWindowWidgetsImages();
4518
    DemoWindowWidgetsListBoxes();
4519
    DemoWindowWidgetsMultiComponents();
4520
    DemoWindowWidgetsPlotting();
4521
    DemoWindowWidgetsProgressBars();
4522
    DemoWindowWidgetsQueryingStatuses();
4523
    DemoWindowWidgetsSelectables();
4524
    DemoWindowWidgetsSelectionAndMultiSelect(demo_data);
4525
    DemoWindowWidgetsTabs();
4526
    DemoWindowWidgetsText();
4527
    DemoWindowWidgetsTextFilter();
4528
    DemoWindowWidgetsTextInput();
4529
    DemoWindowWidgetsTooltips();
4530
    DemoWindowWidgetsTreeNodes();
4531
    DemoWindowWidgetsVerticalSliders();
4532
4533
    if (disable_all)
4534
        ImGui::EndDisabled();
4535
}
4536
4537
//-----------------------------------------------------------------------------
4538
// [SECTION] DemoWindowLayout()
4539
//-----------------------------------------------------------------------------
4540
4541
static void DemoWindowLayout()
4542
{
4543
    if (!ImGui::CollapsingHeader("Layout & Scrolling"))
4544
        return;
4545
4546
    if (ImGui::TreeNode("Child windows"))
4547
    {
4548
        IMGUI_DEMO_MARKER("Layout/Child windows");
4549
        ImGui::SeparatorText("Child windows");
4550
4551
        HelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window.");
4552
        static bool disable_mouse_wheel = false;
4553
        static bool disable_menu = false;
4554
        ImGui::Checkbox("Disable Mouse Wheel", &disable_mouse_wheel);
4555
        ImGui::Checkbox("Disable Menu", &disable_menu);
4556
4557
        // Child 1: no border, enable horizontal scrollbar
4558
        {
4559
            ImGuiWindowFlags window_flags = ImGuiWindowFlags_HorizontalScrollbar;
4560
            if (disable_mouse_wheel)
4561
                window_flags |= ImGuiWindowFlags_NoScrollWithMouse;
4562
            ImGui::BeginChild("ChildL", ImVec2(ImGui::GetContentRegionAvail().x * 0.5f, 260), ImGuiChildFlags_None, window_flags);
4563
            for (int i = 0; i < 100; i++)
4564
                ImGui::Text("%04d: scrollable region", i);
4565
            ImGui::EndChild();
4566
        }
4567
4568
        ImGui::SameLine();
4569
4570
        // Child 2: rounded border
4571
        {
4572
            ImGuiWindowFlags window_flags = ImGuiWindowFlags_None;
4573
            if (disable_mouse_wheel)
4574
                window_flags |= ImGuiWindowFlags_NoScrollWithMouse;
4575
            if (!disable_menu)
4576
                window_flags |= ImGuiWindowFlags_MenuBar;
4577
            ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f);
4578
            ImGui::BeginChild("ChildR", ImVec2(0, 260), ImGuiChildFlags_Borders, window_flags);
4579
            if (!disable_menu && ImGui::BeginMenuBar())
4580
            {
4581
                if (ImGui::BeginMenu("Menu"))
4582
                {
4583
                    ShowExampleMenuFile();
4584
                    ImGui::EndMenu();
4585
                }
4586
                ImGui::EndMenuBar();
4587
            }
4588
            if (ImGui::BeginTable("split", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings))
4589
            {
4590
                for (int i = 0; i < 100; i++)
4591
                {
4592
                    char buf[32];
4593
                    sprintf(buf, "%03d", i);
4594
                    ImGui::TableNextColumn();
4595
                    ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f));
4596
                }
4597
                ImGui::EndTable();
4598
            }
4599
            ImGui::EndChild();
4600
            ImGui::PopStyleVar();
4601
        }
4602
4603
        // Child 3: manual-resize
4604
        ImGui::SeparatorText("Manual-resize");
4605
        {
4606
            HelpMarker("Drag bottom border to resize. Double-click bottom border to auto-fit to vertical contents.");
4607
            //if (ImGui::Button("Set Height to 200"))
4608
            //    ImGui::SetNextWindowSize(ImVec2(-FLT_MIN, 200.0f));
4609
4610
            ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyleColorVec4(ImGuiCol_FrameBg));
4611
            if (ImGui::BeginChild("ResizableChild", ImVec2(-FLT_MIN, ImGui::GetTextLineHeightWithSpacing() * 8), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeY))
4612
                for (int n = 0; n < 10; n++)
4613
                    ImGui::Text("Line %04d", n);
4614
            ImGui::PopStyleColor();
4615
            ImGui::EndChild();
4616
        }
4617
4618
        // Child 4: auto-resizing height with a limit
4619
        ImGui::SeparatorText("Auto-resize with constraints");
4620
        {
4621
            static int draw_lines = 3;
4622
            static int max_height_in_lines = 10;
4623
            ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
4624
            ImGui::DragInt("Lines Count", &draw_lines, 0.2f);
4625
            ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
4626
            ImGui::DragInt("Max Height (in Lines)", &max_height_in_lines, 0.2f);
4627
4628
            ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 1), ImVec2(FLT_MAX, ImGui::GetTextLineHeightWithSpacing() * max_height_in_lines));
4629
            if (ImGui::BeginChild("ConstrainedChild", ImVec2(-FLT_MIN, 0.0f), ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeY))
4630
                for (int n = 0; n < draw_lines; n++)
4631
                    ImGui::Text("Line %04d", n);
4632
            ImGui::EndChild();
4633
        }
4634
4635
        ImGui::SeparatorText("Misc/Advanced");
4636
4637
        // Demonstrate a few extra things
4638
        // - Changing ImGuiCol_ChildBg (which is transparent black in default styles)
4639
        // - Using SetCursorPos() to position child window (the child window is an item from the POV of parent window)
4640
        //   You can also call SetNextWindowPos() to position the child window. The parent window will effectively
4641
        //   layout from this position.
4642
        // - Using ImGui::GetItemRectMin/Max() to query the "item" state (because the child window is an item from
4643
        //   the POV of the parent window). See 'Demo->Querying Status (Edited/Active/Hovered etc.)' for details.
4644
        {
4645
            static int offset_x = 0;
4646
            static bool override_bg_color = true;
4647
            static ImGuiChildFlags child_flags = ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY;
4648
            ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
4649
            ImGui::DragInt("Offset X", &offset_x, 1.0f, -1000, 1000);
4650
            ImGui::Checkbox("Override ChildBg color", &override_bg_color);
4651
            ImGui::CheckboxFlags("ImGuiChildFlags_Borders", &child_flags, ImGuiChildFlags_Borders);
4652
            ImGui::CheckboxFlags("ImGuiChildFlags_AlwaysUseWindowPadding", &child_flags, ImGuiChildFlags_AlwaysUseWindowPadding);
4653
            ImGui::CheckboxFlags("ImGuiChildFlags_ResizeX", &child_flags, ImGuiChildFlags_ResizeX);
4654
            ImGui::CheckboxFlags("ImGuiChildFlags_ResizeY", &child_flags, ImGuiChildFlags_ResizeY);
4655
            ImGui::CheckboxFlags("ImGuiChildFlags_FrameStyle", &child_flags, ImGuiChildFlags_FrameStyle);
4656
            ImGui::SameLine(); HelpMarker("Style the child window like a framed item: use FrameBg, FrameRounding, FrameBorderSize, FramePadding instead of ChildBg, ChildRounding, ChildBorderSize, WindowPadding.");
4657
            if (child_flags & ImGuiChildFlags_FrameStyle)
4658
                override_bg_color = false;
4659
4660
            ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (float)offset_x);
4661
            if (override_bg_color)
4662
                ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(255, 0, 0, 100));
4663
            ImGui::BeginChild("Red", ImVec2(200, 100), child_flags, ImGuiWindowFlags_None);
4664
            if (override_bg_color)
4665
                ImGui::PopStyleColor();
4666
4667
            for (int n = 0; n < 50; n++)
4668
                ImGui::Text("Some test %d", n);
4669
            ImGui::EndChild();
4670
            bool child_is_hovered = ImGui::IsItemHovered();
4671
            ImVec2 child_rect_min = ImGui::GetItemRectMin();
4672
            ImVec2 child_rect_max = ImGui::GetItemRectMax();
4673
            ImGui::Text("Hovered: %d", child_is_hovered);
4674
            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);
4675
        }
4676
4677
        ImGui::TreePop();
4678
    }
4679
4680
    if (ImGui::TreeNode("Widgets Width"))
4681
    {
4682
        IMGUI_DEMO_MARKER("Layout/Widgets Width");
4683
        static float f = 0.0f;
4684
        static bool show_indented_items = true;
4685
        ImGui::Checkbox("Show indented items", &show_indented_items);
4686
4687
        // Use SetNextItemWidth() to set the width of a single upcoming item.
4688
        // Use PushItemWidth()/PopItemWidth() to set the width of a group of items.
4689
        // In real code use you'll probably want to choose width values that are proportional to your font size
4690
        // e.g. Using '20.0f * GetFontSize()' as width instead of '200.0f', etc.
4691
4692
        ImGui::Text("SetNextItemWidth/PushItemWidth(100)");
4693
        ImGui::SameLine(); HelpMarker("Fixed width.");
4694
        ImGui::PushItemWidth(100);
4695
        ImGui::DragFloat("float##1b", &f);
4696
        if (show_indented_items)
4697
        {
4698
            ImGui::Indent();
4699
            ImGui::DragFloat("float (indented)##1b", &f);
4700
            ImGui::Unindent();
4701
        }
4702
        ImGui::PopItemWidth();
4703
4704
        ImGui::Text("SetNextItemWidth/PushItemWidth(-100)");
4705
        ImGui::SameLine(); HelpMarker("Align to right edge minus 100");
4706
        ImGui::PushItemWidth(-100);
4707
        ImGui::DragFloat("float##2a", &f);
4708
        if (show_indented_items)
4709
        {
4710
            ImGui::Indent();
4711
            ImGui::DragFloat("float (indented)##2b", &f);
4712
            ImGui::Unindent();
4713
        }
4714
        ImGui::PopItemWidth();
4715
4716
        ImGui::Text("SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)");
4717
        ImGui::SameLine(); HelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)");
4718
        ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * 0.5f);
4719
        ImGui::DragFloat("float##3a", &f);
4720
        if (show_indented_items)
4721
        {
4722
            ImGui::Indent();
4723
            ImGui::DragFloat("float (indented)##3b", &f);
4724
            ImGui::Unindent();
4725
        }
4726
        ImGui::PopItemWidth();
4727
4728
        ImGui::Text("SetNextItemWidth/PushItemWidth(-GetContentRegionAvail().x * 0.5f)");
4729
        ImGui::SameLine(); HelpMarker("Align to right edge minus half");
4730
        ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.5f);
4731
        ImGui::DragFloat("float##4a", &f);
4732
        if (show_indented_items)
4733
        {
4734
            ImGui::Indent();
4735
            ImGui::DragFloat("float (indented)##4b", &f);
4736
            ImGui::Unindent();
4737
        }
4738
        ImGui::PopItemWidth();
4739
4740
        ImGui::Text("SetNextItemWidth/PushItemWidth(-Min(GetContentRegionAvail().x * 0.40f, GetFontSize() * 12))");
4741
        ImGui::PushItemWidth(-IM_MIN(ImGui::GetFontSize() * 12, ImGui::GetContentRegionAvail().x * 0.40f));
4742
        ImGui::DragFloat("float##5a", &f);
4743
        if (show_indented_items)
4744
        {
4745
            ImGui::Indent();
4746
            ImGui::DragFloat("float (indented)##5b", &f);
4747
            ImGui::Unindent();
4748
        }
4749
        ImGui::PopItemWidth();
4750
4751
        // Demonstrate using PushItemWidth to surround three items.
4752
        // Calling SetNextItemWidth() before each of them would have the same effect.
4753
        ImGui::Text("SetNextItemWidth/PushItemWidth(-FLT_MIN)");
4754
        ImGui::SameLine(); HelpMarker("Align to right edge");
4755
        ImGui::PushItemWidth(-FLT_MIN);
4756
        ImGui::DragFloat("##float6a", &f);
4757
        if (show_indented_items)
4758
        {
4759
            ImGui::Indent();
4760
            ImGui::DragFloat("float (indented)##6b", &f);
4761
            ImGui::Unindent();
4762
        }
4763
        ImGui::PopItemWidth();
4764
4765
        ImGui::TreePop();
4766
    }
4767
4768
    if (ImGui::TreeNode("Basic Horizontal Layout"))
4769
    {
4770
        IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout");
4771
        ImGui::TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)");
4772
4773
        // Text
4774
        IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine");
4775
        ImGui::Text("Two items: Hello"); ImGui::SameLine();
4776
        ImGui::TextColored(ImVec4(1, 1, 0, 1), "Sailor");
4777
4778
        // Adjust spacing
4779
        ImGui::Text("More spacing: Hello"); ImGui::SameLine(0, 20);
4780
        ImGui::TextColored(ImVec4(1, 1, 0, 1), "Sailor");
4781
4782
        // Button
4783
        ImGui::AlignTextToFramePadding();
4784
        ImGui::Text("Normal buttons"); ImGui::SameLine();
4785
        ImGui::Button("Banana"); ImGui::SameLine();
4786
        ImGui::Button("Apple"); ImGui::SameLine();
4787
        ImGui::Button("Corniflower");
4788
4789
        // Button
4790
        ImGui::Text("Small buttons"); ImGui::SameLine();
4791
        ImGui::SmallButton("Like this one"); ImGui::SameLine();
4792
        ImGui::Text("can fit within a text block.");
4793
4794
        // Aligned to arbitrary position. Easy/cheap column.
4795
        IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (with offset)");
4796
        ImGui::Text("Aligned");
4797
        ImGui::SameLine(150); ImGui::Text("x=150");
4798
        ImGui::SameLine(300); ImGui::Text("x=300");
4799
        ImGui::Text("Aligned");
4800
        ImGui::SameLine(150); ImGui::SmallButton("x=150");
4801
        ImGui::SameLine(300); ImGui::SmallButton("x=300");
4802
4803
        // Checkbox
4804
        IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (more)");
4805
        static bool c1 = false, c2 = false, c3 = false, c4 = false;
4806
        ImGui::Checkbox("My", &c1); ImGui::SameLine();
4807
        ImGui::Checkbox("Tailor", &c2); ImGui::SameLine();
4808
        ImGui::Checkbox("Is", &c3); ImGui::SameLine();
4809
        ImGui::Checkbox("Rich", &c4);
4810
4811
        // Various
4812
        static float f0 = 1.0f, f1 = 2.0f, f2 = 3.0f;
4813
        ImGui::PushItemWidth(ImGui::CalcTextSize("AAAAAAA").x);
4814
        const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD" };
4815
        static int item = -1;
4816
        ImGui::Combo("Combo", &item, items, IM_COUNTOF(items)); ImGui::SameLine();
4817
        ImGui::SliderFloat("X", &f0, 0.0f, 5.0f); ImGui::SameLine();
4818
        ImGui::SliderFloat("Y", &f1, 0.0f, 5.0f); ImGui::SameLine();
4819
        ImGui::SliderFloat("Z", &f2, 0.0f, 5.0f);
4820
4821
        ImGui::Text("Lists:");
4822
        static int selection[4] = { 0, 1, 2, 3 };
4823
        for (int i = 0; i < 4; i++)
4824
        {
4825
            if (i > 0) ImGui::SameLine();
4826
            ImGui::PushID(i);
4827
            ImGui::ListBox("", &selection[i], items, IM_COUNTOF(items));
4828
            ImGui::PopID();
4829
            //ImGui::SetItemTooltip("ListBox %d hovered", i);
4830
        }
4831
        ImGui::PopItemWidth();
4832
4833
        // Dummy
4834
        IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Dummy");
4835
        ImVec2 button_sz(40, 40);
4836
        ImGui::Button("A", button_sz); ImGui::SameLine();
4837
        ImGui::Dummy(button_sz); ImGui::SameLine();
4838
        ImGui::Button("B", button_sz);
4839
4840
        // Manually wrapping
4841
        // (we should eventually provide this as an automatic layout feature, but for now you can do it manually)
4842
        IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Manual wrapping");
4843
        ImGui::Text("Manual wrapping:");
4844
        ImGuiStyle& style = ImGui::GetStyle();
4845
        int buttons_count = 20;
4846
        float window_visible_x2 = ImGui::GetCursorScreenPos().x + ImGui::GetContentRegionAvail().x;
4847
        for (int n = 0; n < buttons_count; n++)
4848
        {
4849
            ImGui::PushID(n);
4850
            ImGui::Button("Box", button_sz);
4851
            float last_button_x2 = ImGui::GetItemRectMax().x;
4852
            float next_button_x2 = last_button_x2 + style.ItemSpacing.x + button_sz.x; // Expected position if next button was on same line
4853
            if (n + 1 < buttons_count && next_button_x2 < window_visible_x2)
4854
                ImGui::SameLine();
4855
            ImGui::PopID();
4856
        }
4857
4858
        ImGui::TreePop();
4859
    }
4860
4861
    if (ImGui::TreeNode("Groups"))
4862
    {
4863
        IMGUI_DEMO_MARKER("Layout/Groups");
4864
        HelpMarker(
4865
            "BeginGroup() basically locks the horizontal position for new line. "
4866
            "EndGroup() bundles the whole group so that you can use \"item\" functions such as "
4867
            "IsItemHovered()/IsItemActive() or SameLine() etc. on the whole group.");
4868
        ImGui::BeginGroup();
4869
        {
4870
            ImGui::BeginGroup();
4871
            ImGui::Button("AAA");
4872
            ImGui::SameLine();
4873
            ImGui::Button("BBB");
4874
            ImGui::SameLine();
4875
            ImGui::BeginGroup();
4876
            ImGui::Button("CCC");
4877
            ImGui::Button("DDD");
4878
            ImGui::EndGroup();
4879
            ImGui::SameLine();
4880
            ImGui::Button("EEE");
4881
            ImGui::EndGroup();
4882
            ImGui::SetItemTooltip("First group hovered");
4883
        }
4884
        // Capture the group size and create widgets using the same size
4885
        ImVec2 size = ImGui::GetItemRectSize();
4886
        const float values[5] = { 0.5f, 0.20f, 0.80f, 0.60f, 0.25f };
4887
        ImGui::PlotHistogram("##values", values, IM_COUNTOF(values), 0, NULL, 0.0f, 1.0f, size);
4888
4889
        ImGui::Button("ACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y));
4890
        ImGui::SameLine();
4891
        ImGui::Button("REACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y));
4892
        ImGui::EndGroup();
4893
        ImGui::SameLine();
4894
4895
        ImGui::Button("LEVERAGE\nBUZZWORD", size);
4896
        ImGui::SameLine();
4897
4898
        if (ImGui::BeginListBox("List", size))
4899
        {
4900
            ImGui::Selectable("Selected", true);
4901
            ImGui::Selectable("Not Selected", false);
4902
            ImGui::EndListBox();
4903
        }
4904
4905
        ImGui::TreePop();
4906
    }
4907
4908
    if (ImGui::TreeNode("Text Baseline Alignment"))
4909
    {
4910
        IMGUI_DEMO_MARKER("Layout/Text Baseline Alignment");
4911
        {
4912
            ImGui::BulletText("Text baseline:");
4913
            ImGui::SameLine(); HelpMarker(
4914
                "This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. "
4915
                "Lines only composed of text or \"small\" widgets use less vertical space than lines with framed widgets.");
4916
            ImGui::Indent();
4917
4918
            ImGui::Text("KO Blahblah"); ImGui::SameLine();
4919
            ImGui::Button("Some framed item"); ImGui::SameLine();
4920
            HelpMarker("Baseline of button will look misaligned with text..");
4921
4922
            // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets.
4923
            // (because we don't know what's coming after the Text() statement, we need to move the text baseline
4924
            // down by FramePadding.y ahead of time)
4925
            ImGui::AlignTextToFramePadding();
4926
            ImGui::Text("OK Blahblah"); ImGui::SameLine();
4927
            ImGui::Button("Some framed item##2"); ImGui::SameLine();
4928
            HelpMarker("We call AlignTextToFramePadding() to vertically align the text baseline by +FramePadding.y");
4929
4930
            // SmallButton() uses the same vertical padding as Text
4931
            ImGui::Button("TEST##1"); ImGui::SameLine();
4932
            ImGui::Text("TEST"); ImGui::SameLine();
4933
            ImGui::SmallButton("TEST##2");
4934
4935
            // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets.
4936
            ImGui::AlignTextToFramePadding();
4937
            ImGui::Text("Text aligned to framed item"); ImGui::SameLine();
4938
            ImGui::Button("Item##1"); ImGui::SameLine();
4939
            ImGui::Text("Item"); ImGui::SameLine();
4940
            ImGui::SmallButton("Item##2"); ImGui::SameLine();
4941
            ImGui::Button("Item##3");
4942
4943
            ImGui::Unindent();
4944
        }
4945
4946
        ImGui::Spacing();
4947
4948
        {
4949
            ImGui::BulletText("Multi-line text:");
4950
            ImGui::Indent();
4951
            ImGui::Text("One\nTwo\nThree"); ImGui::SameLine();
4952
            ImGui::Text("Hello\nWorld"); ImGui::SameLine();
4953
            ImGui::Text("Banana");
4954
4955
            ImGui::Text("Banana"); ImGui::SameLine();
4956
            ImGui::Text("Hello\nWorld"); ImGui::SameLine();
4957
            ImGui::Text("One\nTwo\nThree");
4958
4959
            ImGui::Button("HOP##1"); ImGui::SameLine();
4960
            ImGui::Text("Banana"); ImGui::SameLine();
4961
            ImGui::Text("Hello\nWorld"); ImGui::SameLine();
4962
            ImGui::Text("Banana");
4963
4964
            ImGui::Button("HOP##2"); ImGui::SameLine();
4965
            ImGui::Text("Hello\nWorld"); ImGui::SameLine();
4966
            ImGui::Text("Banana");
4967
            ImGui::Unindent();
4968
        }
4969
4970
        ImGui::Spacing();
4971
4972
        {
4973
            ImGui::BulletText("Misc items:");
4974
            ImGui::Indent();
4975
4976
            // SmallButton() sets FramePadding to zero. Text baseline is aligned to match baseline of previous Button.
4977
            ImGui::Button("80x80", ImVec2(80, 80));
4978
            ImGui::SameLine();
4979
            ImGui::Button("50x50", ImVec2(50, 50));
4980
            ImGui::SameLine();
4981
            ImGui::Button("Button()");
4982
            ImGui::SameLine();
4983
            ImGui::SmallButton("SmallButton()");
4984
4985
            // Tree
4986
            // (here the node appears after a button and has odd intent, so we use ImGuiTreeNodeFlags_DrawLinesNone to disable hierarchy outline)
4987
            const float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
4988
            ImGui::Button("Button##1"); // Will make line higher
4989
            ImGui::SameLine(0.0f, spacing);
4990
            if (ImGui::TreeNodeEx("Node##1", ImGuiTreeNodeFlags_DrawLinesNone))
4991
            {
4992
                // Placeholder tree data
4993
                for (int i = 0; i < 6; i++)
4994
                    ImGui::BulletText("Item %d..", i);
4995
                ImGui::TreePop();
4996
            }
4997
4998
            const float padding = (float)(int)(ImGui::GetFontSize() * 1.20f); // Large padding
4999
            ImGui::PushStyleVarY(ImGuiStyleVar_FramePadding, padding);
5000
            ImGui::Button("Button##2");
5001
            ImGui::PopStyleVar();
5002
            ImGui::SameLine(0.0f, spacing);
5003
            if (ImGui::TreeNodeEx("Node##2", ImGuiTreeNodeFlags_DrawLinesNone))
5004
                ImGui::TreePop();
5005
5006
            // Vertically align text node a bit lower so it'll be vertically centered with upcoming widget.
5007
            // Otherwise you can use SmallButton() (smaller fit).
5008
            ImGui::AlignTextToFramePadding();
5009
5010
            // Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add
5011
            // other contents "inside" the node.
5012
            bool node_open = ImGui::TreeNode("Node##3");
5013
            ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##3");
5014
            if (node_open)
5015
            {
5016
                // Placeholder tree data
5017
                for (int i = 0; i < 6; i++)
5018
                    ImGui::BulletText("Item %d..", i);
5019
                ImGui::TreePop();
5020
            }
5021
5022
            // Bullet
5023
            ImGui::Button("Button##4");
5024
            ImGui::SameLine(0.0f, spacing);
5025
            ImGui::BulletText("Bullet text");
5026
5027
            ImGui::AlignTextToFramePadding();
5028
            ImGui::BulletText("Node");
5029
            ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##5");
5030
            ImGui::Unindent();
5031
        }
5032
5033
        ImGui::TreePop();
5034
    }
5035
5036
    if (ImGui::TreeNode("Scrolling"))
5037
    {
5038
        IMGUI_DEMO_MARKER("Layout/Scrolling/Vertical");
5039
        // Vertical scroll functions
5040
        HelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given vertical position.");
5041
5042
        static int track_item = 50;
5043
        static bool enable_track = true;
5044
        static bool enable_extra_decorations = false;
5045
        static float scroll_to_off_px = 0.0f;
5046
        static float scroll_to_pos_px = 200.0f;
5047
5048
        ImGui::Checkbox("Decoration", &enable_extra_decorations);
5049
5050
        ImGui::PushItemWidth(ImGui::GetFontSize() * 10);
5051
        enable_track |= ImGui::DragInt("##item", &track_item, 0.25f, 0, 99, "Item = %d");
5052
        ImGui::SameLine();
5053
        ImGui::Checkbox("Track", &enable_track);
5054
5055
        bool scroll_to_off = ImGui::DragFloat("##off", &scroll_to_off_px, 1.00f, 0, FLT_MAX, "+%.0f px");
5056
        ImGui::SameLine();
5057
        scroll_to_off |= ImGui::Button("Scroll Offset");
5058
5059
        bool scroll_to_pos = ImGui::DragFloat("##pos", &scroll_to_pos_px, 1.00f, -10, FLT_MAX, "X/Y = %.0f px");
5060
        ImGui::SameLine();
5061
        scroll_to_pos |= ImGui::Button("Scroll To Pos");
5062
        ImGui::PopItemWidth();
5063
5064
        if (scroll_to_off || scroll_to_pos)
5065
            enable_track = false;
5066
5067
        ImGuiStyle& style = ImGui::GetStyle();
5068
        float child_w = (ImGui::GetContentRegionAvail().x - 4 * style.ItemSpacing.x) / 5;
5069
        if (child_w < 1.0f)
5070
            child_w = 1.0f;
5071
        ImGui::PushID("##VerticalScrolling");
5072
        for (int i = 0; i < 5; i++)
5073
        {
5074
            if (i > 0) ImGui::SameLine();
5075
            ImGui::BeginGroup();
5076
            const char* names[] = { "Top", "25%", "Center", "75%", "Bottom" };
5077
            ImGui::TextUnformatted(names[i]);
5078
5079
            const ImGuiWindowFlags child_flags = enable_extra_decorations ? ImGuiWindowFlags_MenuBar : 0;
5080
            const ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i);
5081
            const bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(child_w, 200.0f), ImGuiChildFlags_Borders, child_flags);
5082
            if (ImGui::BeginMenuBar())
5083
            {
5084
                ImGui::TextUnformatted("abc");
5085
                ImGui::EndMenuBar();
5086
            }
5087
            if (scroll_to_off)
5088
                ImGui::SetScrollY(scroll_to_off_px);
5089
            if (scroll_to_pos)
5090
                ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_pos_px, i * 0.25f);
5091
            if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items
5092
            {
5093
                for (int item = 0; item < 100; item++)
5094
                {
5095
                    if (enable_track && item == track_item)
5096
                    {
5097
                        ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item);
5098
                        ImGui::SetScrollHereY(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom
5099
                    }
5100
                    else
5101
                    {
5102
                        ImGui::Text("Item %d", item);
5103
                    }
5104
                }
5105
            }
5106
            float scroll_y = ImGui::GetScrollY();
5107
            float scroll_max_y = ImGui::GetScrollMaxY();
5108
            ImGui::EndChild();
5109
            ImGui::Text("%.0f/%.0f", scroll_y, scroll_max_y);
5110
            ImGui::EndGroup();
5111
        }
5112
        ImGui::PopID();
5113
5114
        // Horizontal scroll functions
5115
        IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal");
5116
        ImGui::Spacing();
5117
        HelpMarker(
5118
            "Use SetScrollHereX() or SetScrollFromPosX() to scroll to a given horizontal position.\n\n"
5119
            "Because the clipping rectangle of most window hides half worth of WindowPadding on the "
5120
            "left/right, using SetScrollFromPosX(+1) will usually result in clipped text whereas the "
5121
            "equivalent SetScrollFromPosY(+1) wouldn't.");
5122
        ImGui::PushID("##HorizontalScrolling");
5123
        for (int i = 0; i < 5; i++)
5124
        {
5125
            float child_height = ImGui::GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0f;
5126
            ImGuiWindowFlags child_flags = ImGuiWindowFlags_HorizontalScrollbar | (enable_extra_decorations ? ImGuiWindowFlags_AlwaysVerticalScrollbar : 0);
5127
            ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i);
5128
            bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(-100, child_height), ImGuiChildFlags_Borders, child_flags);
5129
            if (scroll_to_off)
5130
                ImGui::SetScrollX(scroll_to_off_px);
5131
            if (scroll_to_pos)
5132
                ImGui::SetScrollFromPosX(ImGui::GetCursorStartPos().x + scroll_to_pos_px, i * 0.25f);
5133
            if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items
5134
            {
5135
                for (int item = 0; item < 100; item++)
5136
                {
5137
                    if (item > 0)
5138
                        ImGui::SameLine();
5139
                    if (enable_track && item == track_item)
5140
                    {
5141
                        ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item);
5142
                        ImGui::SetScrollHereX(i * 0.25f); // 0.0f:left, 0.5f:center, 1.0f:right
5143
                    }
5144
                    else
5145
                    {
5146
                        ImGui::Text("Item %d", item);
5147
                    }
5148
                }
5149
            }
5150
            float scroll_x = ImGui::GetScrollX();
5151
            float scroll_max_x = ImGui::GetScrollMaxX();
5152
            ImGui::EndChild();
5153
            ImGui::SameLine();
5154
            const char* names[] = { "Left", "25%", "Center", "75%", "Right" };
5155
            ImGui::Text("%s\n%.0f/%.0f", names[i], scroll_x, scroll_max_x);
5156
            ImGui::Spacing();
5157
        }
5158
        ImGui::PopID();
5159
5160
        // Miscellaneous Horizontal Scrolling Demo
5161
        IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal (more)");
5162
        HelpMarker(
5163
            "Horizontal scrolling for a window is enabled via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\n"
5164
            "You may want to also explicitly specify content width by using SetNextWindowContentWidth() before Begin().");
5165
        static int lines = 7;
5166
        ImGui::SliderInt("Lines", &lines, 1, 15);
5167
        ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
5168
        ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f));
5169
        ImVec2 scrolling_child_size = ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30);
5170
        ImGui::BeginChild("scrolling", scrolling_child_size, ImGuiChildFlags_Borders, ImGuiWindowFlags_HorizontalScrollbar);
5171
        for (int line = 0; line < lines; line++)
5172
        {
5173
            // Display random stuff. For the sake of this trivial demo we are using basic Button() + SameLine()
5174
            // If you want to create your own time line for a real application you may be better off manipulating
5175
            // the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets
5176
            // yourself. You may also want to use the lower-level ImDrawList API.
5177
            int num_buttons = 10 + ((line & 1) ? line * 9 : line * 3);
5178
            for (int n = 0; n < num_buttons; n++)
5179
            {
5180
                if (n > 0) ImGui::SameLine();
5181
                ImGui::PushID(n + line * 1000);
5182
                char num_buf[16];
5183
                sprintf(num_buf, "%d", n);
5184
                const char* label = (!(n % 15)) ? "FizzBuzz" : (!(n % 3)) ? "Fizz" : (!(n % 5)) ? "Buzz" : num_buf;
5185
                float hue = n * 0.05f;
5186
                ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(hue, 0.6f, 0.6f));
5187
                ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(hue, 0.7f, 0.7f));
5188
                ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(hue, 0.8f, 0.8f));
5189
                ImGui::Button(label, ImVec2(40.0f + sinf((float)(line + n)) * 20.0f, 0.0f));
5190
                ImGui::PopStyleColor(3);
5191
                ImGui::PopID();
5192
            }
5193
        }
5194
        float scroll_x = ImGui::GetScrollX();
5195
        float scroll_max_x = ImGui::GetScrollMaxX();
5196
        ImGui::EndChild();
5197
        ImGui::PopStyleVar(2);
5198
        float scroll_x_delta = 0.0f;
5199
        ImGui::SmallButton("<<");
5200
        if (ImGui::IsItemActive())
5201
            scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f;
5202
        ImGui::SameLine();
5203
        ImGui::Text("Scroll from code"); ImGui::SameLine();
5204
        ImGui::SmallButton(">>");
5205
        if (ImGui::IsItemActive())
5206
            scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f;
5207
        ImGui::SameLine();
5208
        ImGui::Text("%.0f/%.0f", scroll_x, scroll_max_x);
5209
        if (scroll_x_delta != 0.0f)
5210
        {
5211
            // Demonstrate a trick: you can use Begin to set yourself in the context of another window
5212
            // (here we are already out of your child window)
5213
            ImGui::BeginChild("scrolling");
5214
            ImGui::SetScrollX(ImGui::GetScrollX() + scroll_x_delta);
5215
            ImGui::EndChild();
5216
        }
5217
        ImGui::Spacing();
5218
5219
        static bool show_horizontal_contents_size_demo_window = false;
5220
        ImGui::Checkbox("Show Horizontal contents size demo window", &show_horizontal_contents_size_demo_window);
5221
5222
        if (show_horizontal_contents_size_demo_window)
5223
        {
5224
            static bool show_h_scrollbar = true;
5225
            static bool show_button = true;
5226
            static bool show_tree_nodes = true;
5227
            static bool show_text_wrapped = false;
5228
            static bool show_columns = true;
5229
            static bool show_tab_bar = true;
5230
            static bool show_child = false;
5231
            static bool explicit_content_size = false;
5232
            static float contents_size_x = 300.0f;
5233
            if (explicit_content_size)
5234
                ImGui::SetNextWindowContentSize(ImVec2(contents_size_x, 0.0f));
5235
            ImGui::Begin("Horizontal contents size demo window", &show_horizontal_contents_size_demo_window, show_h_scrollbar ? ImGuiWindowFlags_HorizontalScrollbar : 0);
5236
            IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal contents size demo window");
5237
            ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 0));
5238
            ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 0));
5239
            HelpMarker(
5240
                "Test how different widgets react and impact the work rectangle growing when horizontal scrolling is enabled.\n\n"
5241
                "Use 'Metrics->Tools->Show windows rectangles' to visualize rectangles.");
5242
            ImGui::Checkbox("H-scrollbar", &show_h_scrollbar);
5243
            ImGui::Checkbox("Button", &show_button);            // Will grow contents size (unless explicitly overwritten)
5244
            ImGui::Checkbox("Tree nodes", &show_tree_nodes);    // Will grow contents size and display highlight over full width
5245
            ImGui::Checkbox("Text wrapped", &show_text_wrapped);// Will grow and use contents size
5246
            ImGui::Checkbox("Columns", &show_columns);          // Will use contents size
5247
            ImGui::Checkbox("Tab bar", &show_tab_bar);          // Will use contents size
5248
            ImGui::Checkbox("Child", &show_child);              // Will grow and use contents size
5249
            ImGui::Checkbox("Explicit content size", &explicit_content_size);
5250
            ImGui::Text("Scroll %.1f/%.1f %.1f/%.1f", ImGui::GetScrollX(), ImGui::GetScrollMaxX(), ImGui::GetScrollY(), ImGui::GetScrollMaxY());
5251
            if (explicit_content_size)
5252
            {
5253
                ImGui::SameLine();
5254
                ImGui::SetNextItemWidth(ImGui::CalcTextSize("123456").x);
5255
                ImGui::DragFloat("##csx", &contents_size_x);
5256
                ImVec2 p = ImGui::GetCursorScreenPos();
5257
                ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + 10, p.y + 10), IM_COL32_WHITE);
5258
                ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(p.x + contents_size_x - 10, p.y), ImVec2(p.x + contents_size_x, p.y + 10), IM_COL32_WHITE);
5259
                ImGui::Dummy(ImVec2(0, 10));
5260
            }
5261
            ImGui::PopStyleVar(2);
5262
            ImGui::Separator();
5263
            if (show_button)
5264
            {
5265
                ImGui::Button("this is a 300-wide button", ImVec2(300, 0));
5266
            }
5267
            if (show_tree_nodes)
5268
            {
5269
                bool open = true;
5270
                if (ImGui::TreeNode("this is a tree node"))
5271
                {
5272
                    if (ImGui::TreeNode("another one of those tree node..."))
5273
                    {
5274
                        ImGui::Text("Some tree contents");
5275
                        ImGui::TreePop();
5276
                    }
5277
                    ImGui::TreePop();
5278
                }
5279
                ImGui::CollapsingHeader("CollapsingHeader", &open);
5280
            }
5281
            if (show_text_wrapped)
5282
            {
5283
                ImGui::TextWrapped("This text should automatically wrap on the edge of the work rectangle.");
5284
            }
5285
            if (show_columns)
5286
            {
5287
                ImGui::Text("Tables:");
5288
                if (ImGui::BeginTable("table", 4, ImGuiTableFlags_Borders))
5289
                {
5290
                    for (int n = 0; n < 4; n++)
5291
                    {
5292
                        ImGui::TableNextColumn();
5293
                        ImGui::Text("Width %.2f", ImGui::GetContentRegionAvail().x);
5294
                    }
5295
                    ImGui::EndTable();
5296
                }
5297
                ImGui::Text("Columns:");
5298
                ImGui::Columns(4);
5299
                for (int n = 0; n < 4; n++)
5300
                {
5301
                    ImGui::Text("Width %.2f", ImGui::GetColumnWidth());
5302
                    ImGui::NextColumn();
5303
                }
5304
                ImGui::Columns(1);
5305
            }
5306
            if (show_tab_bar && ImGui::BeginTabBar("Hello"))
5307
            {
5308
                if (ImGui::BeginTabItem("OneOneOne")) { ImGui::EndTabItem(); }
5309
                if (ImGui::BeginTabItem("TwoTwoTwo")) { ImGui::EndTabItem(); }
5310
                if (ImGui::BeginTabItem("ThreeThreeThree")) { ImGui::EndTabItem(); }
5311
                if (ImGui::BeginTabItem("FourFourFour")) { ImGui::EndTabItem(); }
5312
                ImGui::EndTabBar();
5313
            }
5314
            if (show_child)
5315
            {
5316
                ImGui::BeginChild("child", ImVec2(0, 0), ImGuiChildFlags_Borders);
5317
                ImGui::EndChild();
5318
            }
5319
            ImGui::End();
5320
        }
5321
5322
        ImGui::TreePop();
5323
    }
5324
5325
    if (ImGui::TreeNode("Text Clipping"))
5326
    {
5327
        IMGUI_DEMO_MARKER("Layout/Text Clipping");
5328
        static ImVec2 size(100.0f, 100.0f);
5329
        static ImVec2 offset(30.0f, 30.0f);
5330
        ImGui::DragFloat2("size", (float*)&size, 0.5f, 1.0f, 200.0f, "%.0f");
5331
        ImGui::TextWrapped("(Click and drag to scroll)");
5332
5333
        HelpMarker(
5334
            "(Left) Using ImGui::PushClipRect():\n"
5335
            "Will alter ImGui hit-testing logic + ImDrawList rendering.\n"
5336
            "(use this if you want your clipping rectangle to affect interactions)\n\n"
5337
            "(Center) Using ImDrawList::PushClipRect():\n"
5338
            "Will alter ImDrawList rendering only.\n"
5339
            "(use this as a shortcut if you are only using ImDrawList calls)\n\n"
5340
            "(Right) Using ImDrawList::AddText() with a fine ClipRect:\n"
5341
            "Will alter only this specific ImDrawList::AddText() rendering.\n"
5342
            "This is often used internally to avoid altering the clipping rectangle and minimize draw calls.");
5343
5344
        for (int n = 0; n < 3; n++)
5345
        {
5346
            if (n > 0)
5347
                ImGui::SameLine();
5348
5349
            ImGui::PushID(n);
5350
            ImGui::InvisibleButton("##canvas", size);
5351
            if (ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left))
5352
            {
5353
                offset.x += ImGui::GetIO().MouseDelta.x;
5354
                offset.y += ImGui::GetIO().MouseDelta.y;
5355
            }
5356
            ImGui::PopID();
5357
            if (!ImGui::IsItemVisible()) // Skip rendering as ImDrawList elements are not clipped.
5358
                continue;
5359
5360
            const ImVec2 p0 = ImGui::GetItemRectMin();
5361
            const ImVec2 p1 = ImGui::GetItemRectMax();
5362
            const char* text_str = "Line 1 hello\nLine 2 clip me!";
5363
            const ImVec2 text_pos = ImVec2(p0.x + offset.x, p0.y + offset.y);
5364
            ImDrawList* draw_list = ImGui::GetWindowDrawList();
5365
            switch (n)
5366
            {
5367
            case 0:
5368
                ImGui::PushClipRect(p0, p1, true);
5369
                draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
5370
                draw_list->AddText(text_pos, IM_COL32_WHITE, text_str);
5371
                ImGui::PopClipRect();
5372
                break;
5373
            case 1:
5374
                draw_list->PushClipRect(p0, p1, true);
5375
                draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
5376
                draw_list->AddText(text_pos, IM_COL32_WHITE, text_str);
5377
                draw_list->PopClipRect();
5378
                break;
5379
            case 2:
5380
                ImVec4 clip_rect(p0.x, p0.y, p1.x, p1.y); // AddText() takes a ImVec4* here so let's convert.
5381
                draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
5382
                draw_list->AddText(ImGui::GetFont(), ImGui::GetFontSize(), text_pos, IM_COL32_WHITE, text_str, NULL, 0.0f, &clip_rect);
5383
                break;
5384
            }
5385
        }
5386
5387
        ImGui::TreePop();
5388
    }
5389
5390
    if (ImGui::TreeNode("Overlap Mode"))
5391
    {
5392
        IMGUI_DEMO_MARKER("Layout/Overlap Mode");
5393
        static bool enable_allow_overlap = true;
5394
5395
        HelpMarker(
5396
            "Hit-testing is by default performed in item submission order, which generally is perceived as 'back-to-front'.\n\n"
5397
            "By using SetNextItemAllowOverlap() you can notify that an item may be overlapped by another. "
5398
            "Doing so alters the hovering logic: items using AllowOverlap mode requires an extra frame to accept hovered state.");
5399
        ImGui::Checkbox("Enable AllowOverlap", &enable_allow_overlap);
5400
5401
        ImVec2 button1_pos = ImGui::GetCursorScreenPos();
5402
        ImVec2 button2_pos = ImVec2(button1_pos.x + 50.0f, button1_pos.y + 50.0f);
5403
        if (enable_allow_overlap)
5404
            ImGui::SetNextItemAllowOverlap();
5405
        ImGui::Button("Button 1", ImVec2(80, 80));
5406
        ImGui::SetCursorScreenPos(button2_pos);
5407
        ImGui::Button("Button 2", ImVec2(80, 80));
5408
5409
        // This is typically used with width-spanning items.
5410
        // (note that Selectable() has a dedicated flag ImGuiSelectableFlags_AllowOverlap, which is a shortcut
5411
        // for using SetNextItemAllowOverlap(). For demo purpose we use SetNextItemAllowOverlap() here.)
5412
        if (enable_allow_overlap)
5413
            ImGui::SetNextItemAllowOverlap();
5414
        ImGui::Selectable("Some Selectable", false);
5415
        ImGui::SameLine();
5416
        ImGui::SmallButton("++");
5417
5418
        ImGui::TreePop();
5419
    }
5420
}
5421
5422
//-----------------------------------------------------------------------------
5423
// [SECTION] DemoWindowPopups()
5424
//-----------------------------------------------------------------------------
5425
5426
static void DemoWindowPopups()
5427
{
5428
    if (!ImGui::CollapsingHeader("Popups & Modal windows"))
5429
        return;
5430
5431
    // The properties of popups windows are:
5432
    // - They block normal mouse hovering detection outside them. (*)
5433
    // - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE.
5434
    // - Their visibility state (~bool) is held internally by Dear ImGui instead of being held by the programmer as
5435
    //   we are used to with regular Begin() calls. User can manipulate the visibility state by calling OpenPopup().
5436
    // (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even
5437
    //     when normally blocked by a popup.
5438
    // Those three properties are connected. The library needs to hold their visibility state BECAUSE it can close
5439
    // popups at any time.
5440
5441
    // Typical use for regular windows:
5442
    //   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();
5443
    // Typical use for popups:
5444
    //   if (ImGui::Button("Open")) ImGui::OpenPopup("MyPopup"); if (ImGui::BeginPopup("MyPopup")) { [...] EndPopup(); }
5445
5446
    // With popups we have to go through a library call (here OpenPopup) to manipulate the visibility state.
5447
    // This may be a bit confusing at first but it should quickly make sense. Follow on the examples below.
5448
5449
    if (ImGui::TreeNode("Popups"))
5450
    {
5451
        IMGUI_DEMO_MARKER("Popups/Popups");
5452
        ImGui::TextWrapped(
5453
            "When a popup is active, it inhibits interacting with windows that are behind the popup. "
5454
            "Clicking outside the popup closes it.");
5455
5456
        static int selected_fish = -1;
5457
        const char* names[] = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" };
5458
        static bool toggles[] = { true, false, false, false, false };
5459
5460
        // Simple selection popup (if you want to show the current selection inside the Button itself,
5461
        // you may want to build a string using the "###" operator to preserve a constant ID with a variable label)
5462
        if (ImGui::Button("Select.."))
5463
            ImGui::OpenPopup("my_select_popup");
5464
        ImGui::SameLine();
5465
        ImGui::TextUnformatted(selected_fish == -1 ? "<None>" : names[selected_fish]);
5466
        if (ImGui::BeginPopup("my_select_popup"))
5467
        {
5468
            ImGui::SeparatorText("Aquarium");
5469
            for (int i = 0; i < IM_COUNTOF(names); i++)
5470
                if (ImGui::Selectable(names[i]))
5471
                    selected_fish = i;
5472
            ImGui::EndPopup();
5473
        }
5474
5475
        // Showing a menu with toggles
5476
        if (ImGui::Button("Toggle.."))
5477
            ImGui::OpenPopup("my_toggle_popup");
5478
        if (ImGui::BeginPopup("my_toggle_popup"))
5479
        {
5480
            for (int i = 0; i < IM_COUNTOF(names); i++)
5481
                ImGui::MenuItem(names[i], "", &toggles[i]);
5482
            if (ImGui::BeginMenu("Sub-menu"))
5483
            {
5484
                ImGui::MenuItem("Click me");
5485
                ImGui::EndMenu();
5486
            }
5487
5488
            ImGui::Separator();
5489
            ImGui::Text("Tooltip here");
5490
            ImGui::SetItemTooltip("I am a tooltip over a popup");
5491
5492
            if (ImGui::Button("Stacked Popup"))
5493
                ImGui::OpenPopup("another popup");
5494
            if (ImGui::BeginPopup("another popup"))
5495
            {
5496
                for (int i = 0; i < IM_COUNTOF(names); i++)
5497
                    ImGui::MenuItem(names[i], "", &toggles[i]);
5498
                if (ImGui::BeginMenu("Sub-menu"))
5499
                {
5500
                    ImGui::MenuItem("Click me");
5501
                    if (ImGui::Button("Stacked Popup"))
5502
                        ImGui::OpenPopup("another popup");
5503
                    if (ImGui::BeginPopup("another popup"))
5504
                    {
5505
                        ImGui::Text("I am the last one here.");
5506
                        ImGui::EndPopup();
5507
                    }
5508
                    ImGui::EndMenu();
5509
                }
5510
                ImGui::EndPopup();
5511
            }
5512
            ImGui::EndPopup();
5513
        }
5514
5515
        // Call the more complete ShowExampleMenuFile which we use in various places of this demo
5516
        if (ImGui::Button("With a menu.."))
5517
            ImGui::OpenPopup("my_file_popup");
5518
        if (ImGui::BeginPopup("my_file_popup", ImGuiWindowFlags_MenuBar))
5519
        {
5520
            if (ImGui::BeginMenuBar())
5521
            {
5522
                if (ImGui::BeginMenu("File"))
5523
                {
5524
                    ShowExampleMenuFile();
5525
                    ImGui::EndMenu();
5526
                }
5527
                if (ImGui::BeginMenu("Edit"))
5528
                {
5529
                    ImGui::MenuItem("Dummy");
5530
                    ImGui::EndMenu();
5531
                }
5532
                ImGui::EndMenuBar();
5533
            }
5534
            ImGui::Text("Hello from popup!");
5535
            ImGui::Button("This is a dummy button..");
5536
            ImGui::EndPopup();
5537
        }
5538
5539
        ImGui::TreePop();
5540
    }
5541
5542
    if (ImGui::TreeNode("Context menus"))
5543
    {
5544
        IMGUI_DEMO_MARKER("Popups/Context menus");
5545
        HelpMarker("\"Context\" functions are simple helpers to associate a Popup to a given Item or Window identifier.");
5546
5547
        // BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing:
5548
        //     if (id == 0)
5549
        //         id = GetItemID(); // Use last item id
5550
        //     if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right))
5551
        //         OpenPopup(id);
5552
        //     return BeginPopup(id);
5553
        // For advanced uses you may want to replicate and customize this code.
5554
        // See more details in BeginPopupContextItem().
5555
5556
        // Example 1
5557
        // When used after an item that has an ID (e.g. Button), we can skip providing an ID to BeginPopupContextItem(),
5558
        // and BeginPopupContextItem() will use the last item ID as the popup ID.
5559
        {
5560
            const char* names[5] = { "Label1", "Label2", "Label3", "Label4", "Label5" };
5561
            static int selected = -1;
5562
            for (int n = 0; n < 5; n++)
5563
            {
5564
                if (ImGui::Selectable(names[n], selected == n))
5565
                    selected = n;
5566
                if (ImGui::BeginPopupContextItem()) // <-- use last item id as popup id
5567
                {
5568
                    selected = n;
5569
                    ImGui::Text("This is a popup for \"%s\"!", names[n]);
5570
                    if (ImGui::Button("Close"))
5571
                        ImGui::CloseCurrentPopup();
5572
                    ImGui::EndPopup();
5573
                }
5574
                ImGui::SetItemTooltip("Right-click to open popup");
5575
            }
5576
        }
5577
5578
        // Example 2
5579
        // Popup on a Text() element which doesn't have an identifier: we need to provide an identifier to BeginPopupContextItem().
5580
        // Using an explicit identifier is also convenient if you want to activate the popups from different locations.
5581
        {
5582
            HelpMarker("Text() elements don't have stable identifiers so we need to provide one.");
5583
            static float value = 0.5f;
5584
            ImGui::Text("Value = %.3f <-- (1) right-click this text", value);
5585
            if (ImGui::BeginPopupContextItem("my popup"))
5586
            {
5587
                if (ImGui::Selectable("Set to zero")) value = 0.0f;
5588
                if (ImGui::Selectable("Set to PI")) value = 3.1415f;
5589
                ImGui::SetNextItemWidth(-FLT_MIN);
5590
                ImGui::DragFloat("##Value", &value, 0.1f, 0.0f, 0.0f);
5591
                ImGui::EndPopup();
5592
            }
5593
5594
            // We can also use OpenPopupOnItemClick() to toggle the visibility of a given popup.
5595
            // Here we make it that right-clicking this other text element opens the same popup as above.
5596
            // The popup itself will be submitted by the code above.
5597
            ImGui::Text("(2) Or right-click this text");
5598
            ImGui::OpenPopupOnItemClick("my popup", ImGuiPopupFlags_MouseButtonRight);
5599
5600
            // Back to square one: manually open the same popup.
5601
            if (ImGui::Button("(3) Or click this button"))
5602
                ImGui::OpenPopup("my popup");
5603
        }
5604
5605
        // Example 3
5606
        // When using BeginPopupContextItem() with an implicit identifier (NULL == use last item ID),
5607
        // we need to make sure your item identifier is stable.
5608
        // In this example we showcase altering the item label while preserving its identifier, using the ### operator (see FAQ).
5609
        {
5610
            HelpMarker("Showcase using a popup ID linked to item ID, with the item having a changing label + stable ID using the ### operator.");
5611
            static char name[32] = "Label1";
5612
            char buf[64];
5613
            sprintf(buf, "Button: %s###Button", name); // ### operator override ID ignoring the preceding label
5614
            ImGui::Button(buf);
5615
            if (ImGui::BeginPopupContextItem())
5616
            {
5617
                ImGui::Text("Edit name:");
5618
                ImGui::InputText("##edit", name, IM_COUNTOF(name));
5619
                if (ImGui::Button("Close"))
5620
                    ImGui::CloseCurrentPopup();
5621
                ImGui::EndPopup();
5622
            }
5623
            ImGui::SameLine(); ImGui::Text("(<-- right-click here)");
5624
        }
5625
5626
        ImGui::TreePop();
5627
    }
5628
5629
    if (ImGui::TreeNode("Modals"))
5630
    {
5631
        IMGUI_DEMO_MARKER("Popups/Modals");
5632
        ImGui::TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside.");
5633
5634
        if (ImGui::Button("Delete.."))
5635
            ImGui::OpenPopup("Delete?");
5636
5637
        // Always center this window when appearing
5638
        ImVec2 center = ImGui::GetMainViewport()->GetCenter();
5639
        ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
5640
5641
        if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize))
5642
        {
5643
            ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!");
5644
            ImGui::Separator();
5645
5646
            //static int unused_i = 0;
5647
            //ImGui::Combo("Combo", &unused_i, "Delete\0Delete harder\0");
5648
5649
            static bool dont_ask_me_next_time = false;
5650
            ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
5651
            ImGui::Checkbox("Don't ask me next time", &dont_ask_me_next_time);
5652
            ImGui::PopStyleVar();
5653
5654
            if (ImGui::Button("OK", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); }
5655
            ImGui::SetItemDefaultFocus();
5656
            ImGui::SameLine();
5657
            if (ImGui::Button("Cancel", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); }
5658
            ImGui::EndPopup();
5659
        }
5660
5661
        if (ImGui::Button("Stacked modals.."))
5662
            ImGui::OpenPopup("Stacked 1");
5663
        if (ImGui::BeginPopupModal("Stacked 1", NULL, ImGuiWindowFlags_MenuBar))
5664
        {
5665
            if (ImGui::BeginMenuBar())
5666
            {
5667
                if (ImGui::BeginMenu("File"))
5668
                {
5669
                    if (ImGui::MenuItem("Some menu item")) {}
5670
                    ImGui::EndMenu();
5671
                }
5672
                ImGui::EndMenuBar();
5673
            }
5674
            ImGui::Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it.");
5675
5676
            // Testing behavior of widgets stacking their own regular popups over the modal.
5677
            static int item = 1;
5678
            static float color[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
5679
            ImGui::Combo("Combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
5680
            ImGui::ColorEdit4("Color", color);
5681
5682
            if (ImGui::Button("Add another modal.."))
5683
                ImGui::OpenPopup("Stacked 2");
5684
5685
            // Also demonstrate passing a bool* to BeginPopupModal(), this will create a regular close button which
5686
            // will close the popup. Note that the visibility state of popups is owned by imgui, so the input value
5687
            // of the bool actually doesn't matter here.
5688
            bool unused_open = true;
5689
            if (ImGui::BeginPopupModal("Stacked 2", &unused_open))
5690
            {
5691
                ImGui::Text("Hello from Stacked The Second!");
5692
                ImGui::ColorEdit4("Color", color); // Allow opening another nested popup
5693
                if (ImGui::Button("Close"))
5694
                    ImGui::CloseCurrentPopup();
5695
                ImGui::EndPopup();
5696
            }
5697
5698
            if (ImGui::Button("Close"))
5699
                ImGui::CloseCurrentPopup();
5700
            ImGui::EndPopup();
5701
        }
5702
5703
        ImGui::TreePop();
5704
    }
5705
5706
    if (ImGui::TreeNode("Menus inside a regular window"))
5707
    {
5708
        IMGUI_DEMO_MARKER("Popups/Menus inside a regular window");
5709
        ImGui::TextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!");
5710
        ImGui::Separator();
5711
5712
        ImGui::MenuItem("Menu item", "Ctrl+M");
5713
        if (ImGui::BeginMenu("Menu inside a regular window"))
5714
        {
5715
            ShowExampleMenuFile();
5716
            ImGui::EndMenu();
5717
        }
5718
        ImGui::Separator();
5719
        ImGui::TreePop();
5720
    }
5721
}
5722
5723
// Dummy data structure that we use for the Table demo.
5724
// (pre-C++11 doesn't allow us to instantiate ImVector<MyItem> template if this structure is defined inside the demo function)
5725
namespace
5726
{
5727
// We are passing our own identifier to TableSetupColumn() to facilitate identifying columns in the sorting code.
5728
// This identifier will be passed down into ImGuiTableSortSpec::ColumnUserID.
5729
// But it is possible to omit the user id parameter of TableSetupColumn() and just use the column index instead! (ImGuiTableSortSpec::ColumnIndex)
5730
// If you don't use sorting, you will generally never care about giving column an ID!
5731
enum MyItemColumnID
5732
{
5733
    MyItemColumnID_ID,
5734
    MyItemColumnID_Name,
5735
    MyItemColumnID_Action,
5736
    MyItemColumnID_Quantity,
5737
    MyItemColumnID_Description
5738
};
5739
5740
struct MyItem
5741
{
5742
    int         ID;
5743
    const char* Name;
5744
    int         Quantity;
5745
5746
    // We have a problem which is affecting _only this demo_ and should not affect your code:
5747
    // As we don't rely on std:: or other third-party library to compile dear imgui, we only have reliable access to qsort(),
5748
    // however qsort doesn't allow passing user data to comparing function.
5749
    // As a workaround, we are storing the sort specs in a static/global for the comparing function to access.
5750
    // In your own use case you would probably pass the sort specs to your sorting/comparing functions directly and not use a global.
5751
    // We could technically call ImGui::TableGetSortSpecs() in CompareWithSortSpecs(), but considering that this function is called
5752
    // very often by the sorting algorithm it would be a little wasteful.
5753
    static const ImGuiTableSortSpecs* s_current_sort_specs;
5754
5755
    static void SortWithSortSpecs(ImGuiTableSortSpecs* sort_specs, MyItem* items, int items_count)
5756
    {
5757
        s_current_sort_specs = sort_specs; // Store in variable accessible by the sort function.
5758
        if (items_count > 1)
5759
            qsort(items, (size_t)items_count, sizeof(items[0]), MyItem::CompareWithSortSpecs);
5760
        s_current_sort_specs = NULL;
5761
    }
5762
5763
    // Compare function to be used by qsort()
5764
    static int IMGUI_CDECL CompareWithSortSpecs(const void* lhs, const void* rhs)
5765
    {
5766
        const MyItem* a = (const MyItem*)lhs;
5767
        const MyItem* b = (const MyItem*)rhs;
5768
        for (int n = 0; n < s_current_sort_specs->SpecsCount; n++)
5769
        {
5770
            // Here we identify columns using the ColumnUserID value that we ourselves passed to TableSetupColumn()
5771
            // We could also choose to identify columns based on their index (sort_spec->ColumnIndex), which is simpler!
5772
            const ImGuiTableColumnSortSpecs* sort_spec = &s_current_sort_specs->Specs[n];
5773
            int delta = 0;
5774
            switch (sort_spec->ColumnUserID)
5775
            {
5776
            case MyItemColumnID_ID:             delta = (a->ID - b->ID);                break;
5777
            case MyItemColumnID_Name:           delta = (strcmp(a->Name, b->Name));     break;
5778
            case MyItemColumnID_Quantity:       delta = (a->Quantity - b->Quantity);    break;
5779
            case MyItemColumnID_Description:    delta = (strcmp(a->Name, b->Name));     break;
5780
            default: IM_ASSERT(0); break;
5781
            }
5782
            if (delta > 0)
5783
                return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? +1 : -1;
5784
            if (delta < 0)
5785
                return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? -1 : +1;
5786
        }
5787
5788
        // qsort() is instable so always return a way to differentiate items.
5789
        // Your own compare function may want to avoid fallback on implicit sort specs.
5790
        // e.g. a Name compare if it wasn't already part of the sort specs.
5791
        return a->ID - b->ID;
5792
    }
5793
};
5794
const ImGuiTableSortSpecs* MyItem::s_current_sort_specs = NULL;
5795
}
5796
5797
// Make the UI compact because there are so many fields
5798
static void PushStyleCompact()
5799
{
5800
    ImGuiStyle& style = ImGui::GetStyle();
5801
    ImGui::PushStyleVarY(ImGuiStyleVar_FramePadding, (float)(int)(style.FramePadding.y * 0.60f));
5802
    ImGui::PushStyleVarY(ImGuiStyleVar_ItemSpacing, (float)(int)(style.ItemSpacing.y * 0.60f));
5803
}
5804
5805
static void PopStyleCompact()
5806
{
5807
    ImGui::PopStyleVar(2);
5808
}
5809
5810
// Show a combo box with a choice of sizing policies
5811
static void EditTableSizingFlags(ImGuiTableFlags* p_flags)
5812
{
5813
    struct EnumDesc { ImGuiTableFlags Value; const char* Name; const char* Tooltip; };
5814
    static const EnumDesc policies[] =
5815
    {
5816
        { 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." },
5817
        { ImGuiTableFlags_SizingFixedFit,     "ImGuiTableFlags_SizingFixedFit",     "Columns default to _WidthFixed (if resizable) or _WidthAuto (if not resizable), matching contents width." },
5818
        { ImGuiTableFlags_SizingFixedSame,    "ImGuiTableFlags_SizingFixedSame",    "Columns are all the same width, matching the maximum contents width.\nImplicitly disable ImGuiTableFlags_Resizable and enable ImGuiTableFlags_NoKeepColumnsVisible." },
5819
        { ImGuiTableFlags_SizingStretchProp,  "ImGuiTableFlags_SizingStretchProp",  "Columns default to _WidthStretch with weights proportional to their widths." },
5820
        { ImGuiTableFlags_SizingStretchSame,  "ImGuiTableFlags_SizingStretchSame",  "Columns default to _WidthStretch with same weights." }
5821
    };
5822
    int idx;
5823
    for (idx = 0; idx < IM_COUNTOF(policies); idx++)
5824
        if (policies[idx].Value == (*p_flags & ImGuiTableFlags_SizingMask_))
5825
            break;
5826
    const char* preview_text = (idx < IM_COUNTOF(policies)) ? policies[idx].Name + (idx > 0 ? strlen("ImGuiTableFlags") : 0) : "";
5827
    if (ImGui::BeginCombo("Sizing Policy", preview_text))
5828
    {
5829
        for (int n = 0; n < IM_COUNTOF(policies); n++)
5830
            if (ImGui::Selectable(policies[n].Name, idx == n))
5831
                *p_flags = (*p_flags & ~ImGuiTableFlags_SizingMask_) | policies[n].Value;
5832
        ImGui::EndCombo();
5833
    }
5834
    ImGui::SameLine();
5835
    ImGui::TextDisabled("(?)");
5836
    if (ImGui::BeginItemTooltip())
5837
    {
5838
        ImGui::PushTextWrapPos(ImGui::GetFontSize() * 50.0f);
5839
        for (int m = 0; m < IM_COUNTOF(policies); m++)
5840
        {
5841
            ImGui::Separator();
5842
            ImGui::Text("%s:", policies[m].Name);
5843
            ImGui::Separator();
5844
            ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetStyle().IndentSpacing * 0.5f);
5845
            ImGui::TextUnformatted(policies[m].Tooltip);
5846
        }
5847
        ImGui::PopTextWrapPos();
5848
        ImGui::EndTooltip();
5849
    }
5850
}
5851
5852
static void EditTableColumnsFlags(ImGuiTableColumnFlags* p_flags)
5853
{
5854
    ImGui::CheckboxFlags("_Disabled", p_flags, ImGuiTableColumnFlags_Disabled); ImGui::SameLine(); HelpMarker("Master disable flag (also hide from context menu)");
5855
    ImGui::CheckboxFlags("_DefaultHide", p_flags, ImGuiTableColumnFlags_DefaultHide);
5856
    ImGui::CheckboxFlags("_DefaultSort", p_flags, ImGuiTableColumnFlags_DefaultSort);
5857
    if (ImGui::CheckboxFlags("_WidthStretch", p_flags, ImGuiTableColumnFlags_WidthStretch))
5858
        *p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthStretch);
5859
    if (ImGui::CheckboxFlags("_WidthFixed", p_flags, ImGuiTableColumnFlags_WidthFixed))
5860
        *p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthFixed);
5861
    ImGui::CheckboxFlags("_NoResize", p_flags, ImGuiTableColumnFlags_NoResize);
5862
    ImGui::CheckboxFlags("_NoReorder", p_flags, ImGuiTableColumnFlags_NoReorder);
5863
    ImGui::CheckboxFlags("_NoHide", p_flags, ImGuiTableColumnFlags_NoHide);
5864
    ImGui::CheckboxFlags("_NoClip", p_flags, ImGuiTableColumnFlags_NoClip);
5865
    ImGui::CheckboxFlags("_NoSort", p_flags, ImGuiTableColumnFlags_NoSort);
5866
    ImGui::CheckboxFlags("_NoSortAscending", p_flags, ImGuiTableColumnFlags_NoSortAscending);
5867
    ImGui::CheckboxFlags("_NoSortDescending", p_flags, ImGuiTableColumnFlags_NoSortDescending);
5868
    ImGui::CheckboxFlags("_NoHeaderLabel", p_flags, ImGuiTableColumnFlags_NoHeaderLabel);
5869
    ImGui::CheckboxFlags("_NoHeaderWidth", p_flags, ImGuiTableColumnFlags_NoHeaderWidth);
5870
    ImGui::CheckboxFlags("_PreferSortAscending", p_flags, ImGuiTableColumnFlags_PreferSortAscending);
5871
    ImGui::CheckboxFlags("_PreferSortDescending", p_flags, ImGuiTableColumnFlags_PreferSortDescending);
5872
    ImGui::CheckboxFlags("_IndentEnable", p_flags, ImGuiTableColumnFlags_IndentEnable); ImGui::SameLine(); HelpMarker("Default for column 0");
5873
    ImGui::CheckboxFlags("_IndentDisable", p_flags, ImGuiTableColumnFlags_IndentDisable); ImGui::SameLine(); HelpMarker("Default for column >0");
5874
    ImGui::CheckboxFlags("_AngledHeader", p_flags, ImGuiTableColumnFlags_AngledHeader);
5875
}
5876
5877
static void ShowTableColumnsStatusFlags(ImGuiTableColumnFlags flags)
5878
{
5879
    ImGui::CheckboxFlags("_IsEnabled", &flags, ImGuiTableColumnFlags_IsEnabled);
5880
    ImGui::CheckboxFlags("_IsVisible", &flags, ImGuiTableColumnFlags_IsVisible);
5881
    ImGui::CheckboxFlags("_IsSorted", &flags, ImGuiTableColumnFlags_IsSorted);
5882
    ImGui::CheckboxFlags("_IsHovered", &flags, ImGuiTableColumnFlags_IsHovered);
5883
}
5884
5885
//-----------------------------------------------------------------------------
5886
// [SECTION] DemoWindowTables()
5887
//-----------------------------------------------------------------------------
5888
5889
static void DemoWindowTables()
5890
{
5891
    //ImGui::SetNextItemOpen(true, ImGuiCond_Once);
5892
    if (!ImGui::CollapsingHeader("Tables & Columns"))
5893
        return;
5894
5895
    // Using those as a base value to create width/height that are factor of the size of our font
5896
    const float TEXT_BASE_WIDTH = ImGui::CalcTextSize("A").x;
5897
    const float TEXT_BASE_HEIGHT = ImGui::GetTextLineHeightWithSpacing();
5898
5899
    ImGui::PushID("Tables");
5900
5901
    int open_action = -1;
5902
    if (ImGui::Button("Expand all"))
5903
        open_action = 1;
5904
    ImGui::SameLine();
5905
    if (ImGui::Button("Collapse all"))
5906
        open_action = 0;
5907
    ImGui::SameLine();
5908
5909
    // Options
5910
    static bool disable_indent = false;
5911
    ImGui::Checkbox("Disable tree indentation", &disable_indent);
5912
    ImGui::SameLine();
5913
    HelpMarker("Disable the indenting of tree nodes so demo tables can use the full window width.");
5914
    ImGui::Separator();
5915
    if (disable_indent)
5916
        ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0.0f);
5917
5918
    // About Styling of tables
5919
    // Most settings are configured on a per-table basis via the flags passed to BeginTable() and TableSetupColumns APIs.
5920
    // There are however a few settings that a shared and part of the ImGuiStyle structure:
5921
    //   style.CellPadding                          // Padding within each cell
5922
    //   style.Colors[ImGuiCol_TableHeaderBg]       // Table header background
5923
    //   style.Colors[ImGuiCol_TableBorderStrong]   // Table outer and header borders
5924
    //   style.Colors[ImGuiCol_TableBorderLight]    // Table inner borders
5925
    //   style.Colors[ImGuiCol_TableRowBg]          // Table row background when ImGuiTableFlags_RowBg is enabled (even rows)
5926
    //   style.Colors[ImGuiCol_TableRowBgAlt]       // Table row background when ImGuiTableFlags_RowBg is enabled (odds rows)
5927
5928
    // Demos
5929
    if (open_action != -1)
5930
        ImGui::SetNextItemOpen(open_action != 0);
5931
    if (ImGui::TreeNode("Basic"))
5932
    {
5933
        IMGUI_DEMO_MARKER("Tables/Basic");
5934
        // Here we will showcase three different ways to output a table.
5935
        // They are very simple variations of a same thing!
5936
5937
        // [Method 1] Using TableNextRow() to create a new row, and TableSetColumnIndex() to select the column.
5938
        // In many situations, this is the most flexible and easy to use pattern.
5939
        HelpMarker("Using TableNextRow() + calling TableSetColumnIndex() _before_ each cell, in a loop.");
5940
        if (ImGui::BeginTable("table1", 3))
5941
        {
5942
            for (int row = 0; row < 4; row++)
5943
            {
5944
                ImGui::TableNextRow();
5945
                for (int column = 0; column < 3; column++)
5946
                {
5947
                    ImGui::TableSetColumnIndex(column);
5948
                    ImGui::Text("Row %d Column %d", row, column);
5949
                }
5950
            }
5951
            ImGui::EndTable();
5952
        }
5953
5954
        // [Method 2] Using TableNextColumn() called multiple times, instead of using a for loop + TableSetColumnIndex().
5955
        // This is generally more convenient when you have code manually submitting the contents of each column.
5956
        HelpMarker("Using TableNextRow() + calling TableNextColumn() _before_ each cell, manually.");
5957
        if (ImGui::BeginTable("table2", 3))
5958
        {
5959
            for (int row = 0; row < 4; row++)
5960
            {
5961
                ImGui::TableNextRow();
5962
                ImGui::TableNextColumn();
5963
                ImGui::Text("Row %d", row);
5964
                ImGui::TableNextColumn();
5965
                ImGui::Text("Some contents");
5966
                ImGui::TableNextColumn();
5967
                ImGui::Text("123.456");
5968
            }
5969
            ImGui::EndTable();
5970
        }
5971
5972
        // [Method 3] We call TableNextColumn() _before_ each cell. We never call TableNextRow(),
5973
        // as TableNextColumn() will automatically wrap around and create new rows as needed.
5974
        // This is generally more convenient when your cells all contains the same type of data.
5975
        HelpMarker(
5976
            "Only using TableNextColumn(), which tends to be convenient for tables where every cell contains "
5977
            "the same type of contents.\n This is also more similar to the old NextColumn() function of the "
5978
            "Columns API, and provided to facilitate the Columns->Tables API transition.");
5979
        if (ImGui::BeginTable("table3", 3))
5980
        {
5981
            for (int item = 0; item < 14; item++)
5982
            {
5983
                ImGui::TableNextColumn();
5984
                ImGui::Text("Item %d", item);
5985
            }
5986
            ImGui::EndTable();
5987
        }
5988
5989
        ImGui::TreePop();
5990
    }
5991
5992
    if (open_action != -1)
5993
        ImGui::SetNextItemOpen(open_action != 0);
5994
    if (ImGui::TreeNode("Borders, background"))
5995
    {
5996
        IMGUI_DEMO_MARKER("Tables/Borders, background");
5997
        // Expose a few Borders related flags interactively
5998
        enum ContentsType { CT_Text, CT_FillButton };
5999
        static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg;
6000
        static bool display_headers = false;
6001
        static int contents_type = CT_Text;
6002
6003
        PushStyleCompact();
6004
        ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg);
6005
        ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags, ImGuiTableFlags_Borders);
6006
        ImGui::SameLine(); HelpMarker("ImGuiTableFlags_Borders\n = ImGuiTableFlags_BordersInnerV\n | ImGuiTableFlags_BordersOuterV\n | ImGuiTableFlags_BordersInnerH\n | ImGuiTableFlags_BordersOuterH");
6007
        ImGui::Indent();
6008
6009
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags, ImGuiTableFlags_BordersH);
6010
        ImGui::Indent();
6011
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterH", &flags, ImGuiTableFlags_BordersOuterH);
6012
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerH", &flags, ImGuiTableFlags_BordersInnerH);
6013
        ImGui::Unindent();
6014
6015
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV);
6016
        ImGui::Indent();
6017
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags, ImGuiTableFlags_BordersOuterV);
6018
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags, ImGuiTableFlags_BordersInnerV);
6019
        ImGui::Unindent();
6020
6021
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuter", &flags, ImGuiTableFlags_BordersOuter);
6022
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersInner", &flags, ImGuiTableFlags_BordersInner);
6023
        ImGui::Unindent();
6024
6025
        ImGui::AlignTextToFramePadding(); ImGui::Text("Cell contents:");
6026
        ImGui::SameLine(); ImGui::RadioButton("Text", &contents_type, CT_Text);
6027
        ImGui::SameLine(); ImGui::RadioButton("FillButton", &contents_type, CT_FillButton);
6028
        ImGui::Checkbox("Display headers", &display_headers);
6029
        ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers)");
6030
        PopStyleCompact();
6031
6032
        if (ImGui::BeginTable("table1", 3, flags))
6033
        {
6034
            // Display headers so we can inspect their interaction with borders
6035
            // (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)
6036
            if (display_headers)
6037
            {
6038
                ImGui::TableSetupColumn("One");
6039
                ImGui::TableSetupColumn("Two");
6040
                ImGui::TableSetupColumn("Three");
6041
                ImGui::TableHeadersRow();
6042
            }
6043
6044
            for (int row = 0; row < 5; row++)
6045
            {
6046
                ImGui::TableNextRow();
6047
                for (int column = 0; column < 3; column++)
6048
                {
6049
                    ImGui::TableSetColumnIndex(column);
6050
                    char buf[32];
6051
                    sprintf(buf, "Hello %d,%d", column, row);
6052
                    if (contents_type == CT_Text)
6053
                        ImGui::TextUnformatted(buf);
6054
                    else if (contents_type == CT_FillButton)
6055
                        ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f));
6056
                }
6057
            }
6058
            ImGui::EndTable();
6059
        }
6060
        ImGui::TreePop();
6061
    }
6062
6063
    if (open_action != -1)
6064
        ImGui::SetNextItemOpen(open_action != 0);
6065
    if (ImGui::TreeNode("Resizable, stretch"))
6066
    {
6067
        IMGUI_DEMO_MARKER("Tables/Resizable, stretch");
6068
        // By default, if we don't enable ScrollX the sizing policy for each column is "Stretch"
6069
        // All columns maintain a sizing weight, and they will occupy all available width.
6070
        static ImGuiTableFlags flags = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody;
6071
        PushStyleCompact();
6072
        ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
6073
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV);
6074
        ImGui::SameLine(); HelpMarker(
6075
            "Using the _Resizable flag automatically enables the _BordersInnerV flag as well, "
6076
            "this is why the resize borders are still showing when unchecking this.");
6077
        PopStyleCompact();
6078
6079
        if (ImGui::BeginTable("table1", 3, flags))
6080
        {
6081
            for (int row = 0; row < 5; row++)
6082
            {
6083
                ImGui::TableNextRow();
6084
                for (int column = 0; column < 3; column++)
6085
                {
6086
                    ImGui::TableSetColumnIndex(column);
6087
                    ImGui::Text("Hello %d,%d", column, row);
6088
                }
6089
            }
6090
            ImGui::EndTable();
6091
        }
6092
        ImGui::TreePop();
6093
    }
6094
6095
    if (open_action != -1)
6096
        ImGui::SetNextItemOpen(open_action != 0);
6097
    if (ImGui::TreeNode("Resizable, fixed"))
6098
    {
6099
        IMGUI_DEMO_MARKER("Tables/Resizable, fixed");
6100
        // Here we use ImGuiTableFlags_SizingFixedFit (even though _ScrollX is not set)
6101
        // So columns will adopt the "Fixed" policy and will maintain a fixed width regardless of the whole available width (unless table is small)
6102
        // If there is not enough available width to fit all columns, they will however be resized down.
6103
        // FIXME-TABLE: Providing a stretch-on-init would make sense especially for tables which don't have saved settings
6104
        HelpMarker(
6105
            "Using _Resizable + _SizingFixedFit flags.\n"
6106
            "Fixed-width columns generally makes more sense if you want to use horizontal scrolling.\n\n"
6107
            "Double-click a column border to auto-fit the column to its contents.");
6108
        PushStyleCompact();
6109
        static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody;
6110
        ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX);
6111
        PopStyleCompact();
6112
6113
        if (ImGui::BeginTable("table1", 3, flags))
6114
        {
6115
            for (int row = 0; row < 5; row++)
6116
            {
6117
                ImGui::TableNextRow();
6118
                for (int column = 0; column < 3; column++)
6119
                {
6120
                    ImGui::TableSetColumnIndex(column);
6121
                    ImGui::Text("Hello %d,%d", column, row);
6122
                }
6123
            }
6124
            ImGui::EndTable();
6125
        }
6126
        ImGui::TreePop();
6127
    }
6128
6129
    if (open_action != -1)
6130
        ImGui::SetNextItemOpen(open_action != 0);
6131
    if (ImGui::TreeNode("Resizable, mixed"))
6132
    {
6133
        IMGUI_DEMO_MARKER("Tables/Resizable, mixed");
6134
        HelpMarker(
6135
            "Using TableSetupColumn() to alter resizing policy on a per-column basis.\n\n"
6136
            "When combining Fixed and Stretch columns, generally you only want one, maybe two trailing columns to use _WidthStretch.");
6137
        static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
6138
6139
        if (ImGui::BeginTable("table1", 3, flags))
6140
        {
6141
            ImGui::TableSetupColumn("AAA", ImGuiTableColumnFlags_WidthFixed);
6142
            ImGui::TableSetupColumn("BBB", ImGuiTableColumnFlags_WidthFixed);
6143
            ImGui::TableSetupColumn("CCC", ImGuiTableColumnFlags_WidthStretch);
6144
            ImGui::TableHeadersRow();
6145
            for (int row = 0; row < 5; row++)
6146
            {
6147
                ImGui::TableNextRow();
6148
                for (int column = 0; column < 3; column++)
6149
                {
6150
                    ImGui::TableSetColumnIndex(column);
6151
                    ImGui::Text("%s %d,%d", (column == 2) ? "Stretch" : "Fixed", column, row);
6152
                }
6153
            }
6154
            ImGui::EndTable();
6155
        }
6156
        if (ImGui::BeginTable("table2", 6, flags))
6157
        {
6158
            ImGui::TableSetupColumn("AAA", ImGuiTableColumnFlags_WidthFixed);
6159
            ImGui::TableSetupColumn("BBB", ImGuiTableColumnFlags_WidthFixed);
6160
            ImGui::TableSetupColumn("CCC", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_DefaultHide);
6161
            ImGui::TableSetupColumn("DDD", ImGuiTableColumnFlags_WidthStretch);
6162
            ImGui::TableSetupColumn("EEE", ImGuiTableColumnFlags_WidthStretch);
6163
            ImGui::TableSetupColumn("FFF", ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_DefaultHide);
6164
            ImGui::TableHeadersRow();
6165
            for (int row = 0; row < 5; row++)
6166
            {
6167
                ImGui::TableNextRow();
6168
                for (int column = 0; column < 6; column++)
6169
                {
6170
                    ImGui::TableSetColumnIndex(column);
6171
                    ImGui::Text("%s %d,%d", (column >= 3) ? "Stretch" : "Fixed", column, row);
6172
                }
6173
            }
6174
            ImGui::EndTable();
6175
        }
6176
        ImGui::TreePop();
6177
    }
6178
6179
    if (open_action != -1)
6180
        ImGui::SetNextItemOpen(open_action != 0);
6181
    if (ImGui::TreeNode("Reorderable, hideable, with headers"))
6182
    {
6183
        IMGUI_DEMO_MARKER("Tables/Reorderable, hideable, with headers");
6184
        HelpMarker(
6185
            "Click and drag column headers to reorder columns.\n\n"
6186
            "Right-click on a header to open a context menu.");
6187
        static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV;
6188
        PushStyleCompact();
6189
        ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
6190
        ImGui::CheckboxFlags("ImGuiTableFlags_Reorderable", &flags, ImGuiTableFlags_Reorderable);
6191
        ImGui::CheckboxFlags("ImGuiTableFlags_Hideable", &flags, ImGuiTableFlags_Hideable);
6192
        ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody);
6193
        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)");
6194
        ImGui::CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", &flags, ImGuiTableFlags_HighlightHoveredColumn);
6195
        PopStyleCompact();
6196
6197
        if (ImGui::BeginTable("table1", 3, flags))
6198
        {
6199
            // Submit columns name with TableSetupColumn() and call TableHeadersRow() to create a row with a header in each column.
6200
            // (Later we will show how TableSetupColumn() has other uses, optional flags, sizing weight etc.)
6201
            ImGui::TableSetupColumn("One");
6202
            ImGui::TableSetupColumn("Two");
6203
            ImGui::TableSetupColumn("Three");
6204
            ImGui::TableHeadersRow();
6205
            for (int row = 0; row < 6; row++)
6206
            {
6207
                ImGui::TableNextRow();
6208
                for (int column = 0; column < 3; column++)
6209
                {
6210
                    ImGui::TableSetColumnIndex(column);
6211
                    ImGui::Text("Hello %d,%d", column, row);
6212
                }
6213
            }
6214
            ImGui::EndTable();
6215
        }
6216
6217
        // Use outer_size.x == 0.0f instead of default to make the table as tight as possible
6218
        // (only valid when no scrolling and no stretch column)
6219
        if (ImGui::BeginTable("table2", 3, flags | ImGuiTableFlags_SizingFixedFit, ImVec2(0.0f, 0.0f)))
6220
        {
6221
            ImGui::TableSetupColumn("One");
6222
            ImGui::TableSetupColumn("Two");
6223
            ImGui::TableSetupColumn("Three");
6224
            ImGui::TableHeadersRow();
6225
            for (int row = 0; row < 6; row++)
6226
            {
6227
                ImGui::TableNextRow();
6228
                for (int column = 0; column < 3; column++)
6229
                {
6230
                    ImGui::TableSetColumnIndex(column);
6231
                    ImGui::Text("Fixed %d,%d", column, row);
6232
                }
6233
            }
6234
            ImGui::EndTable();
6235
        }
6236
        ImGui::TreePop();
6237
    }
6238
6239
    if (open_action != -1)
6240
        ImGui::SetNextItemOpen(open_action != 0);
6241
    if (ImGui::TreeNode("Padding"))
6242
    {
6243
        IMGUI_DEMO_MARKER("Tables/Padding");
6244
        // First example: showcase use of padding flags and effect of BorderOuterV/BorderInnerV on X padding.
6245
        // We don't expose BorderOuterH/BorderInnerH here because they have no effect on X padding.
6246
        HelpMarker(
6247
            "We often want outer padding activated when any using features which makes the edges of a column visible:\n"
6248
            "e.g.:\n"
6249
            "- BorderOuterV\n"
6250
            "- any form of row selection\n"
6251
            "Because of this, activating BorderOuterV sets the default to PadOuterX. "
6252
            "Using PadOuterX or NoPadOuterX you can override the default.\n\n"
6253
            "Actual padding values are using style.CellPadding.\n\n"
6254
            "In this demo we don't show horizontal borders to emphasize how they don't affect default horizontal padding.");
6255
6256
        static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV;
6257
        PushStyleCompact();
6258
        ImGui::CheckboxFlags("ImGuiTableFlags_PadOuterX", &flags1, ImGuiTableFlags_PadOuterX);
6259
        ImGui::SameLine(); HelpMarker("Enable outer-most padding (default if ImGuiTableFlags_BordersOuterV is set)");
6260
        ImGui::CheckboxFlags("ImGuiTableFlags_NoPadOuterX", &flags1, ImGuiTableFlags_NoPadOuterX);
6261
        ImGui::SameLine(); HelpMarker("Disable outer-most padding (default if ImGuiTableFlags_BordersOuterV is not set)");
6262
        ImGui::CheckboxFlags("ImGuiTableFlags_NoPadInnerX", &flags1, ImGuiTableFlags_NoPadInnerX);
6263
        ImGui::SameLine(); HelpMarker("Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off)");
6264
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags1, ImGuiTableFlags_BordersOuterV);
6265
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags1, ImGuiTableFlags_BordersInnerV);
6266
        static bool show_headers = false;
6267
        ImGui::Checkbox("show_headers", &show_headers);
6268
        PopStyleCompact();
6269
6270
        if (ImGui::BeginTable("table_padding", 3, flags1))
6271
        {
6272
            if (show_headers)
6273
            {
6274
                ImGui::TableSetupColumn("One");
6275
                ImGui::TableSetupColumn("Two");
6276
                ImGui::TableSetupColumn("Three");
6277
                ImGui::TableHeadersRow();
6278
            }
6279
6280
            for (int row = 0; row < 5; row++)
6281
            {
6282
                ImGui::TableNextRow();
6283
                for (int column = 0; column < 3; column++)
6284
                {
6285
                    ImGui::TableSetColumnIndex(column);
6286
                    if (row == 0)
6287
                    {
6288
                        ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x);
6289
                    }
6290
                    else
6291
                    {
6292
                        char buf[32];
6293
                        sprintf(buf, "Hello %d,%d", column, row);
6294
                        ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f));
6295
                    }
6296
                    //if (ImGui::TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered)
6297
                    //    ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, IM_COL32(0, 100, 0, 255));
6298
                }
6299
            }
6300
            ImGui::EndTable();
6301
        }
6302
6303
        // Second example: set style.CellPadding to (0.0) or a custom value.
6304
        // FIXME-TABLE: Vertical border effectively not displayed the same way as horizontal one...
6305
        HelpMarker("Setting style.CellPadding to (0,0) or a custom value.");
6306
        static ImGuiTableFlags flags2 = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg;
6307
        static ImVec2 cell_padding(0.0f, 0.0f);
6308
        static bool show_widget_frame_bg = true;
6309
6310
        PushStyleCompact();
6311
        ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags2, ImGuiTableFlags_Borders);
6312
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags2, ImGuiTableFlags_BordersH);
6313
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags2, ImGuiTableFlags_BordersV);
6314
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersInner", &flags2, ImGuiTableFlags_BordersInner);
6315
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuter", &flags2, ImGuiTableFlags_BordersOuter);
6316
        ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags2, ImGuiTableFlags_RowBg);
6317
        ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags2, ImGuiTableFlags_Resizable);
6318
        ImGui::Checkbox("show_widget_frame_bg", &show_widget_frame_bg);
6319
        ImGui::SliderFloat2("CellPadding", &cell_padding.x, 0.0f, 10.0f, "%.0f");
6320
        PopStyleCompact();
6321
6322
        ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, cell_padding);
6323
        if (ImGui::BeginTable("table_padding_2", 3, flags2))
6324
        {
6325
            static char text_bufs[3 * 5][16]; // Mini text storage for 3x5 cells
6326
            static bool init = true;
6327
            if (!show_widget_frame_bg)
6328
                ImGui::PushStyleColor(ImGuiCol_FrameBg, 0);
6329
            for (int cell = 0; cell < 3 * 5; cell++)
6330
            {
6331
                ImGui::TableNextColumn();
6332
                if (init)
6333
                    strcpy(text_bufs[cell], "edit me");
6334
                ImGui::SetNextItemWidth(-FLT_MIN);
6335
                ImGui::PushID(cell);
6336
                ImGui::InputText("##cell", text_bufs[cell], IM_COUNTOF(text_bufs[cell]));
6337
                ImGui::PopID();
6338
            }
6339
            if (!show_widget_frame_bg)
6340
                ImGui::PopStyleColor();
6341
            init = false;
6342
            ImGui::EndTable();
6343
        }
6344
        ImGui::PopStyleVar();
6345
6346
        ImGui::TreePop();
6347
    }
6348
6349
    if (open_action != -1)
6350
        ImGui::SetNextItemOpen(open_action != 0);
6351
    if (ImGui::TreeNode("Sizing policies"))
6352
    {
6353
        IMGUI_DEMO_MARKER("Tables/Explicit widths");
6354
        static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody;
6355
        PushStyleCompact();
6356
        ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags1, ImGuiTableFlags_Resizable);
6357
        ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags1, ImGuiTableFlags_NoHostExtendX);
6358
        PopStyleCompact();
6359
6360
        static ImGuiTableFlags sizing_policy_flags[4] = { ImGuiTableFlags_SizingFixedFit, ImGuiTableFlags_SizingFixedSame, ImGuiTableFlags_SizingStretchProp, ImGuiTableFlags_SizingStretchSame };
6361
        for (int table_n = 0; table_n < 4; table_n++)
6362
        {
6363
            ImGui::PushID(table_n);
6364
            ImGui::SetNextItemWidth(TEXT_BASE_WIDTH * 30);
6365
            EditTableSizingFlags(&sizing_policy_flags[table_n]);
6366
6367
            // To make it easier to understand the different sizing policy,
6368
            // For each policy: we display one table where the columns have equal contents width,
6369
            // and one where the columns have different contents width.
6370
            if (ImGui::BeginTable("table1", 3, sizing_policy_flags[table_n] | flags1))
6371
            {
6372
                for (int row = 0; row < 3; row++)
6373
                {
6374
                    ImGui::TableNextRow();
6375
                    ImGui::TableNextColumn(); ImGui::Text("Oh dear");
6376
                    ImGui::TableNextColumn(); ImGui::Text("Oh dear");
6377
                    ImGui::TableNextColumn(); ImGui::Text("Oh dear");
6378
                }
6379
                ImGui::EndTable();
6380
            }
6381
            if (ImGui::BeginTable("table2", 3, sizing_policy_flags[table_n] | flags1))
6382
            {
6383
                for (int row = 0; row < 3; row++)
6384
                {
6385
                    ImGui::TableNextRow();
6386
                    ImGui::TableNextColumn(); ImGui::Text("AAAA");
6387
                    ImGui::TableNextColumn(); ImGui::Text("BBBBBBBB");
6388
                    ImGui::TableNextColumn(); ImGui::Text("CCCCCCCCCCCC");
6389
                }
6390
                ImGui::EndTable();
6391
            }
6392
            ImGui::PopID();
6393
        }
6394
6395
        ImGui::Spacing();
6396
        ImGui::TextUnformatted("Advanced");
6397
        ImGui::SameLine();
6398
        HelpMarker(
6399
            "This section allows you to interact and see the effect of various sizing policies "
6400
            "depending on whether Scroll is enabled and the contents of your columns.");
6401
6402
        enum ContentsType { CT_ShowWidth, CT_ShortText, CT_LongText, CT_Button, CT_FillButton, CT_InputText };
6403
        static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable;
6404
        static int contents_type = CT_ShowWidth;
6405
        static int column_count = 3;
6406
6407
        PushStyleCompact();
6408
        ImGui::PushID("Advanced");
6409
        ImGui::PushItemWidth(TEXT_BASE_WIDTH * 30);
6410
        EditTableSizingFlags(&flags);
6411
        ImGui::Combo("Contents", &contents_type, "Show width\0Short Text\0Long Text\0Button\0Fill Button\0InputText\0");
6412
        if (contents_type == CT_FillButton)
6413
        {
6414
            ImGui::SameLine();
6415
            HelpMarker(
6416
                "Be mindful that using right-alignment (e.g. size.x = -FLT_MIN) creates a feedback loop "
6417
                "where contents width can feed into auto-column width can feed into contents width.");
6418
        }
6419
        ImGui::DragInt("Columns", &column_count, 0.1f, 1, 64, "%d", ImGuiSliderFlags_AlwaysClamp);
6420
        ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
6421
        ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths);
6422
        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.");
6423
        ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX);
6424
        ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
6425
        ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip);
6426
        ImGui::PopItemWidth();
6427
        ImGui::PopID();
6428
        PopStyleCompact();
6429
6430
        if (ImGui::BeginTable("table2", column_count, flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 7)))
6431
        {
6432
            for (int cell = 0; cell < 10 * column_count; cell++)
6433
            {
6434
                ImGui::TableNextColumn();
6435
                int column = ImGui::TableGetColumnIndex();
6436
                int row = ImGui::TableGetRowIndex();
6437
6438
                ImGui::PushID(cell);
6439
                char label[32];
6440
                static char text_buf[32] = "";
6441
                sprintf(label, "Hello %d,%d", column, row);
6442
                switch (contents_type)
6443
                {
6444
                case CT_ShortText:  ImGui::TextUnformatted(label); break;
6445
                case CT_LongText:   ImGui::Text("Some %s text %d,%d\nOver two lines..", column == 0 ? "long" : "longeeer", column, row); break;
6446
                case CT_ShowWidth:  ImGui::Text("W: %.1f", ImGui::GetContentRegionAvail().x); break;
6447
                case CT_Button:     ImGui::Button(label); break;
6448
                case CT_FillButton: ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f)); break;
6449
                case CT_InputText:  ImGui::SetNextItemWidth(-FLT_MIN); ImGui::InputText("##", text_buf, IM_COUNTOF(text_buf)); break;
6450
                }
6451
                ImGui::PopID();
6452
            }
6453
            ImGui::EndTable();
6454
        }
6455
        ImGui::TreePop();
6456
    }
6457
6458
    if (open_action != -1)
6459
        ImGui::SetNextItemOpen(open_action != 0);
6460
    if (ImGui::TreeNode("Vertical scrolling, with clipping"))
6461
    {
6462
        IMGUI_DEMO_MARKER("Tables/Vertical scrolling, with clipping");
6463
        HelpMarker(
6464
            "Here we activate ScrollY, which will create a child window container to allow hosting scrollable contents.\n\n"
6465
            "We also demonstrate using ImGuiListClipper to virtualize the submission of many items.");
6466
        static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
6467
6468
        PushStyleCompact();
6469
        ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
6470
        PopStyleCompact();
6471
6472
        // When using ScrollX or ScrollY we need to specify a size for our table container!
6473
        // Otherwise by default the table will fit all available space, like a BeginChild() call.
6474
        ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 8);
6475
        if (ImGui::BeginTable("table_scrolly", 3, flags, outer_size))
6476
        {
6477
            ImGui::TableSetupScrollFreeze(0, 1); // Make top row always visible
6478
            ImGui::TableSetupColumn("One", ImGuiTableColumnFlags_None);
6479
            ImGui::TableSetupColumn("Two", ImGuiTableColumnFlags_None);
6480
            ImGui::TableSetupColumn("Three", ImGuiTableColumnFlags_None);
6481
            ImGui::TableHeadersRow();
6482
6483
            // Demonstrate using clipper for large vertical lists
6484
            ImGuiListClipper clipper;
6485
            clipper.Begin(1000);
6486
            while (clipper.Step())
6487
            {
6488
                for (int row = clipper.DisplayStart; row < clipper.DisplayEnd; row++)
6489
                {
6490
                    ImGui::TableNextRow();
6491
                    for (int column = 0; column < 3; column++)
6492
                    {
6493
                        ImGui::TableSetColumnIndex(column);
6494
                        ImGui::Text("Hello %d,%d", column, row);
6495
                    }
6496
                }
6497
            }
6498
            ImGui::EndTable();
6499
        }
6500
        ImGui::TreePop();
6501
    }
6502
6503
    if (open_action != -1)
6504
        ImGui::SetNextItemOpen(open_action != 0);
6505
    if (ImGui::TreeNode("Horizontal scrolling"))
6506
    {
6507
        IMGUI_DEMO_MARKER("Tables/Horizontal scrolling");
6508
        HelpMarker(
6509
            "When ScrollX is enabled, the default sizing policy becomes ImGuiTableFlags_SizingFixedFit, "
6510
            "as automatically stretching columns doesn't make much sense with horizontal scrolling.\n\n"
6511
            "Also note that as of the current version, you will almost always want to enable ScrollY along with ScrollX, "
6512
            "because the container window won't automatically extend vertically to fix contents "
6513
            "(this may be improved in future versions).");
6514
        static ImGuiTableFlags flags = ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
6515
        static int freeze_cols = 1;
6516
        static int freeze_rows = 1;
6517
6518
        PushStyleCompact();
6519
        ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
6520
        ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX);
6521
        ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
6522
        ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
6523
        ImGui::DragInt("freeze_cols", &freeze_cols, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
6524
        ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
6525
        ImGui::DragInt("freeze_rows", &freeze_rows, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
6526
        PopStyleCompact();
6527
6528
        // When using ScrollX or ScrollY we need to specify a size for our table container!
6529
        // Otherwise by default the table will fit all available space, like a BeginChild() call.
6530
        ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 8);
6531
        if (ImGui::BeginTable("table_scrollx", 7, flags, outer_size))
6532
        {
6533
            ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows);
6534
            ImGui::TableSetupColumn("Line #", ImGuiTableColumnFlags_NoHide); // Make the first column not hideable to match our use of TableSetupScrollFreeze()
6535
            ImGui::TableSetupColumn("One");
6536
            ImGui::TableSetupColumn("Two");
6537
            ImGui::TableSetupColumn("Three");
6538
            ImGui::TableSetupColumn("Four");
6539
            ImGui::TableSetupColumn("Five");
6540
            ImGui::TableSetupColumn("Six");
6541
            ImGui::TableHeadersRow();
6542
            for (int row = 0; row < 20; row++)
6543
            {
6544
                ImGui::TableNextRow();
6545
                for (int column = 0; column < 7; column++)
6546
                {
6547
                    // Both TableNextColumn() and TableSetColumnIndex() return true when a column is visible or performing width measurement.
6548
                    // Because here we know that:
6549
                    // - A) all our columns are contributing the same to row height
6550
                    // - B) column 0 is always visible,
6551
                    // We only always submit this one column and can skip others.
6552
                    // More advanced per-column clipping behaviors may benefit from polling the status flags via TableGetColumnFlags().
6553
                    if (!ImGui::TableSetColumnIndex(column) && column > 0)
6554
                        continue;
6555
                    if (column == 0)
6556
                        ImGui::Text("Line %d", row);
6557
                    else
6558
                        ImGui::Text("Hello world %d,%d", column, row);
6559
                }
6560
            }
6561
            ImGui::EndTable();
6562
        }
6563
6564
        ImGui::Spacing();
6565
        ImGui::TextUnformatted("Stretch + ScrollX");
6566
        ImGui::SameLine();
6567
        HelpMarker(
6568
            "Showcase using Stretch columns + ScrollX together: "
6569
            "this is rather unusual and only makes sense when specifying an 'inner_width' for the table!\n"
6570
            "Without an explicit value, inner_width is == outer_size.x and therefore using Stretch columns "
6571
            "along with ScrollX doesn't make sense.");
6572
        static ImGuiTableFlags flags2 = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody;
6573
        static float inner_width = 1000.0f;
6574
        PushStyleCompact();
6575
        ImGui::PushID("flags3");
6576
        ImGui::PushItemWidth(TEXT_BASE_WIDTH * 30);
6577
        ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags2, ImGuiTableFlags_ScrollX);
6578
        ImGui::DragFloat("inner_width", &inner_width, 1.0f, 0.0f, FLT_MAX, "%.1f");
6579
        ImGui::PopItemWidth();
6580
        ImGui::PopID();
6581
        PopStyleCompact();
6582
        if (ImGui::BeginTable("table2", 7, flags2, outer_size, inner_width))
6583
        {
6584
            for (int cell = 0; cell < 20 * 7; cell++)
6585
            {
6586
                ImGui::TableNextColumn();
6587
                ImGui::Text("Hello world %d,%d", ImGui::TableGetColumnIndex(), ImGui::TableGetRowIndex());
6588
            }
6589
            ImGui::EndTable();
6590
        }
6591
        ImGui::TreePop();
6592
    }
6593
6594
    if (open_action != -1)
6595
        ImGui::SetNextItemOpen(open_action != 0);
6596
    if (ImGui::TreeNode("Columns flags"))
6597
    {
6598
        IMGUI_DEMO_MARKER("Tables/Columns flags");
6599
        // Create a first table just to show all the options/flags we want to make visible in our example!
6600
        const int column_count = 3;
6601
        const char* column_names[column_count] = { "One", "Two", "Three" };
6602
        static ImGuiTableColumnFlags column_flags[column_count] = { ImGuiTableColumnFlags_DefaultSort, ImGuiTableColumnFlags_None, ImGuiTableColumnFlags_DefaultHide };
6603
        static ImGuiTableColumnFlags column_flags_out[column_count] = { 0, 0, 0 }; // Output from TableGetColumnFlags()
6604
6605
        if (ImGui::BeginTable("table_columns_flags_checkboxes", column_count, ImGuiTableFlags_None))
6606
        {
6607
            PushStyleCompact();
6608
            for (int column = 0; column < column_count; column++)
6609
            {
6610
                ImGui::TableNextColumn();
6611
                ImGui::PushID(column);
6612
                ImGui::AlignTextToFramePadding(); // FIXME-TABLE: Workaround for wrong text baseline propagation across columns
6613
                ImGui::Text("'%s'", column_names[column]);
6614
                ImGui::Spacing();
6615
                ImGui::Text("Input flags:");
6616
                EditTableColumnsFlags(&column_flags[column]);
6617
                ImGui::Spacing();
6618
                ImGui::Text("Output flags:");
6619
                ImGui::BeginDisabled();
6620
                ShowTableColumnsStatusFlags(column_flags_out[column]);
6621
                ImGui::EndDisabled();
6622
                ImGui::PopID();
6623
            }
6624
            PopStyleCompact();
6625
            ImGui::EndTable();
6626
        }
6627
6628
        // Create the real table we care about for the example!
6629
        // We use a scrolling table to be able to showcase the difference between the _IsEnabled and _IsVisible flags above,
6630
        // otherwise in a non-scrolling table columns are always visible (unless using ImGuiTableFlags_NoKeepColumnsVisible
6631
        // + resizing the parent window down).
6632
        const ImGuiTableFlags flags
6633
            = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY
6634
            | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV
6635
            | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable;
6636
        ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 9);
6637
        if (ImGui::BeginTable("table_columns_flags", column_count, flags, outer_size))
6638
        {
6639
            bool has_angled_header = false;
6640
            for (int column = 0; column < column_count; column++)
6641
            {
6642
                has_angled_header |= (column_flags[column] & ImGuiTableColumnFlags_AngledHeader) != 0;
6643
                ImGui::TableSetupColumn(column_names[column], column_flags[column]);
6644
            }
6645
            if (has_angled_header)
6646
                ImGui::TableAngledHeadersRow();
6647
            ImGui::TableHeadersRow();
6648
            for (int column = 0; column < column_count; column++)
6649
                column_flags_out[column] = ImGui::TableGetColumnFlags(column);
6650
            float indent_step = (float)((int)TEXT_BASE_WIDTH / 2);
6651
            for (int row = 0; row < 8; row++)
6652
            {
6653
                // Add some indentation to demonstrate usage of per-column IndentEnable/IndentDisable flags.
6654
                ImGui::Indent(indent_step);
6655
                ImGui::TableNextRow();
6656
                for (int column = 0; column < column_count; column++)
6657
                {
6658
                    ImGui::TableSetColumnIndex(column);
6659
                    ImGui::Text("%s %s", (column == 0) ? "Indented" : "Hello", ImGui::TableGetColumnName(column));
6660
                }
6661
            }
6662
            ImGui::Unindent(indent_step * 8.0f);
6663
6664
            ImGui::EndTable();
6665
        }
6666
        ImGui::TreePop();
6667
    }
6668
6669
    if (open_action != -1)
6670
        ImGui::SetNextItemOpen(open_action != 0);
6671
    if (ImGui::TreeNode("Columns widths"))
6672
    {
6673
        IMGUI_DEMO_MARKER("Tables/Columns widths");
6674
        HelpMarker("Using TableSetupColumn() to setup default width.");
6675
6676
        static ImGuiTableFlags flags1 = ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBodyUntilResize;
6677
        PushStyleCompact();
6678
        ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags1, ImGuiTableFlags_Resizable);
6679
        ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags1, ImGuiTableFlags_NoBordersInBodyUntilResize);
6680
        PopStyleCompact();
6681
        if (ImGui::BeginTable("table1", 3, flags1))
6682
        {
6683
            // We could also set ImGuiTableFlags_SizingFixedFit on the table and all columns will default to ImGuiTableColumnFlags_WidthFixed.
6684
            ImGui::TableSetupColumn("one", ImGuiTableColumnFlags_WidthFixed, 100.0f); // Default to 100.0f
6685
            ImGui::TableSetupColumn("two", ImGuiTableColumnFlags_WidthFixed, 200.0f); // Default to 200.0f
6686
            ImGui::TableSetupColumn("three", ImGuiTableColumnFlags_WidthFixed);       // Default to auto
6687
            ImGui::TableHeadersRow();
6688
            for (int row = 0; row < 4; row++)
6689
            {
6690
                ImGui::TableNextRow();
6691
                for (int column = 0; column < 3; column++)
6692
                {
6693
                    ImGui::TableSetColumnIndex(column);
6694
                    if (row == 0)
6695
                        ImGui::Text("(w: %5.1f)", ImGui::GetContentRegionAvail().x);
6696
                    else
6697
                        ImGui::Text("Hello %d,%d", column, row);
6698
                }
6699
            }
6700
            ImGui::EndTable();
6701
        }
6702
6703
        HelpMarker(
6704
            "Using TableSetupColumn() to setup explicit width.\n\nUnless _NoKeepColumnsVisible is set, "
6705
            "fixed columns with set width may still be shrunk down if there's not enough space in the host.");
6706
6707
        static ImGuiTableFlags flags2 = ImGuiTableFlags_None;
6708
        PushStyleCompact();
6709
        ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags2, ImGuiTableFlags_NoKeepColumnsVisible);
6710
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags2, ImGuiTableFlags_BordersInnerV);
6711
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags2, ImGuiTableFlags_BordersOuterV);
6712
        PopStyleCompact();
6713
        if (ImGui::BeginTable("table2", 4, flags2))
6714
        {
6715
            // We could also set ImGuiTableFlags_SizingFixedFit on the table and then all columns
6716
            // will default to ImGuiTableColumnFlags_WidthFixed.
6717
            ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 100.0f);
6718
            ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f);
6719
            ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 30.0f);
6720
            ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f);
6721
            for (int row = 0; row < 5; row++)
6722
            {
6723
                ImGui::TableNextRow();
6724
                for (int column = 0; column < 4; column++)
6725
                {
6726
                    ImGui::TableSetColumnIndex(column);
6727
                    if (row == 0)
6728
                        ImGui::Text("(w: %5.1f)", ImGui::GetContentRegionAvail().x);
6729
                    else
6730
                        ImGui::Text("Hello %d,%d", column, row);
6731
                }
6732
            }
6733
            ImGui::EndTable();
6734
        }
6735
        ImGui::TreePop();
6736
    }
6737
6738
    if (open_action != -1)
6739
        ImGui::SetNextItemOpen(open_action != 0);
6740
    if (ImGui::TreeNode("Nested tables"))
6741
    {
6742
        IMGUI_DEMO_MARKER("Tables/Nested tables");
6743
        HelpMarker("This demonstrates embedding a table into another table cell.");
6744
6745
        if (ImGui::BeginTable("table_nested1", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
6746
        {
6747
            ImGui::TableSetupColumn("A0");
6748
            ImGui::TableSetupColumn("A1");
6749
            ImGui::TableHeadersRow();
6750
6751
            ImGui::TableNextColumn();
6752
            ImGui::Text("A0 Row 0");
6753
            {
6754
                float rows_height = (TEXT_BASE_HEIGHT * 2.0f) + (ImGui::GetStyle().CellPadding.y * 2.0f);
6755
                if (ImGui::BeginTable("table_nested2", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
6756
                {
6757
                    ImGui::TableSetupColumn("B0");
6758
                    ImGui::TableSetupColumn("B1");
6759
                    ImGui::TableHeadersRow();
6760
6761
                    ImGui::TableNextRow(ImGuiTableRowFlags_None, rows_height);
6762
                    ImGui::TableNextColumn();
6763
                    ImGui::Text("B0 Row 0");
6764
                    ImGui::TableNextColumn();
6765
                    ImGui::Text("B1 Row 0");
6766
                    ImGui::TableNextRow(ImGuiTableRowFlags_None, rows_height);
6767
                    ImGui::TableNextColumn();
6768
                    ImGui::Text("B0 Row 1");
6769
                    ImGui::TableNextColumn();
6770
                    ImGui::Text("B1 Row 1");
6771
6772
                    ImGui::EndTable();
6773
                }
6774
            }
6775
            ImGui::TableNextColumn(); ImGui::Text("A1 Row 0");
6776
            ImGui::TableNextColumn(); ImGui::Text("A0 Row 1");
6777
            ImGui::TableNextColumn(); ImGui::Text("A1 Row 1");
6778
            ImGui::EndTable();
6779
        }
6780
        ImGui::TreePop();
6781
    }
6782
6783
    if (open_action != -1)
6784
        ImGui::SetNextItemOpen(open_action != 0);
6785
    if (ImGui::TreeNode("Row height"))
6786
    {
6787
        IMGUI_DEMO_MARKER("Tables/Row height");
6788
        HelpMarker(
6789
            "You can pass a 'min_row_height' to TableNextRow().\n\nRows are padded with 'style.CellPadding.y' on top and bottom, "
6790
            "so effectively the minimum row height will always be >= 'style.CellPadding.y * 2.0f'.\n\n"
6791
            "We cannot honor a _maximum_ row height as that would require a unique clipping rectangle per row.");
6792
        if (ImGui::BeginTable("table_row_height", 1, ImGuiTableFlags_Borders))
6793
        {
6794
            for (int row = 0; row < 8; row++)
6795
            {
6796
                float min_row_height = (float)(int)(TEXT_BASE_HEIGHT * 0.30f * row + ImGui::GetStyle().CellPadding.y * 2.0f);
6797
                ImGui::TableNextRow(ImGuiTableRowFlags_None, min_row_height);
6798
                ImGui::TableNextColumn();
6799
                ImGui::Text("min_row_height = %.2f", min_row_height);
6800
            }
6801
            ImGui::EndTable();
6802
        }
6803
6804
        HelpMarker(
6805
            "Showcase using SameLine(0,0) to share Current Line Height between cells.\n\n"
6806
            "Please note that Tables Row Height is not the same thing as Current Line Height, "
6807
            "as a table cell may contains multiple lines.");
6808
        if (ImGui::BeginTable("table_share_lineheight", 2, ImGuiTableFlags_Borders))
6809
        {
6810
            ImGui::TableNextRow();
6811
            ImGui::TableNextColumn();
6812
            ImGui::ColorButton("##1", ImVec4(0.13f, 0.26f, 0.40f, 1.0f), ImGuiColorEditFlags_None, ImVec2(40, 40));
6813
            ImGui::TableNextColumn();
6814
            ImGui::Text("Line 1");
6815
            ImGui::Text("Line 2");
6816
6817
            ImGui::TableNextRow();
6818
            ImGui::TableNextColumn();
6819
            ImGui::ColorButton("##2", ImVec4(0.13f, 0.26f, 0.40f, 1.0f), ImGuiColorEditFlags_None, ImVec2(40, 40));
6820
            ImGui::TableNextColumn();
6821
            ImGui::SameLine(0.0f, 0.0f); // Reuse line height from previous column
6822
            ImGui::Text("Line 1, with SameLine(0,0)");
6823
            ImGui::Text("Line 2");
6824
6825
            ImGui::EndTable();
6826
        }
6827
6828
        HelpMarker("Showcase altering CellPadding.y between rows. Note that CellPadding.x is locked for the entire table.");
6829
        if (ImGui::BeginTable("table_changing_cellpadding_y", 1, ImGuiTableFlags_Borders))
6830
        {
6831
            ImGuiStyle& style = ImGui::GetStyle();
6832
            for (int row = 0; row < 8; row++)
6833
            {
6834
                if ((row % 3) == 2)
6835
                    ImGui::PushStyleVarY(ImGuiStyleVar_CellPadding, 20.0f);
6836
                ImGui::TableNextRow(ImGuiTableRowFlags_None);
6837
                ImGui::TableNextColumn();
6838
                ImGui::Text("CellPadding.y = %.2f", style.CellPadding.y);
6839
                if ((row % 3) == 2)
6840
                    ImGui::PopStyleVar();
6841
            }
6842
            ImGui::EndTable();
6843
        }
6844
6845
        ImGui::TreePop();
6846
    }
6847
6848
    if (open_action != -1)
6849
        ImGui::SetNextItemOpen(open_action != 0);
6850
    if (ImGui::TreeNode("Outer size"))
6851
    {
6852
        IMGUI_DEMO_MARKER("Tables/Outer size");
6853
        // Showcasing use of ImGuiTableFlags_NoHostExtendX and ImGuiTableFlags_NoHostExtendY
6854
        // Important to that note how the two flags have slightly different behaviors!
6855
        ImGui::Text("Using NoHostExtendX and NoHostExtendY:");
6856
        PushStyleCompact();
6857
        static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_ContextMenuInBody | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX;
6858
        ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX);
6859
        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.");
6860
        ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendY", &flags, ImGuiTableFlags_NoHostExtendY);
6861
        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.");
6862
        PopStyleCompact();
6863
6864
        ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 5.5f);
6865
        if (ImGui::BeginTable("table1", 3, flags, outer_size))
6866
        {
6867
            for (int row = 0; row < 10; row++)
6868
            {
6869
                ImGui::TableNextRow();
6870
                for (int column = 0; column < 3; column++)
6871
                {
6872
                    ImGui::TableNextColumn();
6873
                    ImGui::Text("Cell %d,%d", column, row);
6874
                }
6875
            }
6876
            ImGui::EndTable();
6877
        }
6878
        ImGui::SameLine();
6879
        ImGui::Text("Hello!");
6880
6881
        ImGui::Spacing();
6882
6883
        ImGui::Text("Using explicit size:");
6884
        if (ImGui::BeginTable("table2", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(TEXT_BASE_WIDTH * 30, 0.0f)))
6885
        {
6886
            for (int row = 0; row < 5; row++)
6887
            {
6888
                ImGui::TableNextRow();
6889
                for (int column = 0; column < 3; column++)
6890
                {
6891
                    ImGui::TableNextColumn();
6892
                    ImGui::Text("Cell %d,%d", column, row);
6893
                }
6894
            }
6895
            ImGui::EndTable();
6896
        }
6897
        ImGui::SameLine();
6898
        if (ImGui::BeginTable("table3", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(TEXT_BASE_WIDTH * 30, 0.0f)))
6899
        {
6900
            const float rows_height = TEXT_BASE_HEIGHT * 1.5f + ImGui::GetStyle().CellPadding.y * 2.0f;
6901
            for (int row = 0; row < 3; row++)
6902
            {
6903
                ImGui::TableNextRow(0, rows_height);
6904
                for (int column = 0; column < 3; column++)
6905
                {
6906
                    ImGui::TableNextColumn();
6907
                    ImGui::Text("Cell %d,%d", column, row);
6908
                }
6909
            }
6910
            ImGui::EndTable();
6911
        }
6912
6913
        ImGui::TreePop();
6914
    }
6915
6916
    if (open_action != -1)
6917
        ImGui::SetNextItemOpen(open_action != 0);
6918
    if (ImGui::TreeNode("Background color"))
6919
    {
6920
        IMGUI_DEMO_MARKER("Tables/Background color");
6921
        static ImGuiTableFlags flags = ImGuiTableFlags_RowBg;
6922
        static int row_bg_type = 1;
6923
        static int row_bg_target = 1;
6924
        static int cell_bg_type = 1;
6925
6926
        PushStyleCompact();
6927
        ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags, ImGuiTableFlags_Borders);
6928
        ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg);
6929
        ImGui::SameLine(); HelpMarker("ImGuiTableFlags_RowBg automatically sets RowBg0 to alternative colors pulled from the Style.");
6930
        ImGui::Combo("row bg type", (int*)&row_bg_type, "None\0Red\0Gradient\0");
6931
        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.");
6932
        ImGui::Combo("cell bg type", (int*)&cell_bg_type, "None\0Blue\0"); ImGui::SameLine(); HelpMarker("We are colorizing cells to B1->C2 here.");
6933
        IM_ASSERT(row_bg_type >= 0 && row_bg_type <= 2);
6934
        IM_ASSERT(row_bg_target >= 0 && row_bg_target <= 1);
6935
        IM_ASSERT(cell_bg_type >= 0 && cell_bg_type <= 1);
6936
        PopStyleCompact();
6937
6938
        if (ImGui::BeginTable("table1", 5, flags))
6939
        {
6940
            for (int row = 0; row < 6; row++)
6941
            {
6942
                ImGui::TableNextRow();
6943
6944
                // Demonstrate setting a row background color with 'ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBgX, ...)'
6945
                // 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.
6946
                if (row_bg_type != 0)
6947
                {
6948
                    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?
6949
                    ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0 + row_bg_target, row_bg_color);
6950
                }
6951
6952
                // Fill cells
6953
                for (int column = 0; column < 5; column++)
6954
                {
6955
                    ImGui::TableSetColumnIndex(column);
6956
                    ImGui::Text("%c%c", 'A' + row, '0' + column);
6957
6958
                    // Change background of Cells B1->C2
6959
                    // Demonstrate setting a cell background color with 'ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ...)'
6960
                    // (the CellBg color will be blended over the RowBg and ColumnBg colors)
6961
                    // We can also pass a column number as a third parameter to TableSetBgColor() and do this outside the column loop.
6962
                    if (row >= 1 && row <= 2 && column >= 1 && column <= 2 && cell_bg_type == 1)
6963
                    {
6964
                        ImU32 cell_bg_color = ImGui::GetColorU32(ImVec4(0.3f, 0.3f, 0.7f, 0.65f));
6965
                        ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, cell_bg_color);
6966
                    }
6967
                }
6968
            }
6969
            ImGui::EndTable();
6970
        }
6971
        ImGui::TreePop();
6972
    }
6973
6974
    if (open_action != -1)
6975
        ImGui::SetNextItemOpen(open_action != 0);
6976
    if (ImGui::TreeNode("Tree view"))
6977
    {
6978
        IMGUI_DEMO_MARKER("Tables/Tree view");
6979
        static ImGuiTableFlags table_flags = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody;
6980
6981
        static ImGuiTreeNodeFlags tree_node_flags_base = ImGuiTreeNodeFlags_SpanAllColumns | ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_DrawLinesFull;
6982
        ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth",  &tree_node_flags_base, ImGuiTreeNodeFlags_SpanFullWidth);
6983
        ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanLabelWidth",  &tree_node_flags_base, ImGuiTreeNodeFlags_SpanLabelWidth);
6984
        ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &tree_node_flags_base, ImGuiTreeNodeFlags_SpanAllColumns);
6985
        ImGui::CheckboxFlags("ImGuiTreeNodeFlags_LabelSpanAllColumns", &tree_node_flags_base, ImGuiTreeNodeFlags_LabelSpanAllColumns);
6986
        ImGui::SameLine(); HelpMarker("Useful if you know that you aren't displaying contents in other columns");
6987
6988
        HelpMarker("See \"Columns flags\" section to configure how indentation is applied to individual columns.");
6989
        if (ImGui::BeginTable("3ways", 3, table_flags))
6990
        {
6991
            // The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On
6992
            ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_NoHide);
6993
            ImGui::TableSetupColumn("Size", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f);
6994
            ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 18.0f);
6995
            ImGui::TableHeadersRow();
6996
6997
            // Simple storage to output a dummy file-system.
6998
            struct MyTreeNode
6999
            {
7000
                const char*     Name;
7001
                const char*     Type;
7002
                int             Size;
7003
                int             ChildIdx;
7004
                int             ChildCount;
7005
                static void DisplayNode(const MyTreeNode* node, const MyTreeNode* all_nodes)
7006
                {
7007
                    ImGui::TableNextRow();
7008
                    ImGui::TableNextColumn();
7009
                    const bool is_folder = (node->ChildCount > 0);
7010
7011
                    ImGuiTreeNodeFlags node_flags = tree_node_flags_base;
7012
                    if (node != &all_nodes[0])
7013
                        node_flags &= ~ImGuiTreeNodeFlags_LabelSpanAllColumns; // Only demonstrate this on the root node.
7014
7015
                    if (is_folder)
7016
                    {
7017
                        bool open = ImGui::TreeNodeEx(node->Name, node_flags);
7018
                        if ((node_flags & ImGuiTreeNodeFlags_LabelSpanAllColumns) == 0)
7019
                        {
7020
                            ImGui::TableNextColumn();
7021
                            ImGui::TextDisabled("--");
7022
                            ImGui::TableNextColumn();
7023
                            ImGui::TextUnformatted(node->Type);
7024
                        }
7025
                        if (open)
7026
                        {
7027
                            for (int child_n = 0; child_n < node->ChildCount; child_n++)
7028
                                DisplayNode(&all_nodes[node->ChildIdx + child_n], all_nodes);
7029
                            ImGui::TreePop();
7030
                        }
7031
                    }
7032
                    else
7033
                    {
7034
                        ImGui::TreeNodeEx(node->Name, node_flags | ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_NoTreePushOnOpen);
7035
                        ImGui::TableNextColumn();
7036
                        ImGui::Text("%d", node->Size);
7037
                        ImGui::TableNextColumn();
7038
                        ImGui::TextUnformatted(node->Type);
7039
                    }
7040
                }
7041
            };
7042
            static const MyTreeNode nodes[] =
7043
            {
7044
                { "Root with Long Name",          "Folder",       -1,       1, 3    }, // 0
7045
                { "Music",                        "Folder",       -1,       4, 2    }, // 1
7046
                { "Textures",                     "Folder",       -1,       6, 3    }, // 2
7047
                { "desktop.ini",                  "System file",  1024,    -1,-1    }, // 3
7048
                { "File1_a.wav",                  "Audio file",   123000,  -1,-1    }, // 4
7049
                { "File1_b.wav",                  "Audio file",   456000,  -1,-1    }, // 5
7050
                { "Image001.png",                 "Image file",   203128,  -1,-1    }, // 6
7051
                { "Copy of Image001.png",         "Image file",   203256,  -1,-1    }, // 7
7052
                { "Copy of Image001 (Final2).png","Image file",   203512,  -1,-1    }, // 8
7053
            };
7054
7055
            MyTreeNode::DisplayNode(&nodes[0], nodes);
7056
7057
            ImGui::EndTable();
7058
        }
7059
        ImGui::TreePop();
7060
    }
7061
7062
    if (open_action != -1)
7063
        ImGui::SetNextItemOpen(open_action != 0);
7064
    if (ImGui::TreeNode("Item width"))
7065
    {
7066
        IMGUI_DEMO_MARKER("Tables/Item width");
7067
        HelpMarker(
7068
            "Showcase using PushItemWidth() and how it is preserved on a per-column basis.\n\n"
7069
            "Note that on auto-resizing non-resizable fixed columns, querying the content width for "
7070
            "e.g. right-alignment doesn't make sense.");
7071
        if (ImGui::BeginTable("table_item_width", 3, ImGuiTableFlags_Borders))
7072
        {
7073
            ImGui::TableSetupColumn("small");
7074
            ImGui::TableSetupColumn("half");
7075
            ImGui::TableSetupColumn("right-align");
7076
            ImGui::TableHeadersRow();
7077
7078
            for (int row = 0; row < 3; row++)
7079
            {
7080
                ImGui::TableNextRow();
7081
                if (row == 0)
7082
                {
7083
                    // Setup ItemWidth once (instead of setting up every time, which is also possible but less efficient)
7084
                    ImGui::TableSetColumnIndex(0);
7085
                    ImGui::PushItemWidth(TEXT_BASE_WIDTH * 3.0f); // Small
7086
                    ImGui::TableSetColumnIndex(1);
7087
                    ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.5f);
7088
                    ImGui::TableSetColumnIndex(2);
7089
                    ImGui::PushItemWidth(-FLT_MIN); // Right-aligned
7090
                }
7091
7092
                // Draw our contents
7093
                static float dummy_f = 0.0f;
7094
                ImGui::PushID(row);
7095
                ImGui::TableSetColumnIndex(0);
7096
                ImGui::SliderFloat("float0", &dummy_f, 0.0f, 1.0f);
7097
                ImGui::TableSetColumnIndex(1);
7098
                ImGui::SliderFloat("float1", &dummy_f, 0.0f, 1.0f);
7099
                ImGui::TableSetColumnIndex(2);
7100
                ImGui::SliderFloat("##float2", &dummy_f, 0.0f, 1.0f); // No visible label since right-aligned
7101
                ImGui::PopID();
7102
            }
7103
            ImGui::EndTable();
7104
        }
7105
        ImGui::TreePop();
7106
    }
7107
7108
    // Demonstrate using TableHeader() calls instead of TableHeadersRow()
7109
    if (open_action != -1)
7110
        ImGui::SetNextItemOpen(open_action != 0);
7111
    if (ImGui::TreeNode("Custom headers"))
7112
    {
7113
        IMGUI_DEMO_MARKER("Tables/Custom headers");
7114
        const int COLUMNS_COUNT = 3;
7115
        if (ImGui::BeginTable("table_custom_headers", COLUMNS_COUNT, ImGuiTableFlags_Borders | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
7116
        {
7117
            ImGui::TableSetupColumn("Apricot");
7118
            ImGui::TableSetupColumn("Banana");
7119
            ImGui::TableSetupColumn("Cherry");
7120
7121
            // Dummy entire-column selection storage
7122
            // FIXME: It would be nice to actually demonstrate full-featured selection using those checkbox.
7123
            static bool column_selected[3] = {};
7124
7125
            // Instead of calling TableHeadersRow() we'll submit custom headers ourselves.
7126
            // (A different approach is also possible:
7127
            //    - Specify ImGuiTableColumnFlags_NoHeaderLabel in some TableSetupColumn() call.
7128
            //    - Call TableHeadersRow() normally. This will submit TableHeader() with no name.
7129
            //    - Then call TableSetColumnIndex() to position yourself in the column and submit your stuff e.g. Checkbox().)
7130
            ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
7131
            for (int column = 0; column < COLUMNS_COUNT; column++)
7132
            {
7133
                ImGui::TableSetColumnIndex(column);
7134
                const char* column_name = ImGui::TableGetColumnName(column); // Retrieve name passed to TableSetupColumn()
7135
                ImGui::PushID(column);
7136
                ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
7137
                ImGui::Checkbox("##checkall", &column_selected[column]);
7138
                ImGui::PopStyleVar();
7139
                ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
7140
                ImGui::TableHeader(column_name);
7141
                ImGui::PopID();
7142
            }
7143
7144
            // Submit table contents
7145
            for (int row = 0; row < 5; row++)
7146
            {
7147
                ImGui::TableNextRow();
7148
                for (int column = 0; column < 3; column++)
7149
                {
7150
                    char buf[32];
7151
                    sprintf(buf, "Cell %d,%d", column, row);
7152
                    ImGui::TableSetColumnIndex(column);
7153
                    ImGui::Selectable(buf, column_selected[column]);
7154
                }
7155
            }
7156
            ImGui::EndTable();
7157
        }
7158
        ImGui::TreePop();
7159
    }
7160
7161
    // Demonstrate using ImGuiTableColumnFlags_AngledHeader flag to create angled headers
7162
    if (open_action != -1)
7163
        ImGui::SetNextItemOpen(open_action != 0);
7164
    if (ImGui::TreeNode("Angled headers"))
7165
    {
7166
        IMGUI_DEMO_MARKER("Tables/Angled headers");
7167
        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" };
7168
        const int columns_count = IM_COUNTOF(column_names);
7169
        const int rows_count = 12;
7170
7171
        static ImGuiTableFlags table_flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_Hideable | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_HighlightHoveredColumn;
7172
        static ImGuiTableColumnFlags column_flags = ImGuiTableColumnFlags_AngledHeader | ImGuiTableColumnFlags_WidthFixed;
7173
        static bool bools[columns_count * rows_count] = {}; // Dummy storage selection storage
7174
        static int frozen_cols = 1;
7175
        static int frozen_rows = 2;
7176
        ImGui::CheckboxFlags("_ScrollX", &table_flags, ImGuiTableFlags_ScrollX);
7177
        ImGui::CheckboxFlags("_ScrollY", &table_flags, ImGuiTableFlags_ScrollY);
7178
        ImGui::CheckboxFlags("_Resizable", &table_flags, ImGuiTableFlags_Resizable);
7179
        ImGui::CheckboxFlags("_Sortable", &table_flags, ImGuiTableFlags_Sortable);
7180
        ImGui::CheckboxFlags("_NoBordersInBody", &table_flags, ImGuiTableFlags_NoBordersInBody);
7181
        ImGui::CheckboxFlags("_HighlightHoveredColumn", &table_flags, ImGuiTableFlags_HighlightHoveredColumn);
7182
        ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
7183
        ImGui::SliderInt("Frozen columns", &frozen_cols, 0, 2);
7184
        ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
7185
        ImGui::SliderInt("Frozen rows", &frozen_rows, 0, 2);
7186
        ImGui::CheckboxFlags("Disable header contributing to column width", &column_flags, ImGuiTableColumnFlags_NoHeaderWidth);
7187
7188
        if (ImGui::TreeNode("Style settings"))
7189
        {
7190
            ImGui::SameLine();
7191
            HelpMarker("Giving access to some ImGuiStyle value in this demo for convenience.");
7192
            ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
7193
            ImGui::SliderAngle("style.TableAngledHeadersAngle", &ImGui::GetStyle().TableAngledHeadersAngle, -50.0f, +50.0f);
7194
            ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
7195
            ImGui::SliderFloat2("style.TableAngledHeadersTextAlign", (float*)&ImGui::GetStyle().TableAngledHeadersTextAlign, 0.0f, 1.0f, "%.2f");
7196
            ImGui::TreePop();
7197
        }
7198
7199
        if (ImGui::BeginTable("table_angled_headers", columns_count, table_flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 12)))
7200
        {
7201
            ImGui::TableSetupColumn(column_names[0], ImGuiTableColumnFlags_NoHide | ImGuiTableColumnFlags_NoReorder);
7202
            for (int n = 1; n < columns_count; n++)
7203
                ImGui::TableSetupColumn(column_names[n], column_flags);
7204
            ImGui::TableSetupScrollFreeze(frozen_cols, frozen_rows);
7205
7206
            ImGui::TableAngledHeadersRow(); // Draw angled headers for all columns with the ImGuiTableColumnFlags_AngledHeader flag.
7207
            ImGui::TableHeadersRow();       // Draw remaining headers and allow access to context-menu and other functions.
7208
            for (int row = 0; row < rows_count; row++)
7209
            {
7210
                ImGui::PushID(row);
7211
                ImGui::TableNextRow();
7212
                ImGui::TableSetColumnIndex(0);
7213
                ImGui::AlignTextToFramePadding();
7214
                ImGui::Text("Track %d", row);
7215
                for (int column = 1; column < columns_count; column++)
7216
                    if (ImGui::TableSetColumnIndex(column))
7217
                    {
7218
                        ImGui::PushID(column);
7219
                        ImGui::Checkbox("", &bools[row * columns_count + column]);
7220
                        ImGui::PopID();
7221
                    }
7222
                ImGui::PopID();
7223
            }
7224
            ImGui::EndTable();
7225
        }
7226
        ImGui::TreePop();
7227
    }
7228
7229
    // Demonstrate creating custom context menus inside columns,
7230
    // while playing it nice with context menus provided by TableHeadersRow()/TableHeader()
7231
    if (open_action != -1)
7232
        ImGui::SetNextItemOpen(open_action != 0);
7233
    if (ImGui::TreeNode("Context menus"))
7234
    {
7235
        IMGUI_DEMO_MARKER("Tables/Context menus");
7236
        HelpMarker(
7237
            "By default, right-clicking over a TableHeadersRow()/TableHeader() line will open the default context-menu.\n"
7238
            "Using ImGuiTableFlags_ContextMenuInBody we also allow right-clicking over columns body.");
7239
        static ImGuiTableFlags flags1 = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_ContextMenuInBody;
7240
7241
        PushStyleCompact();
7242
        ImGui::CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", &flags1, ImGuiTableFlags_ContextMenuInBody);
7243
        PopStyleCompact();
7244
7245
        // Context Menus: first example
7246
        // [1.1] Right-click on the TableHeadersRow() line to open the default table context menu.
7247
        // [1.2] Right-click in columns also open the default table context menu (if ImGuiTableFlags_ContextMenuInBody is set)
7248
        const int COLUMNS_COUNT = 3;
7249
        if (ImGui::BeginTable("table_context_menu", COLUMNS_COUNT, flags1))
7250
        {
7251
            ImGui::TableSetupColumn("One");
7252
            ImGui::TableSetupColumn("Two");
7253
            ImGui::TableSetupColumn("Three");
7254
7255
            // [1.1]] Right-click on the TableHeadersRow() line to open the default table context menu.
7256
            ImGui::TableHeadersRow();
7257
7258
            // Submit dummy contents
7259
            for (int row = 0; row < 4; row++)
7260
            {
7261
                ImGui::TableNextRow();
7262
                for (int column = 0; column < COLUMNS_COUNT; column++)
7263
                {
7264
                    ImGui::TableSetColumnIndex(column);
7265
                    ImGui::Text("Cell %d,%d", column, row);
7266
                }
7267
            }
7268
            ImGui::EndTable();
7269
        }
7270
7271
        // Context Menus: second example
7272
        // [2.1] Right-click on the TableHeadersRow() line to open the default table context menu.
7273
        // [2.2] Right-click on the ".." to open a custom popup
7274
        // [2.3] Right-click in columns to open another custom popup
7275
        HelpMarker(
7276
            "Demonstrate mixing table context menu (over header), item context button (over button) "
7277
            "and custom per-column context menu (over column body).");
7278
        ImGuiTableFlags flags2 = ImGuiTableFlags_Resizable | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders;
7279
        if (ImGui::BeginTable("table_context_menu_2", COLUMNS_COUNT, flags2))
7280
        {
7281
            ImGui::TableSetupColumn("One");
7282
            ImGui::TableSetupColumn("Two");
7283
            ImGui::TableSetupColumn("Three");
7284
7285
            // [2.1] Right-click on the TableHeadersRow() line to open the default table context menu.
7286
            ImGui::TableHeadersRow();
7287
            for (int row = 0; row < 4; row++)
7288
            {
7289
                ImGui::TableNextRow();
7290
                for (int column = 0; column < COLUMNS_COUNT; column++)
7291
                {
7292
                    // Submit dummy contents
7293
                    ImGui::TableSetColumnIndex(column);
7294
                    ImGui::Text("Cell %d,%d", column, row);
7295
                    ImGui::SameLine();
7296
7297
                    // [2.2] Right-click on the ".." to open a custom popup
7298
                    ImGui::PushID(row * COLUMNS_COUNT + column);
7299
                    ImGui::SmallButton("..");
7300
                    if (ImGui::BeginPopupContextItem())
7301
                    {
7302
                        ImGui::Text("This is the popup for Button(\"..\") in Cell %d,%d", column, row);
7303
                        if (ImGui::Button("Close"))
7304
                            ImGui::CloseCurrentPopup();
7305
                        ImGui::EndPopup();
7306
                    }
7307
                    ImGui::PopID();
7308
                }
7309
            }
7310
7311
            // [2.3] Right-click anywhere in columns to open another custom popup
7312
            // (instead of testing for !IsAnyItemHovered() we could also call OpenPopup() with ImGuiPopupFlags_NoOpenOverExistingPopup
7313
            // to manage popup priority as the popups triggers, here "are we hovering a column" are overlapping)
7314
            int hovered_column = -1;
7315
            for (int column = 0; column < COLUMNS_COUNT + 1; column++)
7316
            {
7317
                ImGui::PushID(column);
7318
                if (ImGui::TableGetColumnFlags(column) & ImGuiTableColumnFlags_IsHovered)
7319
                    hovered_column = column;
7320
                if (hovered_column == column && !ImGui::IsAnyItemHovered() && ImGui::IsMouseReleased(1))
7321
                    ImGui::OpenPopup("MyPopup");
7322
                if (ImGui::BeginPopup("MyPopup"))
7323
                {
7324
                    if (column == COLUMNS_COUNT)
7325
                        ImGui::Text("This is a custom popup for unused space after the last column.");
7326
                    else
7327
                        ImGui::Text("This is a custom popup for Column %d", column);
7328
                    if (ImGui::Button("Close"))
7329
                        ImGui::CloseCurrentPopup();
7330
                    ImGui::EndPopup();
7331
                }
7332
                ImGui::PopID();
7333
            }
7334
7335
            ImGui::EndTable();
7336
            ImGui::Text("Hovered column: %d", hovered_column);
7337
        }
7338
        ImGui::TreePop();
7339
    }
7340
7341
    // Demonstrate creating multiple tables with the same ID
7342
    if (open_action != -1)
7343
        ImGui::SetNextItemOpen(open_action != 0);
7344
    if (ImGui::TreeNode("Synced instances"))
7345
    {
7346
        IMGUI_DEMO_MARKER("Tables/Synced instances");
7347
        HelpMarker("Multiple tables with the same identifier will share their settings, width, visibility, order etc.");
7348
7349
        static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoSavedSettings;
7350
        ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
7351
        ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
7352
        ImGui::CheckboxFlags("ImGuiTableFlags_SizingFixedFit", &flags, ImGuiTableFlags_SizingFixedFit);
7353
        ImGui::CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", &flags, ImGuiTableFlags_HighlightHoveredColumn);
7354
        for (int n = 0; n < 3; n++)
7355
        {
7356
            char buf[32];
7357
            sprintf(buf, "Synced Table %d", n);
7358
            bool open = ImGui::CollapsingHeader(buf, ImGuiTreeNodeFlags_DefaultOpen);
7359
            if (open && ImGui::BeginTable("Table", 3, flags, ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 5)))
7360
            {
7361
                ImGui::TableSetupColumn("One");
7362
                ImGui::TableSetupColumn("Two");
7363
                ImGui::TableSetupColumn("Three");
7364
                ImGui::TableHeadersRow();
7365
                const int cell_count = (n == 1) ? 27 : 9; // Make second table have a scrollbar to verify that additional decoration is not affecting column positions.
7366
                for (int cell = 0; cell < cell_count; cell++)
7367
                {
7368
                    ImGui::TableNextColumn();
7369
                    ImGui::Text("this cell %d", cell);
7370
                }
7371
                ImGui::EndTable();
7372
            }
7373
        }
7374
        ImGui::TreePop();
7375
    }
7376
7377
    // Demonstrate using Sorting facilities
7378
    // This is a simplified version of the "Advanced" example, where we mostly focus on the code necessary to handle sorting.
7379
    // Note that the "Advanced" example also showcase manually triggering a sort (e.g. if item quantities have been modified)
7380
    static const char* template_items_names[] =
7381
    {
7382
        "Banana", "Apple", "Cherry", "Watermelon", "Grapefruit", "Strawberry", "Mango",
7383
        "Kiwi", "Orange", "Pineapple", "Blueberry", "Plum", "Coconut", "Pear", "Apricot"
7384
    };
7385
    if (open_action != -1)
7386
        ImGui::SetNextItemOpen(open_action != 0);
7387
    if (ImGui::TreeNode("Sorting"))
7388
    {
7389
        IMGUI_DEMO_MARKER("Tables/Sorting");
7390
        // Create item list
7391
        static ImVector<MyItem> items;
7392
        if (items.Size == 0)
7393
        {
7394
            items.resize(50, MyItem());
7395
            for (int n = 0; n < items.Size; n++)
7396
            {
7397
                const int template_n = n % IM_COUNTOF(template_items_names);
7398
                MyItem& item = items[n];
7399
                item.ID = n;
7400
                item.Name = template_items_names[template_n];
7401
                item.Quantity = (n * n - n) % 20; // Assign default quantities
7402
            }
7403
        }
7404
7405
        // Options
7406
        static ImGuiTableFlags flags =
7407
            ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti
7408
            | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_NoBordersInBody
7409
            | ImGuiTableFlags_ScrollY;
7410
        PushStyleCompact();
7411
        ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti);
7412
        ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).");
7413
        ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate);
7414
        ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).");
7415
        PopStyleCompact();
7416
7417
        if (ImGui::BeginTable("table_sorting", 4, flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 15), 0.0f))
7418
        {
7419
            // Declare columns
7420
            // We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications.
7421
            // This is so our sort function can identify a column given our own identifier. We could also identify them based on their index!
7422
            // Demonstrate using a mixture of flags among available sort-related flags:
7423
            // - ImGuiTableColumnFlags_DefaultSort
7424
            // - ImGuiTableColumnFlags_NoSort / ImGuiTableColumnFlags_NoSortAscending / ImGuiTableColumnFlags_NoSortDescending
7425
            // - ImGuiTableColumnFlags_PreferSortAscending / ImGuiTableColumnFlags_PreferSortDescending
7426
            ImGui::TableSetupColumn("ID",       ImGuiTableColumnFlags_DefaultSort          | ImGuiTableColumnFlags_WidthFixed,   0.0f, MyItemColumnID_ID);
7427
            ImGui::TableSetupColumn("Name",                                                  ImGuiTableColumnFlags_WidthFixed,   0.0f, MyItemColumnID_Name);
7428
            ImGui::TableSetupColumn("Action",   ImGuiTableColumnFlags_NoSort               | ImGuiTableColumnFlags_WidthFixed,   0.0f, MyItemColumnID_Action);
7429
            ImGui::TableSetupColumn("Quantity", ImGuiTableColumnFlags_PreferSortDescending | ImGuiTableColumnFlags_WidthStretch, 0.0f, MyItemColumnID_Quantity);
7430
            ImGui::TableSetupScrollFreeze(0, 1); // Make row always visible
7431
            ImGui::TableHeadersRow();
7432
7433
            // Sort our data if sort specs have been changed!
7434
            if (ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs())
7435
                if (sort_specs->SpecsDirty)
7436
                {
7437
                    MyItem::SortWithSortSpecs(sort_specs, items.Data, items.Size);
7438
                    sort_specs->SpecsDirty = false;
7439
                }
7440
7441
            // Demonstrate using clipper for large vertical lists
7442
            ImGuiListClipper clipper;
7443
            clipper.Begin(items.Size);
7444
            while (clipper.Step())
7445
                for (int row_n = clipper.DisplayStart; row_n < clipper.DisplayEnd; row_n++)
7446
                {
7447
                    // Display a data item
7448
                    MyItem* item = &items[row_n];
7449
                    ImGui::PushID(item->ID);
7450
                    ImGui::TableNextRow();
7451
                    ImGui::TableNextColumn();
7452
                    ImGui::Text("%04d", item->ID);
7453
                    ImGui::TableNextColumn();
7454
                    ImGui::TextUnformatted(item->Name);
7455
                    ImGui::TableNextColumn();
7456
                    ImGui::SmallButton("None");
7457
                    ImGui::TableNextColumn();
7458
                    ImGui::Text("%d", item->Quantity);
7459
                    ImGui::PopID();
7460
                }
7461
            ImGui::EndTable();
7462
        }
7463
        ImGui::TreePop();
7464
    }
7465
7466
    // In this example we'll expose most table flags and settings.
7467
    // For specific flags and settings refer to the corresponding section for more detailed explanation.
7468
    // This section is mostly useful to experiment with combining certain flags or settings with each others.
7469
    //ImGui::SetNextItemOpen(true, ImGuiCond_Once); // [DEBUG]
7470
    if (open_action != -1)
7471
        ImGui::SetNextItemOpen(open_action != 0);
7472
    if (ImGui::TreeNode("Advanced"))
7473
    {
7474
        IMGUI_DEMO_MARKER("Tables/Advanced");
7475
        static ImGuiTableFlags flags =
7476
            ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable
7477
            | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti
7478
            | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBody
7479
            | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY
7480
            | ImGuiTableFlags_SizingFixedFit;
7481
        static ImGuiTableColumnFlags columns_base_flags = ImGuiTableColumnFlags_None;
7482
7483
        enum ContentsType { CT_Text, CT_Button, CT_SmallButton, CT_FillButton, CT_Selectable, CT_SelectableSpanRow };
7484
        static int contents_type = CT_SelectableSpanRow;
7485
        const char* contents_type_names[] = { "Text", "Button", "SmallButton", "FillButton", "Selectable", "Selectable (span row)" };
7486
        static int freeze_cols = 1;
7487
        static int freeze_rows = 1;
7488
        static int items_count = IM_COUNTOF(template_items_names) * 2;
7489
        static ImVec2 outer_size_value = ImVec2(0.0f, TEXT_BASE_HEIGHT * 12);
7490
        static float row_min_height = 0.0f; // Auto
7491
        static float inner_width_with_scroll = 0.0f; // Auto-extend
7492
        static bool outer_size_enabled = true;
7493
        static bool show_headers = true;
7494
        static bool show_wrapped_text = false;
7495
        //static ImGuiTextFilter filter;
7496
        //ImGui::SetNextItemOpen(true, ImGuiCond_Once); // FIXME-TABLE: Enabling this results in initial clipped first pass on table which tend to affect column sizing
7497
        if (ImGui::TreeNode("Options"))
7498
        {
7499
            // Make the UI compact because there are so many fields
7500
            PushStyleCompact();
7501
            ImGui::PushItemWidth(TEXT_BASE_WIDTH * 28.0f);
7502
7503
            if (ImGui::TreeNodeEx("Features:", ImGuiTreeNodeFlags_DefaultOpen))
7504
            {
7505
                ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
7506
                ImGui::CheckboxFlags("ImGuiTableFlags_Reorderable", &flags, ImGuiTableFlags_Reorderable);
7507
                ImGui::CheckboxFlags("ImGuiTableFlags_Hideable", &flags, ImGuiTableFlags_Hideable);
7508
                ImGui::CheckboxFlags("ImGuiTableFlags_Sortable", &flags, ImGuiTableFlags_Sortable);
7509
                ImGui::CheckboxFlags("ImGuiTableFlags_NoSavedSettings", &flags, ImGuiTableFlags_NoSavedSettings);
7510
                ImGui::CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", &flags, ImGuiTableFlags_ContextMenuInBody);
7511
                ImGui::TreePop();
7512
            }
7513
7514
            if (ImGui::TreeNodeEx("Decorations:", ImGuiTreeNodeFlags_DefaultOpen))
7515
            {
7516
                ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg);
7517
                ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV);
7518
                ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags, ImGuiTableFlags_BordersOuterV);
7519
                ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags, ImGuiTableFlags_BordersInnerV);
7520
                ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags, ImGuiTableFlags_BordersH);
7521
                ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterH", &flags, ImGuiTableFlags_BordersOuterH);
7522
                ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerH", &flags, ImGuiTableFlags_BordersInnerH);
7523
                ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers)");
7524
                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)");
7525
                ImGui::TreePop();
7526
            }
7527
7528
            if (ImGui::TreeNodeEx("Sizing:", ImGuiTreeNodeFlags_DefaultOpen))
7529
            {
7530
                EditTableSizingFlags(&flags);
7531
                ImGui::SameLine(); HelpMarker("In the Advanced demo we override the policy of each column so those table-wide settings have less effect that typical.");
7532
                ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX);
7533
                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.");
7534
                ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendY", &flags, ImGuiTableFlags_NoHostExtendY);
7535
                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.");
7536
                ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags, ImGuiTableFlags_NoKeepColumnsVisible);
7537
                ImGui::SameLine(); HelpMarker("Only available if ScrollX is disabled.");
7538
                ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths);
7539
                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.");
7540
                ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip);
7541
                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.");
7542
                ImGui::TreePop();
7543
            }
7544
7545
            if (ImGui::TreeNodeEx("Padding:", ImGuiTreeNodeFlags_DefaultOpen))
7546
            {
7547
                ImGui::CheckboxFlags("ImGuiTableFlags_PadOuterX", &flags, ImGuiTableFlags_PadOuterX);
7548
                ImGui::CheckboxFlags("ImGuiTableFlags_NoPadOuterX", &flags, ImGuiTableFlags_NoPadOuterX);
7549
                ImGui::CheckboxFlags("ImGuiTableFlags_NoPadInnerX", &flags, ImGuiTableFlags_NoPadInnerX);
7550
                ImGui::TreePop();
7551
            }
7552
7553
            if (ImGui::TreeNodeEx("Scrolling:", ImGuiTreeNodeFlags_DefaultOpen))
7554
            {
7555
                ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX);
7556
                ImGui::SameLine();
7557
                ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
7558
                ImGui::DragInt("freeze_cols", &freeze_cols, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
7559
                ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
7560
                ImGui::SameLine();
7561
                ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
7562
                ImGui::DragInt("freeze_rows", &freeze_rows, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
7563
                ImGui::TreePop();
7564
            }
7565
7566
            if (ImGui::TreeNodeEx("Sorting:", ImGuiTreeNodeFlags_DefaultOpen))
7567
            {
7568
                ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti);
7569
                ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).");
7570
                ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate);
7571
                ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).");
7572
                ImGui::TreePop();
7573
            }
7574
7575
            if (ImGui::TreeNodeEx("Headers:", ImGuiTreeNodeFlags_DefaultOpen))
7576
            {
7577
                ImGui::Checkbox("show_headers", &show_headers);
7578
                ImGui::CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", &flags, ImGuiTableFlags_HighlightHoveredColumn);
7579
                ImGui::CheckboxFlags("ImGuiTableColumnFlags_AngledHeader", &columns_base_flags, ImGuiTableColumnFlags_AngledHeader);
7580
                ImGui::SameLine(); HelpMarker("Enable AngledHeader on all columns. Best enabled on selected narrow columns (see \"Angled headers\" section of the demo).");
7581
                ImGui::TreePop();
7582
            }
7583
7584
            if (ImGui::TreeNodeEx("Other:", ImGuiTreeNodeFlags_DefaultOpen))
7585
            {
7586
                ImGui::Checkbox("show_wrapped_text", &show_wrapped_text);
7587
7588
                ImGui::DragFloat2("##OuterSize", &outer_size_value.x);
7589
                ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
7590
                ImGui::Checkbox("outer_size", &outer_size_enabled);
7591
                ImGui::SameLine();
7592
                HelpMarker("If scrolling is disabled (ScrollX and ScrollY not set):\n"
7593
                    "- The table is output directly in the parent window.\n"
7594
                    "- OuterSize.x < 0.0f will right-align the table.\n"
7595
                    "- OuterSize.x = 0.0f will narrow fit the table unless there are any Stretch columns.\n"
7596
                    "- OuterSize.y then becomes the minimum size for the table, which will extend vertically if there are more rows (unless NoHostExtendY is set).");
7597
7598
                // From a user point of view we will tend to use 'inner_width' differently depending on whether our table is embedding scrolling.
7599
                // To facilitate toying with this demo we will actually pass 0.0f to the BeginTable() when ScrollX is disabled.
7600
                ImGui::DragFloat("inner_width (when ScrollX active)", &inner_width_with_scroll, 1.0f, 0.0f, FLT_MAX);
7601
7602
                ImGui::DragFloat("row_min_height", &row_min_height, 1.0f, 0.0f, FLT_MAX);
7603
                ImGui::SameLine(); HelpMarker("Specify height of the Selectable item.");
7604
7605
                ImGui::DragInt("items_count", &items_count, 0.1f, 0, 9999);
7606
                ImGui::Combo("items_type (first column)", &contents_type, contents_type_names, IM_COUNTOF(contents_type_names));
7607
                //filter.Draw("filter");
7608
                ImGui::TreePop();
7609
            }
7610
7611
            ImGui::PopItemWidth();
7612
            PopStyleCompact();
7613
            ImGui::Spacing();
7614
            ImGui::TreePop();
7615
        }
7616
7617
        // Update item list if we changed the number of items
7618
        static ImVector<MyItem> items;
7619
        static ImVector<int> selection;
7620
        static bool items_need_sort = false;
7621
        if (items.Size != items_count)
7622
        {
7623
            items.resize(items_count, MyItem());
7624
            for (int n = 0; n < items_count; n++)
7625
            {
7626
                const int template_n = n % IM_COUNTOF(template_items_names);
7627
                MyItem& item = items[n];
7628
                item.ID = n;
7629
                item.Name = template_items_names[template_n];
7630
                item.Quantity = (template_n == 3) ? 10 : (template_n == 4) ? 20 : 0; // Assign default quantities
7631
            }
7632
        }
7633
7634
        const ImDrawList* parent_draw_list = ImGui::GetWindowDrawList();
7635
        const int parent_draw_list_draw_cmd_count = parent_draw_list->CmdBuffer.Size;
7636
        ImVec2 table_scroll_cur, table_scroll_max; // For debug display
7637
        const ImDrawList* table_draw_list = NULL;  // "
7638
7639
        // Submit table
7640
        const float inner_width_to_use = (flags & ImGuiTableFlags_ScrollX) ? inner_width_with_scroll : 0.0f;
7641
        if (ImGui::BeginTable("table_advanced", 6, flags, outer_size_enabled ? outer_size_value : ImVec2(0, 0), inner_width_to_use))
7642
        {
7643
            // Declare columns
7644
            // We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications.
7645
            // This is so our sort function can identify a column given our own identifier. We could also identify them based on their index!
7646
            ImGui::TableSetupColumn("ID",           columns_base_flags | ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoHide, 0.0f, MyItemColumnID_ID);
7647
            ImGui::TableSetupColumn("Name",         columns_base_flags | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Name);
7648
            ImGui::TableSetupColumn("Action",       columns_base_flags | ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Action);
7649
            ImGui::TableSetupColumn("Quantity",     columns_base_flags | ImGuiTableColumnFlags_PreferSortDescending, 0.0f, MyItemColumnID_Quantity);
7650
            ImGui::TableSetupColumn("Description",  columns_base_flags | ((flags & ImGuiTableFlags_NoHostExtendX) ? 0 : ImGuiTableColumnFlags_WidthStretch), 0.0f, MyItemColumnID_Description);
7651
            ImGui::TableSetupColumn("Hidden",       columns_base_flags |  ImGuiTableColumnFlags_DefaultHide | ImGuiTableColumnFlags_NoSort);
7652
            ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows);
7653
7654
            // Sort our data if sort specs have been changed!
7655
            ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs();
7656
            if (sort_specs && sort_specs->SpecsDirty)
7657
                items_need_sort = true;
7658
            if (sort_specs && items_need_sort && items.Size > 1)
7659
            {
7660
                MyItem::SortWithSortSpecs(sort_specs, items.Data, items.Size);
7661
                sort_specs->SpecsDirty = false;
7662
            }
7663
            items_need_sort = false;
7664
7665
            // Take note of whether we are currently sorting based on the Quantity field,
7666
            // we will use this to trigger sorting when we know the data of this column has been modified.
7667
            const bool sorts_specs_using_quantity = (ImGui::TableGetColumnFlags(3) & ImGuiTableColumnFlags_IsSorted) != 0;
7668
7669
            // Show headers
7670
            if (show_headers && (columns_base_flags & ImGuiTableColumnFlags_AngledHeader) != 0)
7671
                ImGui::TableAngledHeadersRow();
7672
            if (show_headers)
7673
                ImGui::TableHeadersRow();
7674
7675
            // Show data
7676
            // FIXME-TABLE FIXME-NAV: How we can get decent up/down even though we have the buttons here?
7677
#if 1
7678
            // Demonstrate using clipper for large vertical lists
7679
            ImGuiListClipper clipper;
7680
            clipper.Begin(items.Size);
7681
            while (clipper.Step())
7682
            {
7683
                for (int row_n = clipper.DisplayStart; row_n < clipper.DisplayEnd; row_n++)
7684
#else
7685
            // Without clipper
7686
            {
7687
                for (int row_n = 0; row_n < items.Size; row_n++)
7688
#endif
7689
                {
7690
                    MyItem* item = &items[row_n];
7691
                    //if (!filter.PassFilter(item->Name))
7692
                    //    continue;
7693
7694
                    const bool item_is_selected = selection.contains(item->ID);
7695
                    ImGui::PushID(item->ID);
7696
                    ImGui::TableNextRow(ImGuiTableRowFlags_None, row_min_height);
7697
7698
                    // For the demo purpose we can select among different type of items submitted in the first column
7699
                    ImGui::TableSetColumnIndex(0);
7700
                    char label[32];
7701
                    sprintf(label, "%04d", item->ID);
7702
                    if (contents_type == CT_Text)
7703
                        ImGui::TextUnformatted(label);
7704
                    else if (contents_type == CT_Button)
7705
                        ImGui::Button(label);
7706
                    else if (contents_type == CT_SmallButton)
7707
                        ImGui::SmallButton(label);
7708
                    else if (contents_type == CT_FillButton)
7709
                        ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f));
7710
                    else if (contents_type == CT_Selectable || contents_type == CT_SelectableSpanRow)
7711
                    {
7712
                        ImGuiSelectableFlags selectable_flags = (contents_type == CT_SelectableSpanRow) ? ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap : ImGuiSelectableFlags_None;
7713
                        if (ImGui::Selectable(label, item_is_selected, selectable_flags, ImVec2(0, row_min_height)))
7714
                        {
7715
                            if (ImGui::GetIO().KeyCtrl)
7716
                            {
7717
                                if (item_is_selected)
7718
                                    selection.find_erase_unsorted(item->ID);
7719
                                else
7720
                                    selection.push_back(item->ID);
7721
                            }
7722
                            else
7723
                            {
7724
                                selection.clear();
7725
                                selection.push_back(item->ID);
7726
                            }
7727
                        }
7728
                    }
7729
7730
                    if (ImGui::TableSetColumnIndex(1))
7731
                        ImGui::TextUnformatted(item->Name);
7732
7733
                    // Here we demonstrate marking our data set as needing to be sorted again if we modified a quantity,
7734
                    // and we are currently sorting on the column showing the Quantity.
7735
                    // To avoid triggering a sort while holding the button, we only trigger it when the button has been released.
7736
                    // You will probably need some extra logic if you want to automatically sort when a specific entry changes.
7737
                    if (ImGui::TableSetColumnIndex(2))
7738
                    {
7739
                        if (ImGui::SmallButton("Chop")) { item->Quantity += 1; }
7740
                        if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) { items_need_sort = true; }
7741
                        ImGui::SameLine();
7742
                        if (ImGui::SmallButton("Eat")) { item->Quantity -= 1; }
7743
                        if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) { items_need_sort = true; }
7744
                    }
7745
7746
                    if (ImGui::TableSetColumnIndex(3))
7747
                        ImGui::Text("%d", item->Quantity);
7748
7749
                    ImGui::TableSetColumnIndex(4);
7750
                    if (show_wrapped_text)
7751
                        ImGui::TextWrapped("Lorem ipsum dolor sit amet");
7752
                    else
7753
                        ImGui::Text("Lorem ipsum dolor sit amet");
7754
7755
                    if (ImGui::TableSetColumnIndex(5))
7756
                        ImGui::Text("1234");
7757
7758
                    ImGui::PopID();
7759
                }
7760
            }
7761
7762
            // Store some info to display debug details below
7763
            table_scroll_cur = ImVec2(ImGui::GetScrollX(), ImGui::GetScrollY());
7764
            table_scroll_max = ImVec2(ImGui::GetScrollMaxX(), ImGui::GetScrollMaxY());
7765
            table_draw_list = ImGui::GetWindowDrawList();
7766
            ImGui::EndTable();
7767
        }
7768
        static bool show_debug_details = false;
7769
        ImGui::Checkbox("Debug details", &show_debug_details);
7770
        if (show_debug_details && table_draw_list)
7771
        {
7772
            ImGui::SameLine(0.0f, 0.0f);
7773
            const int table_draw_list_draw_cmd_count = table_draw_list->CmdBuffer.Size;
7774
            if (table_draw_list == parent_draw_list)
7775
                ImGui::Text(": DrawCmd: +%d (in same window)",
7776
                    table_draw_list_draw_cmd_count - parent_draw_list_draw_cmd_count);
7777
            else
7778
                ImGui::Text(": DrawCmd: +%d (in child window), Scroll: (%.f/%.f) (%.f/%.f)",
7779
                    table_draw_list_draw_cmd_count - 1, table_scroll_cur.x, table_scroll_max.x, table_scroll_cur.y, table_scroll_max.y);
7780
        }
7781
        ImGui::TreePop();
7782
    }
7783
7784
    ImGui::PopID();
7785
7786
    DemoWindowColumns();
7787
7788
    if (disable_indent)
7789
        ImGui::PopStyleVar();
7790
}
7791
7792
// Demonstrate old/legacy Columns API!
7793
// [2020: Columns are under-featured and not maintained. Prefer using the more flexible and powerful BeginTable() API!]
7794
static void DemoWindowColumns()
7795
{
7796
    bool open = ImGui::TreeNode("Legacy Columns API");
7797
    ImGui::SameLine();
7798
    HelpMarker("Columns() is an old API! Prefer using the more flexible and powerful BeginTable() API!");
7799
    if (!open)
7800
        return;
7801
7802
    // Basic columns
7803
    if (ImGui::TreeNode("Basic"))
7804
    {
7805
        IMGUI_DEMO_MARKER("Columns (legacy API)/Basic");
7806
        ImGui::Text("Without border:");
7807
        ImGui::Columns(3, "mycolumns3", false);  // 3-ways, no border
7808
        ImGui::Separator();
7809
        for (int n = 0; n < 14; n++)
7810
        {
7811
            char label[32];
7812
            sprintf(label, "Item %d", n);
7813
            if (ImGui::Selectable(label)) {}
7814
            //if (ImGui::Button(label, ImVec2(-FLT_MIN,0.0f))) {}
7815
            ImGui::NextColumn();
7816
        }
7817
        ImGui::Columns(1);
7818
        ImGui::Separator();
7819
7820
        ImGui::Text("With border:");
7821
        ImGui::Columns(4, "mycolumns"); // 4-ways, with border
7822
        ImGui::Separator();
7823
        ImGui::Text("ID"); ImGui::NextColumn();
7824
        ImGui::Text("Name"); ImGui::NextColumn();
7825
        ImGui::Text("Path"); ImGui::NextColumn();
7826
        ImGui::Text("Hovered"); ImGui::NextColumn();
7827
        ImGui::Separator();
7828
        const char* names[3] = { "One", "Two", "Three" };
7829
        const char* paths[3] = { "/path/one", "/path/two", "/path/three" };
7830
        static int selected = -1;
7831
        for (int i = 0; i < 3; i++)
7832
        {
7833
            char label[32];
7834
            sprintf(label, "%04d", i);
7835
            if (ImGui::Selectable(label, selected == i, ImGuiSelectableFlags_SpanAllColumns))
7836
                selected = i;
7837
            bool hovered = ImGui::IsItemHovered();
7838
            ImGui::NextColumn();
7839
            ImGui::Text(names[i]); ImGui::NextColumn();
7840
            ImGui::Text(paths[i]); ImGui::NextColumn();
7841
            ImGui::Text("%d", hovered); ImGui::NextColumn();
7842
        }
7843
        ImGui::Columns(1);
7844
        ImGui::Separator();
7845
        ImGui::TreePop();
7846
    }
7847
7848
    if (ImGui::TreeNode("Borders"))
7849
    {
7850
        IMGUI_DEMO_MARKER("Columns (legacy API)/Borders");
7851
        // NB: Future columns API should allow automatic horizontal borders.
7852
        static bool h_borders = true;
7853
        static bool v_borders = true;
7854
        static int columns_count = 4;
7855
        const int lines_count = 3;
7856
        ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
7857
        ImGui::DragInt("##columns_count", &columns_count, 0.1f, 2, 10, "%d columns");
7858
        if (columns_count < 2)
7859
            columns_count = 2;
7860
        ImGui::SameLine();
7861
        ImGui::Checkbox("horizontal", &h_borders);
7862
        ImGui::SameLine();
7863
        ImGui::Checkbox("vertical", &v_borders);
7864
        ImGui::Columns(columns_count, NULL, v_borders);
7865
        for (int i = 0; i < columns_count * lines_count; i++)
7866
        {
7867
            if (h_borders && ImGui::GetColumnIndex() == 0)
7868
                ImGui::Separator();
7869
            ImGui::PushID(i);
7870
            ImGui::Text("%c%c%c", 'a' + i, 'a' + i, 'a' + i);
7871
            ImGui::Text("Width %.2f", ImGui::GetColumnWidth());
7872
            ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x);
7873
            ImGui::Text("Offset %.2f", ImGui::GetColumnOffset());
7874
            ImGui::Text("Long text that is likely to clip");
7875
            ImGui::Button("Button", ImVec2(-FLT_MIN, 0.0f));
7876
            ImGui::PopID();
7877
            ImGui::NextColumn();
7878
        }
7879
        ImGui::Columns(1);
7880
        if (h_borders)
7881
            ImGui::Separator();
7882
        ImGui::TreePop();
7883
    }
7884
7885
    // Create multiple items in a same cell before switching to next column
7886
    if (ImGui::TreeNode("Mixed items"))
7887
    {
7888
        IMGUI_DEMO_MARKER("Columns (legacy API)/Mixed items");
7889
        ImGui::Columns(3, "mixed");
7890
        ImGui::Separator();
7891
7892
        ImGui::Text("Hello");
7893
        ImGui::Button("Banana");
7894
        ImGui::NextColumn();
7895
7896
        ImGui::Text("ImGui");
7897
        ImGui::Button("Apple");
7898
        static float foo = 1.0f;
7899
        ImGui::InputFloat("red", &foo, 0.05f, 0, "%.3f");
7900
        ImGui::Text("An extra line here.");
7901
        ImGui::NextColumn();
7902
7903
        ImGui::Text("Sailor");
7904
        ImGui::Button("Corniflower");
7905
        static float bar = 1.0f;
7906
        ImGui::InputFloat("blue", &bar, 0.05f, 0, "%.3f");
7907
        ImGui::NextColumn();
7908
7909
        if (ImGui::CollapsingHeader("Category A")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
7910
        if (ImGui::CollapsingHeader("Category B")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
7911
        if (ImGui::CollapsingHeader("Category C")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
7912
        ImGui::Columns(1);
7913
        ImGui::Separator();
7914
        ImGui::TreePop();
7915
    }
7916
7917
    // Word wrapping
7918
    if (ImGui::TreeNode("Word-wrapping"))
7919
    {
7920
        IMGUI_DEMO_MARKER("Columns (legacy API)/Word-wrapping");
7921
        ImGui::Columns(2, "word-wrapping");
7922
        ImGui::Separator();
7923
        ImGui::TextWrapped("The quick brown fox jumps over the lazy dog.");
7924
        ImGui::TextWrapped("Hello Left");
7925
        ImGui::NextColumn();
7926
        ImGui::TextWrapped("The quick brown fox jumps over the lazy dog.");
7927
        ImGui::TextWrapped("Hello Right");
7928
        ImGui::Columns(1);
7929
        ImGui::Separator();
7930
        ImGui::TreePop();
7931
    }
7932
7933
    if (ImGui::TreeNode("Horizontal Scrolling"))
7934
    {
7935
        IMGUI_DEMO_MARKER("Columns (legacy API)/Horizontal Scrolling");
7936
        ImGui::SetNextWindowContentSize(ImVec2(1500.0f, 0.0f));
7937
        ImVec2 child_size = ImVec2(0, ImGui::GetFontSize() * 20.0f);
7938
        ImGui::BeginChild("##ScrollingRegion", child_size, ImGuiChildFlags_None, ImGuiWindowFlags_HorizontalScrollbar);
7939
        ImGui::Columns(10);
7940
7941
        // Also demonstrate using clipper for large vertical lists
7942
        int ITEMS_COUNT = 2000;
7943
        ImGuiListClipper clipper;
7944
        clipper.Begin(ITEMS_COUNT);
7945
        while (clipper.Step())
7946
        {
7947
            for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
7948
                for (int j = 0; j < 10; j++)
7949
                {
7950
                    ImGui::Text("Line %d Column %d...", i, j);
7951
                    ImGui::NextColumn();
7952
                }
7953
        }
7954
        ImGui::Columns(1);
7955
        ImGui::EndChild();
7956
        ImGui::TreePop();
7957
    }
7958
7959
    if (ImGui::TreeNode("Tree"))
7960
    {
7961
        IMGUI_DEMO_MARKER("Columns (legacy API)/Tree");
7962
        ImGui::Columns(2, "tree", true);
7963
        for (int x = 0; x < 3; x++)
7964
        {
7965
            bool open1 = ImGui::TreeNode((void*)(intptr_t)x, "Node%d", x);
7966
            ImGui::NextColumn();
7967
            ImGui::Text("Node contents");
7968
            ImGui::NextColumn();
7969
            if (open1)
7970
            {
7971
                for (int y = 0; y < 3; y++)
7972
                {
7973
                    bool open2 = ImGui::TreeNode((void*)(intptr_t)y, "Node%d.%d", x, y);
7974
                    ImGui::NextColumn();
7975
                    ImGui::Text("Node contents");
7976
                    if (open2)
7977
                    {
7978
                        ImGui::Text("Even more contents");
7979
                        if (ImGui::TreeNode("Tree in column"))
7980
                        {
7981
                            ImGui::Text("The quick brown fox jumps over the lazy dog");
7982
                            ImGui::TreePop();
7983
                        }
7984
                    }
7985
                    ImGui::NextColumn();
7986
                    if (open2)
7987
                        ImGui::TreePop();
7988
                }
7989
                ImGui::TreePop();
7990
            }
7991
        }
7992
        ImGui::Columns(1);
7993
        ImGui::TreePop();
7994
    }
7995
7996
    ImGui::TreePop();
7997
}
7998
7999
//-----------------------------------------------------------------------------
8000
// [SECTION] DemoWindowInputs()
8001
//-----------------------------------------------------------------------------
8002
8003
static void DemoWindowInputs()
8004
{
8005
    if (ImGui::CollapsingHeader("Inputs & Focus"))
8006
    {
8007
        ImGuiIO& io = ImGui::GetIO();
8008
8009
        // Display inputs submitted to ImGuiIO
8010
        ImGui::SetNextItemOpen(true, ImGuiCond_Once);
8011
        bool inputs_opened = ImGui::TreeNode("Inputs");
8012
        ImGui::SameLine();
8013
        HelpMarker(
8014
            "This is a simplified view. See more detailed input state:\n"
8015
            "- in 'Tools->Metrics/Debugger->Inputs'.\n"
8016
            "- in 'Tools->Debug Log->IO'.");
8017
        if (inputs_opened)
8018
        {
8019
            IMGUI_DEMO_MARKER("Inputs & Focus/Inputs");
8020
            if (ImGui::IsMousePosValid())
8021
                ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y);
8022
            else
8023
                ImGui::Text("Mouse pos: <INVALID>");
8024
            ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y);
8025
            ImGui::Text("Mouse down:");
8026
            for (int i = 0; i < IM_COUNTOF(io.MouseDown); i++) if (ImGui::IsMouseDown(i)) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); }
8027
            ImGui::Text("Mouse wheel: %.1f", io.MouseWheel);
8028
            ImGui::Text("Mouse clicked count:");
8029
            for (int i = 0; i < IM_COUNTOF(io.MouseDown); i++) if (io.MouseClickedCount[i] > 0) { ImGui::SameLine(); ImGui::Text("b%d: %d", i, io.MouseClickedCount[i]); }
8030
8031
            // We iterate both legacy native range and named ImGuiKey ranges. This is a little unusual/odd but this allows
8032
            // displaying the data for old/new backends.
8033
            // User code should never have to go through such hoops!
8034
            // You can generally iterate between ImGuiKey_NamedKey_BEGIN and ImGuiKey_NamedKey_END.
8035
            struct funcs { static bool IsLegacyNativeDupe(ImGuiKey) { return false; } };
8036
            ImGuiKey start_key = ImGuiKey_NamedKey_BEGIN;
8037
            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); }
8038
            ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : "");
8039
            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.
8040
8041
            ImGui::TreePop();
8042
        }
8043
8044
        // Display ImGuiIO output flags
8045
        ImGui::SetNextItemOpen(true, ImGuiCond_Once);
8046
        bool outputs_opened = ImGui::TreeNode("Outputs");
8047
        ImGui::SameLine();
8048
        HelpMarker(
8049
            "The value of io.WantCaptureMouse and io.WantCaptureKeyboard are normally set by Dear ImGui "
8050
            "to instruct your application of how to route inputs. Typically, when a value is true, it means "
8051
            "Dear ImGui wants the corresponding inputs and we expect the underlying application to ignore them.\n\n"
8052
            "The most typical case is: when hovering a window, Dear ImGui set io.WantCaptureMouse to true, "
8053
            "and underlying application should ignore mouse inputs (in practice there are many and more subtle "
8054
            "rules leading to how those flags are set).");
8055
        if (outputs_opened)
8056
        {
8057
            IMGUI_DEMO_MARKER("Inputs & Focus/Outputs");
8058
            ImGui::Text("io.WantCaptureMouse: %d", io.WantCaptureMouse);
8059
            ImGui::Text("io.WantCaptureMouseUnlessPopupClose: %d", io.WantCaptureMouseUnlessPopupClose);
8060
            ImGui::Text("io.WantCaptureKeyboard: %d", io.WantCaptureKeyboard);
8061
            ImGui::Text("io.WantTextInput: %d", io.WantTextInput);
8062
            ImGui::Text("io.WantSetMousePos: %d", io.WantSetMousePos);
8063
            ImGui::Text("io.NavActive: %d, io.NavVisible: %d", io.NavActive, io.NavVisible);
8064
8065
            IMGUI_DEMO_MARKER("Inputs & Focus/Outputs/WantCapture override");
8066
            if (ImGui::TreeNode("WantCapture override"))
8067
            {
8068
                HelpMarker(
8069
                    "Hovering the colored canvas will override io.WantCaptureXXX fields.\n"
8070
                    "Notice how normally (when set to none), the value of io.WantCaptureKeyboard would be false when hovering "
8071
                    "and true when clicking.");
8072
                static int capture_override_mouse = -1;
8073
                static int capture_override_keyboard = -1;
8074
                const char* capture_override_desc[] = { "None", "Set to false", "Set to true" };
8075
                ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15);
8076
                ImGui::SliderInt("SetNextFrameWantCaptureMouse() on hover", &capture_override_mouse, -1, +1, capture_override_desc[capture_override_mouse + 1], ImGuiSliderFlags_AlwaysClamp);
8077
                ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15);
8078
                ImGui::SliderInt("SetNextFrameWantCaptureKeyboard() on hover", &capture_override_keyboard, -1, +1, capture_override_desc[capture_override_keyboard + 1], ImGuiSliderFlags_AlwaysClamp);
8079
8080
                ImGui::ColorButton("##panel", ImVec4(0.7f, 0.1f, 0.7f, 1.0f), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop, ImVec2(128.0f, 96.0f)); // Dummy item
8081
                if (ImGui::IsItemHovered() && capture_override_mouse != -1)
8082
                    ImGui::SetNextFrameWantCaptureMouse(capture_override_mouse == 1);
8083
                if (ImGui::IsItemHovered() && capture_override_keyboard != -1)
8084
                    ImGui::SetNextFrameWantCaptureKeyboard(capture_override_keyboard == 1);
8085
8086
                ImGui::TreePop();
8087
            }
8088
            ImGui::TreePop();
8089
        }
8090
8091
        // Demonstrate using Shortcut() and Routing Policies.
8092
        // The general flow is:
8093
        // - Code interested in a chord (e.g. "Ctrl+A") declares their intent.
8094
        // - Multiple locations may be interested in same chord! Routing helps find a winner.
8095
        // - Every frame, we resolve all claims and assign one owner if the modifiers are matching.
8096
        // - The lower-level function is 'bool SetShortcutRouting()', returns true when caller got the route.
8097
        // - Most of the times, SetShortcutRouting() is not called directly. User mostly calls Shortcut() with routing flags.
8098
        // - If you call Shortcut() WITHOUT any routing option, it uses ImGuiInputFlags_RouteFocused.
8099
        // TL;DR: Most uses will simply be:
8100
        // - Shortcut(ImGuiMod_Ctrl | ImGuiKey_A); // Use ImGuiInputFlags_RouteFocused policy.
8101
        if (ImGui::TreeNode("Shortcuts"))
8102
        {
8103
            IMGUI_DEMO_MARKER("Inputs & Focus/Shortcuts");
8104
            static ImGuiInputFlags route_options = ImGuiInputFlags_Repeat;
8105
            static ImGuiInputFlags route_type = ImGuiInputFlags_RouteFocused;
8106
            ImGui::CheckboxFlags("ImGuiInputFlags_Repeat", &route_options, ImGuiInputFlags_Repeat);
8107
            ImGui::RadioButton("ImGuiInputFlags_RouteActive", &route_type, ImGuiInputFlags_RouteActive);
8108
            ImGui::RadioButton("ImGuiInputFlags_RouteFocused (default)", &route_type, ImGuiInputFlags_RouteFocused);
8109
            ImGui::Indent();
8110
            ImGui::BeginDisabled(route_type != ImGuiInputFlags_RouteFocused);
8111
            ImGui::CheckboxFlags("ImGuiInputFlags_RouteOverActive##0", &route_options, ImGuiInputFlags_RouteOverActive);
8112
            ImGui::EndDisabled();
8113
            ImGui::Unindent();
8114
            ImGui::RadioButton("ImGuiInputFlags_RouteGlobal", &route_type, ImGuiInputFlags_RouteGlobal);
8115
            ImGui::Indent();
8116
            ImGui::BeginDisabled(route_type != ImGuiInputFlags_RouteGlobal);
8117
            ImGui::CheckboxFlags("ImGuiInputFlags_RouteOverFocused", &route_options, ImGuiInputFlags_RouteOverFocused);
8118
            ImGui::CheckboxFlags("ImGuiInputFlags_RouteOverActive", &route_options, ImGuiInputFlags_RouteOverActive);
8119
            ImGui::CheckboxFlags("ImGuiInputFlags_RouteUnlessBgFocused", &route_options, ImGuiInputFlags_RouteUnlessBgFocused);
8120
            ImGui::EndDisabled();
8121
            ImGui::Unindent();
8122
            ImGui::RadioButton("ImGuiInputFlags_RouteAlways", &route_type, ImGuiInputFlags_RouteAlways);
8123
            ImGuiInputFlags flags = route_type | route_options; // Merged flags
8124
            if (route_type != ImGuiInputFlags_RouteGlobal)
8125
                flags &= ~(ImGuiInputFlags_RouteOverFocused | ImGuiInputFlags_RouteOverActive | ImGuiInputFlags_RouteUnlessBgFocused);
8126
8127
            ImGui::SeparatorText("Using SetNextItemShortcut()");
8128
            ImGui::Text("Ctrl+S");
8129
            ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_S, flags | ImGuiInputFlags_Tooltip);
8130
            ImGui::Button("Save");
8131
            ImGui::Text("Alt+F");
8132
            ImGui::SetNextItemShortcut(ImGuiMod_Alt | ImGuiKey_F, flags | ImGuiInputFlags_Tooltip);
8133
            static float f = 0.5f;
8134
            ImGui::SliderFloat("Factor", &f, 0.0f, 1.0f);
8135
8136
            ImGui::SeparatorText("Using Shortcut()");
8137
            const float line_height = ImGui::GetTextLineHeightWithSpacing();
8138
            const ImGuiKeyChord key_chord = ImGuiMod_Ctrl | ImGuiKey_A;
8139
8140
            ImGui::Text("Ctrl+A");
8141
            ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "...");
8142
8143
            ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 0.0f, 1.0f, 0.1f));
8144
8145
            ImGui::BeginChild("WindowA", ImVec2(-FLT_MIN, line_height * 14), true);
8146
            ImGui::Text("Press Ctrl+A and see who receives it!");
8147
            ImGui::Separator();
8148
8149
            // 1: Window polling for Ctrl+A
8150
            ImGui::Text("(in WindowA)");
8151
            ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "...");
8152
8153
            // 2: InputText also polling for Ctrl+A: it always uses _RouteFocused internally (gets priority when active)
8154
            // (Commented because the owner-aware version of Shortcut() is still in imgui_internal.h)
8155
            //char str[16] = "Press Ctrl+A";
8156
            //ImGui::Spacing();
8157
            //ImGui::InputText("InputTextB", str, IM_COUNTOF(str), ImGuiInputTextFlags_ReadOnly);
8158
            //ImGuiID item_id = ImGui::GetItemID();
8159
            //ImGui::SameLine(); HelpMarker("Internal widgets always use _RouteFocused");
8160
            //ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags, item_id) ? "PRESSED" : "...");
8161
8162
            // 3: Dummy child is not claiming the route: focusing them shouldn't steal route away from WindowA
8163
            ImGui::BeginChild("ChildD", ImVec2(-FLT_MIN, line_height * 4), true);
8164
            ImGui::Text("(in ChildD: not using same Shortcut)");
8165
            ImGui::Text("IsWindowFocused: %d", ImGui::IsWindowFocused());
8166
            ImGui::EndChild();
8167
8168
            // 4: Child window polling for Ctrl+A. It is deeper than WindowA and gets priority when focused.
8169
            ImGui::BeginChild("ChildE", ImVec2(-FLT_MIN, line_height * 4), true);
8170
            ImGui::Text("(in ChildE: using same Shortcut)");
8171
            ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "...");
8172
            ImGui::EndChild();
8173
8174
            // 5: In a popup
8175
            if (ImGui::Button("Open Popup"))
8176
                ImGui::OpenPopup("PopupF");
8177
            if (ImGui::BeginPopup("PopupF"))
8178
            {
8179
                ImGui::Text("(in PopupF)");
8180
                ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "...");
8181
                // (Commented because the owner-aware version of Shortcut() is still in imgui_internal.h)
8182
                //ImGui::InputText("InputTextG", str, IM_COUNTOF(str), ImGuiInputTextFlags_ReadOnly);
8183
                //ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags, ImGui::GetItemID()) ? "PRESSED" : "...");
8184
                ImGui::EndPopup();
8185
            }
8186
            ImGui::EndChild();
8187
            ImGui::PopStyleColor();
8188
8189
            ImGui::TreePop();
8190
        }
8191
8192
        // Display mouse cursors
8193
        if (ImGui::TreeNode("Mouse Cursors"))
8194
        {
8195
            IMGUI_DEMO_MARKER("Inputs & Focus/Mouse Cursors");
8196
            const char* mouse_cursors_names[] = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "Wait", "Progress", "NotAllowed" };
8197
            IM_ASSERT(IM_COUNTOF(mouse_cursors_names) == ImGuiMouseCursor_COUNT);
8198
8199
            ImGuiMouseCursor current = ImGui::GetMouseCursor();
8200
            const char* cursor_name = (current >= ImGuiMouseCursor_Arrow) && (current < ImGuiMouseCursor_COUNT) ? mouse_cursors_names[current] : "N/A";
8201
            ImGui::Text("Current mouse cursor = %d: %s", current, cursor_name);
8202
            ImGui::BeginDisabled(true);
8203
            ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors);
8204
            ImGui::EndDisabled();
8205
8206
            ImGui::Text("Hover to see mouse cursors:");
8207
            ImGui::SameLine(); HelpMarker(
8208
                "Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. "
8209
                "If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, "
8210
                "otherwise your backend needs to handle it.");
8211
            for (int i = 0; i < ImGuiMouseCursor_COUNT; i++)
8212
            {
8213
                char label[32];
8214
                sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]);
8215
                ImGui::Bullet(); ImGui::Selectable(label, false);
8216
                if (ImGui::IsItemHovered())
8217
                    ImGui::SetMouseCursor(i);
8218
            }
8219
            ImGui::TreePop();
8220
        }
8221
8222
        if (ImGui::TreeNode("Tabbing"))
8223
        {
8224
            IMGUI_DEMO_MARKER("Inputs & Focus/Tabbing");
8225
            ImGui::Text("Use Tab/Shift+Tab to cycle through keyboard editable fields.");
8226
            static char buf[32] = "hello";
8227
            ImGui::InputText("1", buf, IM_COUNTOF(buf));
8228
            ImGui::InputText("2", buf, IM_COUNTOF(buf));
8229
            ImGui::InputText("3", buf, IM_COUNTOF(buf));
8230
            ImGui::PushItemFlag(ImGuiItemFlags_NoTabStop, true);
8231
            ImGui::InputText("4 (tab skip)", buf, IM_COUNTOF(buf));
8232
            ImGui::SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab.");
8233
            ImGui::PopItemFlag();
8234
            ImGui::InputText("5", buf, IM_COUNTOF(buf));
8235
            ImGui::TreePop();
8236
        }
8237
8238
        if (ImGui::TreeNode("Focus from code"))
8239
        {
8240
            IMGUI_DEMO_MARKER("Inputs & Focus/Focus from code");
8241
            bool focus_1 = ImGui::Button("Focus on 1"); ImGui::SameLine();
8242
            bool focus_2 = ImGui::Button("Focus on 2"); ImGui::SameLine();
8243
            bool focus_3 = ImGui::Button("Focus on 3");
8244
            int has_focus = 0;
8245
            static char buf[128] = "click on a button to set focus";
8246
8247
            if (focus_1) ImGui::SetKeyboardFocusHere();
8248
            ImGui::InputText("1", buf, IM_COUNTOF(buf));
8249
            if (ImGui::IsItemActive()) has_focus = 1;
8250
8251
            if (focus_2) ImGui::SetKeyboardFocusHere();
8252
            ImGui::InputText("2", buf, IM_COUNTOF(buf));
8253
            if (ImGui::IsItemActive()) has_focus = 2;
8254
8255
            ImGui::PushItemFlag(ImGuiItemFlags_NoTabStop, true);
8256
            if (focus_3) ImGui::SetKeyboardFocusHere();
8257
            ImGui::InputText("3 (tab skip)", buf, IM_COUNTOF(buf));
8258
            if (ImGui::IsItemActive()) has_focus = 3;
8259
            ImGui::SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab.");
8260
            ImGui::PopItemFlag();
8261
8262
            if (has_focus)
8263
                ImGui::Text("Item with focus: %d", has_focus);
8264
            else
8265
                ImGui::Text("Item with focus: <none>");
8266
8267
            // Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item
8268
            static float f3[3] = { 0.0f, 0.0f, 0.0f };
8269
            int focus_ahead = -1;
8270
            if (ImGui::Button("Focus on X")) { focus_ahead = 0; } ImGui::SameLine();
8271
            if (ImGui::Button("Focus on Y")) { focus_ahead = 1; } ImGui::SameLine();
8272
            if (ImGui::Button("Focus on Z")) { focus_ahead = 2; }
8273
            if (focus_ahead != -1) ImGui::SetKeyboardFocusHere(focus_ahead);
8274
            ImGui::SliderFloat3("Float3", &f3[0], 0.0f, 1.0f);
8275
8276
            ImGui::TextWrapped("NB: Cursor & selection are preserved when refocusing last used item in code.");
8277
            ImGui::TreePop();
8278
        }
8279
8280
        if (ImGui::TreeNode("Dragging"))
8281
        {
8282
            IMGUI_DEMO_MARKER("Inputs & Focus/Dragging");
8283
            ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget.");
8284
            for (int button = 0; button < 3; button++)
8285
            {
8286
                ImGui::Text("IsMouseDragging(%d):", button);
8287
                ImGui::Text("  w/ default threshold: %d,", ImGui::IsMouseDragging(button));
8288
                ImGui::Text("  w/ zero threshold: %d,", ImGui::IsMouseDragging(button, 0.0f));
8289
                ImGui::Text("  w/ large threshold: %d,", ImGui::IsMouseDragging(button, 20.0f));
8290
            }
8291
8292
            ImGui::Button("Drag Me");
8293
            if (ImGui::IsItemActive())
8294
                ImGui::GetForegroundDrawList()->AddLine(io.MouseClickedPos[0], io.MousePos, ImGui::GetColorU32(ImGuiCol_Button), 4.0f); // Draw a line between the button and the mouse cursor
8295
8296
            // Drag operations gets "unlocked" when the mouse has moved past a certain threshold
8297
            // (the default threshold is stored in io.MouseDragThreshold). You can request a lower or higher
8298
            // threshold using the second parameter of IsMouseDragging() and GetMouseDragDelta().
8299
            ImVec2 value_raw = ImGui::GetMouseDragDelta(0, 0.0f);
8300
            ImVec2 value_with_lock_threshold = ImGui::GetMouseDragDelta(0);
8301
            ImVec2 mouse_delta = io.MouseDelta;
8302
            ImGui::Text("GetMouseDragDelta(0):");
8303
            ImGui::Text("  w/ default threshold: (%.1f, %.1f)", value_with_lock_threshold.x, value_with_lock_threshold.y);
8304
            ImGui::Text("  w/ zero threshold: (%.1f, %.1f)", value_raw.x, value_raw.y);
8305
            ImGui::Text("io.MouseDelta: (%.1f, %.1f)", mouse_delta.x, mouse_delta.y);
8306
            ImGui::TreePop();
8307
        }
8308
    }
8309
}
8310
8311
//-----------------------------------------------------------------------------
8312
// [SECTION] About Window / ShowAboutWindow()
8313
// Access from Dear ImGui Demo -> Tools -> About
8314
//-----------------------------------------------------------------------------
8315
8316
void ImGui::ShowAboutWindow(bool* p_open)
8317
{
8318
    if (!ImGui::Begin("About Dear ImGui", p_open, ImGuiWindowFlags_AlwaysAutoResize))
8319
    {
8320
        ImGui::End();
8321
        return;
8322
    }
8323
    IMGUI_DEMO_MARKER("Tools/About Dear ImGui");
8324
    ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
8325
8326
    ImGui::TextLinkOpenURL("Homepage", "https://github.com/ocornut/imgui");
8327
    ImGui::SameLine();
8328
    ImGui::TextLinkOpenURL("FAQ", "https://github.com/ocornut/imgui/blob/master/docs/FAQ.md");
8329
    ImGui::SameLine();
8330
    ImGui::TextLinkOpenURL("Wiki", "https://github.com/ocornut/imgui/wiki");
8331
    ImGui::SameLine();
8332
    ImGui::TextLinkOpenURL("Extensions", "https://github.com/ocornut/imgui/wiki/Useful-Extensions");
8333
    ImGui::SameLine();
8334
    ImGui::TextLinkOpenURL("Releases", "https://github.com/ocornut/imgui/releases");
8335
    ImGui::SameLine();
8336
    ImGui::TextLinkOpenURL("Funding", "https://github.com/ocornut/imgui/wiki/Funding");
8337
8338
    ImGui::Separator();
8339
    ImGui::Text("(c) 2014-2026 Omar Cornut");
8340
    ImGui::Text("Developed by Omar Cornut and all Dear ImGui contributors.");
8341
    ImGui::Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information.");
8342
    ImGui::Text("If your company uses this, please consider funding the project.");
8343
8344
    static bool show_config_info = false;
8345
    ImGui::Checkbox("Config/Build Information", &show_config_info);
8346
    if (show_config_info)
8347
    {
8348
        ImGuiIO& io = ImGui::GetIO();
8349
        ImGuiStyle& style = ImGui::GetStyle();
8350
8351
        bool copy_to_clipboard = ImGui::Button("Copy to clipboard");
8352
        ImVec2 child_size = ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 18);
8353
        ImGui::BeginChild(ImGui::GetID("cfg_infos"), child_size, ImGuiChildFlags_FrameStyle);
8354
        if (copy_to_clipboard)
8355
        {
8356
            ImGui::LogToClipboard();
8357
            ImGui::LogText("// (Copy from the next line. Keep the ``` markers for formatting.)\n");
8358
            ImGui::LogText("```cpp\n"); // Back quotes will make text appears without formatting when pasting on GitHub
8359
        }
8360
8361
        ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
8362
        ImGui::Separator();
8363
        ImGui::Text("sizeof(size_t): %d, sizeof(ImDrawIdx): %d, sizeof(ImDrawVert): %d", (int)sizeof(size_t), (int)sizeof(ImDrawIdx), (int)sizeof(ImDrawVert));
8364
        ImGui::Text("define: __cplusplus=%d", (int)__cplusplus);
8365
#ifdef IMGUI_ENABLE_TEST_ENGINE
8366
        ImGui::Text("define: IMGUI_ENABLE_TEST_ENGINE");
8367
#endif
8368
#ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
8369
        ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_FUNCTIONS");
8370
#endif
8371
#ifdef IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS
8372
        ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS");
8373
#endif
8374
#ifdef IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
8375
        ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS");
8376
#endif
8377
#ifdef IMGUI_DISABLE_WIN32_FUNCTIONS
8378
        ImGui::Text("define: IMGUI_DISABLE_WIN32_FUNCTIONS");
8379
#endif
8380
#ifdef IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS
8381
        ImGui::Text("define: IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS");
8382
#endif
8383
#ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
8384
        ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS");
8385
#endif
8386
#ifdef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS
8387
        ImGui::Text("define: IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS");
8388
#endif
8389
#ifdef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
8390
        ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS");
8391
#endif
8392
#ifdef IMGUI_DISABLE_FILE_FUNCTIONS
8393
        ImGui::Text("define: IMGUI_DISABLE_FILE_FUNCTIONS");
8394
#endif
8395
#ifdef IMGUI_DISABLE_DEFAULT_ALLOCATORS
8396
        ImGui::Text("define: IMGUI_DISABLE_DEFAULT_ALLOCATORS");
8397
#endif
8398
#ifdef IMGUI_USE_BGRA_PACKED_COLOR
8399
        ImGui::Text("define: IMGUI_USE_BGRA_PACKED_COLOR");
8400
#endif
8401
#ifdef _WIN32
8402
        ImGui::Text("define: _WIN32");
8403
#endif
8404
#ifdef _WIN64
8405
        ImGui::Text("define: _WIN64");
8406
#endif
8407
#ifdef __linux__
8408
        ImGui::Text("define: __linux__");
8409
#endif
8410
#ifdef __APPLE__
8411
        ImGui::Text("define: __APPLE__");
8412
#endif
8413
#ifdef _MSC_VER
8414
        ImGui::Text("define: _MSC_VER=%d", _MSC_VER);
8415
#endif
8416
#ifdef _MSVC_LANG
8417
        ImGui::Text("define: _MSVC_LANG=%d", (int)_MSVC_LANG);
8418
#endif
8419
#ifdef __MINGW32__
8420
        ImGui::Text("define: __MINGW32__");
8421
#endif
8422
#ifdef __MINGW64__
8423
        ImGui::Text("define: __MINGW64__");
8424
#endif
8425
#ifdef __GNUC__
8426
        ImGui::Text("define: __GNUC__=%d", (int)__GNUC__);
8427
#endif
8428
#ifdef __clang_version__
8429
        ImGui::Text("define: __clang_version__=%s", __clang_version__);
8430
#endif
8431
#ifdef __EMSCRIPTEN__
8432
        ImGui::Text("define: __EMSCRIPTEN__");
8433
#ifdef __EMSCRIPTEN_MAJOR__
8434
        ImGui::Text("Emscripten: %d.%d.%d", __EMSCRIPTEN_MAJOR__, __EMSCRIPTEN_MINOR__, __EMSCRIPTEN_TINY__);
8435
#else
8436
        ImGui::Text("Emscripten: %d.%d.%d", __EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__);
8437
#endif
8438
#endif
8439
#ifdef IMGUI_HAS_VIEWPORT
8440
        ImGui::Text("define: IMGUI_HAS_VIEWPORT");
8441
#endif
8442
#ifdef IMGUI_HAS_DOCK
8443
        ImGui::Text("define: IMGUI_HAS_DOCK");
8444
#endif
8445
#ifdef NDEBUG
8446
        ImGui::Text("define: NDEBUG");
8447
#endif
8448
8449
        // Heuristic to detect no-op IM_ASSERT() macros
8450
        // - This is designed so people opening bug reports would convey and notice that they have disabled asserts for Dear ImGui code.
8451
        // - 16 is > strlen("((void)(_EXPR))") which we suggested in our imconfig.h template as a possible way to disable.
8452
        int assert_runs_expression = 0;
8453
        IM_ASSERT(++assert_runs_expression);
8454
        int assert_expand_len = (int)strlen(IM_STRINGIFY((IM_ASSERT(true))));
8455
        bool assert_maybe_disabled = (!assert_runs_expression || assert_expand_len <= 16);
8456
        ImGui::Text("IM_ASSERT: runs expression: %s. expand size: %s%s",
8457
            assert_runs_expression ? "OK" : "KO", (assert_expand_len > 16) ? "OK" : "KO", assert_maybe_disabled ? " (MAYBE DISABLED?!)" : "");
8458
        if (assert_maybe_disabled)
8459
        {
8460
            ImGui::SameLine();
8461
            HelpMarker("IM_ASSERT() calls assert() by default. Compiling with NDEBUG will usually strip out assert() to nothing, which is NOT recommended because we use asserts to notify of programmer mistakes!");
8462
        }
8463
8464
        ImGui::Separator();
8465
        ImGui::Text("io.BackendPlatformName: %s", io.BackendPlatformName ? io.BackendPlatformName : "NULL");
8466
        ImGui::Text("io.BackendRendererName: %s", io.BackendRendererName ? io.BackendRendererName : "NULL");
8467
        ImGui::Text("io.ConfigFlags: 0x%08X", io.ConfigFlags);
8468
        if (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard)        ImGui::Text(" NavEnableKeyboard");
8469
        if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad)         ImGui::Text(" NavEnableGamepad");
8470
        if (io.ConfigFlags & ImGuiConfigFlags_NoMouse)                  ImGui::Text(" NoMouse");
8471
        if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)      ImGui::Text(" NoMouseCursorChange");
8472
        if (io.ConfigFlags & ImGuiConfigFlags_NoKeyboard)               ImGui::Text(" NoKeyboard");
8473
        if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)            ImGui::Text(" DockingEnable");
8474
        if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)          ImGui::Text(" ViewportsEnable");
8475
        if (io.MouseDrawCursor)                                         ImGui::Text("io.MouseDrawCursor");
8476
        if (io.ConfigDpiScaleFonts)                                     ImGui::Text("io.ConfigDpiScaleFonts");
8477
        if (io.ConfigDpiScaleViewports)                                 ImGui::Text("io.ConfigDpiScaleViewports");
8478
        if (io.ConfigViewportsNoAutoMerge)                              ImGui::Text("io.ConfigViewportsNoAutoMerge");
8479
        if (io.ConfigViewportsNoTaskBarIcon)                            ImGui::Text("io.ConfigViewportsNoTaskBarIcon");
8480
        if (io.ConfigViewportsNoDecoration)                             ImGui::Text("io.ConfigViewportsNoDecoration");
8481
        if (io.ConfigViewportsNoDefaultParent)                          ImGui::Text("io.ConfigViewportsNoDefaultParent");
8482
        if (io.ConfigDockingNoSplit)                                    ImGui::Text("io.ConfigDockingNoSplit");
8483
        if (io.ConfigDockingNoDockingOver)                              ImGui::Text("io.ConfigDockingNoDockingOver");
8484
        if (io.ConfigDockingWithShift)                                  ImGui::Text("io.ConfigDockingWithShift");
8485
        if (io.ConfigDockingAlwaysTabBar)                               ImGui::Text("io.ConfigDockingAlwaysTabBar");
8486
        if (io.ConfigDockingTransparentPayload)                         ImGui::Text("io.ConfigDockingTransparentPayload");
8487
        if (io.ConfigMacOSXBehaviors)                                   ImGui::Text("io.ConfigMacOSXBehaviors");
8488
        if (io.ConfigNavMoveSetMousePos)                                ImGui::Text("io.ConfigNavMoveSetMousePos");
8489
        if (io.ConfigNavCaptureKeyboard)                                ImGui::Text("io.ConfigNavCaptureKeyboard");
8490
        if (io.ConfigInputTextCursorBlink)                              ImGui::Text("io.ConfigInputTextCursorBlink");
8491
        if (io.ConfigWindowsResizeFromEdges)                            ImGui::Text("io.ConfigWindowsResizeFromEdges");
8492
        if (io.ConfigWindowsMoveFromTitleBarOnly)                       ImGui::Text("io.ConfigWindowsMoveFromTitleBarOnly");
8493
        if (io.ConfigMemoryCompactTimer >= 0.0f)                        ImGui::Text("io.ConfigMemoryCompactTimer = %.1f", io.ConfigMemoryCompactTimer);
8494
        ImGui::Text("io.BackendFlags: 0x%08X", io.BackendFlags);
8495
        if (io.BackendFlags & ImGuiBackendFlags_HasGamepad)             ImGui::Text(" HasGamepad");
8496
        if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors)        ImGui::Text(" HasMouseCursors");
8497
        if (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos)         ImGui::Text(" HasSetMousePos");
8498
        if (io.BackendFlags & ImGuiBackendFlags_PlatformHasViewports)   ImGui::Text(" PlatformHasViewports");
8499
        if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport)ImGui::Text(" HasMouseHoveredViewport");
8500
        if (io.BackendFlags & ImGuiBackendFlags_HasParentViewport)      ImGui::Text(" HasParentViewport");
8501
        if (io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset)   ImGui::Text(" RendererHasVtxOffset");
8502
        if (io.BackendFlags & ImGuiBackendFlags_RendererHasTextures)    ImGui::Text(" RendererHasTextures");
8503
        if (io.BackendFlags & ImGuiBackendFlags_RendererHasViewports)   ImGui::Text(" RendererHasViewports");
8504
        ImGui::Separator();
8505
        ImGui::Text("io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", io.Fonts->Fonts.Size, io.Fonts->Flags, io.Fonts->TexData->Width, io.Fonts->TexData->Height);
8506
        ImGui::Text("io.Fonts->FontLoaderName: %s", io.Fonts->FontLoaderName ? io.Fonts->FontLoaderName : "NULL");
8507
        ImGui::Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y);
8508
        ImGui::Text("io.DisplayFramebufferScale: %.2f,%.2f", io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y);
8509
        ImGui::Separator();
8510
        ImGui::Text("style.WindowPadding: %.2f,%.2f", style.WindowPadding.x, style.WindowPadding.y);
8511
        ImGui::Text("style.WindowBorderSize: %.2f", style.WindowBorderSize);
8512
        ImGui::Text("style.FramePadding: %.2f,%.2f", style.FramePadding.x, style.FramePadding.y);
8513
        ImGui::Text("style.FrameRounding: %.2f", style.FrameRounding);
8514
        ImGui::Text("style.FrameBorderSize: %.2f", style.FrameBorderSize);
8515
        ImGui::Text("style.ItemSpacing: %.2f,%.2f", style.ItemSpacing.x, style.ItemSpacing.y);
8516
        ImGui::Text("style.ItemInnerSpacing: %.2f,%.2f", style.ItemInnerSpacing.x, style.ItemInnerSpacing.y);
8517
8518
        if (copy_to_clipboard)
8519
        {
8520
            ImGui::LogText("\n```\n");
8521
            ImGui::LogFinish();
8522
        }
8523
        ImGui::EndChild();
8524
    }
8525
    ImGui::End();
8526
}
8527
8528
//-----------------------------------------------------------------------------
8529
// [SECTION] Style Editor / ShowStyleEditor()
8530
//-----------------------------------------------------------------------------
8531
// - ShowStyleSelector()
8532
// - ShowStyleEditor()
8533
//-----------------------------------------------------------------------------
8534
8535
// Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options.
8536
bool ImGui::ShowStyleSelector(const char* label)
8537
{
8538
    // FIXME: This is a bit tricky to get right as style are functions, they don't register a name nor the fact that one is active.
8539
    // So we keep track of last active one among our limited selection.
8540
    static int style_idx = -1;
8541
    const char* style_names[] = { "Dark", "Light", "Classic" };
8542
    bool ret = false;
8543
    if (ImGui::BeginCombo(label, (style_idx >= 0 && style_idx < IM_COUNTOF(style_names)) ? style_names[style_idx] : ""))
8544
    {
8545
        for (int n = 0; n < IM_COUNTOF(style_names); n++)
8546
        {
8547
            if (ImGui::Selectable(style_names[n], style_idx == n, ImGuiSelectableFlags_SelectOnNav))
8548
            {
8549
                style_idx = n;
8550
                ret = true;
8551
                switch (style_idx)
8552
                {
8553
                case 0: ImGui::StyleColorsDark(); break;
8554
                case 1: ImGui::StyleColorsLight(); break;
8555
                case 2: ImGui::StyleColorsClassic(); break;
8556
                }
8557
            }
8558
            else if (style_idx == n)
8559
                ImGui::SetItemDefaultFocus();
8560
        }
8561
        ImGui::EndCombo();
8562
    }
8563
    return ret;
8564
}
8565
8566
static const char* GetTreeLinesFlagsName(ImGuiTreeNodeFlags flags)
8567
{
8568
    if (flags == ImGuiTreeNodeFlags_DrawLinesNone) return "DrawLinesNone";
8569
    if (flags == ImGuiTreeNodeFlags_DrawLinesFull) return "DrawLinesFull";
8570
    if (flags == ImGuiTreeNodeFlags_DrawLinesToNodes) return "DrawLinesToNodes";
8571
    return "";
8572
}
8573
8574
// We omit the ImGui:: prefix in this function, as we don't expect user to be copy and pasting this code.
8575
void ImGui::ShowStyleEditor(ImGuiStyle* ref)
8576
{
8577
    IMGUI_DEMO_MARKER("Tools/Style Editor");
8578
    // You can pass in a reference ImGuiStyle structure to compare to, revert to and save to
8579
    // (without a reference style pointer, we will use one compared locally as a reference)
8580
    ImGuiStyle& style = GetStyle();
8581
    static ImGuiStyle ref_saved_style;
8582
8583
    // Default to using internal storage as reference
8584
    static bool init = true;
8585
    if (init && ref == NULL)
8586
        ref_saved_style = style;
8587
    init = false;
8588
    if (ref == NULL)
8589
        ref = &ref_saved_style;
8590
8591
    // The logic behind dynamically changing 'max_border_size' is to not encourage people to increase border size too much: it'll likely reveal lots of subtle rendering artifacts and this isn't a priority right now.
8592
    // Note that _MainScale is currently internal PLEASE DO NOT USE IN YOUR CODE.
8593
    const float default_border_size = (float)(int)style._MainScale;
8594
    const float max_border_size = IM_MAX(default_border_size, 2.0f);
8595
8596
    PushItemWidth(GetWindowWidth() * 0.50f);
8597
8598
    {
8599
        // General
8600
        SeparatorText("General");
8601
        if ((GetIO().BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0)
8602
        {
8603
            BulletText("Warning: Font scaling will NOT be smooth, because\nImGuiBackendFlags_RendererHasTextures is not set!");
8604
            BulletText("For instructions, see:");
8605
            SameLine();
8606
            TextLinkOpenURL("docs/BACKENDS.md", "https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md");
8607
        }
8608
8609
        if (ShowStyleSelector("Colors##Selector"))
8610
            ref_saved_style = style;
8611
        ShowFontSelector("Fonts##Selector");
8612
        if (DragFloat("FontSizeBase", &style.FontSizeBase, 0.20f, 5.0f, 100.0f, "%.0f"))
8613
            style._NextFrameFontSizeBase = style.FontSizeBase; // FIXME: Temporary hack until we finish remaining work.
8614
        SameLine(0.0f, 0.0f); Text(" (out %.2f)", GetFontSize());
8615
        DragFloat("FontScaleMain", &style.FontScaleMain, 0.02f, 0.5f, 4.0f);
8616
        BeginDisabled(GetIO().ConfigDpiScaleFonts);
8617
        DragFloat("FontScaleDpi", &style.FontScaleDpi, 0.02f, 0.5f, 4.0f);
8618
        SetItemTooltip("When io.ConfigDpiScaleFonts is set, this value is automatically overwritten.");
8619
        EndDisabled();
8620
8621
        // Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f)
8622
        if (SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"))
8623
            style.GrabRounding = style.FrameRounding; // Make GrabRounding always the same value as FrameRounding
8624
        { bool border = (style.WindowBorderSize > 0.0f); if (Checkbox("WindowBorder", &border)) { style.WindowBorderSize = border ? default_border_size : 0.0f; } }
8625
        SameLine();
8626
        { bool border = (style.FrameBorderSize > 0.0f);  if (Checkbox("FrameBorder", &border)) { style.FrameBorderSize = border ? default_border_size : 0.0f; } }
8627
        SameLine();
8628
        { bool border = (style.PopupBorderSize > 0.0f);  if (Checkbox("PopupBorder", &border)) { style.PopupBorderSize = border ? default_border_size : 0.0f; } }
8629
    }
8630
8631
    // Save/Revert button
8632
    if (Button("Save Ref"))
8633
        *ref = ref_saved_style = style;
8634
    SameLine();
8635
    if (Button("Revert Ref"))
8636
        style = *ref;
8637
    SameLine();
8638
    HelpMarker(
8639
        "Save/Revert in local non-persistent storage. Default Colors definition are not affected. "
8640
        "Use \"Export\" below to save them somewhere.");
8641
8642
    SeparatorText("Details");
8643
    if (BeginTabBar("##tabs", ImGuiTabBarFlags_None))
8644
    {
8645
        if (BeginTabItem("Sizes"))
8646
        {
8647
            SeparatorText("Main");
8648
            SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f");
8649
            SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f");
8650
            SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f");
8651
            SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f");
8652
            SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f");
8653
            SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f");
8654
            SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f");
8655
8656
            SeparatorText("Borders");
8657
            SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, max_border_size, "%.0f");
8658
            SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, max_border_size, "%.0f");
8659
            SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, max_border_size, "%.0f");
8660
            SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, max_border_size, "%.0f");
8661
8662
            SeparatorText("Rounding");
8663
            SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f");
8664
            SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f");
8665
            SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f");
8666
            SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f, "%.0f");
8667
            SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f");
8668
            SliderFloat("MenuItemRounding", &style.MenuItemRounding, 0.0f, 12.0f, "%.0f");
8669
            // NB: SelectableRounding is intentionally NOT made visible here. We don't want to encourage people using that.
8670
8671
            SeparatorText("Scrollbar");
8672
            SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f");
8673
            SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f");
8674
            SliderFloat("ScrollbarPadding", &style.ScrollbarPadding, 0.0f, 10.0f, "%.0f");
8675
8676
            SeparatorText("Tabs");
8677
            SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, max_border_size, "%.0f");
8678
            SliderFloat("TabBarBorderSize", &style.TabBarBorderSize, 0.0f, max_border_size, "%.0f");
8679
            SliderFloat("TabBarOverlineSize", &style.TabBarOverlineSize, 0.0f, IM_MAX(3.0f, max_border_size), "%.0f");
8680
            SameLine(); HelpMarker("Overline is only drawn over the selected tab when ImGuiTabBarFlags_DrawSelectedOverline is set.");
8681
            DragFloat("TabMinWidthBase", &style.TabMinWidthBase, 0.5f, 1.0f, 500.0f, "%.0f");
8682
            DragFloat("TabMinWidthShrink", &style.TabMinWidthShrink, 0.5f, 1.0f, 500.0f, "%0.f");
8683
            DragFloat("TabCloseButtonMinWidthSelected", &style.TabCloseButtonMinWidthSelected, 0.5f, -1.0f, 100.0f, (style.TabCloseButtonMinWidthSelected < 0.0f) ? "%.0f (Always)" : "%.0f");
8684
            DragFloat("TabCloseButtonMinWidthUnselected", &style.TabCloseButtonMinWidthUnselected, 0.5f, -1.0f, 100.0f, (style.TabCloseButtonMinWidthUnselected < 0.0f) ? "%.0f (Always)" : "%.0f");
8685
            SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f");
8686
8687
            SeparatorText("Tables");
8688
            SliderFloat2("CellPadding", (float*)&style.CellPadding, 0.0f, 20.0f, "%.0f");
8689
            SliderAngle("TableAngledHeadersAngle", &style.TableAngledHeadersAngle, -50.0f, +50.0f);
8690
            SliderFloat2("TableAngledHeadersTextAlign", (float*)&style.TableAngledHeadersTextAlign, 0.0f, 1.0f, "%.2f");
8691
8692
            SeparatorText("Trees");
8693
            bool combo_open = BeginCombo("TreeLinesFlags", GetTreeLinesFlagsName(style.TreeLinesFlags));
8694
            SameLine();
8695
            HelpMarker("[Experimental] Tree lines may not work in all situations (e.g. using a clipper) and may incurs slight traversal overhead.\n\nImGuiTreeNodeFlags_DrawLinesFull is faster than ImGuiTreeNodeFlags_DrawLinesToNode.");
8696
            if (combo_open)
8697
            {
8698
                const ImGuiTreeNodeFlags options[] = { ImGuiTreeNodeFlags_DrawLinesNone, ImGuiTreeNodeFlags_DrawLinesFull, ImGuiTreeNodeFlags_DrawLinesToNodes };
8699
                for (ImGuiTreeNodeFlags option : options)
8700
                    if (Selectable(GetTreeLinesFlagsName(option), style.TreeLinesFlags == option))
8701
                        style.TreeLinesFlags = option;
8702
                EndCombo();
8703
            }
8704
            SliderFloat("TreeLinesSize", &style.TreeLinesSize, 0.0f, max_border_size, "%.0f");
8705
            SliderFloat("TreeLinesRounding", &style.TreeLinesRounding, 0.0f, 12.0f, "%.0f");
8706
8707
            SeparatorText("Windows");
8708
            SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f");
8709
            SliderFloat("WindowBorderHoverPadding", &style.WindowBorderHoverPadding, 1.0f, 20.0f, "%.0f");
8710
            int window_menu_button_position = style.WindowMenuButtonPosition + 1;
8711
            if (Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0"))
8712
                style.WindowMenuButtonPosition = (ImGuiDir)(window_menu_button_position - 1);
8713
8714
            SeparatorText("Widgets");
8715
            SliderFloat("ColorMarkerSize", &style.ColorMarkerSize, 0.0f, 8.0f, "%.0f");
8716
            Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, "Left\0Right\0");
8717
            SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f");
8718
            SameLine(); HelpMarker("Alignment applies when a button is larger than its text content.");
8719
            SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f");
8720
            SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content.");
8721
            SliderFloat("SeparatorSize", &style.SeparatorSize, 0.0f, 10.0f, "%.0f");
8722
            SliderFloat("SeparatorTextBorderSize", &style.SeparatorTextBorderSize, 0.0f, 10.0f, "%.0f");
8723
            SliderFloat2("SeparatorTextAlign", (float*)&style.SeparatorTextAlign, 0.0f, 1.0f, "%.2f");
8724
            SliderFloat2("SeparatorTextPadding", (float*)&style.SeparatorTextPadding, 0.0f, 40.0f, "%.0f");
8725
            SliderFloat("LogSliderDeadzone", &style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f");
8726
            SliderFloat("ImageRounding", &style.ImageRounding, 0.0f, 12.0f, "%.0f");
8727
            SliderFloat("ImageBorderSize", &style.ImageBorderSize, 0.0f, max_border_size, "%.0f");
8728
8729
            SeparatorText("Docking");
8730
            //SetCursorPosX(GetCursorPosX() + CalcItemWidth() - GetFrameHeight());
8731
            Checkbox("DockingNodeHasCloseButton", &style.DockingNodeHasCloseButton);
8732
            SliderFloat("DockingSeparatorSize", &style.DockingSeparatorSize, 0.0f, 12.0f, "%.0f");
8733
8734
            SeparatorText("Tooltips");
8735
            for (int n = 0; n < 2; n++)
8736
                if (TreeNodeEx(n == 0 ? "HoverFlagsForTooltipMouse" : "HoverFlagsForTooltipNav"))
8737
                {
8738
                    ImGuiHoveredFlags* p = (n == 0) ? &style.HoverFlagsForTooltipMouse : &style.HoverFlagsForTooltipNav;
8739
                    CheckboxFlags("ImGuiHoveredFlags_DelayNone", p, ImGuiHoveredFlags_DelayNone);
8740
                    CheckboxFlags("ImGuiHoveredFlags_DelayShort", p, ImGuiHoveredFlags_DelayShort);
8741
                    CheckboxFlags("ImGuiHoveredFlags_DelayNormal", p, ImGuiHoveredFlags_DelayNormal);
8742
                    CheckboxFlags("ImGuiHoveredFlags_Stationary", p, ImGuiHoveredFlags_Stationary);
8743
                    CheckboxFlags("ImGuiHoveredFlags_NoSharedDelay", p, ImGuiHoveredFlags_NoSharedDelay);
8744
                    TreePop();
8745
                }
8746
8747
            SeparatorText("Misc");
8748
            SliderFloat2("DisplayWindowPadding", (float*)&style.DisplayWindowPadding, 0.0f, 30.0f, "%.0f"); SameLine(); HelpMarker("Apply to regular windows: amount which we enforce to keep visible when moving near edges of your screen.");
8749
            SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); 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).");
8750
8751
            EndTabItem();
8752
        }
8753
8754
        if (BeginTabItem("Colors"))
8755
        {
8756
            static int output_dest = 0;
8757
            static bool output_only_modified = true;
8758
            if (Button("Export"))
8759
            {
8760
                if (output_dest == 0)
8761
                    LogToClipboard();
8762
                else
8763
                    LogToTTY();
8764
                LogText("ImVec4* colors = GetStyle().Colors;" IM_NEWLINE);
8765
                for (int i = 0; i < ImGuiCol_COUNT; i++)
8766
                {
8767
                    const ImVec4& col = style.Colors[i];
8768
                    const char* name = GetStyleColorName(i);
8769
                    if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0)
8770
                        LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE,
8771
                            name, 23 - (int)strlen(name), "", col.x, col.y, col.z, col.w);
8772
                }
8773
                LogFinish();
8774
            }
8775
            SameLine(); SetNextItemWidth(GetFontSize() * 10); Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0");
8776
            SameLine(); Checkbox("Only Modified Colors", &output_only_modified);
8777
8778
            static ImGuiTextFilter filter;
8779
            filter.Draw("Filter colors", GetFontSize() * 16);
8780
8781
            static ImGuiColorEditFlags alpha_flags = 0;
8782
            if (RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_AlphaOpaque))       { alpha_flags = ImGuiColorEditFlags_AlphaOpaque; } SameLine();
8783
            if (RadioButton("Alpha",  alpha_flags == ImGuiColorEditFlags_None))              { alpha_flags = ImGuiColorEditFlags_None; } SameLine();
8784
            if (RadioButton("Both",   alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf))  { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } SameLine();
8785
            HelpMarker(
8786
                "In the color list:\n"
8787
                "Left-click on color square to open color picker,\n"
8788
                "Right-click to open edit options menu.");
8789
8790
            SetNextWindowSizeConstraints(ImVec2(0.0f, GetTextLineHeightWithSpacing() * 10), ImVec2(FLT_MAX, FLT_MAX));
8791
            BeginChild("##colors", ImVec2(0, 0), ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar);
8792
            PushItemWidth(GetFontSize() * -12);
8793
            for (int i = 0; i < ImGuiCol_COUNT; i++)
8794
            {
8795
                const char* name = GetStyleColorName(i);
8796
                if (!filter.PassFilter(name))
8797
                    continue;
8798
                PushID(i);
8799
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
8800
                if (Button("?"))
8801
                    DebugFlashStyleColor((ImGuiCol)i);
8802
                SetItemTooltip("Flash given color to identify places where it is used.");
8803
                SameLine();
8804
#endif
8805
                ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags);
8806
                if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0)
8807
                {
8808
                    // Tips: in a real user application, you may want to merge and use an icon font into the main font,
8809
                    // so instead of "Save"/"Revert" you'd use icons!
8810
                    // Read the FAQ and docs/FONTS.md about using icon fonts. It's really easy and super convenient!
8811
                    SameLine(0.0f, style.ItemInnerSpacing.x); if (Button("Save")) { ref->Colors[i] = style.Colors[i]; }
8812
                    SameLine(0.0f, style.ItemInnerSpacing.x); if (Button("Revert")) { style.Colors[i] = ref->Colors[i]; }
8813
                }
8814
                SameLine(0.0f, style.ItemInnerSpacing.x);
8815
                TextUnformatted(name);
8816
                PopID();
8817
            }
8818
            PopItemWidth();
8819
            EndChild();
8820
8821
            EndTabItem();
8822
        }
8823
8824
        if (BeginTabItem("Fonts"))
8825
        {
8826
            ImGuiIO& io = GetIO();
8827
            ImFontAtlas* atlas = io.Fonts;
8828
            ShowFontAtlas(atlas);
8829
8830
            // Post-baking font scaling. Note that this is NOT the nice way of scaling fonts, read below.
8831
            // (we enforce hard clamping manually as by default DragFloat/SliderFloat allows Ctrl+Click text to get out of bounds).
8832
            /*
8833
            SeparatorText("Legacy Scaling");
8834
            const float MIN_SCALE = 0.3f;
8835
            const float MAX_SCALE = 2.0f;
8836
            HelpMarker(
8837
                "Those are old settings provided for convenience.\n"
8838
                "However, the _correct_ way of scaling your UI is currently to reload your font at the designed size, "
8839
                "rebuild the font atlas, and call style.ScaleAllSizes() on a reference ImGuiStyle structure.\n"
8840
                "Using those settings here will give you poor quality results.");
8841
            PushItemWidth(GetFontSize() * 8);
8842
            DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp); // Scale everything
8843
            //static float window_scale = 1.0f;
8844
            //if (DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp)) // Scale only this window
8845
            //    SetWindowFontScale(window_scale);
8846
            PopItemWidth();
8847
            */
8848
8849
            EndTabItem();
8850
        }
8851
8852
        if (BeginTabItem("Rendering"))
8853
        {
8854
            Checkbox("Anti-aliased lines", &style.AntiAliasedLines);
8855
            SameLine();
8856
            HelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well.");
8857
8858
            Checkbox("Anti-aliased lines use texture", &style.AntiAliasedLinesUseTex);
8859
            SameLine();
8860
            HelpMarker("Faster lines using texture data. Require backend to render with bilinear filtering (not point/nearest filtering).");
8861
8862
            Checkbox("Anti-aliased fill", &style.AntiAliasedFill);
8863
            PushItemWidth(GetFontSize() * 8);
8864
            DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, 10.0f, "%.2f");
8865
            if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f;
8866
8867
            // When editing the "Circle Segment Max Error" value, draw a preview of its effect on auto-tessellated circles.
8868
            DragFloat("Circle Tessellation Max Error", &style.CircleTessellationMaxError , 0.005f, 0.10f, 5.0f, "%.2f", ImGuiSliderFlags_AlwaysClamp);
8869
            const bool show_samples = IsItemActive();
8870
            if (show_samples)
8871
                SetNextWindowPos(GetCursorScreenPos());
8872
            if (show_samples && BeginTooltip())
8873
            {
8874
                TextUnformatted("(R = radius, N = approx number of segments)");
8875
                Spacing();
8876
                ImDrawList* draw_list = GetWindowDrawList();
8877
                const float min_widget_width = CalcTextSize("R: MMM\nN: MMM").x;
8878
                for (int n = 0; n < 8; n++)
8879
                {
8880
                    const float RAD_MIN = 5.0f;
8881
                    const float RAD_MAX = 70.0f;
8882
                    const float rad = RAD_MIN + (RAD_MAX - RAD_MIN) * (float)n / (8.0f - 1.0f);
8883
8884
                    BeginGroup();
8885
8886
                    // N is not always exact here due to how PathArcTo() function work internally
8887
                    Text("R: %.f\nN: %d", rad, draw_list->_CalcCircleAutoSegmentCount(rad));
8888
8889
                    const float canvas_width = IM_MAX(min_widget_width, rad * 2.0f);
8890
                    const float offset_x     = floorf(canvas_width * 0.5f);
8891
                    const float offset_y     = floorf(RAD_MAX);
8892
8893
                    const ImVec2 p1 = GetCursorScreenPos();
8894
                    draw_list->AddCircle(ImVec2(p1.x + offset_x, p1.y + offset_y), rad, GetColorU32(ImGuiCol_Text));
8895
                    Dummy(ImVec2(canvas_width, RAD_MAX * 2));
8896
8897
                    /*
8898
                    const ImVec2 p2 = GetCursorScreenPos();
8899
                    draw_list->AddCircleFilled(ImVec2(p2.x + offset_x, p2.y + offset_y), rad, GetColorU32(ImGuiCol_Text));
8900
                    Dummy(ImVec2(canvas_width, RAD_MAX * 2));
8901
                    */
8902
8903
                    EndGroup();
8904
                    SameLine();
8905
                }
8906
                EndTooltip();
8907
            }
8908
            SameLine();
8909
            HelpMarker("When drawing circle primitives with \"num_segments == 0\" tessellation will be calculated automatically.");
8910
8911
            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.
8912
            DragFloat("Disabled Alpha", &style.DisabledAlpha, 0.005f, 0.0f, 1.0f, "%.2f"); SameLine(); HelpMarker("Additional alpha multiplier for disabled items (multiply over current value of Alpha).");
8913
            PopItemWidth();
8914
8915
            EndTabItem();
8916
        }
8917
8918
        EndTabBar();
8919
    }
8920
    PopItemWidth();
8921
}
8922
8923
//-----------------------------------------------------------------------------
8924
// [SECTION] User Guide / ShowUserGuide()
8925
//-----------------------------------------------------------------------------
8926
8927
// We omit the ImGui:: prefix in this function, as we don't expect user to be copy and pasting this code.
8928
void ImGui::ShowUserGuide()
8929
{
8930
    ImGuiIO& io = GetIO();
8931
    BulletText("Double-click on title bar to collapse window.");
8932
    BulletText(
8933
        "Click and drag on lower corner or border to resize window.\n"
8934
        "(double-click to auto fit window to its contents)");
8935
    BulletText("Ctrl+Click on a slider or drag box to input value as text.");
8936
    BulletText("Tab/Shift+Tab to cycle through keyboard editable fields.");
8937
    BulletText("Ctrl+Tab/Ctrl+Shift+Tab to focus windows.");
8938
    if (io.FontAllowUserScaling)
8939
        BulletText("Ctrl+Mouse Wheel to zoom window contents.");
8940
    BulletText("While inputting text:\n");
8941
    Indent();
8942
    BulletText("Ctrl+Left/Right to word jump.");
8943
    BulletText("Ctrl+A or double-click to select all.");
8944
    BulletText("Ctrl+X/C/V to use clipboard cut/copy/paste.");
8945
    BulletText("Ctrl+Z to undo, Ctrl+Y/Ctrl+Shift+Z to redo.");
8946
    BulletText("Escape to revert.");
8947
    Unindent();
8948
    BulletText("With Keyboard controls enabled:");
8949
    Indent();
8950
    BulletText("Arrow keys or Home/End/PageUp/PageDown to navigate.");
8951
    BulletText("Space to activate a widget.");
8952
    BulletText("Return to input text into a widget.");
8953
    BulletText("Escape to deactivate a widget, close popup,\nexit a child window or the menu layer, clear focus.");
8954
    BulletText("Alt to jump to the menu layer of a window.");
8955
    BulletText("Menu or Shift+F10 to open a context menu.");
8956
    Unindent();
8957
    BulletText("With Gamepad controls enabled:");
8958
    Indent();
8959
    BulletText("D-Pad: Navigate / Tweak / Resize (in Windowing mode).");
8960
    BulletText("%s Face button: Activate / Open / Toggle. Hold: activate with text input.", io.ConfigNavSwapGamepadButtons ? "East" : "South");
8961
    BulletText("%s Face button: Cancel / Close / Exit.", io.ConfigNavSwapGamepadButtons ? "South" : "East");
8962
    BulletText("West Face button: Toggle Menu. Hold for Windowing mode (Focus/Move/Resize windows).");
8963
    BulletText("North Face button: Open Context Menu.");
8964
    BulletText("L1/R1: Tweak Slower/Faster, Focus Previous/Next (in Windowing Mode).");
8965
    Unindent();
8966
}
8967
8968
//-----------------------------------------------------------------------------
8969
// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar()
8970
//-----------------------------------------------------------------------------
8971
// - ShowExampleAppMainMenuBar()
8972
// - ShowExampleMenuFile()
8973
//-----------------------------------------------------------------------------
8974
8975
// Demonstrate creating a "main" fullscreen menu bar and populating it.
8976
// Note the difference between BeginMainMenuBar() and BeginMenuBar():
8977
// - BeginMenuBar() = menu-bar inside current window (which needs the ImGuiWindowFlags_MenuBar flag!)
8978
// - BeginMainMenuBar() = helper to create menu-bar-sized window at the top of the main viewport + call BeginMenuBar() into it.
8979
static void ShowExampleAppMainMenuBar()
8980
{
8981
    if (ImGui::BeginMainMenuBar())
8982
    {
8983
        if (ImGui::BeginMenu("File"))
8984
        {
8985
            IMGUI_DEMO_MARKER("Menu/File");
8986
            ShowExampleMenuFile();
8987
            ImGui::EndMenu();
8988
        }
8989
        if (ImGui::BeginMenu("Edit"))
8990
        {
8991
            IMGUI_DEMO_MARKER("Menu/Edit");
8992
            if (ImGui::MenuItem("Undo", "Ctrl+Z")) {}
8993
            if (ImGui::MenuItem("Redo", "Ctrl+Y", false, false)) {} // Disabled item
8994
            ImGui::Separator();
8995
            if (ImGui::MenuItem("Cut", "Ctrl+X")) {}
8996
            if (ImGui::MenuItem("Copy", "Ctrl+C")) {}
8997
            if (ImGui::MenuItem("Paste", "Ctrl+V")) {}
8998
            ImGui::EndMenu();
8999
        }
9000
        ImGui::EndMainMenuBar();
9001
    }
9002
}
9003
9004
// Note that shortcuts are currently provided for display only
9005
// (future version will add explicit flags to BeginMenu() to request processing shortcuts)
9006
static void ShowExampleMenuFile()
9007
{
9008
    IMGUI_DEMO_MARKER("Examples/Menu");
9009
    ImGui::MenuItem("(demo menu)", NULL, false, false);
9010
    if (ImGui::MenuItem("New")) {}
9011
    if (ImGui::MenuItem("Open", "Ctrl+O")) {}
9012
    if (ImGui::BeginMenu("Open Recent"))
9013
    {
9014
        ImGui::MenuItem("fish_hat.c");
9015
        ImGui::MenuItem("fish_hat.inl");
9016
        ImGui::MenuItem("fish_hat.h");
9017
        if (ImGui::BeginMenu("More.."))
9018
        {
9019
            ImGui::MenuItem("Hello");
9020
            ImGui::MenuItem("Sailor");
9021
            if (ImGui::BeginMenu("Recurse.."))
9022
            {
9023
                ShowExampleMenuFile();
9024
                ImGui::EndMenu();
9025
            }
9026
            ImGui::EndMenu();
9027
        }
9028
        ImGui::EndMenu();
9029
    }
9030
    if (ImGui::MenuItem("Save", "Ctrl+S")) {}
9031
    if (ImGui::MenuItem("Save As..")) {}
9032
9033
    ImGui::Separator();
9034
    if (ImGui::BeginMenu("Options"))
9035
    {
9036
        IMGUI_DEMO_MARKER("Examples/Menu/Options");
9037
        static bool enabled = true;
9038
        ImGui::MenuItem("Enabled", "", &enabled);
9039
        ImGui::BeginChild("child", ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 5.0f), ImGuiChildFlags_Borders);
9040
        for (int i = 0; i < 10; i++)
9041
            ImGui::Text("Scrolling Text %d", i);
9042
        ImGui::EndChild();
9043
        static float f = 0.5f;
9044
        static int n = 0;
9045
        ImGui::SliderFloat("Value", &f, 0.0f, 1.0f);
9046
        ImGui::InputFloat("Input", &f, 0.1f);
9047
        ImGui::Combo("Combo", &n, "Yes\0No\0Maybe\0\0");
9048
        ImGui::EndMenu();
9049
    }
9050
9051
    if (ImGui::BeginMenu("Colors"))
9052
    {
9053
        IMGUI_DEMO_MARKER("Examples/Menu/Colors");
9054
        float sz = ImGui::GetTextLineHeight();
9055
        for (int i = 0; i < ImGuiCol_COUNT; i++)
9056
        {
9057
            const char* name = ImGui::GetStyleColorName((ImGuiCol)i);
9058
            ImVec2 p = ImGui::GetCursorScreenPos();
9059
            ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + sz, p.y + sz), ImGui::GetColorU32((ImGuiCol)i));
9060
            ImGui::Dummy(ImVec2(sz, sz));
9061
            ImGui::SameLine();
9062
            ImGui::MenuItem(name);
9063
        }
9064
        ImGui::EndMenu();
9065
    }
9066
9067
    // Here we demonstrate appending again to the "Options" menu (which we already created above)
9068
    // Of course in this demo it is a little bit silly that this function calls BeginMenu("Options") twice.
9069
    // In a real code-base using it would make senses to use this feature from very different code locations.
9070
    if (ImGui::BeginMenu("Options")) // <-- Append!
9071
    {
9072
        IMGUI_DEMO_MARKER("Examples/Menu/Append to an existing menu");
9073
        static bool b = true;
9074
        ImGui::Checkbox("SomeOption", &b);
9075
        ImGui::EndMenu();
9076
    }
9077
9078
    if (ImGui::BeginMenu("Disabled", false)) // Disabled
9079
    {
9080
        IM_ASSERT(0);
9081
    }
9082
    if (ImGui::MenuItem("Checked", NULL, true)) {}
9083
    ImGui::Separator();
9084
    if (ImGui::MenuItem("Quit", "Alt+F4")) {}
9085
}
9086
9087
//-----------------------------------------------------------------------------
9088
// [SECTION] Example App: Debug Console / ShowExampleAppConsole()
9089
//-----------------------------------------------------------------------------
9090
9091
// Demonstrate creating a simple console window, with scrolling, filtering, completion and history.
9092
// For the console example, we are using a more C++ like approach of declaring a class to hold both data and functions.
9093
struct ExampleAppConsole
9094
{
9095
    char                  InputBuf[256];
9096
    ImVector<char*>       Items;
9097
    ImVector<const char*> Commands;
9098
    ImVector<char*>       History;
9099
    int                   HistoryPos;    // -1: new line, 0..History.Size-1 browsing history.
9100
    ImGuiTextFilter       Filter;
9101
    bool                  AutoScroll;
9102
    bool                  ScrollToBottom;
9103
9104
    ExampleAppConsole()
9105
    {
9106
        ClearLog();
9107
        memset(InputBuf, 0, sizeof(InputBuf));
9108
        HistoryPos = -1;
9109
9110
        // "CLASSIFY" is here to provide the test case where "C"+[tab] completes to "CL" and display multiple matches.
9111
        Commands.push_back("HELP");
9112
        Commands.push_back("HISTORY");
9113
        Commands.push_back("CLEAR");
9114
        Commands.push_back("CLASSIFY");
9115
        AutoScroll = true;
9116
        ScrollToBottom = false;
9117
        AddLog("Welcome to Dear ImGui!");
9118
    }
9119
    ~ExampleAppConsole()
9120
    {
9121
        ClearLog();
9122
        for (int i = 0; i < History.Size; i++)
9123
            ImGui::MemFree(History[i]);
9124
    }
9125
9126
    // Portable helpers
9127
    static int   Stricmp(const char* s1, const char* s2)         { int d; while ((d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; } return d; }
9128
    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; }
9129
    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); }
9130
    static void  Strtrim(char* s)                                { char* str_end = s + strlen(s); while (str_end > s && str_end[-1] == ' ') str_end--; *str_end = 0; }
9131
9132
    void    ClearLog()
9133
    {
9134
        for (int i = 0; i < Items.Size; i++)
9135
            ImGui::MemFree(Items[i]);
9136
        Items.clear();
9137
    }
9138
9139
    void    AddLog(const char* fmt, ...) IM_FMTARGS(2)
9140
    {
9141
        // FIXME-OPT
9142
        char buf[1024];
9143
        va_list args;
9144
        va_start(args, fmt);
9145
        vsnprintf(buf, IM_COUNTOF(buf), fmt, args);
9146
        buf[IM_COUNTOF(buf)-1] = 0;
9147
        va_end(args);
9148
        Items.push_back(Strdup(buf));
9149
    }
9150
9151
    void    Draw(const char* title, bool* p_open)
9152
    {
9153
        ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
9154
        if (!ImGui::Begin(title, p_open))
9155
        {
9156
            ImGui::End();
9157
            return;
9158
        }
9159
        IMGUI_DEMO_MARKER("Examples/Console");
9160
9161
        // As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar.
9162
        // So e.g. IsItemHovered() will return true when hovering the title bar.
9163
        // Here we create a context menu only available from the title bar.
9164
        if (ImGui::BeginPopupContextItem())
9165
        {
9166
            if (ImGui::MenuItem("Close Console"))
9167
                *p_open = false;
9168
            ImGui::EndPopup();
9169
        }
9170
9171
        ImGui::TextWrapped(
9172
            "This example implements a console with basic coloring, completion (TAB key) and history (Up/Down keys). A more elaborate "
9173
            "implementation may want to store entries along with extra data such as timestamp, emitter, etc.");
9174
        ImGui::TextWrapped("Enter 'HELP' for help.");
9175
9176
        // TODO: display items starting from the bottom
9177
9178
        if (ImGui::SmallButton("Add Debug Text"))  { AddLog("%d some text", Items.Size); AddLog("some more text"); AddLog("display very important message here!"); }
9179
        ImGui::SameLine();
9180
        if (ImGui::SmallButton("Add Debug Error")) { AddLog("[error] something went wrong"); }
9181
        ImGui::SameLine();
9182
        if (ImGui::SmallButton("Clear"))           { ClearLog(); }
9183
        ImGui::SameLine();
9184
        bool copy_to_clipboard = ImGui::SmallButton("Copy");
9185
        //static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); }
9186
9187
        ImGui::Separator();
9188
9189
        // Options menu
9190
        if (ImGui::BeginPopup("Options"))
9191
        {
9192
            ImGui::Checkbox("Auto-scroll", &AutoScroll);
9193
            ImGui::EndPopup();
9194
        }
9195
9196
        // Options, Filter
9197
        ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_O, ImGuiInputFlags_Tooltip);
9198
        if (ImGui::Button("Options"))
9199
            ImGui::OpenPopup("Options");
9200
        ImGui::SameLine();
9201
        Filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180);
9202
        ImGui::Separator();
9203
9204
        // Reserve enough left-over height for 1 separator + 1 input text
9205
        ImGuiStyle& style = ImGui::GetStyle();
9206
        const float footer_height_to_reserve = style.SeparatorSize + style.ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
9207
        if (ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_HorizontalScrollbar))
9208
        {
9209
            if (ImGui::BeginPopupContextWindow())
9210
            {
9211
                if (ImGui::Selectable("Clear")) ClearLog();
9212
                ImGui::EndPopup();
9213
            }
9214
9215
            // Display every line as a separate entry so we can change their color or add custom widgets.
9216
            // If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end());
9217
            // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping
9218
            // to only process visible items. The clipper will automatically measure the height of your first item and then
9219
            // "seek" to display only items in the visible area.
9220
            // To use the clipper we can replace your standard loop:
9221
            //      for (int i = 0; i < Items.Size; i++)
9222
            //   With:
9223
            //      ImGuiListClipper clipper;
9224
            //      clipper.Begin(Items.Size);
9225
            //      while (clipper.Step())
9226
            //         for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
9227
            // - That your items are evenly spaced (same height)
9228
            // - That you have cheap random access to your elements (you can access them given their index,
9229
            //   without processing all the ones before)
9230
            // You cannot this code as-is if a filter is active because it breaks the 'cheap random-access' property.
9231
            // We would need random-access on the post-filtered list.
9232
            // A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices
9233
            // or offsets of items that passed the filtering test, recomputing this array when user changes the filter,
9234
            // and appending newly elements as they are inserted. This is left as a task to the user until we can manage
9235
            // to improve this example code!
9236
            // If your items are of variable height:
9237
            // - Split them into same height items would be simpler and facilitate random-seeking into your list.
9238
            // - Consider using manual call to IsRectVisible() and skipping extraneous decoration from your items.
9239
            ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing
9240
            if (copy_to_clipboard)
9241
                ImGui::LogToClipboard();
9242
            for (const char* item : Items)
9243
            {
9244
                if (!Filter.PassFilter(item))
9245
                    continue;
9246
9247
                // Normally you would store more information in your item than just a string.
9248
                // (e.g. make Items[] an array of structure, store color/type etc.)
9249
                ImVec4 color;
9250
                bool has_color = false;
9251
                if (strstr(item, "[error]")) { color = ImVec4(1.0f, 0.4f, 0.4f, 1.0f); has_color = true; }
9252
                else if (strncmp(item, "# ", 2) == 0) { color = ImVec4(1.0f, 0.8f, 0.6f, 1.0f); has_color = true; }
9253
                if (has_color)
9254
                    ImGui::PushStyleColor(ImGuiCol_Text, color);
9255
                ImGui::TextUnformatted(item);
9256
                if (has_color)
9257
                    ImGui::PopStyleColor();
9258
            }
9259
            if (copy_to_clipboard)
9260
                ImGui::LogFinish();
9261
9262
            // Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame.
9263
            // Using a scrollbar or mouse-wheel will take away from the bottom edge.
9264
            if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()))
9265
                ImGui::SetScrollHereY(1.0f);
9266
            ScrollToBottom = false;
9267
9268
            ImGui::PopStyleVar();
9269
        }
9270
        ImGui::EndChild();
9271
        ImGui::Separator();
9272
9273
        // Command-line
9274
        bool reclaim_focus = false;
9275
        ImGuiInputTextFlags input_text_flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_EscapeClearsAll | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory;
9276
        if (ImGui::InputText("Input", InputBuf, IM_COUNTOF(InputBuf), input_text_flags, &TextEditCallbackStub, (void*)this))
9277
        {
9278
            char* s = InputBuf;
9279
            Strtrim(s);
9280
            if (s[0])
9281
                ExecCommand(s);
9282
            strcpy(s, "");
9283
            reclaim_focus = true;
9284
        }
9285
9286
        // Auto-focus on window apparition
9287
        ImGui::SetItemDefaultFocus();
9288
        if (reclaim_focus)
9289
            ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget
9290
9291
        ImGui::End();
9292
    }
9293
9294
    void    ExecCommand(const char* command_line)
9295
    {
9296
        AddLog("# %s\n", command_line);
9297
9298
        // Insert into history. First find match and delete it so it can be pushed to the back.
9299
        // This isn't trying to be smart or optimal.
9300
        HistoryPos = -1;
9301
        for (int i = History.Size - 1; i >= 0; i--)
9302
            if (Stricmp(History[i], command_line) == 0)
9303
            {
9304
                ImGui::MemFree(History[i]);
9305
                History.erase(History.begin() + i);
9306
                break;
9307
            }
9308
        History.push_back(Strdup(command_line));
9309
9310
        // Process command
9311
        if (Stricmp(command_line, "CLEAR") == 0)
9312
        {
9313
            ClearLog();
9314
        }
9315
        else if (Stricmp(command_line, "HELP") == 0)
9316
        {
9317
            AddLog("Commands:");
9318
            for (int i = 0; i < Commands.Size; i++)
9319
                AddLog("- %s", Commands[i]);
9320
        }
9321
        else if (Stricmp(command_line, "HISTORY") == 0)
9322
        {
9323
            int first = History.Size - 10;
9324
            for (int i = first > 0 ? first : 0; i < History.Size; i++)
9325
                AddLog("%3d: %s\n", i, History[i]);
9326
        }
9327
        else
9328
        {
9329
            AddLog("Unknown command: '%s'\n", command_line);
9330
        }
9331
9332
        // On command input, we scroll to bottom even if AutoScroll==false
9333
        ScrollToBottom = true;
9334
    }
9335
9336
    // In C++11 you'd be better off using lambdas for this sort of forwarding callbacks
9337
    static int TextEditCallbackStub(ImGuiInputTextCallbackData* data)
9338
    {
9339
        ExampleAppConsole* console = (ExampleAppConsole*)data->UserData;
9340
        return console->TextEditCallback(data);
9341
    }
9342
9343
    int     TextEditCallback(ImGuiInputTextCallbackData* data)
9344
    {
9345
        //AddLog("cursor: %d, selection: %d-%d", data->CursorPos, data->SelectionStart, data->SelectionEnd);
9346
        switch (data->EventFlag)
9347
        {
9348
        case ImGuiInputTextFlags_CallbackCompletion:
9349
            {
9350
                // Example of TEXT COMPLETION
9351
9352
                // Locate beginning of current word
9353
                const char* word_end = data->Buf + data->CursorPos;
9354
                const char* word_start = word_end;
9355
                while (word_start > data->Buf)
9356
                {
9357
                    const char c = word_start[-1];
9358
                    if (c == ' ' || c == '\t' || c == ',' || c == ';')
9359
                        break;
9360
                    word_start--;
9361
                }
9362
9363
                // Build a list of candidates
9364
                ImVector<const char*> candidates;
9365
                for (int i = 0; i < Commands.Size; i++)
9366
                    if (Strnicmp(Commands[i], word_start, (int)(word_end - word_start)) == 0)
9367
                        candidates.push_back(Commands[i]);
9368
9369
                if (candidates.Size == 0)
9370
                {
9371
                    // No match
9372
                    AddLog("No match for \"%.*s\"!\n", (int)(word_end - word_start), word_start);
9373
                }
9374
                else if (candidates.Size == 1)
9375
                {
9376
                    // Single match. Delete the beginning of the word and replace it entirely so we've got nice casing.
9377
                    data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start));
9378
                    data->InsertChars(data->CursorPos, candidates[0]);
9379
                    data->InsertChars(data->CursorPos, " ");
9380
                }
9381
                else
9382
                {
9383
                    // Multiple matches. Complete as much as we can..
9384
                    // So inputting "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches.
9385
                    int match_len = (int)(word_end - word_start);
9386
                    for (;;)
9387
                    {
9388
                        int c = 0;
9389
                        bool all_candidates_matches = true;
9390
                        for (int i = 0; i < candidates.Size && all_candidates_matches; i++)
9391
                            if (i == 0)
9392
                                c = toupper(candidates[i][match_len]);
9393
                            else if (c == 0 || c != toupper(candidates[i][match_len]))
9394
                                all_candidates_matches = false;
9395
                        if (!all_candidates_matches)
9396
                            break;
9397
                        match_len++;
9398
                    }
9399
9400
                    if (match_len > 0)
9401
                    {
9402
                        data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start));
9403
                        data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len);
9404
                    }
9405
9406
                    // List matches
9407
                    AddLog("Possible matches:\n");
9408
                    for (int i = 0; i < candidates.Size; i++)
9409
                        AddLog("- %s\n", candidates[i]);
9410
                }
9411
9412
                break;
9413
            }
9414
        case ImGuiInputTextFlags_CallbackHistory:
9415
            {
9416
                // Example of HISTORY
9417
                const int prev_history_pos = HistoryPos;
9418
                if (data->EventKey == ImGuiKey_UpArrow)
9419
                {
9420
                    if (HistoryPos == -1)
9421
                        HistoryPos = History.Size - 1;
9422
                    else if (HistoryPos > 0)
9423
                        HistoryPos--;
9424
                }
9425
                else if (data->EventKey == ImGuiKey_DownArrow)
9426
                {
9427
                    if (HistoryPos != -1)
9428
                        if (++HistoryPos >= History.Size)
9429
                            HistoryPos = -1;
9430
                }
9431
9432
                // A better implementation would preserve the data on the current input line along with cursor position.
9433
                if (prev_history_pos != HistoryPos)
9434
                {
9435
                    const char* history_str = (HistoryPos >= 0) ? History[HistoryPos] : "";
9436
                    data->DeleteChars(0, data->BufTextLen);
9437
                    data->InsertChars(0, history_str);
9438
                }
9439
            }
9440
        }
9441
        return 0;
9442
    }
9443
};
9444
9445
static void ShowExampleAppConsole(bool* p_open)
9446
{
9447
    static ExampleAppConsole console;
9448
    console.Draw("Example: Console", p_open);
9449
}
9450
9451
//-----------------------------------------------------------------------------
9452
// [SECTION] Example App: Image Viewer / ShowExampleAppImageViewer()
9453
//-----------------------------------------------------------------------------
9454
9455
static void ShowExampleAppImageViewer(bool* p_open)
9456
{
9457
    ImFontAtlas* atlas = ImGui::GetIO().Fonts;
9458
    ImTextureRef tex_ref = atlas->TexRef; // We don't have access to other textures in this demo!
9459
    int tex_w = atlas->TexData->Width;
9460
    int tex_h = atlas->TexData->Height;
9461
    if (ImGui::Begin("Example: Image Viewer", p_open))
9462
    {
9463
        static ExampleImageViewerData image_viewer;
9464
        ExampleImageViewer_DrawOptions(&image_viewer);
9465
        ImVec2 canvas_size = ImGui::GetContentRegionAvail();
9466
        ImVec2 canvas_min_size = ImGui::IsWindowAppearing() ? ImVec2(3.0f * tex_w, 4.0f * tex_h) : ImVec2(1.0f, 1.0f);
9467
        canvas_size = ImVec2(IM_MAX(canvas_size.x, canvas_min_size.x), IM_MAX(canvas_size.y, canvas_min_size.y));
9468
        ExampleImageViewer_DrawCanvas(&image_viewer, canvas_size, tex_ref, tex_w, tex_h);
9469
    }
9470
    ImGui::End();
9471
}
9472
9473
//-----------------------------------------------------------------------------
9474
// [SECTION] Example App: Debug Log / ShowExampleAppLog()
9475
//-----------------------------------------------------------------------------
9476
9477
// Usage:
9478
//  static ExampleAppLog my_log;
9479
//  my_log.AddLog("Hello %d world\n", 123);
9480
//  my_log.Draw("title");
9481
struct ExampleAppLog
9482
{
9483
    ImGuiTextBuffer     Buf;
9484
    ImGuiTextFilter     Filter;
9485
    ImVector<int>       LineOffsets; // Index to lines offset. We maintain this with AddLog() calls.
9486
    bool                AutoScroll;  // Keep scrolling if already at the bottom.
9487
9488
    ExampleAppLog()
9489
    {
9490
        AutoScroll = true;
9491
        Clear();
9492
    }
9493
9494
    void    Clear()
9495
    {
9496
        Buf.clear();
9497
        LineOffsets.clear();
9498
        LineOffsets.push_back(0);
9499
    }
9500
9501
    void    AddLog(const char* fmt, ...) IM_FMTARGS(2)
9502
    {
9503
        int old_size = Buf.size();
9504
        va_list args;
9505
        va_start(args, fmt);
9506
        Buf.appendfv(fmt, args);
9507
        va_end(args);
9508
        for (int new_size = Buf.size(); old_size < new_size; old_size++)
9509
            if (Buf[old_size] == '\n')
9510
                LineOffsets.push_back(old_size + 1);
9511
    }
9512
9513
    void    Draw(const char* title, bool* p_open = NULL)
9514
    {
9515
        if (!ImGui::Begin(title, p_open))
9516
        {
9517
            ImGui::End();
9518
            return;
9519
        }
9520
9521
        // Options menu
9522
        if (ImGui::BeginPopup("Options"))
9523
        {
9524
            ImGui::Checkbox("Auto-scroll", &AutoScroll);
9525
            ImGui::EndPopup();
9526
        }
9527
9528
        // Main window
9529
        if (ImGui::Button("Options"))
9530
            ImGui::OpenPopup("Options");
9531
        ImGui::SameLine();
9532
        bool clear = ImGui::Button("Clear");
9533
        ImGui::SameLine();
9534
        bool copy = ImGui::Button("Copy");
9535
        ImGui::SameLine();
9536
        Filter.Draw("Filter", -100.0f);
9537
9538
        ImGui::Separator();
9539
9540
        if (ImGui::BeginChild("scrolling", ImVec2(0, 0), ImGuiChildFlags_None, ImGuiWindowFlags_HorizontalScrollbar))
9541
        {
9542
            if (clear)
9543
                Clear();
9544
            if (copy)
9545
                ImGui::LogToClipboard();
9546
9547
            ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
9548
            const char* buf = Buf.begin();
9549
            const char* buf_end = Buf.end();
9550
            if (Filter.IsActive())
9551
            {
9552
                // In this example we don't use the clipper when Filter is enabled.
9553
                // This is because we don't have random access to the result of our filter.
9554
                // A real application processing logs with ten of thousands of entries may want to store the result of
9555
                // search/filter.. especially if the filtering function is not trivial (e.g. reg-exp).
9556
                for (int line_no = 0; line_no < LineOffsets.Size; line_no++)
9557
                {
9558
                    const char* line_start = buf + LineOffsets[line_no];
9559
                    const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
9560
                    if (Filter.PassFilter(line_start, line_end))
9561
                        ImGui::TextUnformatted(line_start, line_end);
9562
                }
9563
            }
9564
            else
9565
            {
9566
                // The simplest and easy way to display the entire buffer:
9567
                //   ImGui::TextUnformatted(buf_begin, buf_end);
9568
                // And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward
9569
                // to skip non-visible lines. Here we instead demonstrate using the clipper to only process lines that are
9570
                // within the visible area.
9571
                // If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them
9572
                // on your side is recommended. Using ImGuiListClipper requires
9573
                // - A) random access into your data
9574
                // - B) items all being the  same height,
9575
                // both of which we can handle since we have an array pointing to the beginning of each line of text.
9576
                // When using the filter (in the block of code above) we don't have random access into the data to display
9577
                // anymore, which is why we don't use the clipper. Storing or skimming through the search result would make
9578
                // it possible (and would be recommended if you want to search through tens of thousands of entries).
9579
                ImGuiListClipper clipper;
9580
                clipper.Begin(LineOffsets.Size);
9581
                while (clipper.Step())
9582
                {
9583
                    for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++)
9584
                    {
9585
                        const char* line_start = buf + LineOffsets[line_no];
9586
                        const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
9587
                        ImGui::TextUnformatted(line_start, line_end);
9588
                    }
9589
                }
9590
                clipper.End();
9591
            }
9592
            ImGui::PopStyleVar();
9593
9594
            // Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame.
9595
            // Using a scrollbar or mouse-wheel will take away from the bottom edge.
9596
            if (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())
9597
                ImGui::SetScrollHereY(1.0f);
9598
        }
9599
        ImGui::EndChild();
9600
        ImGui::End();
9601
    }
9602
};
9603
9604
// Demonstrate creating a simple log window with basic filtering.
9605
static void ShowExampleAppLog(bool* p_open)
9606
{
9607
    static ExampleAppLog log;
9608
9609
    // For the demo: add a debug button _BEFORE_ the normal log window contents
9610
    // We take advantage of a rarely used feature: multiple calls to Begin()/End() are appending to the _same_ window.
9611
    // Most of the contents of the window will be added by the log.Draw() call.
9612
    ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver);
9613
    ImGui::Begin("Example: Log", p_open);
9614
    IMGUI_DEMO_MARKER("Examples/Log");
9615
    if (ImGui::SmallButton("[Debug] Add 5 entries"))
9616
    {
9617
        static int counter = 0;
9618
        const char* categories[3] = { "info", "warn", "error" };
9619
        const char* words[] = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" };
9620
        for (int n = 0; n < 5; n++)
9621
        {
9622
            const char* category = categories[counter % IM_COUNTOF(categories)];
9623
            const char* word = words[counter % IM_COUNTOF(words)];
9624
            log.AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n",
9625
                ImGui::GetFrameCount(), category, ImGui::GetTime(), word);
9626
            counter++;
9627
        }
9628
    }
9629
    ImGui::End();
9630
9631
    // Actually call in the regular Log helper (which will Begin() into the same window as we just did)
9632
    log.Draw("Example: Log", p_open);
9633
}
9634
9635
//-----------------------------------------------------------------------------
9636
// [SECTION] Example App: Simple Layout / ShowExampleAppLayout()
9637
//-----------------------------------------------------------------------------
9638
9639
// Demonstrate create a window with multiple child windows.
9640
static void ShowExampleAppLayout(bool* p_open)
9641
{
9642
    ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiCond_FirstUseEver);
9643
    if (ImGui::Begin("Example: Simple layout", p_open, ImGuiWindowFlags_MenuBar))
9644
    {
9645
        IMGUI_DEMO_MARKER("Examples/Simple layout");
9646
        if (ImGui::BeginMenuBar())
9647
        {
9648
            if (ImGui::BeginMenu("File"))
9649
            {
9650
                if (ImGui::MenuItem("Close", "Ctrl+W")) { *p_open = false; }
9651
                ImGui::EndMenu();
9652
            }
9653
            ImGui::EndMenuBar();
9654
        }
9655
9656
        // Left
9657
        static int selected = 0;
9658
        {
9659
            ImGui::BeginChild("left pane", ImVec2(150, 0), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeX);
9660
            for (int i = 0; i < 100; i++)
9661
            {
9662
                char label[128];
9663
                sprintf(label, "MyObject %d", i);
9664
                if (ImGui::Selectable(label, selected == i, ImGuiSelectableFlags_SelectOnNav))
9665
                    selected = i;
9666
            }
9667
            ImGui::EndChild();
9668
        }
9669
        ImGui::SameLine();
9670
9671
        // Right
9672
        {
9673
            ImGui::BeginGroup();
9674
            ImGui::BeginChild("item view", ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us
9675
            ImGui::Text("MyObject: %d", selected);
9676
            ImGui::Separator();
9677
            if (ImGui::BeginTabBar("##Tabs", ImGuiTabBarFlags_None))
9678
            {
9679
                if (ImGui::BeginTabItem("Description"))
9680
                {
9681
                    ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ");
9682
                    ImGui::EndTabItem();
9683
                }
9684
                if (ImGui::BeginTabItem("Details"))
9685
                {
9686
                    ImGui::Text("ID: 0123456789");
9687
                    ImGui::EndTabItem();
9688
                }
9689
                ImGui::EndTabBar();
9690
            }
9691
            ImGui::EndChild();
9692
            if (ImGui::Button("Revert")) {}
9693
            ImGui::SameLine();
9694
            if (ImGui::Button("Save")) {}
9695
            ImGui::EndGroup();
9696
        }
9697
    }
9698
    ImGui::End();
9699
}
9700
9701
//-----------------------------------------------------------------------------
9702
// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor()
9703
//-----------------------------------------------------------------------------
9704
// Some of the interactions are a bit lack-luster:
9705
// - We would want pressing validating or leaving the filter to somehow restore focus.
9706
// - We may want more advanced filtering (child nodes) and clipper support: both will need extra work.
9707
// - We would want to customize some keyboard interactions to easily keyboard navigate between the tree and the properties.
9708
//-----------------------------------------------------------------------------
9709
9710
struct ExampleAppPropertyEditor
9711
{
9712
    ImGuiTextFilter     Filter;
9713
    ExampleTreeNode*    SelectedNode = NULL;
9714
    bool                UseClipper = false;
9715
9716
    void Draw(ExampleTreeNode* root_node)
9717
    {
9718
        IMGUI_DEMO_MARKER("Examples/Property editor");
9719
9720
        // Left side: draw tree
9721
        // - Currently using a table to benefit from RowBg feature
9722
        // - Our tree node are all of equal height, facilitating the use of a clipper.
9723
        if (ImGui::BeginChild("##tree", ImVec2(300, 0), ImGuiChildFlags_ResizeX | ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened))
9724
        {
9725
            ImGui::PushItemFlag(ImGuiItemFlags_NoNavDefaultFocus, true);
9726
            ImGui::Checkbox("Use Clipper", &UseClipper);
9727
            ImGui::SameLine();
9728
            ImGui::Text("(%d root nodes)", root_node->Childs.Size);
9729
            ImGui::SetNextItemWidth(-FLT_MIN);
9730
            ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F, ImGuiInputFlags_Tooltip);
9731
            if (ImGui::InputTextWithHint("##Filter", "incl,-excl", Filter.InputBuf, IM_COUNTOF(Filter.InputBuf), ImGuiInputTextFlags_EscapeClearsAll))
9732
                Filter.Build();
9733
            ImGui::PopItemFlag();
9734
9735
            if (ImGui::BeginTable("##list", 1, ImGuiTableFlags_RowBg))
9736
            {
9737
                if (UseClipper)
9738
                    DrawClippedTree(root_node);
9739
                else
9740
                    DrawTree(root_node);
9741
                ImGui::EndTable();
9742
            }
9743
        }
9744
        ImGui::EndChild();
9745
9746
        // Right side: draw properties
9747
        ImGui::SameLine();
9748
9749
        ImGui::BeginGroup(); // Lock X position
9750
        if (ExampleTreeNode* node = SelectedNode)
9751
        {
9752
            ImGui::Text("%s", node->Name);
9753
            ImGui::TextDisabled("UID: 0x%08X", node->UID);
9754
            ImGui::Separator();
9755
            if (ImGui::BeginTable("##properties", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY))
9756
            {
9757
                // Push object ID after we entered the table, so table is shared for all objects
9758
                ImGui::PushID((int)node->UID);
9759
                ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed);
9760
                ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 2.0f); // Default twice larger
9761
                if (node->HasData)
9762
                {
9763
                    // In a typical application, the structure description would be derived from a data-driven system.
9764
                    // - We try to mimic this with our ExampleMemberInfo structure and the ExampleTreeNodeMemberInfos[] array.
9765
                    // - Limits and some details are hard-coded to simplify the demo.
9766
                    for (const ExampleMemberInfo& field_desc : ExampleTreeNodeMemberInfos)
9767
                    {
9768
                        ImGui::TableNextRow();
9769
                        ImGui::PushID(field_desc.Name);
9770
                        ImGui::TableNextColumn();
9771
                        ImGui::AlignTextToFramePadding();
9772
                        ImGui::TextUnformatted(field_desc.Name);
9773
                        ImGui::TableNextColumn();
9774
                        void* field_ptr = (void*)(((unsigned char*)node) + field_desc.Offset);
9775
                        switch (field_desc.DataType)
9776
                        {
9777
                        case ImGuiDataType_Bool:
9778
                        {
9779
                            IM_ASSERT(field_desc.DataCount == 1);
9780
                            ImGui::Checkbox("##Editor", (bool*)field_ptr);
9781
                            break;
9782
                        }
9783
                        case ImGuiDataType_S32:
9784
                        {
9785
                            int v_min = INT_MIN, v_max = INT_MAX;
9786
                            ImGui::SetNextItemWidth(-FLT_MIN);
9787
                            ImGui::DragScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, 1.0f, &v_min, &v_max);
9788
                            break;
9789
                        }
9790
                        case ImGuiDataType_Float:
9791
                        {
9792
                            float v_min = 0.0f, v_max = 1.0f;
9793
                            ImGui::SetNextItemWidth(-FLT_MIN);
9794
                            ImGui::SliderScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, &v_min, &v_max);
9795
                            break;
9796
                        }
9797
                        case ImGuiDataType_String:
9798
                        {
9799
                            ImGui::InputText("##Editor", reinterpret_cast<char*>(field_ptr), 28);
9800
                            break;
9801
                        }
9802
                        }
9803
                        ImGui::PopID();
9804
                    }
9805
                }
9806
                ImGui::PopID();
9807
                ImGui::EndTable();
9808
            }
9809
        }
9810
        ImGui::EndGroup();
9811
    }
9812
9813
    // Custom search filter
9814
    // - Here we apply on root node only.
9815
    // - This does a case insensitive stristr which is pretty heavy. In a real large-scale app you would likely store a filtered list which in turns would be trivial to linearize.
9816
    inline bool IsNodePassingFilter(ExampleTreeNode* node)
9817
    {
9818
        return node->Parent->Parent != NULL || Filter.PassFilter(node->Name);
9819
    }
9820
9821
    // Basic version, recursive. This is how you would generally draw a tree.
9822
    // - Simple but going to be noticeably costly if you have a large amount of nodes as DrawTreeNode() is called for all of them.
9823
    // - On my desktop PC (2020), for 10K nodes in an optimized build this takes ~1.2 ms
9824
    // - Unlike arrays or grids which are very easy to clip, trees are currently more difficult to clip.
9825
    void DrawTree(ExampleTreeNode* node)
9826
    {
9827
        for (ExampleTreeNode* child : node->Childs)
9828
            if (IsNodePassingFilter(child) && DrawTreeNode(child))
9829
            {
9830
                DrawTree(child);
9831
                ImGui::TreePop();
9832
            }
9833
    }
9834
9835
    // More advanced version. Use a alternative clipping technique: fast-forwarding through non-visible chunks.
9836
    // - On my desktop PC (2020), for 10K nodes in an optimized build this takes ~0.1 ms
9837
    //   (in ExampleTree_CreateDemoTree(), change 'int ROOT_ITEMS_COUNT = 10000' to try with this amount of root nodes).
9838
    // - 1. Use clipper with indeterminate count (items_count = INT_MAX): we need to call SeekCursorForItem() at the end once we know the count.
9839
    // - 2. Use SetNextItemStorageID() to specify ID used for open/close storage, making it easy to call TreeNodeGetOpen() on any arbitrary node.
9840
    // - 3. Linearize tree during traversal: our tree data structure makes it easy to access sibling and parents.
9841
    // - Unlike clipping for a regular array or grid which may be done using random access limited to visible areas,
9842
    //   this technique requires traversing most accessible nodes. This could be made more optimal with extra work,
9843
    //   but this is a decent simplicity<>speed trade-off.
9844
    // See https://github.com/ocornut/imgui/issues/3823 for discussions about this.
9845
    void DrawClippedTree(ExampleTreeNode* root_node)
9846
    {
9847
        ExampleTreeNode* node = root_node->Childs[0]; // First node
9848
        ImGuiListClipper clipper;
9849
        clipper.Begin(INT_MAX);
9850
        while (clipper.Step())
9851
            while (clipper.UserIndex < clipper.DisplayEnd && node != NULL)
9852
                node = DrawClippedTreeNodeAndAdvanceToNext(&clipper, node);
9853
9854
        // Keep going to count nodes and submit final count so we have a reliable scrollbar.
9855
        // - One could consider caching this value and only refreshing it occasionally e.g. window is focused and an action occurs.
9856
        // - Incorrect but cheap approximation would be to use 'clipper_current_idx = IM_MAX(clipper_current_idx, root_node->Childs.Size)' instead.
9857
        // - If either of those is implemented, the general cost will approach zero when scrolling is at the top of the tree.
9858
        while (node != NULL)
9859
            node = DrawClippedTreeNodeAndAdvanceToNext(&clipper, node);
9860
        //clipper.UserIndex = IM_MAX(clipper.UserIndex, root_node->Childs.Size); // <-- Cheap approximation instead of while() loop above.
9861
        clipper.SeekCursorForItem(clipper.UserIndex);
9862
    }
9863
9864
    ExampleTreeNode* DrawClippedTreeNodeAndAdvanceToNext(ImGuiListClipper* clipper, ExampleTreeNode* node)
9865
    {
9866
        if (IsNodePassingFilter(node))
9867
        {
9868
            // Draw node if within visible range
9869
            bool is_open = false;
9870
            if (clipper->UserIndex >= clipper->DisplayStart && clipper->UserIndex < clipper->DisplayEnd)
9871
            {
9872
                is_open = DrawTreeNode(node);
9873
            }
9874
            else
9875
            {
9876
                is_open = (node->Childs.Size > 0 && ImGui::TreeNodeGetOpen((ImGuiID)node->UID));
9877
                if (is_open)
9878
                    ImGui::TreePush(node->Name);
9879
            }
9880
            clipper->UserIndex++;
9881
9882
            // Next node: recurse into childs
9883
            if (is_open)
9884
                return node->Childs[0];
9885
        }
9886
9887
        // Next node: next sibling, otherwise move back to parent
9888
        while (node != NULL)
9889
        {
9890
            if (node->IndexInParent + 1 < node->Parent->Childs.Size)
9891
                return node->Parent->Childs[node->IndexInParent + 1];
9892
            node = node->Parent;
9893
            if (node->Parent == NULL)
9894
                break;
9895
            ImGui::TreePop();
9896
        }
9897
        return NULL;
9898
    }
9899
9900
    // To support node with same name we incorporate node->UID into the item ID.
9901
    // (this would more naturally be done using PushID(node->UID) + TreeNodeEx(node->Name, tree_flags),
9902
    //   but it would require in DrawClippedTreeNodeAndAdvanceToNext() to add PushID() before TreePush(), and PopID() after TreePop(),
9903
    //   so instead we use TreeNodeEx(node->UID, tree_flags, "%s", node->Name) here)
9904
    bool DrawTreeNode(ExampleTreeNode* node)
9905
    {
9906
        ImGui::TableNextRow();
9907
        ImGui::TableNextColumn();
9908
        ImGuiTreeNodeFlags tree_flags = ImGuiTreeNodeFlags_None;
9909
        tree_flags |= ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; // Standard opening mode as we are likely to want to add selection afterwards
9910
        tree_flags |= ImGuiTreeNodeFlags_NavLeftJumpsToParent;  // Left arrow support
9911
        tree_flags |= ImGuiTreeNodeFlags_SpanFullWidth;         // Span full width for easier mouse reach
9912
        tree_flags |= ImGuiTreeNodeFlags_DrawLinesToNodes;      // Always draw hierarchy outlines
9913
        if (node == SelectedNode)
9914
            tree_flags |= ImGuiTreeNodeFlags_Selected;          // Draw selection highlight
9915
        if (node->Childs.Size == 0)
9916
            tree_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_NoTreePushOnOpen; // Use _NoTreePushOnOpen + set is_open=false to avoid unnecessarily push/pop on leaves.
9917
        if (node->DataMyBool == false)
9918
            ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]);
9919
        ImGui::SetNextItemStorageID((ImGuiID)node->UID);        // Use node->UID as storage id
9920
        bool is_open = ImGui::TreeNodeEx((void*)(intptr_t)node->UID, tree_flags, "%s", node->Name);
9921
        if (node->Childs.Size == 0)
9922
            is_open = false;
9923
        if (node->DataMyBool == false)
9924
            ImGui::PopStyleColor();
9925
        if (ImGui::IsItemFocused())
9926
            SelectedNode = node;
9927
        return is_open;
9928
    }
9929
};
9930
9931
// Demonstrate creating a simple property editor.
9932
static void ShowExampleAppPropertyEditor(bool* p_open, ImGuiDemoWindowData* demo_data)
9933
{
9934
    ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver);
9935
    if (!ImGui::Begin("Example: Property editor", p_open))
9936
    {
9937
        ImGui::End();
9938
        return;
9939
    }
9940
9941
    IMGUI_DEMO_MARKER("Examples/Property Editor");
9942
    static ExampleAppPropertyEditor property_editor;
9943
    if (demo_data->DemoTree == NULL)
9944
        demo_data->DemoTree = ExampleTree_CreateDemoTree();
9945
    property_editor.Draw(demo_data->DemoTree);
9946
9947
    ImGui::End();
9948
}
9949
9950
//-----------------------------------------------------------------------------
9951
// [SECTION] Example App: Long Text / ShowExampleAppLongText()
9952
//-----------------------------------------------------------------------------
9953
9954
// Demonstrate/test rendering huge amount of text, and the incidence of clipping.
9955
static void ShowExampleAppLongText(bool* p_open)
9956
{
9957
    ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
9958
    if (!ImGui::Begin("Example: Long text display", p_open))
9959
    {
9960
        ImGui::End();
9961
        return;
9962
    }
9963
    IMGUI_DEMO_MARKER("Examples/Long text display");
9964
9965
    static int test_type = 0;
9966
    static ImGuiTextBuffer log;
9967
    static int lines = 0;
9968
    ImGui::Text("Printing unusually long amount of text.");
9969
    ImGui::Combo("Test type", &test_type,
9970
        "Single call to TextUnformatted()\0"
9971
        "Multiple calls to Text(), clipped\0"
9972
        "Multiple calls to Text(), not clipped (slow)\0");
9973
    ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size());
9974
    if (ImGui::Button("Clear")) { log.clear(); lines = 0; }
9975
    ImGui::SameLine();
9976
    if (ImGui::Button("Add 1000 lines"))
9977
    {
9978
        for (int i = 0; i < 1000; i++)
9979
            log.appendf("%i The quick brown fox jumps over the lazy dog\n", lines + i);
9980
        lines += 1000;
9981
    }
9982
    ImGui::BeginChild("Log");
9983
    switch (test_type)
9984
    {
9985
    case 0:
9986
        // Single call to TextUnformatted() with a big buffer
9987
        ImGui::TextUnformatted(log.begin(), log.end());
9988
        break;
9989
    case 1:
9990
        {
9991
            // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper.
9992
            ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
9993
            ImGuiListClipper clipper;
9994
            clipper.Begin(lines);
9995
            while (clipper.Step())
9996
                for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
9997
                    ImGui::Text("%i The quick brown fox jumps over the lazy dog", i);
9998
            ImGui::PopStyleVar();
9999
            break;
10000
        }
10001
    case 2:
10002
        // Multiple calls to Text(), not clipped (slow)
10003
        ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
10004
        for (int i = 0; i < lines; i++)
10005
            ImGui::Text("%i The quick brown fox jumps over the lazy dog", i);
10006
        ImGui::PopStyleVar();
10007
        break;
10008
    }
10009
    ImGui::EndChild();
10010
    ImGui::End();
10011
}
10012
10013
//-----------------------------------------------------------------------------
10014
// [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize()
10015
//-----------------------------------------------------------------------------
10016
10017
// Demonstrate creating a window which gets auto-resized according to its content.
10018
static void ShowExampleAppAutoResize(bool* p_open)
10019
{
10020
    if (!ImGui::Begin("Example: Auto-resizing window", p_open, ImGuiWindowFlags_AlwaysAutoResize))
10021
    {
10022
        ImGui::End();
10023
        return;
10024
    }
10025
    IMGUI_DEMO_MARKER("Examples/Auto-resizing window");
10026
10027
    static int lines = 10;
10028
    ImGui::TextUnformatted(
10029
        "Window will resize every-frame to the size of its content.\n"
10030
        "Note that you probably don't want to query the window size to\n"
10031
        "output your content because that would create a feedback loop.");
10032
    ImGui::SliderInt("Number of lines", &lines, 1, 20);
10033
    for (int i = 0; i < lines; i++)
10034
        ImGui::Text("%*sThis is line %d", i * 4, "", i); // Pad with space to extend size horizontally
10035
    ImGui::End();
10036
}
10037
10038
//-----------------------------------------------------------------------------
10039
// [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize()
10040
//-----------------------------------------------------------------------------
10041
10042
// Demonstrate creating a window with custom resize constraints.
10043
// Note that size constraints currently don't work on a docked window (when in 'docking' branch)
10044
static void ShowExampleAppConstrainedResize(bool* p_open)
10045
{
10046
    struct CustomConstraints
10047
    {
10048
        // Helper functions to demonstrate programmatic constraints
10049
        // FIXME: This doesn't take account of decoration size (e.g. title bar), library should make this easier.
10050
        // FIXME: None of the three demos works consistently when resizing from borders.
10051
        static void AspectRatio(ImGuiSizeCallbackData* data)
10052
        {
10053
            float aspect_ratio = *(float*)data->UserData;
10054
            data->DesiredSize.y = (float)(int)(data->DesiredSize.x / aspect_ratio);
10055
        }
10056
        static void Square(ImGuiSizeCallbackData* data)
10057
        {
10058
            data->DesiredSize.x = data->DesiredSize.y = IM_MAX(data->DesiredSize.x, data->DesiredSize.y);
10059
        }
10060
        static void Step(ImGuiSizeCallbackData* data)
10061
        {
10062
            float step = *(float*)data->UserData;
10063
            data->DesiredSize = ImVec2((int)(data->DesiredSize.x / step + 0.5f) * step, (int)(data->DesiredSize.y / step + 0.5f) * step);
10064
        }
10065
    };
10066
10067
    const char* test_desc[] =
10068
    {
10069
        "Between 100x100 and 500x500",
10070
        "At least 100x100",
10071
        "Resize vertical + lock current width",
10072
        "Resize horizontal + lock current height",
10073
        "Width Between 400 and 500",
10074
        "Height at least 400",
10075
        "Custom: Aspect Ratio 16:9",
10076
        "Custom: Always Square",
10077
        "Custom: Fixed Steps (100)",
10078
    };
10079
10080
    // Options
10081
    static bool auto_resize = false;
10082
    static bool window_padding = true;
10083
    static int type = 6; // Aspect Ratio
10084
    static int display_lines = 10;
10085
10086
    // Submit constraint
10087
    float aspect_ratio = 16.0f / 9.0f;
10088
    float fixed_step = 100.0f;
10089
    if (type == 0) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(500, 500));         // Between 100x100 and 500x500
10090
    if (type == 1) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100
10091
    if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 0),    ImVec2(-1, FLT_MAX));      // Resize vertical + lock current width
10092
    if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1),    ImVec2(FLT_MAX, -1));      // Resize horizontal + lock current height
10093
    if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1),  ImVec2(500, -1));          // Width Between and 400 and 500
10094
    if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400),  ImVec2(-1, FLT_MAX));      // Height at least 400
10095
    if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0),     ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::AspectRatio, (void*)&aspect_ratio);   // Aspect ratio
10096
    if (type == 7) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0),     ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square);                              // Always Square
10097
    if (type == 8) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0),     ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)&fixed_step);            // Fixed Step
10098
10099
    // Submit window
10100
    if (!window_padding)
10101
        ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
10102
    const ImGuiWindowFlags window_flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0;
10103
    const bool window_open = ImGui::Begin("Example: Constrained Resize", p_open, window_flags);
10104
    if (!window_padding)
10105
        ImGui::PopStyleVar();
10106
    IMGUI_DEMO_MARKER("Examples/Constrained Resizing window");
10107
    if (window_open)
10108
    {
10109
        if (ImGui::GetIO().KeyShift)
10110
        {
10111
            // Display a dummy viewport (in your real app you would likely use ImageButton() to display a texture)
10112
            ImVec2 avail_size = ImGui::GetContentRegionAvail();
10113
            ImVec2 pos = ImGui::GetCursorScreenPos();
10114
            ImGui::ColorButton("viewport", ImVec4(0.5f, 0.2f, 0.5f, 1.0f), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop, avail_size);
10115
            ImGui::SetCursorScreenPos(ImVec2(pos.x + 10, pos.y + 10));
10116
            ImGui::Text("%.2f x %.2f", avail_size.x, avail_size.y);
10117
        }
10118
        else
10119
        {
10120
            ImGui::Text("(Hold Shift to display a dummy viewport)");
10121
            if (ImGui::IsWindowDocked())
10122
                ImGui::Text("Warning: Sizing Constraints won't work if the window is docked!");
10123
            if (ImGui::Button("Set 200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine();
10124
            if (ImGui::Button("Set 500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine();
10125
            if (ImGui::Button("Set 800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); }
10126
            ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20);
10127
            ImGui::Combo("Constraint", &type, test_desc, IM_COUNTOF(test_desc));
10128
            ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20);
10129
            ImGui::DragInt("Lines", &display_lines, 0.2f, 1, 100);
10130
            ImGui::Checkbox("Auto-resize", &auto_resize);
10131
            ImGui::Checkbox("Window padding", &window_padding);
10132
            for (int i = 0; i < display_lines; i++)
10133
                ImGui::Text("%*sHello, sailor! Making this line long enough for the example.", i * 4, "");
10134
        }
10135
    }
10136
    ImGui::End();
10137
}
10138
10139
//-----------------------------------------------------------------------------
10140
// [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay()
10141
//-----------------------------------------------------------------------------
10142
10143
// Demonstrate creating a simple static window with no decoration
10144
// + a context-menu to choose which corner of the screen to use.
10145
static void ShowExampleAppSimpleOverlay(bool* p_open)
10146
{
10147
    static int location = 0;
10148
    ImGuiIO& io = ImGui::GetIO();
10149
    ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav;
10150
    if (location >= 0)
10151
    {
10152
        const float PAD = 10.0f;
10153
        const ImGuiViewport* viewport = ImGui::GetMainViewport();
10154
        ImVec2 work_pos = viewport->WorkPos; // Use work area to avoid menu-bar/task-bar, if any!
10155
        ImVec2 work_size = viewport->WorkSize;
10156
        ImVec2 window_pos, window_pos_pivot;
10157
        window_pos.x = (location & 1) ? (work_pos.x + work_size.x - PAD) : (work_pos.x + PAD);
10158
        window_pos.y = (location & 2) ? (work_pos.y + work_size.y - PAD) : (work_pos.y + PAD);
10159
        window_pos_pivot.x = (location & 1) ? 1.0f : 0.0f;
10160
        window_pos_pivot.y = (location & 2) ? 1.0f : 0.0f;
10161
        ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot);
10162
        ImGui::SetNextWindowViewport(viewport->ID);
10163
        window_flags |= ImGuiWindowFlags_NoMove;
10164
    }
10165
    else if (location == -2)
10166
    {
10167
        // Center window
10168
        ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Always, ImVec2(0.5f, 0.5f));
10169
        window_flags |= ImGuiWindowFlags_NoMove;
10170
    }
10171
    ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background
10172
    if (ImGui::Begin("Example: Simple overlay", p_open, window_flags))
10173
    {
10174
        IMGUI_DEMO_MARKER("Examples/Simple overlay"); // Scroll up to the beginning of this function to see overlay flags
10175
        ImGui::Text("Simple overlay\n" "(right-click to change position)");
10176
        ImGui::Separator();
10177
        if (ImGui::IsMousePosValid())
10178
            ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y);
10179
        else
10180
            ImGui::Text("Mouse Position: <invalid>");
10181
        if (ImGui::BeginPopupContextWindow())
10182
        {
10183
            if (ImGui::MenuItem("Custom",       NULL, location == -1)) location = -1;
10184
            if (ImGui::MenuItem("Center",       NULL, location == -2)) location = -2;
10185
            if (ImGui::MenuItem("Top-left",     NULL, location == 0)) location = 0;
10186
            if (ImGui::MenuItem("Top-right",    NULL, location == 1)) location = 1;
10187
            if (ImGui::MenuItem("Bottom-left",  NULL, location == 2)) location = 2;
10188
            if (ImGui::MenuItem("Bottom-right", NULL, location == 3)) location = 3;
10189
            if (p_open && ImGui::MenuItem("Close")) *p_open = false;
10190
            ImGui::EndPopup();
10191
        }
10192
    }
10193
    ImGui::End();
10194
}
10195
10196
//-----------------------------------------------------------------------------
10197
// [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen()
10198
//-----------------------------------------------------------------------------
10199
10200
// Demonstrate creating a window covering the entire screen/viewport
10201
static void ShowExampleAppFullscreen(bool* p_open)
10202
{
10203
    static bool use_work_area = true;
10204
    static ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings;
10205
10206
    // We demonstrate using the full viewport area or the work area (without menu-bars, task-bars etc.)
10207
    // Based on your use case you may want one or the other.
10208
    const ImGuiViewport* viewport = ImGui::GetMainViewport();
10209
    ImGui::SetNextWindowPos(use_work_area ? viewport->WorkPos : viewport->Pos);
10210
    ImGui::SetNextWindowSize(use_work_area ? viewport->WorkSize : viewport->Size);
10211
10212
    if (ImGui::Begin("Example: Fullscreen window", p_open, flags))
10213
    {
10214
        IMGUI_DEMO_MARKER("Examples/Fullscreen window");
10215
        ImGui::Checkbox("Use work area instead of main area", &use_work_area);
10216
        ImGui::SameLine();
10217
        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.");
10218
10219
        ImGui::CheckboxFlags("ImGuiWindowFlags_NoBackground", &flags, ImGuiWindowFlags_NoBackground);
10220
        ImGui::CheckboxFlags("ImGuiWindowFlags_NoDecoration", &flags, ImGuiWindowFlags_NoDecoration);
10221
        ImGui::Indent();
10222
        ImGui::CheckboxFlags("ImGuiWindowFlags_NoTitleBar", &flags, ImGuiWindowFlags_NoTitleBar);
10223
        ImGui::CheckboxFlags("ImGuiWindowFlags_NoCollapse", &flags, ImGuiWindowFlags_NoCollapse);
10224
        ImGui::CheckboxFlags("ImGuiWindowFlags_NoScrollbar", &flags, ImGuiWindowFlags_NoScrollbar);
10225
        ImGui::Unindent();
10226
10227
        if (p_open && ImGui::Button("Close this window"))
10228
            *p_open = false;
10229
    }
10230
    ImGui::End();
10231
}
10232
10233
//-----------------------------------------------------------------------------
10234
// [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles()
10235
//-----------------------------------------------------------------------------
10236
10237
// Demonstrate the use of "##" and "###" in identifiers to manipulate ID generation.
10238
// This applies to all regular items as well.
10239
// Read FAQ section "How can I have multiple widgets with the same label?" for details.
10240
static void ShowExampleAppWindowTitles(bool*)
10241
{
10242
    const ImGuiViewport* viewport = ImGui::GetMainViewport();
10243
    const ImVec2 base_pos = viewport->Pos;
10244
10245
    // By default, Windows are uniquely identified by their title.
10246
    // You can use the "##" and "###" markers to manipulate the display/ID.
10247
10248
    // Using "##" to display same title but have unique identifier.
10249
    ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 100), ImGuiCond_FirstUseEver);
10250
    ImGui::Begin("Same title as another window##1");
10251
    IMGUI_DEMO_MARKER("Examples/Manipulating window titles##1");
10252
    ImGui::Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique.");
10253
    ImGui::End();
10254
10255
    ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 200), ImGuiCond_FirstUseEver);
10256
    ImGui::Begin("Same title as another window##2");
10257
    IMGUI_DEMO_MARKER("Examples/Manipulating window titles##2");
10258
    ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique.");
10259
    ImGui::End();
10260
10261
    // Using "###" to display a changing title but keep a static identifier "AnimatedTitle"
10262
    char buf[128];
10263
    sprintf(buf, "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime() / 0.25f) & 3], ImGui::GetFrameCount());
10264
    ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 300), ImGuiCond_FirstUseEver);
10265
    ImGui::Begin(buf);
10266
    IMGUI_DEMO_MARKER("Examples/Manipulating window titles##3");
10267
    ImGui::Text("This window has a changing title.");
10268
    ImGui::End();
10269
}
10270
10271
//-----------------------------------------------------------------------------
10272
// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering()
10273
//-----------------------------------------------------------------------------
10274
10275
// Add a |_| looking shape
10276
static void PathConcaveShape(ImDrawList* draw_list, float x, float y, float sz)
10277
{
10278
    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 } };
10279
    for (const ImVec2& p : pos_norms)
10280
        draw_list->PathLineTo(ImVec2(x + 0.5f + (int)(sz * p.x), y + 0.5f + (int)(sz * p.y)));
10281
}
10282
10283
// Demonstrate using the low-level ImDrawList to draw custom shapes.
10284
static void ShowExampleAppCustomRendering(bool* p_open)
10285
{
10286
    if (!ImGui::Begin("Example: Custom rendering", p_open))
10287
    {
10288
        ImGui::End();
10289
        return;
10290
    }
10291
    IMGUI_DEMO_MARKER("Examples/Custom rendering");
10292
10293
    // Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of
10294
    // overloaded operators, etc. Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your
10295
    // types and ImVec2/ImVec4. Dear ImGui defines overloaded operators but they are internal to imgui.cpp and not
10296
    // exposed outside (to avoid messing with your types) In this example we are not using the maths operators!
10297
10298
    if (ImGui::BeginTabBar("##TabBar"))
10299
    {
10300
        if (ImGui::BeginTabItem("Primitives"))
10301
        {
10302
            IMGUI_DEMO_MARKER("Examples/Custom rendering/Primitives");
10303
            ImGui::PushItemWidth(-ImGui::GetFontSize() * 15);
10304
            ImDrawList* draw_list = ImGui::GetWindowDrawList();
10305
10306
            // Draw gradients
10307
            // (note that those are currently exacerbating our sRGB/Linear issues)
10308
            // Calling ImGui::GetColorU32() multiplies the given colors by the current Style Alpha, but you may pass the IM_COL32() directly as well..
10309
            ImGui::Text("Gradients");
10310
            ImVec2 gradient_size = ImVec2(ImGui::CalcItemWidth(), ImGui::GetFrameHeight());
10311
            {
10312
                ImVec2 p0 = ImGui::GetCursorScreenPos();
10313
                ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y);
10314
                ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 0, 0, 255));
10315
                ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 255, 255, 255));
10316
                draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a);
10317
                ImGui::InvisibleButton("##gradient1", gradient_size);
10318
            }
10319
            {
10320
                ImVec2 p0 = ImGui::GetCursorScreenPos();
10321
                ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y);
10322
                ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 255, 0, 255));
10323
                ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 0, 0, 255));
10324
                draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a);
10325
                ImGui::InvisibleButton("##gradient2", gradient_size);
10326
            }
10327
10328
            // Draw a bunch of primitives
10329
            ImGui::Text("All primitives");
10330
            static float sz = 36.0f;
10331
            static float thickness = 3.0f;
10332
            static int ngon_sides = 6;
10333
            static bool circle_segments_override = false;
10334
            static int circle_segments_override_v = 12;
10335
            static bool curve_segments_override = false;
10336
            static int curve_segments_override_v = 8;
10337
            static ImVec4 colf = ImVec4(1.0f, 1.0f, 0.4f, 1.0f);
10338
            ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 100.0f, "%.0f");
10339
            ImGui::DragFloat("Thickness", &thickness, 0.05f, 1.0f, 8.0f, "%.02f");
10340
            ImGui::SliderInt("N-gon sides", &ngon_sides, 3, 12);
10341
            ImGui::Checkbox("##circlesegmentoverride", &circle_segments_override);
10342
            ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
10343
            circle_segments_override |= ImGui::SliderInt("Circle segments override", &circle_segments_override_v, 3, 40);
10344
            ImGui::Checkbox("##curvessegmentoverride", &curve_segments_override);
10345
            ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
10346
            curve_segments_override |= ImGui::SliderInt("Curves segments override", &curve_segments_override_v, 3, 40);
10347
            ImGui::ColorEdit4("Color", &colf.x);
10348
10349
            const ImVec2 p = ImGui::GetCursorScreenPos();
10350
            const ImU32 col = ImColor(colf);
10351
            const float spacing = 10.0f;
10352
            const ImDrawFlags corners_tl_br = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersBottomRight;
10353
            const float rounding = sz / 5.0f;
10354
            const int circle_segments = circle_segments_override ? circle_segments_override_v : 0;
10355
            const int curve_segments = curve_segments_override ? curve_segments_override_v : 0;
10356
            const ImVec2 cp3[3] = { ImVec2(0.0f, sz * 0.6f), ImVec2(sz * 0.5f, -sz * 0.4f), ImVec2(sz, sz) }; // Control points for curves
10357
            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) };
10358
10359
            float x = p.x + 4.0f;
10360
            float y = p.y + 4.0f;
10361
            for (int n = 0; n < 2; n++)
10362
            {
10363
                // First line uses a thickness of 1.0f, second line uses the configurable thickness
10364
                float th = (n == 0) ? 1.0f : thickness;
10365
                draw_list->AddNgon(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, ngon_sides, th);                 x += sz + spacing;  // N-gon
10366
                draw_list->AddCircle(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments, th);          x += sz + spacing;  // Circle
10367
                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
10368
                draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0f, th);                            x += sz + spacing;  // Square
10369
                draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, th);                        x += sz + spacing;  // Square with all rounded corners
10370
                draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, th, corners_tl_br);         x += sz + spacing;  // Square with two rounded corners
10371
                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
10372
                //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
10373
                PathConcaveShape(draw_list, x, y, sz); draw_list->PathStroke(col, th, ImDrawFlags_Closed);          x += sz + spacing;  // Concave Shape
10374
                //draw_list->AddPolyline(concave_shape, IM_COUNTOF(concave_shape), col, ImDrawFlags_Closed, th);
10375
                draw_list->AddLineH(x, x + sz, y, col, th);                                                         x += sz + spacing;  // Horizontal line (note: drawing a filled rectangle will be faster!)
10376
                draw_list->AddLineV(x, y, y + sz, col, th);                                                         x += spacing;       // Vertical line (note: drawing a filled rectangle will be faster!)
10377
                draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y + sz), col, th);                                  x += sz + spacing;  // Diagonal line
10378
10379
                // Path
10380
                draw_list->PathArcTo(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, 3.141592f, 3.141592f * -0.5f);
10381
                draw_list->PathStroke(col, th);
10382
                x += sz + spacing;
10383
10384
                // Quadratic Bezier Curve (3 control points)
10385
                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);
10386
                x += sz + spacing;
10387
10388
                // Cubic Bezier Curve (4 control points)
10389
                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);
10390
10391
                x = p.x + 4;
10392
                y += sz + spacing;
10393
            }
10394
10395
            // Filled shapes
10396
            draw_list->AddNgonFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, col, ngon_sides);             x += sz + spacing;  // N-gon
10397
            draw_list->AddCircleFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, col, circle_segments);      x += sz + spacing;  // Circle
10398
            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
10399
            draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col);                                    x += sz + spacing;  // Square
10400
            draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f);                             x += sz + spacing;  // Square with all rounded corners
10401
            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
10402
            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
10403
            //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
10404
            PathConcaveShape(draw_list, x, y, sz); draw_list->PathFillConcave(col);                                 x += sz + spacing;  // Concave shape
10405
            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)
10406
            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)
10407
            draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + 1, y + 1), col);                                      x += sz;            // Pixel (faster than AddLine)
10408
10409
            // Path
10410
            draw_list->PathArcTo(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, 3.141592f * -0.5f, 3.141592f);
10411
            draw_list->PathFillConvex(col);
10412
            x += sz + spacing;
10413
10414
            // Quadratic Bezier Curve (3 control points)
10415
            draw_list->PathLineTo(ImVec2(x + cp3[0].x, y + cp3[0].y));
10416
            draw_list->PathBezierQuadraticCurveTo(ImVec2(x + cp3[1].x, y + cp3[1].y), ImVec2(x + cp3[2].x, y + cp3[2].y), curve_segments);
10417
            draw_list->PathFillConvex(col);
10418
            x += sz + spacing;
10419
10420
            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));
10421
            x += sz + spacing;
10422
10423
            ImGui::Dummy(ImVec2((sz + spacing) * 13.2f, (sz + spacing) * 3.0f));
10424
            ImGui::PopItemWidth();
10425
            ImGui::EndTabItem();
10426
        }
10427
10428
        if (ImGui::BeginTabItem("Canvas"))
10429
        {
10430
            IMGUI_DEMO_MARKER("Examples/Custom rendering/Canvas");
10431
            static ImVector<ImVec2> points;
10432
            static ImVec2 scrolling(0.0f, 0.0f);
10433
            static bool opt_enable_grid = true;
10434
            static bool opt_enable_context_menu = true;
10435
            static bool adding_line = false;
10436
10437
            ImGui::Checkbox("Enable grid", &opt_enable_grid);
10438
            ImGui::Checkbox("Enable context menu", &opt_enable_context_menu);
10439
            ImGui::Text("Mouse Left: drag to add lines,\nMouse Right: drag to scroll, click for context menu.");
10440
10441
            // Typically you would use a BeginChild()/EndChild() pair to benefit from a clipping region + own scrolling.
10442
            // Here we demonstrate that this can be replaced by simple offsetting + custom drawing + PushClipRect/PopClipRect() calls.
10443
            // To use a child window instead we could use, e.g:
10444
            //      ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));      // Disable padding
10445
            //      ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(50, 50, 50, 255));  // Set a background color
10446
            //      ImGui::BeginChild("canvas", ImVec2(0.0f, 0.0f), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove);
10447
            //      ImGui::PopStyleColor();
10448
            //      ImGui::PopStyleVar();
10449
            //      [...]
10450
            //      ImGui::EndChild();
10451
10452
            // Using InvisibleButton() as a convenience 1) it will advance the layout cursor and 2) allows us to use IsItemHovered()/IsItemActive()
10453
            ImVec2 canvas_p0 = ImGui::GetCursorScreenPos();      // ImDrawList API uses screen coordinates!
10454
            ImVec2 canvas_sz = ImGui::GetContentRegionAvail();   // Resize canvas to what's available
10455
            if (canvas_sz.x < 50.0f) canvas_sz.x = 50.0f;
10456
            if (canvas_sz.y < 50.0f) canvas_sz.y = 50.0f;
10457
            ImVec2 canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y);
10458
10459
            // Draw border and background color
10460
            ImGuiIO& io = ImGui::GetIO();
10461
            ImDrawList* draw_list = ImGui::GetWindowDrawList();
10462
            draw_list->AddRectFilled(canvas_p0, canvas_p1, IM_COL32(50, 50, 50, 255));
10463
            draw_list->AddRect(canvas_p0, canvas_p1, IM_COL32(255, 255, 255, 255));
10464
10465
            // This will catch our interactions
10466
            ImGui::InvisibleButton("canvas", canvas_sz, ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight);
10467
            const bool is_hovered = ImGui::IsItemHovered(); // Hovered
10468
            const bool is_active = ImGui::IsItemActive();   // Held
10469
            const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y); // Lock scrolled origin
10470
            const ImVec2 mouse_pos_in_canvas(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
10471
10472
            // Add first and second point
10473
            if (is_hovered && !adding_line && ImGui::IsMouseClicked(ImGuiMouseButton_Left))
10474
            {
10475
                points.push_back(mouse_pos_in_canvas);
10476
                points.push_back(mouse_pos_in_canvas);
10477
                adding_line = true;
10478
            }
10479
            if (adding_line)
10480
            {
10481
                points.back() = mouse_pos_in_canvas;
10482
                if (!ImGui::IsMouseDown(ImGuiMouseButton_Left))
10483
                    adding_line = false;
10484
            }
10485
10486
            // Pan (we use a zero mouse threshold when there's no context menu)
10487
            // You may decide to make that threshold dynamic based on whether the mouse is hovering something etc.
10488
            const float mouse_threshold_for_pan = opt_enable_context_menu ? -1.0f : 0.0f;
10489
            if (is_active && ImGui::IsMouseDragging(ImGuiMouseButton_Right, mouse_threshold_for_pan))
10490
            {
10491
                scrolling.x += io.MouseDelta.x;
10492
                scrolling.y += io.MouseDelta.y;
10493
            }
10494
10495
            // Context menu (under default mouse threshold)
10496
            ImVec2 drag_delta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Right);
10497
            if (opt_enable_context_menu && drag_delta.x == 0.0f && drag_delta.y == 0.0f)
10498
                ImGui::OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight);
10499
            if (ImGui::BeginPopup("context"))
10500
            {
10501
                if (adding_line)
10502
                    points.resize(points.size() - 2);
10503
                adding_line = false;
10504
                if (ImGui::MenuItem("Remove one", NULL, false, points.Size > 0)) { points.resize(points.size() - 2); }
10505
                if (ImGui::MenuItem("Remove all", NULL, false, points.Size > 0)) { points.clear(); }
10506
                ImGui::EndPopup();
10507
            }
10508
10509
            // Draw grid + all lines in the canvas
10510
            draw_list->PushClipRect(canvas_p0, canvas_p1, true);
10511
            if (opt_enable_grid)
10512
            {
10513
                const float GRID_STEP = 64.0f;
10514
                for (float x = fmodf(scrolling.x, GRID_STEP); x < canvas_sz.x; x += GRID_STEP)
10515
                    draw_list->AddLineV(canvas_p0.x + x, canvas_p0.y, canvas_p1.y, IM_COL32(200, 200, 200, 40));
10516
                for (float y = fmodf(scrolling.y, GRID_STEP); y < canvas_sz.y; y += GRID_STEP)
10517
                    draw_list->AddLineH(canvas_p0.x, canvas_p1.x, canvas_p0.y + y, IM_COL32(200, 200, 200, 40));
10518
            }
10519
            for (int n = 0; n < points.Size; n += 2)
10520
                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);
10521
            draw_list->PopClipRect();
10522
10523
            ImGui::EndTabItem();
10524
        }
10525
10526
        if (ImGui::BeginTabItem("BG/FG draw lists"))
10527
        {
10528
            IMGUI_DEMO_MARKER("Examples/Custom rendering/BG & FG draw lists");
10529
            static bool draw_bg = true;
10530
            static bool draw_fg = true;
10531
            ImGui::Checkbox("Draw in Background draw list", &draw_bg);
10532
            ImGui::SameLine(); HelpMarker("The Background draw list will be rendered below every Dear ImGui windows.");
10533
            ImGui::Checkbox("Draw in Foreground draw list", &draw_fg);
10534
            ImGui::SameLine(); HelpMarker("The Foreground draw list will be rendered over every Dear ImGui windows.");
10535
            ImVec2 window_pos = ImGui::GetWindowPos();
10536
            ImVec2 window_size = ImGui::GetWindowSize();
10537
            ImVec2 window_center = ImVec2(window_pos.x + window_size.x * 0.5f, window_pos.y + window_size.y * 0.5f);
10538
            if (draw_bg)
10539
                ImGui::GetBackgroundDrawList()->AddCircle(window_center, window_size.x * 0.6f, IM_COL32(255, 0, 0, 200), 0, 10 + 4);
10540
            if (draw_fg)
10541
                ImGui::GetForegroundDrawList()->AddCircle(window_center, window_size.y * 0.6f, IM_COL32(0, 255, 0, 200), 0, 10);
10542
            ImGui::EndTabItem();
10543
        }
10544
10545
        // Demonstrate out-of-order rendering via channels splitting
10546
        // We use functions in ImDrawList as each draw list contains a convenience splitter,
10547
        // but you can also instantiate your own ImDrawListSplitter if you need to nest them.
10548
        if (ImGui::BeginTabItem("Draw Channels"))
10549
        {
10550
            IMGUI_DEMO_MARKER("Examples/Custom rendering/Draw Channels");
10551
            ImDrawList* draw_list = ImGui::GetWindowDrawList();
10552
            {
10553
                ImGui::Text("Blue shape is drawn first: appears in back");
10554
                ImGui::Text("Red shape is drawn after: appears in front");
10555
                ImVec2 p0 = ImGui::GetCursorScreenPos();
10556
                draw_list->AddRectFilled(ImVec2(p0.x, p0.y), ImVec2(p0.x + 50, p0.y + 50), IM_COL32(0, 0, 255, 255)); // Blue
10557
                draw_list->AddRectFilled(ImVec2(p0.x + 25, p0.y + 25), ImVec2(p0.x + 75, p0.y + 75), IM_COL32(255, 0, 0, 255)); // Red
10558
                ImGui::Dummy(ImVec2(75, 75));
10559
            }
10560
            ImGui::Separator();
10561
            {
10562
                ImGui::Text("Blue shape is drawn first, into channel 1: appears in front");
10563
                ImGui::Text("Red shape is drawn after, into channel 0: appears in back");
10564
                ImVec2 p1 = ImGui::GetCursorScreenPos();
10565
10566
                // Create 2 channels and draw a Blue shape THEN a Red shape.
10567
                // You can create any number of channels. Tables API use 1 channel per column in order to better batch draw calls.
10568
                draw_list->ChannelsSplit(2);
10569
                draw_list->ChannelsSetCurrent(1);
10570
                draw_list->AddRectFilled(ImVec2(p1.x, p1.y), ImVec2(p1.x + 50, p1.y + 50), IM_COL32(0, 0, 255, 255)); // Blue
10571
                draw_list->ChannelsSetCurrent(0);
10572
                draw_list->AddRectFilled(ImVec2(p1.x + 25, p1.y + 25), ImVec2(p1.x + 75, p1.y + 75), IM_COL32(255, 0, 0, 255)); // Red
10573
10574
                // Flatten/reorder channels. Red shape is in channel 0 and it appears below the Blue shape in channel 1.
10575
                // This works by copying draw indices only (vertices are not copied).
10576
                draw_list->ChannelsMerge();
10577
                ImGui::Dummy(ImVec2(75, 75));
10578
                ImGui::Text("After reordering, contents of channel 0 appears below channel 1.");
10579
            }
10580
            ImGui::EndTabItem();
10581
        }
10582
10583
        ImGui::EndTabBar();
10584
    }
10585
10586
    ImGui::End();
10587
}
10588
10589
//-----------------------------------------------------------------------------
10590
// [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace()
10591
//-----------------------------------------------------------------------------
10592
10593
struct ImGuiDemoDockspaceArgs
10594
{
10595
    bool                IsFullscreen = true;
10596
    bool                KeepWindowPadding = false; // Keep WindowPadding to help understand that DockSpace() is a widget inside the window.
10597
    ImGuiDockNodeFlags  DockSpaceFlags  = ImGuiDockNodeFlags_None;
10598
};
10599
10600
// THIS IS A DEMO FOR ADVANCED USAGE OF DockSpace().
10601
// MOST REGULAR APPLICATIONS WANTING TO ALLOW DOCKING WINDOWS ON THE EDGE OF YOUR SCREEN CAN SIMPLY USE:
10602
//    ImGui::NewFrame(); + ImGui::DockSpaceOverViewport();                                                   // Create a dockspace in main viewport
10603
// OR:
10604
//    ImGui::NewFrame(); + ImGui::DockSpaceOverViewport(0, nullptr, ImGuiDockNodeFlags_PassthruCentralNode); // Create a dockspace in main viewport, where central node is transparent.
10605
// Demonstrate using DockSpace() to create an explicit docking node within an existing window, with various options.
10606
// Read https://github.com/ocornut/imgui/wiki/Docking for details.
10607
// The reasons we do not use DockSpaceOverViewport() in this demo is because:
10608
// - (1) we allow the host window to be floating/moveable instead of filling the viewport (when args->IsFullscreen == false)
10609
//       which is mostly to showcase the idea that DockSpace() may be submitted anywhere.
10610
//       Also see 'Demo->Examples->Documents' for a less abstract version of this.
10611
// - (2) we allow the host window to have padding (when args->UsePadding == true)
10612
// - (3) we expose variety of other flags.
10613
static void ShowExampleAppDockSpaceAdvanced(ImGuiDemoDockspaceArgs* args, bool* p_open)
10614
{
10615
    ImGuiDockNodeFlags dockspace_flags = args->DockSpaceFlags;
10616
10617
    // We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into,
10618
    // because it would be confusing to have two docking targets within each others.
10619
    ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDocking;
10620
    if (args->IsFullscreen)
10621
    {
10622
        // Fullscreen dockspace: practically the same as calling DockSpaceOverViewport();
10623
        const ImGuiViewport* viewport = ImGui::GetMainViewport();
10624
        ImGui::SetNextWindowPos(viewport->WorkPos);
10625
        ImGui::SetNextWindowSize(viewport->WorkSize);
10626
        ImGui::SetNextWindowViewport(viewport->ID);
10627
        ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
10628
        ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
10629
        window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
10630
        window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
10631
        window_flags |= ImGuiWindowFlags_NoBackground;
10632
    }
10633
    else
10634
    {
10635
        // Floating dockspace
10636
        dockspace_flags &= ~ImGuiDockNodeFlags_PassthruCentralNode;
10637
    }
10638
10639
    // Important: note that we proceed even if Begin() returns false (aka window is collapsed).
10640
    // This is because we want to keep our DockSpace() active. If a DockSpace() is inactive,
10641
    // all active windows docked into it will lose their parent and become undocked.
10642
    // We cannot preserve the docking relationship between an active window and an inactive docking, otherwise
10643
    // any change of dockspace/settings would lead to windows being stuck in limbo and never being visible.
10644
    if (!args->KeepWindowPadding)
10645
        ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
10646
    ImGui::Begin("Window with a DockSpace", p_open, window_flags);
10647
    if (!args->KeepWindowPadding)
10648
        ImGui::PopStyleVar();
10649
10650
    if (args->IsFullscreen)
10651
        ImGui::PopStyleVar(2);
10652
10653
    // Submit the DockSpace widget inside our window
10654
    // - Note that the id here is different from the one used by DockSpaceOverViewport(), so docking state won't get transfered between "Basic" and "Advanced" demos.
10655
    // - If we made the ShowExampleAppDockSpaceBasic() calculate its own ID and pass it to DockSpaceOverViewport() the ID could easily match.
10656
    ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
10657
    ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
10658
10659
    ImGui::End();
10660
}
10661
10662
static void ShowExampleAppDockSpaceBasic(ImGuiDockNodeFlags flags)
10663
{
10664
    // Basic version which you can use in many apps:
10665
    // e.g:
10666
    //   ImGui::DockSpaceOverViewport();
10667
    // or:
10668
    //   ImGui::DockSpaceOverViewport(0, nullptr, ImGuiDockNodeFlags_PassthruCentralNode); // Central node will be transparent
10669
    // or:
10670
    //   ImGuiViewport* viewport = ImGui::GetMainViewport();
10671
    //   ImGui::DockSpaceOverViewport(0, viewport, ImGuiDockNodeFlags_None);
10672
10673
    ImGui::DockSpaceOverViewport(0, nullptr, flags);
10674
}
10675
10676
void ShowExampleAppDockSpace(bool* p_open)
10677
{
10678
    static int opt_demo_mode = 0;
10679
    static bool opt_demo_mode_changed = false;
10680
    static ImGuiDemoDockspaceArgs args;
10681
10682
    if (opt_demo_mode == 0)
10683
        ShowExampleAppDockSpaceBasic(args.DockSpaceFlags);
10684
    else
10685
        ShowExampleAppDockSpaceAdvanced(&args, p_open);
10686
10687
    // Refocus our window to minimize perceived loss of focus when changing mode (caused by the fact that each use a different window, which would not happen in a real app)
10688
    if (opt_demo_mode_changed)
10689
        ImGui::SetNextWindowFocus();
10690
    ImGui::Begin("Examples: Dockspace", p_open, ImGuiWindowFlags_MenuBar);
10691
    opt_demo_mode_changed = false;
10692
    opt_demo_mode_changed |= ImGui::RadioButton("Basic demo mode", &opt_demo_mode, 0);
10693
    opt_demo_mode_changed |= ImGui::RadioButton("Advanced demo mode", &opt_demo_mode, 1);
10694
10695
    ImGui::SeparatorText("Options");
10696
10697
    if ((ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_DockingEnable) == 0)
10698
    {
10699
        ShowDockingDisabledMessage();
10700
    }
10701
    else if (opt_demo_mode == 0)
10702
    {
10703
        args.DockSpaceFlags &= ImGuiDockNodeFlags_PassthruCentralNode; // Allowed flags
10704
        ImGui::CheckboxFlags("Flag: PassthruCentralNode", &args.DockSpaceFlags, ImGuiDockNodeFlags_PassthruCentralNode);
10705
    }
10706
    else if (opt_demo_mode == 1)
10707
    {
10708
        ImGui::Checkbox("Fullscreen", &args.IsFullscreen);
10709
        ImGui::Checkbox("Keep Window Padding", &args.KeepWindowPadding);
10710
        ImGui::SameLine();
10711
        HelpMarker("This is mostly exposed to facilitate understanding that a DockSpace() is _inside_ a window.");
10712
        ImGui::BeginDisabled(args.IsFullscreen == false);
10713
        ImGui::CheckboxFlags("Flag: PassthruCentralNode",      &args.DockSpaceFlags, ImGuiDockNodeFlags_PassthruCentralNode);
10714
        ImGui::EndDisabled();
10715
        ImGui::CheckboxFlags("Flag: NoDockingOverCentralNode", &args.DockSpaceFlags, ImGuiDockNodeFlags_NoDockingOverCentralNode);
10716
        ImGui::CheckboxFlags("Flag: NoDockingSplit",           &args.DockSpaceFlags, ImGuiDockNodeFlags_NoDockingSplit);
10717
        ImGui::CheckboxFlags("Flag: NoUndocking",              &args.DockSpaceFlags, ImGuiDockNodeFlags_NoUndocking);
10718
        ImGui::CheckboxFlags("Flag: NoResize",                 &args.DockSpaceFlags, ImGuiDockNodeFlags_NoResize);
10719
        ImGui::CheckboxFlags("Flag: AutoHideTabBar",           &args.DockSpaceFlags, ImGuiDockNodeFlags_AutoHideTabBar);
10720
    }
10721
10722
    // Show demo options and help
10723
    if (ImGui::BeginMenuBar())
10724
    {
10725
        if (ImGui::BeginMenu("Help"))
10726
        {
10727
            ImGui::TextUnformatted(
10728
                "This demonstrates the use of ImGui::DockSpace() which allows you to manually\ncreate a docking node _within_ another window." "\n"
10729
                "The \"Basic\" version uses the ImGui::DockSpaceOverViewport() helper. Most applications can probably use this.");
10730
            ImGui::Separator();
10731
            ImGui::TextUnformatted("When docking is enabled, you can ALWAYS dock MOST window into another! Try it now!" "\n"
10732
                "- Drag from window title bar or their tab to dock/undock." "\n"
10733
                "- Drag from window menu button (upper-left button) to undock an entire node (all windows)." "\n"
10734
                "- Hold SHIFT to disable docking (if io.ConfigDockingWithShift == false, default)" "\n"
10735
                "- Hold SHIFT to enable docking (if io.ConfigDockingWithShift == true)");
10736
            ImGui::Separator();
10737
            ImGui::TextUnformatted("More details:"); ImGui::Bullet(); ImGui::SameLine(); ImGui::TextLinkOpenURL("Docking Wiki page", "https://github.com/ocornut/imgui/wiki/Docking");
10738
            ImGui::BulletText("Read comments in ShowExampleAppDockSpace()");
10739
            ImGui::EndMenu();
10740
        }
10741
        ImGui::EndMenuBar();
10742
    }
10743
10744
    ImGui::End();
10745
}
10746
10747
//-----------------------------------------------------------------------------
10748
// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
10749
//-----------------------------------------------------------------------------
10750
10751
// Simplified structure to mimic a Document model
10752
struct MyDocument
10753
{
10754
    char        Name[32];   // Document title
10755
    int         UID;        // Unique ID (necessary as we can change title)
10756
    bool        Open;       // Set when open (we keep an array of all available documents to simplify demo code!)
10757
    bool        OpenPrev;   // Copy of Open from last update.
10758
    bool        Dirty;      // Set when the document has been modified
10759
    ImVec4      Color;      // An arbitrary variable associated to the document
10760
10761
    MyDocument(int uid, const char* name, bool open = true, const ImVec4& color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f))
10762
    {
10763
        UID = uid;
10764
        snprintf(Name, sizeof(Name), "%s", name);
10765
        Open = OpenPrev = open;
10766
        Dirty = false;
10767
        Color = color;
10768
    }
10769
    void DoOpen()       { Open = true; }
10770
    void DoForceClose() { Open = false; Dirty = false; }
10771
    void DoSave()       { Dirty = false; }
10772
};
10773
10774
struct ExampleAppDocuments
10775
{
10776
    ImVector<MyDocument>    Documents;
10777
    ImVector<MyDocument*>   CloseQueue;
10778
    MyDocument*             RenamingDoc = NULL;
10779
    bool                    RenamingStarted = false;
10780
10781
    ExampleAppDocuments()
10782
    {
10783
        Documents.push_back(MyDocument(0, "Lettuce",             true,  ImVec4(0.4f, 0.8f, 0.4f, 1.0f)));
10784
        Documents.push_back(MyDocument(1, "Eggplant",            true,  ImVec4(0.8f, 0.5f, 1.0f, 1.0f)));
10785
        Documents.push_back(MyDocument(2, "Carrot",              true,  ImVec4(1.0f, 0.8f, 0.5f, 1.0f)));
10786
        Documents.push_back(MyDocument(3, "Tomato",              false, ImVec4(1.0f, 0.3f, 0.4f, 1.0f)));
10787
        Documents.push_back(MyDocument(4, "A Rather Long Title", false, ImVec4(0.4f, 0.8f, 0.8f, 1.0f)));
10788
        Documents.push_back(MyDocument(5, "Some Document",       false, ImVec4(0.8f, 0.8f, 1.0f, 1.0f)));
10789
    }
10790
10791
    // As we allow to change document name, we append a never-changing document ID so tabs are stable
10792
    void GetTabName(MyDocument* doc, char* out_buf, size_t out_buf_size)
10793
    {
10794
        snprintf(out_buf, out_buf_size, "%s###doc%d", doc->Name, doc->UID);
10795
    }
10796
10797
    // Display placeholder contents for the Document
10798
    void DisplayDocContents(MyDocument* doc)
10799
    {
10800
        ImGui::PushID(doc);
10801
        ImGui::Text("Document \"%s\"", doc->Name);
10802
        ImGui::PushStyleColor(ImGuiCol_Text, doc->Color);
10803
        ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.");
10804
        ImGui::PopStyleColor();
10805
10806
        ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_R, ImGuiInputFlags_Tooltip);
10807
        if (ImGui::Button("Rename.."))
10808
        {
10809
            RenamingDoc = doc;
10810
            RenamingStarted = true;
10811
        }
10812
        ImGui::SameLine();
10813
10814
        ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_M, ImGuiInputFlags_Tooltip);
10815
        if (ImGui::Button("Modify"))
10816
            doc->Dirty = true;
10817
10818
        ImGui::SameLine();
10819
        ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_S, ImGuiInputFlags_Tooltip);
10820
        if (ImGui::Button("Save"))
10821
            doc->DoSave();
10822
10823
        ImGui::SameLine();
10824
        ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_W, ImGuiInputFlags_Tooltip);
10825
        if (ImGui::Button("Close"))
10826
            CloseQueue.push_back(doc);
10827
        ImGui::ColorEdit3("color", &doc->Color.x);  // Useful to test drag and drop and hold-dragged-to-open-tab behavior.
10828
        ImGui::PopID();
10829
    }
10830
10831
    // Display context menu for the Document
10832
    void DisplayDocContextMenu(MyDocument* doc)
10833
    {
10834
        if (!ImGui::BeginPopupContextItem())
10835
            return;
10836
10837
        char buf[256];
10838
        sprintf(buf, "Save %s", doc->Name);
10839
        if (ImGui::MenuItem(buf, "Ctrl+S", false, doc->Open))
10840
            doc->DoSave();
10841
        if (ImGui::MenuItem("Rename...", "Ctrl+R", false, doc->Open))
10842
            RenamingDoc = doc;
10843
        if (ImGui::MenuItem("Close", "Ctrl+W", false, doc->Open))
10844
            CloseQueue.push_back(doc);
10845
        ImGui::EndPopup();
10846
    }
10847
10848
    // [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface.
10849
    // If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo,
10850
    // as opposed to clicking on the regular tab closing button) and stops being submitted, it will take a frame for
10851
    // 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
10852
    // disappeared was the selected one, the tab bar will report no selected tab during the frame. This will effectively
10853
    // give the impression of a flicker for one frame.
10854
    // We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch.
10855
    // Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag.
10856
    void NotifyOfDocumentsClosedElsewhere()
10857
    {
10858
        for (MyDocument& doc : Documents)
10859
        {
10860
            if (!doc.Open && doc.OpenPrev)
10861
                ImGui::SetTabItemClosed(doc.Name);
10862
            doc.OpenPrev = doc.Open;
10863
        }
10864
    }
10865
};
10866
10867
void ShowExampleAppDocuments(bool* p_open)
10868
{
10869
    static ExampleAppDocuments app;
10870
10871
    // Options
10872
    enum Target
10873
    {
10874
        Target_None,
10875
        Target_Tab,                 // Create documents as local tab into a local tab bar
10876
        Target_DockSpaceAndWindow   // Create documents as regular windows, and create an embedded dockspace
10877
    };
10878
    static Target opt_target = Target_Tab;
10879
    static bool opt_reorderable = true;
10880
    static ImGuiTabBarFlags opt_fitting_flags = ImGuiTabBarFlags_FittingPolicyDefault_;
10881
10882
    // When (opt_target == Target_DockSpaceAndWindow) there is the possibily that one of our child Document window (e.g. "Eggplant")
10883
    // that we emit gets docked into the same spot as the parent window ("Example: Documents").
10884
    // This would create a problematic feedback loop because selecting the "Eggplant" tab would make the "Example: Documents" tab
10885
    // not visible, which in turn would stop submitting the "Eggplant" window.
10886
    // We avoid this problem by submitting our documents window even if our parent window is not currently visible.
10887
    // Another solution may be to make the "Example: Documents" window use the ImGuiWindowFlags_NoDocking.
10888
10889
    bool window_contents_visible = ImGui::Begin("Example: Documents", p_open, ImGuiWindowFlags_MenuBar);
10890
    if (!window_contents_visible && opt_target != Target_DockSpaceAndWindow)
10891
    {
10892
        ImGui::End();
10893
        return;
10894
    }
10895
    IMGUI_DEMO_MARKER("Examples/Documents");
10896
10897
    // Menu
10898
    if (ImGui::BeginMenuBar())
10899
    {
10900
        if (ImGui::BeginMenu("File"))
10901
        {
10902
            int open_count = 0;
10903
            for (MyDocument& doc : app.Documents)
10904
                open_count += doc.Open ? 1 : 0;
10905
10906
            if (ImGui::BeginMenu("Open", open_count < app.Documents.Size))
10907
            {
10908
                for (MyDocument& doc : app.Documents)
10909
                    if (!doc.Open && ImGui::MenuItem(doc.Name))
10910
                        doc.DoOpen();
10911
                ImGui::EndMenu();
10912
            }
10913
            if (ImGui::MenuItem("Close All Documents", NULL, false, open_count > 0))
10914
                for (MyDocument& doc : app.Documents)
10915
                    app.CloseQueue.push_back(&doc);
10916
            if (ImGui::MenuItem("Exit") && p_open)
10917
                *p_open = false;
10918
            ImGui::EndMenu();
10919
        }
10920
        ImGui::EndMenuBar();
10921
    }
10922
10923
    // [Debug] List documents with one checkbox for each
10924
    for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
10925
    {
10926
        MyDocument& doc = app.Documents[doc_n];
10927
        if (doc_n > 0)
10928
            ImGui::SameLine();
10929
        ImGui::PushID(&doc);
10930
        if (ImGui::Checkbox(doc.Name, &doc.Open))
10931
            if (!doc.Open)
10932
                doc.DoForceClose();
10933
        ImGui::PopID();
10934
    }
10935
    ImGui::PushItemWidth(ImGui::GetFontSize() * 12);
10936
    ImGui::Combo("Output", (int*)&opt_target, "None\0TabBar+Tabs\0DockSpace+Window\0");
10937
    ImGui::PopItemWidth();
10938
    bool redock_all = false;
10939
    if (opt_target == Target_Tab)                { ImGui::SameLine(); ImGui::Checkbox("Reorderable Tabs", &opt_reorderable); }
10940
    if (opt_target == Target_DockSpaceAndWindow) { ImGui::SameLine(); redock_all = ImGui::Button("Redock all"); }
10941
10942
    ImGui::Separator();
10943
10944
    // About the ImGuiWindowFlags_UnsavedDocument / ImGuiTabItemFlags_UnsavedDocument flags.
10945
    // They have multiple effects:
10946
    // - Display a dot next to the title.
10947
    // - Tab is selected when clicking the X close button.
10948
    // - Closure is not assumed (will wait for user to stop submitting the tab).
10949
    //   Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar.
10950
    //   We need to assume closure by default otherwise waiting for "lack of submission" on the next frame would leave an empty
10951
    //   hole for one-frame, both in the tab-bar and in tab-contents when closing a tab/window.
10952
    //   The rarely used SetTabItemClosed() function is a way to notify of programmatic closure to avoid the one-frame hole.
10953
10954
    // Tabs
10955
    if (opt_target == Target_Tab)
10956
    {
10957
        ImGuiTabBarFlags tab_bar_flags = (opt_fitting_flags) | (opt_reorderable ? ImGuiTabBarFlags_Reorderable : 0);
10958
        tab_bar_flags |= ImGuiTabBarFlags_DrawSelectedOverline;
10959
        if (ImGui::BeginTabBar("##tabs", tab_bar_flags))
10960
        {
10961
            if (opt_reorderable)
10962
                app.NotifyOfDocumentsClosedElsewhere();
10963
10964
            // [DEBUG] Stress tests
10965
            //if ((ImGui::GetFrameCount() % 30) == 0) docs[1].Open ^= 1;            // [DEBUG] Automatically show/hide a tab. Test various interactions e.g. dragging with this on.
10966
            //if (ImGui::GetIO().KeyCtrl) ImGui::SetTabItemSelected(docs[1].Name);  // [DEBUG] Test SetTabItemSelected(), probably not very useful as-is anyway..
10967
10968
            // Submit Tabs
10969
            for (MyDocument& doc : app.Documents)
10970
            {
10971
                if (!doc.Open)
10972
                    continue;
10973
10974
                // As we allow to change document name, we append a never-changing document id so tabs are stable
10975
                char doc_name_buf[64];
10976
                app.GetTabName(&doc, doc_name_buf, sizeof(doc_name_buf));
10977
                ImGuiTabItemFlags tab_flags = (doc.Dirty ? ImGuiTabItemFlags_UnsavedDocument : 0);
10978
                bool visible = ImGui::BeginTabItem(doc_name_buf, &doc.Open, tab_flags);
10979
10980
                // Cancel attempt to close when unsaved add to save queue so we can display a popup.
10981
                if (!doc.Open && doc.Dirty)
10982
                {
10983
                    doc.Open = true;
10984
                    app.CloseQueue.push_back(&doc);
10985
                }
10986
10987
                app.DisplayDocContextMenu(&doc);
10988
                if (visible)
10989
                {
10990
                    app.DisplayDocContents(&doc);
10991
                    ImGui::EndTabItem();
10992
                }
10993
            }
10994
10995
            ImGui::EndTabBar();
10996
        }
10997
    }
10998
    else if (opt_target == Target_DockSpaceAndWindow)
10999
    {
11000
        if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_DockingEnable)
11001
        {
11002
            app.NotifyOfDocumentsClosedElsewhere();
11003
11004
            // Create a DockSpace node where any window can be docked
11005
            ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
11006
            ImGui::DockSpace(dockspace_id);
11007
11008
            // Create Windows
11009
            for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
11010
            {
11011
                MyDocument* doc = &app.Documents[doc_n];
11012
                if (!doc->Open)
11013
                    continue;
11014
11015
                ImGui::SetNextWindowDockID(dockspace_id, redock_all ? ImGuiCond_Always : ImGuiCond_FirstUseEver);
11016
                ImGuiWindowFlags window_flags = (doc->Dirty ? ImGuiWindowFlags_UnsavedDocument : 0);
11017
                bool visible = ImGui::Begin(doc->Name, &doc->Open, window_flags);
11018
11019
                // Cancel attempt to close when unsaved add to save queue so we can display a popup.
11020
                if (!doc->Open && doc->Dirty)
11021
                {
11022
                    doc->Open = true;
11023
                    app.CloseQueue.push_back(doc);
11024
                }
11025
11026
                app.DisplayDocContextMenu(doc);
11027
                if (visible)
11028
                    app.DisplayDocContents(doc);
11029
11030
                ImGui::End();
11031
            }
11032
        }
11033
        else
11034
        {
11035
            ShowDockingDisabledMessage();
11036
        }
11037
    }
11038
11039
    // Early out other contents
11040
    if (!window_contents_visible)
11041
    {
11042
        ImGui::End();
11043
        return;
11044
    }
11045
11046
    // Display renaming UI
11047
    if (app.RenamingDoc != NULL)
11048
    {
11049
        if (app.RenamingStarted)
11050
            ImGui::OpenPopup("Rename");
11051
        if (ImGui::BeginPopup("Rename"))
11052
        {
11053
            ImGui::SetNextItemWidth(ImGui::GetFontSize() * 30);
11054
            if (ImGui::InputText("###Name", app.RenamingDoc->Name, IM_COUNTOF(app.RenamingDoc->Name), ImGuiInputTextFlags_EnterReturnsTrue))
11055
            {
11056
                ImGui::CloseCurrentPopup();
11057
                app.RenamingDoc = NULL;
11058
            }
11059
            if (app.RenamingStarted)
11060
                ImGui::SetKeyboardFocusHere(-1);
11061
            ImGui::EndPopup();
11062
        }
11063
        else
11064
        {
11065
            app.RenamingDoc = NULL;
11066
        }
11067
        app.RenamingStarted = false;
11068
    }
11069
11070
    // Display closing confirmation UI
11071
    if (!app.CloseQueue.empty())
11072
    {
11073
        int close_queue_unsaved_documents = 0;
11074
        for (int n = 0; n < app.CloseQueue.Size; n++)
11075
            if (app.CloseQueue[n]->Dirty)
11076
                close_queue_unsaved_documents++;
11077
11078
        if (close_queue_unsaved_documents == 0)
11079
        {
11080
            // Close documents when all are unsaved
11081
            for (int n = 0; n < app.CloseQueue.Size; n++)
11082
                app.CloseQueue[n]->DoForceClose();
11083
            app.CloseQueue.clear();
11084
        }
11085
        else
11086
        {
11087
            if (!ImGui::IsPopupOpen("Save?"))
11088
                ImGui::OpenPopup("Save?");
11089
            if (ImGui::BeginPopupModal("Save?", NULL, ImGuiWindowFlags_AlwaysAutoResize))
11090
            {
11091
                ImGui::Text("Save change to the following items?");
11092
                float item_height = ImGui::GetTextLineHeightWithSpacing();
11093
                if (ImGui::BeginChild(ImGui::GetID("frame"), ImVec2(-FLT_MIN, 6.25f * item_height), ImGuiChildFlags_FrameStyle))
11094
                    for (MyDocument* doc : app.CloseQueue)
11095
                        if (doc->Dirty)
11096
                            ImGui::Text("%s", doc->Name);
11097
                ImGui::EndChild();
11098
11099
                ImVec2 button_size(ImGui::GetFontSize() * 7.0f, 0.0f);
11100
                if (ImGui::Button("Yes", button_size))
11101
                {
11102
                    for (MyDocument* doc : app.CloseQueue)
11103
                    {
11104
                        if (doc->Dirty)
11105
                            doc->DoSave();
11106
                        doc->DoForceClose();
11107
                    }
11108
                    app.CloseQueue.clear();
11109
                    ImGui::CloseCurrentPopup();
11110
                }
11111
                ImGui::SameLine();
11112
                if (ImGui::Button("No", button_size))
11113
                {
11114
                    for (MyDocument* doc : app.CloseQueue)
11115
                        doc->DoForceClose();
11116
                    app.CloseQueue.clear();
11117
                    ImGui::CloseCurrentPopup();
11118
                }
11119
                ImGui::SameLine();
11120
                if (ImGui::Button("Cancel", button_size))
11121
                {
11122
                    app.CloseQueue.clear();
11123
                    ImGui::CloseCurrentPopup();
11124
                }
11125
                ImGui::EndPopup();
11126
            }
11127
        }
11128
    }
11129
11130
    ImGui::End();
11131
}
11132
11133
//-----------------------------------------------------------------------------
11134
// [SECTION] Example App: Assets Browser / ShowExampleAppAssetsBrowser()
11135
//-----------------------------------------------------------------------------
11136
11137
//#include "imgui_internal.h" // NavMoveRequestTryWrapping()
11138
11139
struct ExampleAsset
11140
{
11141
    ImGuiID ID;
11142
    int     Type;
11143
11144
    ExampleAsset(ImGuiID id, int type) { ID = id; Type = type; }
11145
11146
    static const ImGuiTableSortSpecs* s_current_sort_specs;
11147
11148
    static void SortWithSortSpecs(ImGuiTableSortSpecs* sort_specs, ExampleAsset* items, int items_count)
11149
    {
11150
        s_current_sort_specs = sort_specs; // Store in variable accessible by the sort function.
11151
        if (items_count > 1)
11152
            qsort(items, (size_t)items_count, sizeof(items[0]), ExampleAsset::CompareWithSortSpecs);
11153
        s_current_sort_specs = NULL;
11154
    }
11155
11156
    // Compare function to be used by qsort()
11157
    static int IMGUI_CDECL CompareWithSortSpecs(const void* lhs, const void* rhs)
11158
    {
11159
        const ExampleAsset* a = (const ExampleAsset*)lhs;
11160
        const ExampleAsset* b = (const ExampleAsset*)rhs;
11161
        for (int n = 0; n < s_current_sort_specs->SpecsCount; n++)
11162
        {
11163
            const ImGuiTableColumnSortSpecs* sort_spec = &s_current_sort_specs->Specs[n];
11164
            int delta = 0;
11165
            if (sort_spec->ColumnIndex == 0)
11166
                delta = ((int)a->ID - (int)b->ID);
11167
            else if (sort_spec->ColumnIndex == 1)
11168
                delta = (a->Type - b->Type);
11169
            if (delta > 0)
11170
                return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? +1 : -1;
11171
            if (delta < 0)
11172
                return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? -1 : +1;
11173
        }
11174
        return (int)a->ID - (int)b->ID;
11175
    }
11176
};
11177
const ImGuiTableSortSpecs* ExampleAsset::s_current_sort_specs = NULL;
11178
11179
struct ExampleAssetsBrowser
11180
{
11181
    // Options
11182
    bool            ShowTypeOverlay = true;
11183
    bool            AllowSorting = true;
11184
    bool            AllowBoxSelect = true;                  // Will set ImGuiMultiSelectFlags_BoxSelect2d
11185
    bool            AllowBoxSelectInsideSelection = false;  // Will set ImGuiMultiSelectFlags_SelectOnClickAlways
11186
    bool            AllowDragUnselected = false;            // Will set ImGuiMultiSelectFlags_SelectOnClickRelease
11187
    float           IconSize = 0;
11188
    int             IconSpacing = 10;
11189
    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.
11190
    bool            StretchSpacing = true;
11191
    bool            UseScrollX = false;                     // Debug: submit twice the number of items per line (overflow horizontally to exercise ScrollX + box-select)
11192
11193
    // State
11194
    ImVector<ExampleAsset> Items;               // Our items
11195
    ExampleSelectionWithDeletion Selection;     // Our selection (ImGuiSelectionBasicStorage + helper funcs to handle deletion)
11196
    ImGuiID         NextItemId = 0;             // Unique identifier when creating new items
11197
    bool            RequestDelete = false;      // Deferred deletion request
11198
    bool            RequestSort = false;        // Deferred sort request
11199
    float           ZoomWheelAccum = 0.0f;      // Mouse wheel accumulator to handle smooth wheels better
11200
11201
    // Calculated sizes for layout, output of UpdateLayoutSizes(). Could be locals but our code is simpler this way.
11202
    ImVec2          LayoutItemSize;
11203
    ImVec2          LayoutItemStep;             // == LayoutItemSize + LayoutItemSpacing
11204
    float           LayoutItemSpacing = 0.0f;
11205
    float           LayoutSelectableSpacing = 0.0f;
11206
    float           LayoutOuterPadding = 0.0f;
11207
    int             LayoutColumnCount = 0;
11208
    int             LayoutLineCount = 0;
11209
11210
    // Functions
11211
    ExampleAssetsBrowser()
11212
    {
11213
        AddItems(10000);
11214
    }
11215
    void AddItems(int count)
11216
    {
11217
        if (Items.Size == 0)
11218
            NextItemId = 0;
11219
        Items.reserve(Items.Size + count);
11220
        for (int n = 0; n < count; n++, NextItemId++)
11221
            Items.push_back(ExampleAsset(NextItemId, (NextItemId % 20) < 15 ? 0 : (NextItemId % 20) < 18 ? 1 : 2));
11222
        RequestSort = true;
11223
    }
11224
    void ClearItems()
11225
    {
11226
        Items.clear();
11227
        Selection.Clear();
11228
    }
11229
11230
    // Logic would be written in the main code BeginChild() and outputting to local variables.
11231
    // We extracted it into a function so we can call it easily from multiple places.
11232
    void UpdateLayoutSizes(float avail_width)
11233
    {
11234
        // Layout: when not stretching: allow extending into right-most spacing.
11235
        LayoutItemSpacing = (float)IconSpacing;
11236
        if (StretchSpacing == false)
11237
            avail_width += floorf(LayoutItemSpacing * 0.5f);
11238
11239
        // Layout: calculate number of icon per line and number of lines
11240
        LayoutItemSize = ImVec2(floorf(IconSize), floorf(IconSize));
11241
        LayoutColumnCount = IM_MAX((int)(avail_width / (LayoutItemSize.x + LayoutItemSpacing)), 1);
11242
11243
        // Layout: when stretching: allocate remaining space to more spacing. Round before division, so item_spacing may be non-integer.
11244
        if (StretchSpacing && LayoutColumnCount > 1)
11245
            LayoutItemSpacing = floorf(avail_width - LayoutItemSize.x * LayoutColumnCount) / LayoutColumnCount;
11246
11247
        if (UseScrollX)
11248
            LayoutColumnCount *= 2;
11249
        LayoutLineCount = (Items.Size + LayoutColumnCount - 1) / LayoutColumnCount;
11250
11251
        LayoutItemStep = ImVec2(LayoutItemSize.x + LayoutItemSpacing, LayoutItemSize.y + LayoutItemSpacing);
11252
        LayoutSelectableSpacing = IM_MAX(floorf(LayoutItemSpacing) - IconHitSpacing, 0.0f);
11253
        LayoutOuterPadding = floorf(LayoutItemSpacing * 0.5f);
11254
    }
11255
11256
    void Draw(const char* title, bool* p_open)
11257
    {
11258
        if (IconSize <= 0.0f)
11259
            IconSize = ImGui::CalcTextSize("99999").x;
11260
11261
        ImGui::SetNextWindowSize(ImVec2(IconSize * 25, IconSize * 15), ImGuiCond_FirstUseEver);
11262
        if (!ImGui::Begin(title, p_open, ImGuiWindowFlags_MenuBar))
11263
        {
11264
            ImGui::End();
11265
            return;
11266
        }
11267
        IMGUI_DEMO_MARKER("Examples/Assets Browser");
11268
11269
        // Menu bar
11270
        if (ImGui::BeginMenuBar())
11271
        {
11272
            if (ImGui::BeginMenu("File"))
11273
            {
11274
                if (ImGui::MenuItem("Add 10000 items"))
11275
                    AddItems(10000);
11276
                if (ImGui::MenuItem("Clear items"))
11277
                    ClearItems();
11278
                ImGui::Separator();
11279
                if (ImGui::MenuItem("Close", NULL, false, p_open != NULL))
11280
                    *p_open = false;
11281
                ImGui::EndMenu();
11282
            }
11283
            if (ImGui::BeginMenu("Edit"))
11284
            {
11285
                if (ImGui::MenuItem("Delete", "Del", false, Selection.Size > 0))
11286
                    RequestDelete = true;
11287
                ImGui::EndMenu();
11288
            }
11289
            if (ImGui::BeginMenu("Options"))
11290
            {
11291
                ImGui::PushItemWidth(ImGui::GetFontSize() * 10);
11292
11293
                ImGui::SeparatorText("Contents");
11294
                ImGui::Checkbox("Show Type Overlay", &ShowTypeOverlay);
11295
                ImGui::Checkbox("Allow Sorting", &AllowSorting);
11296
11297
                ImGui::SeparatorText("Selection Behavior");
11298
                ImGui::Checkbox("Allow box-selection", &AllowBoxSelect);
11299
                if (ImGui::Checkbox("Allow box-selection from selected items", &AllowBoxSelectInsideSelection) && AllowBoxSelectInsideSelection)
11300
                    AllowDragUnselected = false;
11301
                if (ImGui::Checkbox("Allow dragging unselected item", &AllowDragUnselected) && AllowDragUnselected)
11302
                    AllowBoxSelectInsideSelection = false;
11303
11304
                ImGui::SeparatorText("Layout");
11305
                ImGui::SliderFloat("Icon Size", &IconSize, 16.0f, 128.0f, "%.0f");
11306
                ImGui::SameLine(); HelpMarker("Use Ctrl+Wheel to zoom");
11307
                ImGui::SliderInt("Icon Spacing", &IconSpacing, 0, 32);
11308
                ImGui::SliderInt("Icon Hit Spacing", &IconHitSpacing, 0, 32);
11309
                ImGui::Checkbox("Stretch Spacing", &StretchSpacing);
11310
                ImGui::Checkbox("Use ScrollX", &UseScrollX);
11311
                ImGui::PopItemWidth();
11312
                ImGui::EndMenu();
11313
            }
11314
            ImGui::EndMenuBar();
11315
        }
11316
11317
        // Show a table with ONLY one header row to showcase the idea/possibility of using this to provide a sorting UI
11318
        if (AllowSorting)
11319
        {
11320
            ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
11321
            ImGuiTableFlags table_flags_for_sort_specs = ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Borders;
11322
            if (ImGui::BeginTable("for_sort_specs_only", 2, table_flags_for_sort_specs, ImVec2(0.0f, ImGui::GetFrameHeight())))
11323
            {
11324
                ImGui::TableSetupColumn("Index");
11325
                ImGui::TableSetupColumn("Type");
11326
                ImGui::TableHeadersRow();
11327
                if (ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs())
11328
                    if (sort_specs->SpecsDirty || RequestSort)
11329
                    {
11330
                        ExampleAsset::SortWithSortSpecs(sort_specs, Items.Data, Items.Size);
11331
                        sort_specs->SpecsDirty = RequestSort = false;
11332
                    }
11333
                ImGui::EndTable();
11334
            }
11335
            ImGui::PopStyleVar();
11336
        }
11337
11338
        ImGuiIO& io = ImGui::GetIO();
11339
        ImGui::SetNextWindowContentSize(ImVec2(0.0f, LayoutOuterPadding + LayoutLineCount * (LayoutItemSize.y + LayoutItemSpacing)));
11340
        if (ImGui::BeginChild("Assets", ImVec2(0.0f, -ImGui::GetTextLineHeightWithSpacing()), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_HorizontalScrollbar))
11341
        {
11342
            ImDrawList* draw_list = ImGui::GetWindowDrawList();
11343
11344
            const float avail_width = ImGui::GetContentRegionAvail().x;
11345
            UpdateLayoutSizes(avail_width);
11346
11347
            // Calculate and store start position.
11348
            ImVec2 start_pos = ImGui::GetCursorScreenPos();
11349
            start_pos = ImVec2(start_pos.x + LayoutOuterPadding, start_pos.y + LayoutOuterPadding);
11350
            ImGui::SetCursorScreenPos(start_pos);
11351
11352
            // Multi-select
11353
            ImGuiMultiSelectFlags ms_flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_ClearOnClickVoid;
11354
11355
            // - Enable box-select (in 2D mode, so that changing box-select rectangle X1/X2 boundaries will affect clipped items)
11356
            if (AllowBoxSelect)
11357
                ms_flags |= ImGuiMultiSelectFlags_BoxSelect2d;
11358
11359
            // - Selection mode
11360
            if (AllowDragUnselected)
11361
                ms_flags |= ImGuiMultiSelectFlags_SelectOnClickRelease; // Rarely used: Allows dragging an unselected item without selecting it(rarely used)
11362
            else if (AllowBoxSelectInsideSelection)
11363
                ms_flags |= ImGuiMultiSelectFlags_SelectOnClickAlways; // Rarely used: Prevents Drag and Drop from being used on multiple-selection, but allows e.g. BoxSelect to always reselect even when clicking inside an existing selection.
11364
11365
            // - Enable keyboard wrapping on X axis
11366
            // (FIXME-MULTISELECT: We haven't designed/exposed a general nav wrapping api yet, so this flag is provided as a courtesy to avoid doing:
11367
            //    ImGui::NavMoveRequestTryWrapping(ImGui::GetCurrentWindow(), ImGuiNavMoveFlags_WrapX);
11368
            // When we finish implementing a more general API for this, we will obsolete this flag in favor of the new system)
11369
            ms_flags |= ImGuiMultiSelectFlags_NavWrapX;
11370
11371
            ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(ms_flags, Selection.Size, Items.Size);
11372
11373
            // Use custom selection adapter: store ID in selection (recommended)
11374
            Selection.UserData = this;
11375
            Selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self_, int idx) { ExampleAssetsBrowser* self = (ExampleAssetsBrowser*)self_->UserData; return self->Items[idx].ID; };
11376
            Selection.ApplyRequests(ms_io);
11377
11378
            const bool want_delete = (ImGui::Shortcut(ImGuiKey_Delete, ImGuiInputFlags_Repeat) && (Selection.Size > 0)) || RequestDelete;
11379
            const int item_curr_idx_to_focus = want_delete ? Selection.ApplyDeletionPreLoop(ms_io, Items.Size) : -1;
11380
            RequestDelete = false;
11381
11382
            // Push LayoutSelectableSpacing (which is LayoutItemSpacing minus hit-spacing, if we decide to have hit gaps between items)
11383
            // Altering style ItemSpacing may seem unnecessary as we position every items using SetCursorScreenPos()...
11384
            // But it is necessary for two reasons:
11385
            // - Selectables uses it by default to visually fill the space between two items.
11386
            // - The vertical spacing would be measured by Clipper to calculate line height if we didn't provide it explicitly (here we do).
11387
            ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(LayoutSelectableSpacing, LayoutSelectableSpacing));
11388
11389
            // Rendering parameters
11390
            const ImU32 icon_type_overlay_colors[3] = { 0, IM_COL32(200, 70, 70, 255), IM_COL32(70, 170, 70, 255) };
11391
            const ImU32 icon_bg_color = ImGui::GetColorU32(IM_COL32(35, 35, 35, 220));
11392
            const ImVec2 icon_type_overlay_size = ImVec2(4.0f, 4.0f);
11393
            const bool display_label = (LayoutItemSize.x >= ImGui::CalcTextSize("999").x);
11394
11395
            const int column_count = LayoutColumnCount;
11396
            ImGuiListClipper clipper;
11397
            clipper.Begin(LayoutLineCount, LayoutItemStep.y);
11398
            if (item_curr_idx_to_focus != -1)
11399
                clipper.IncludeItemByIndex(item_curr_idx_to_focus / column_count); // Ensure focused item line is not clipped.
11400
            if (ms_io->RangeSrcItem != -1)
11401
                clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem / column_count); // Ensure RangeSrc item line is not clipped.
11402
            while (clipper.Step())
11403
            {
11404
                for (int line_idx = clipper.DisplayStart; line_idx < clipper.DisplayEnd; line_idx++)
11405
                {
11406
                    const int item_min_idx_for_current_line = line_idx * column_count;
11407
                    const int item_max_idx_for_current_line = IM_MIN((line_idx + 1) * column_count, Items.Size);
11408
                    for (int item_idx = item_min_idx_for_current_line; item_idx < item_max_idx_for_current_line; ++item_idx)
11409
                    {
11410
                        ExampleAsset* item_data = &Items[item_idx];
11411
                        ImGui::PushID((int)item_data->ID);
11412
11413
                        // Position item
11414
                        ImVec2 pos = ImVec2(start_pos.x + (item_idx % column_count) * LayoutItemStep.x, start_pos.y + line_idx * LayoutItemStep.y);
11415
                        ImGui::SetCursorScreenPos(pos);
11416
11417
                        ImGui::SetNextItemSelectionUserData(item_idx);
11418
                        bool item_is_selected = Selection.Contains((ImGuiID)item_data->ID);
11419
                        bool item_is_visible = ImGui::IsRectVisible(LayoutItemSize);
11420
                        ImGui::Selectable("", item_is_selected, ImGuiSelectableFlags_None, LayoutItemSize);
11421
11422
                        // Update our selection state immediately (without waiting for EndMultiSelect() requests)
11423
                        // because we use this to alter the color of our text/icon.
11424
                        if (ImGui::IsItemToggledSelection())
11425
                            item_is_selected = !item_is_selected;
11426
11427
                        // Focus (for after deletion)
11428
                        if (item_curr_idx_to_focus == item_idx)
11429
                            ImGui::SetKeyboardFocusHere(-1);
11430
11431
                        // Drag and drop
11432
                        if (ImGui::BeginDragDropSource())
11433
                        {
11434
                            // Create payload with full selection OR single unselected item.
11435
                            // (the later is only possible when using ImGuiMultiSelectFlags_SelectOnClickRelease)
11436
                            if (ImGui::GetDragDropPayload() == NULL)
11437
                            {
11438
                                ImVector<ImGuiID> payload_items;
11439
                                void* it = NULL;
11440
                                ImGuiID id = 0;
11441
                                if (!item_is_selected)
11442
                                    payload_items.push_back(item_data->ID);
11443
                                else
11444
                                    while (Selection.GetNextSelectedItem(&it, &id))
11445
                                        payload_items.push_back(id);
11446
                                ImGui::SetDragDropPayload("ASSETS_BROWSER_ITEMS", payload_items.Data, (size_t)payload_items.size_in_bytes());
11447
                            }
11448
11449
                            // Display payload content in tooltip, by extracting it from the payload data
11450
                            // (we could read from selection, but it is more correct and reusable to read from payload)
11451
                            const ImGuiPayload* payload = ImGui::GetDragDropPayload();
11452
                            const int payload_count = (int)payload->DataSize / (int)sizeof(ImGuiID);
11453
                            ImGui::Text("%d assets", payload_count);
11454
11455
                            ImGui::EndDragDropSource();
11456
                        }
11457
11458
                        // Render icon (a real app would likely display an image/thumbnail here)
11459
                        // Because we use ImGuiMultiSelectFlags_BoxSelect2d, clipping vertical may occasionally be larger, so we coarse-clip our rendering as well.
11460
                        if (item_is_visible)
11461
                        {
11462
                            ImVec2 box_min(pos.x - 1, pos.y - 1);
11463
                            ImVec2 box_max(box_min.x + LayoutItemSize.x + 2, box_min.y + LayoutItemSize.y + 2); // Dubious
11464
                            draw_list->AddRectFilled(box_min, box_max, icon_bg_color); // Background color
11465
                            if (ShowTypeOverlay && item_data->Type != 0)
11466
                            {
11467
                                ImU32 type_col = icon_type_overlay_colors[item_data->Type % IM_COUNTOF(icon_type_overlay_colors)];
11468
                                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);
11469
                            }
11470
                            if (display_label)
11471
                            {
11472
                                ImU32 label_col = ImGui::GetColorU32(item_is_selected ? ImGuiCol_Text : ImGuiCol_TextDisabled);
11473
                                char label[32];
11474
                                sprintf(label, "%d", item_data->ID);
11475
                                draw_list->AddText(ImVec2(box_min.x, box_max.y - ImGui::GetFontSize()), label_col, label);
11476
                            }
11477
                        }
11478
11479
                        ImGui::PopID();
11480
                    }
11481
                }
11482
            }
11483
            clipper.End();
11484
            if (Items.Size == 0)
11485
                ImGui::Dummy(ImVec2(0, 0));
11486
            ImGui::PopStyleVar(); // ImGuiStyleVar_ItemSpacing
11487
11488
            // Context menu
11489
            if (ImGui::BeginPopupContextWindow())
11490
            {
11491
                ImGui::Text("Selection: %d items", Selection.Size);
11492
                ImGui::Separator();
11493
                if (ImGui::MenuItem("Delete", "Del", false, Selection.Size > 0))
11494
                    RequestDelete = true;
11495
                ImGui::EndPopup();
11496
            }
11497
11498
            ms_io = ImGui::EndMultiSelect();
11499
            Selection.ApplyRequests(ms_io);
11500
            if (want_delete)
11501
                Selection.ApplyDeletionPostLoop(ms_io, Items, item_curr_idx_to_focus);
11502
11503
            // Zooming with Ctrl+Wheel
11504
            if (ImGui::IsWindowAppearing())
11505
                ZoomWheelAccum = 0.0f;
11506
            if (ImGui::IsWindowHovered() && io.MouseWheel != 0.0f && ImGui::IsKeyDown(ImGuiMod_Ctrl) && ImGui::IsAnyItemActive() == false)
11507
            {
11508
                ZoomWheelAccum += io.MouseWheel;
11509
                if (fabsf(ZoomWheelAccum) >= 1.0f)
11510
                {
11511
                    // Calculate hovered item index from mouse location
11512
                    // FIXME: Locking aiming on 'hovered_item_idx' (with a cool-down timer) would ensure zoom keeps on it.
11513
                    const float hovered_item_nx = (io.MousePos.x - start_pos.x + LayoutItemSpacing * 0.5f) / LayoutItemStep.x;
11514
                    const float hovered_item_ny = (io.MousePos.y - start_pos.y + LayoutItemSpacing * 0.5f) / LayoutItemStep.y;
11515
                    const int hovered_item_idx = ((int)hovered_item_ny * LayoutColumnCount) + (int)hovered_item_nx;
11516
                    //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
11517
11518
                    // Zoom
11519
                    IconSize *= powf(1.1f, (float)(int)ZoomWheelAccum);
11520
                    IconSize = IM_CLAMP(IconSize, 16.0f, 128.0f);
11521
                    ZoomWheelAccum -= (int)ZoomWheelAccum;
11522
                    UpdateLayoutSizes(avail_width);
11523
11524
                    // Manipulate scroll to that we will land at the same Y location of currently hovered item.
11525
                    // - Calculate next frame position of item under mouse
11526
                    // - Set new scroll position to be used in next ImGui::BeginChild() call.
11527
                    float hovered_item_rel_pos_y = ((float)(hovered_item_idx / LayoutColumnCount) + fmodf(hovered_item_ny, 1.0f)) * LayoutItemStep.y;
11528
                    hovered_item_rel_pos_y += ImGui::GetStyle().WindowPadding.y;
11529
                    float mouse_local_y = io.MousePos.y - ImGui::GetWindowPos().y;
11530
                    ImGui::SetScrollY(hovered_item_rel_pos_y - mouse_local_y);
11531
                }
11532
            }
11533
        }
11534
        ImGui::EndChild();
11535
11536
        ImGui::Text("Selected: %d/%d items", Selection.Size, Items.Size);
11537
        ImGui::End();
11538
    }
11539
};
11540
11541
void ShowExampleAppAssetsBrowser(bool* p_open)
11542
{
11543
    IMGUI_DEMO_MARKER("Examples/Assets Browser");
11544
    static ExampleAssetsBrowser assets_browser;
11545
    assets_browser.Draw("Example: Assets Browser", p_open);
11546
}
11547
11548
// End of Demo code
11549
#else
11550
11551
void ImGui::ShowAboutWindow(bool*) {}
11552
void ImGui::ShowDemoWindow(bool*) {}
11553
void ImGui::ShowUserGuide() {}
11554
void ImGui::ShowStyleEditor(ImGuiStyle*) {}
11555
bool ImGui::ShowStyleSelector(const char*) { return false; }
11556
11557
#endif // #ifndef IMGUI_DISABLE_DEMO_WINDOWS
11558
11559
#endif // #ifndef IMGUI_DISABLE