OXYGENHUB
◆ rrdc-perf enhanced-x16-emulator / src / extern / imgui / imgui_demo.cpp
550.9 KiB · C++ · last changed chore(): initial commit 25 days ago source blame history raw
9120e874 Andy McCall 1
// dear imgui, v1.91.5
2
// (demo code)
3
4
// Help:
5
// - Read FAQ at http://dearimgui.com/faq
6
// - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that.
7
// - Need help integrating Dear ImGui in your codebase?
8
//   - Read Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started
9
//   - Read 'Programmer guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase.
10
// Read top of imgui.cpp and imgui.h for many details, documentation, comments, links.
11
// Get the latest version at https://github.com/ocornut/imgui
12
13
// How to easily locate code?
14
// - Use Tools->Item Picker to debug break in code by clicking any widgets: https://github.com/ocornut/imgui/wiki/Debug-Tools
15
// - Browse an online version the demo with code linked to hovered widgets: https://pthom.github.io/imgui_manual_online/manual/imgui_manual.html
16
// - Find a visible string and search for it in the code!
17
18
//---------------------------------------------------
19
// PLEASE DO NOT REMOVE THIS FILE FROM YOUR PROJECT!
20
//---------------------------------------------------
21
// Message to the person tempted to delete this file when integrating Dear ImGui into their codebase:
22
// Think again! It is the most useful reference code that you and other coders will want to refer to and call.
23
// Have the ImGui::ShowDemoWindow() function wired in an always-available debug menu of your game/app!
24
// Also include Metrics! ItemPicker! DebugLog! and other debug features.
25
// Removing this file from your project is hindering access to documentation for everyone in your team,
26
// likely leading you to poorer usage of the library.
27
// Everything in this file will be stripped out by the linker if you don't call ImGui::ShowDemoWindow().
28
// If you want to link core Dear ImGui in your shipped builds but want a thorough guarantee that the demo will not be
29
// linked, you can setup your imconfig.h with #define IMGUI_DISABLE_DEMO_WINDOWS and those functions will be empty.
30
// In another situation, whenever you have Dear ImGui available you probably want this to be available for reference.
31
// Thank you,
32
// -Your beloved friend, imgui_demo.cpp (which you won't delete)
33
34
//--------------------------------------------
35
// ABOUT THE MEANING OF THE 'static' KEYWORD:
36
//--------------------------------------------
37
// In this demo code, we frequently use 'static' variables inside functions.
38
// A static variable persists across calls. It is essentially a global variable but declared inside the scope of the function.
39
// Think of "static int n = 0;" as "global int n = 0;" !
40
// We do this IN THE DEMO because we want:
41
// - to gather code and data in the same place.
42
// - to make the demo source code faster to read, faster to change, smaller in size.
43
// - it is also a convenient way of storing simple UI related information as long as your function
44
//   doesn't need to be reentrant or used in multiple threads.
45
// This might be a pattern you will want to use in your code, but most of the data you would be working
46
// with in a complex codebase is likely going to be stored outside your functions.
47
48
//-----------------------------------------
49
// ABOUT THE CODING STYLE OF OUR DEMO CODE
50
//-----------------------------------------
51
// The Demo code in this file is designed to be easy to copy-and-paste into your application!
52
// Because of this:
53
// - We never omit the ImGui:: prefix when calling functions, even though most code here is in the same namespace.
54
// - We try to declare static variables in the local scope, as close as possible to the code using them.
55
// - We never use any of the helpers/facilities used internally by Dear ImGui, unless available in the public API.
56
// - We never use maths operators on ImVec2/ImVec4. For our other sources files we use them, and they are provided
57
//   by imgui.h using the IMGUI_DEFINE_MATH_OPERATORS define. For your own sources file they are optional
58
//   and require you either enable those, either provide your own via IM_VEC2_CLASS_EXTRA in imconfig.h.
59
//   Because we can't assume anything about your support of maths operators, we cannot use them in imgui_demo.cpp.
60
61
// Navigating this file:
62
// - In Visual Studio: CTRL+comma ("Edit.GoToAll") can follow symbols inside comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot.
63
// - In Visual Studio w/ Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols inside comments.
64
// - In VS Code, CLion, etc.: CTRL+click can follow symbols inside comments.
65
// - You can search/grep for all sections listed in the index to find the section.
66
67
/*
68
69
Index of this file:
70
71
// [SECTION] Forward Declarations
72
// [SECTION] Helpers
73
// [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor & Multi-Select demos)
74
// [SECTION] Demo Window / ShowDemoWindow()
75
// [SECTION] ShowDemoWindowMenuBar()
76
// [SECTION] ShowDemoWindowWidgets()
77
// [SECTION] ShowDemoWindowMultiSelect()
78
// [SECTION] ShowDemoWindowLayout()
79
// [SECTION] ShowDemoWindowPopups()
80
// [SECTION] ShowDemoWindowTables()
81
// [SECTION] ShowDemoWindowInputs()
82
// [SECTION] About Window / ShowAboutWindow()
83
// [SECTION] Style Editor / ShowStyleEditor()
84
// [SECTION] User Guide / ShowUserGuide()
85
// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar()
86
// [SECTION] Example App: Debug Console / ShowExampleAppConsole()
87
// [SECTION] Example App: Debug Log / ShowExampleAppLog()
88
// [SECTION] Example App: Simple Layout / ShowExampleAppLayout()
89
// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor()
90
// [SECTION] Example App: Long Text / ShowExampleAppLongText()
91
// [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize()
92
// [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize()
93
// [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay()
94
// [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen()
95
// [SECTION] Example App: Manipulating window titles / ShowExampleAppWindowTitles()
96
// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering()
97
// [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace()
98
// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
99
// [SECTION] Example App: Assets Browser / ShowExampleAppAssetsBrowser()
100
101
*/
102
103
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
104
#define _CRT_SECURE_NO_WARNINGS
105
#endif
106
107
#include "imgui.h"
108
#ifndef IMGUI_DISABLE
109
110
// System includes
111
#include <ctype.h>          // toupper
112
#include <limits.h>         // INT_MIN, INT_MAX
113
#include <math.h>           // sqrtf, powf, cosf, sinf, floorf, ceilf
114
#include <stdio.h>          // vsnprintf, sscanf, printf
115
#include <stdlib.h>         // NULL, malloc, free, atoi
116
#include <stdint.h>         // intptr_t
117
#if !defined(_MSC_VER) || _MSC_VER >= 1800
118
#include <inttypes.h>       // PRId64/PRIu64, not avail in some MinGW headers.
119
#endif
120
#ifdef __EMSCRIPTEN__
121
#include <emscripten/version.h>     // __EMSCRIPTEN_major__ etc.
122
#endif
123
124
// Visual Studio warnings
125
#ifdef _MSC_VER
126
#pragma warning (disable: 4127)     // condition expression is constant
127
#pragma warning (disable: 4996)     // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
128
#pragma warning (disable: 26451)    // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to an 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2).
129
#endif
130
131
// Clang/GCC warnings with -Weverything
132
#if defined(__clang__)
133
#if __has_warning("-Wunknown-warning-option")
134
#pragma clang diagnostic ignored "-Wunknown-warning-option"         // warning: unknown warning group 'xxx'                     // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great!
135
#endif
136
#pragma clang diagnostic ignored "-Wunknown-pragmas"                // warning: unknown warning group 'xxx'
137
#pragma clang diagnostic ignored "-Wold-style-cast"                 // warning: use of old-style cast                           // yes, they are more terse.
138
#pragma clang diagnostic ignored "-Wdeprecated-declarations"        // warning: 'xx' is deprecated: The POSIX name for this..   // for strdup used in demo code (so user can copy & paste the code)
139
#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast"       // warning: cast to 'void *' from smaller integer type
140
#pragma clang diagnostic ignored "-Wformat-security"                // warning: format string is not a string literal
141
#pragma clang diagnostic ignored "-Wexit-time-destructors"          // warning: declaration requires an exit-time destructor    // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals.
142
#pragma clang diagnostic ignored "-Wunused-macros"                  // warning: macro is not used                               // we define snprintf/vsnprintf on Windows so they are available, but not always used.
143
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"  // warning: zero as null pointer constant                   // some standard header variations use #define NULL 0
144
#pragma clang diagnostic ignored "-Wdouble-promotion"               // warning: implicit conversion from 'float' to 'double' when passing argument to function  // using printf() is a misery with this as C++ va_arg ellipsis changes float to double.
145
#pragma clang diagnostic ignored "-Wreserved-id-macro"              // warning: macro name is a reserved identifier
146
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"  // warning: implicit conversion from 'xxx' to 'float' may lose precision
147
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"            // warning: 'xxx' is an unsafe pointer used for buffer access
148
#elif defined(__GNUC__)
149
#pragma GCC diagnostic ignored "-Wpragmas"                          // warning: unknown option after '#pragma GCC diagnostic' kind
150
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"              // warning: cast to pointer from integer of different size
151
#pragma GCC diagnostic ignored "-Wformat-security"                  // warning: format string is not a string literal (potentially insecure)
152
#pragma GCC diagnostic ignored "-Wdouble-promotion"                 // warning: implicit conversion from 'float' to 'double' when passing argument to function
153
#pragma GCC diagnostic ignored "-Wconversion"                       // warning: conversion to 'xxxx' from 'xxxx' may alter its value
154
#pragma GCC diagnostic ignored "-Wmisleading-indentation"           // [__GNUC__ >= 6] warning: this 'if' clause does not guard this statement      // GCC 6.0+ only. See #883 on GitHub.
155
#endif
156
157
// Play it nice with Windows users (Update: May 2018, Notepad now supports Unix-style carriage returns!)
158
#ifdef _WIN32
159
#define IM_NEWLINE  "\r\n"
160
#else
161
#define IM_NEWLINE  "\n"
162
#endif
163
164
// Helpers
165
#if defined(_MSC_VER) && !defined(snprintf)
166
#define snprintf    _snprintf
167
#endif
168
#if defined(_MSC_VER) && !defined(vsnprintf)
169
#define vsnprintf   _vsnprintf
170
#endif
171
172
// Format specifiers for 64-bit values (hasn't been decently standardized before VS2013)
173
#if !defined(PRId64) && defined(_MSC_VER)
174
#define PRId64 "I64d"
175
#define PRIu64 "I64u"
176
#elif !defined(PRId64)
177
#define PRId64 "lld"
178
#define PRIu64 "llu"
179
#endif
180
181
// Helpers macros
182
// We normally try to not use many helpers in imgui_demo.cpp in order to make code easier to copy and paste,
183
// but making an exception here as those are largely simplifying code...
184
// In other imgui sources we can use nicer internal functions from imgui_internal.h (ImMin/ImMax) but not in the demo.
185
#define IM_MIN(A, B)            (((A) < (B)) ? (A) : (B))
186
#define IM_MAX(A, B)            (((A) >= (B)) ? (A) : (B))
187
#define IM_CLAMP(V, MN, MX)     ((V) < (MN) ? (MN) : (V) > (MX) ? (MX) : (V))
188
189
// Enforce cdecl calling convention for functions called by the standard library,
190
// in case compilation settings changed the default to e.g. __vectorcall
191
#ifndef IMGUI_CDECL
192
#ifdef _MSC_VER
193
#define IMGUI_CDECL __cdecl
194
#else
195
#define IMGUI_CDECL
196
#endif
197
#endif
198
199
//-----------------------------------------------------------------------------
200
// [SECTION] Forward Declarations
201
//-----------------------------------------------------------------------------
202
203
#if !defined(IMGUI_DISABLE_DEMO_WINDOWS)
204
205
// Forward Declarations
206
struct ImGuiDemoWindowData;
207
static void ShowExampleAppMainMenuBar();
208
static void ShowExampleAppAssetsBrowser(bool* p_open);
209
static void ShowExampleAppConsole(bool* p_open);
210
static void ShowExampleAppCustomRendering(bool* p_open);
211
static void ShowExampleAppDockSpace(bool* p_open);
212
static void ShowExampleAppDocuments(bool* p_open);
213
static void ShowExampleAppLog(bool* p_open);
214
static void ShowExampleAppLayout(bool* p_open);
215
static void ShowExampleAppPropertyEditor(bool* p_open, ImGuiDemoWindowData* demo_data);
216
static void ShowExampleAppSimpleOverlay(bool* p_open);
217
static void ShowExampleAppAutoResize(bool* p_open);
218
static void ShowExampleAppConstrainedResize(bool* p_open);
219
static void ShowExampleAppFullscreen(bool* p_open);
220
static void ShowExampleAppLongText(bool* p_open);
221
static void ShowExampleAppWindowTitles(bool* p_open);
222
static void ShowExampleMenuFile();
223
224
// We split the contents of the big ShowDemoWindow() function into smaller functions
225
// (because the link time of very large functions tends to grow non-linearly)
226
static void ShowDemoWindowMenuBar(ImGuiDemoWindowData* demo_data);
227
static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data);
228
static void ShowDemoWindowMultiSelect(ImGuiDemoWindowData* demo_data);
229
static void ShowDemoWindowLayout();
230
static void ShowDemoWindowPopups();
231
static void ShowDemoWindowTables();
232
static void ShowDemoWindowColumns();
233
static void ShowDemoWindowInputs();
234
235
//-----------------------------------------------------------------------------
236
// [SECTION] Helpers
237
//-----------------------------------------------------------------------------
238
239
// Helper to display a little (?) mark which shows a tooltip when hovered.
240
// In your own code you may want to display an actual icon if you are using a merged icon fonts (see docs/FONTS.md)
241
static void HelpMarker(const char* desc)
242
{
243
    ImGui::TextDisabled("(?)");
244
    if (ImGui::BeginItemTooltip())
245
    {
246
        ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
247
        ImGui::TextUnformatted(desc);
248
        ImGui::PopTextWrapPos();
249
        ImGui::EndTooltip();
250
    }
251
}
252
253
static void ShowDockingDisabledMessage()
254
{
255
    ImGuiIO& io = ImGui::GetIO();
256
    ImGui::Text("ERROR: Docking is not enabled! See Demo > Configuration.");
257
    ImGui::Text("Set io.ConfigFlags |= ImGuiConfigFlags_DockingEnable in your code, or ");
258
    ImGui::SameLine(0.0f, 0.0f);
259
    if (ImGui::SmallButton("click here"))
260
        io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
261
}
262
263
// Helper to wire demo markers located in code to an interactive browser
264
typedef void (*ImGuiDemoMarkerCallback)(const char* file, int line, const char* section, void* user_data);
265
extern ImGuiDemoMarkerCallback      GImGuiDemoMarkerCallback;
266
extern void*                        GImGuiDemoMarkerCallbackUserData;
267
ImGuiDemoMarkerCallback             GImGuiDemoMarkerCallback = NULL;
268
void*                               GImGuiDemoMarkerCallbackUserData = NULL;
269
#define IMGUI_DEMO_MARKER(section)  do { if (GImGuiDemoMarkerCallback != NULL) GImGuiDemoMarkerCallback(__FILE__, __LINE__, section, GImGuiDemoMarkerCallbackUserData); } while (0)
270
271
//-----------------------------------------------------------------------------
272
// [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor etc.)
273
//-----------------------------------------------------------------------------
274
275
// Simple representation for a tree
276
// (this is designed to be simple to understand for our demos, not to be fancy or efficient etc.)
277
struct ExampleTreeNode
278
{
279
    // Tree structure
280
    char                        Name[28] = "";
281
    int                         UID = 0;
282
    ExampleTreeNode*            Parent = NULL;
283
    ImVector<ExampleTreeNode*>  Childs;
284
    unsigned short              IndexInParent = 0;  // Maintaining this allows us to implement linear traversal more easily
285
286
    // Leaf Data
287
    bool                        HasData = false;    // All leaves have data
288
    bool                        DataMyBool = true;
289
    int                         DataMyInt = 128;
290
    ImVec2                      DataMyVec2 = ImVec2(0.0f, 3.141592f);
291
};
292
293
// Simple representation of struct metadata/serialization data.
294
// (this is a minimal version of what a typical advanced application may provide)
295
struct ExampleMemberInfo
296
{
297
    const char*     Name;       // Member name
298
    ImGuiDataType   DataType;   // Member type
299
    int             DataCount;  // Member count (1 when scalar)
300
    int             Offset;     // Offset inside parent structure
301
};
302
303
// Metadata description of ExampleTreeNode struct.
304
static const ExampleMemberInfo ExampleTreeNodeMemberInfos[]
305
{
306
    { "MyBool",     ImGuiDataType_Bool,    1, offsetof(ExampleTreeNode, DataMyBool) },
307
    { "MyInt",      ImGuiDataType_S32,     1, offsetof(ExampleTreeNode, DataMyInt) },
308
    { "MyVec2",     ImGuiDataType_Float,   2, offsetof(ExampleTreeNode, DataMyVec2) },
309
};
310
311
static ExampleTreeNode* ExampleTree_CreateNode(const char* name, int uid, ExampleTreeNode* parent)
312
{
313
    ExampleTreeNode* node = IM_NEW(ExampleTreeNode);
314
    snprintf(node->Name, IM_ARRAYSIZE(node->Name), "%s", name);
315
    node->UID = uid;
316
    node->Parent = parent;
317
    node->IndexInParent = parent ? (unsigned short)parent->Childs.Size : 0;
318
    if (parent)
319
        parent->Childs.push_back(node);
320
    return node;
321
}
322
323
// Create example tree data
324
// (this allocates _many_ more times than most other code in either Dear ImGui or others demo)
325
static ExampleTreeNode* ExampleTree_CreateDemoTree()
326
{
327
    static const char* root_names[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pear", "Pineapple", "Strawberry", "Watermelon" };
328
    const size_t NAME_MAX_LEN = sizeof(ExampleTreeNode::Name);
329
    char name_buf[NAME_MAX_LEN];
330
    int uid = 0;
331
    ExampleTreeNode* node_L0 = ExampleTree_CreateNode("<ROOT>", ++uid, NULL);
332
    const int root_items_multiplier = 2;
333
    for (int idx_L0 = 0; idx_L0 < IM_ARRAYSIZE(root_names) * root_items_multiplier; idx_L0++)
334
    {
335
        snprintf(name_buf, IM_ARRAYSIZE(name_buf), "%s %d", root_names[idx_L0 / root_items_multiplier], idx_L0 % root_items_multiplier);
336
        ExampleTreeNode* node_L1 = ExampleTree_CreateNode(name_buf, ++uid, node_L0);
337
        const int number_of_childs = (int)strlen(node_L1->Name);
338
        for (int idx_L1 = 0; idx_L1 < number_of_childs; idx_L1++)
339
        {
340
            snprintf(name_buf, IM_ARRAYSIZE(name_buf), "Child %d", idx_L1);
341
            ExampleTreeNode* node_L2 = ExampleTree_CreateNode(name_buf, ++uid, node_L1);
342
            node_L2->HasData = true;
343
            if (idx_L1 == 0)
344
            {
345
                snprintf(name_buf, IM_ARRAYSIZE(name_buf), "Sub-child %d", 0);
346
                ExampleTreeNode* node_L3 = ExampleTree_CreateNode(name_buf, ++uid, node_L2);
347
                node_L3->HasData = true;
348
            }
349
        }
350
    }
351
    return node_L0;
352
}
353
354
//-----------------------------------------------------------------------------
355
// [SECTION] Demo Window / ShowDemoWindow()
356
//-----------------------------------------------------------------------------
357
358
// Data to be shared accross different functions of the demo.
359
struct ImGuiDemoWindowData
360
{
361
    // Examples Apps (accessible from the "Examples" menu)
362
    bool ShowMainMenuBar = false;
363
    bool ShowAppAssetsBrowser = false;
364
    bool ShowAppConsole = false;
365
    bool ShowAppCustomRendering = false;
366
    bool ShowAppDocuments = false;
367
    bool ShowAppDockSpace = false;
368
    bool ShowAppLog = false;
369
    bool ShowAppLayout = false;
370
    bool ShowAppPropertyEditor = false;
371
    bool ShowAppSimpleOverlay = false;
372
    bool ShowAppAutoResize = false;
373
    bool ShowAppConstrainedResize = false;
374
    bool ShowAppFullscreen = false;
375
    bool ShowAppLongText = false;
376
    bool ShowAppWindowTitles = false;
377
378
    // Dear ImGui Tools (accessible from the "Tools" menu)
379
    bool ShowMetrics = false;
380
    bool ShowDebugLog = false;
381
    bool ShowIDStackTool = false;
382
    bool ShowStyleEditor = false;
383
    bool ShowAbout = false;
384
385
    // Other data
386
    ExampleTreeNode* DemoTree = NULL;
387
};
388
389
// Demonstrate most Dear ImGui features (this is big function!)
390
// You may execute this function to experiment with the UI and understand what it does.
391
// You may then search for keywords in the code when you are interested by a specific feature.
392
void ImGui::ShowDemoWindow(bool* p_open)
393
{
394
    // Exceptionally add an extra assert here for people confused about initial Dear ImGui setup
395
    // Most functions would normally just assert/crash if the context is missing.
396
    IM_ASSERT(ImGui::GetCurrentContext() != NULL && "Missing Dear ImGui context. Refer to examples app!");
397
398
    // Verify ABI compatibility between caller code and compiled version of Dear ImGui. This helps detects some build issues.
399
    IMGUI_CHECKVERSION();
400
401
    // Stored data
402
    static ImGuiDemoWindowData demo_data;
403
404
    // Examples Apps (accessible from the "Examples" menu)
405
    if (demo_data.ShowMainMenuBar)          { ShowExampleAppMainMenuBar(); }
406
    if (demo_data.ShowAppDockSpace)         { ShowExampleAppDockSpace(&demo_data.ShowAppDockSpace); } // Important: Process the Docking app first, as explicit DockSpace() nodes needs to be submitted early (read comments near the DockSpace function)
407
    if (demo_data.ShowAppDocuments)         { ShowExampleAppDocuments(&demo_data.ShowAppDocuments); } // ...process the Document app next, as it may also use a DockSpace()
408
    if (demo_data.ShowAppAssetsBrowser)     { ShowExampleAppAssetsBrowser(&demo_data.ShowAppAssetsBrowser); }
409
    if (demo_data.ShowAppConsole)           { ShowExampleAppConsole(&demo_data.ShowAppConsole); }
410
    if (demo_data.ShowAppCustomRendering)   { ShowExampleAppCustomRendering(&demo_data.ShowAppCustomRendering); }
411
    if (demo_data.ShowAppLog)               { ShowExampleAppLog(&demo_data.ShowAppLog); }
412
    if (demo_data.ShowAppLayout)            { ShowExampleAppLayout(&demo_data.ShowAppLayout); }
413
    if (demo_data.ShowAppPropertyEditor)    { ShowExampleAppPropertyEditor(&demo_data.ShowAppPropertyEditor, &demo_data); }
414
    if (demo_data.ShowAppSimpleOverlay)     { ShowExampleAppSimpleOverlay(&demo_data.ShowAppSimpleOverlay); }
415
    if (demo_data.ShowAppAutoResize)        { ShowExampleAppAutoResize(&demo_data.ShowAppAutoResize); }
416
    if (demo_data.ShowAppConstrainedResize) { ShowExampleAppConstrainedResize(&demo_data.ShowAppConstrainedResize); }
417
    if (demo_data.ShowAppFullscreen)        { ShowExampleAppFullscreen(&demo_data.ShowAppFullscreen); }
418
    if (demo_data.ShowAppLongText)          { ShowExampleAppLongText(&demo_data.ShowAppLongText); }
419
    if (demo_data.ShowAppWindowTitles)      { ShowExampleAppWindowTitles(&demo_data.ShowAppWindowTitles); }
420
421
    // Dear ImGui Tools (accessible from the "Tools" menu)
422
    if (demo_data.ShowMetrics)              { ImGui::ShowMetricsWindow(&demo_data.ShowMetrics); }
423
    if (demo_data.ShowDebugLog)             { ImGui::ShowDebugLogWindow(&demo_data.ShowDebugLog); }
424
    if (demo_data.ShowIDStackTool)          { ImGui::ShowIDStackToolWindow(&demo_data.ShowIDStackTool); }
425
    if (demo_data.ShowAbout)                { ImGui::ShowAboutWindow(&demo_data.ShowAbout); }
426
    if (demo_data.ShowStyleEditor)
427
    {
428
        ImGui::Begin("Dear ImGui Style Editor", &demo_data.ShowStyleEditor);
429
        ImGui::ShowStyleEditor();
430
        ImGui::End();
431
    }
432
433
    // Demonstrate the various window flags. Typically you would just use the default!
434
    static bool no_titlebar = false;
435
    static bool no_scrollbar = false;
436
    static bool no_menu = false;
437
    static bool no_move = false;
438
    static bool no_resize = false;
439
    static bool no_collapse = false;
440
    static bool no_close = false;
441
    static bool no_nav = false;
442
    static bool no_background = false;
443
    static bool no_bring_to_front = false;
444
    static bool no_docking = false;
445
    static bool unsaved_document = false;
446
447
    ImGuiWindowFlags window_flags = 0;
448
    if (no_titlebar)        window_flags |= ImGuiWindowFlags_NoTitleBar;
449
    if (no_scrollbar)       window_flags |= ImGuiWindowFlags_NoScrollbar;
450
    if (!no_menu)           window_flags |= ImGuiWindowFlags_MenuBar;
451
    if (no_move)            window_flags |= ImGuiWindowFlags_NoMove;
452
    if (no_resize)          window_flags |= ImGuiWindowFlags_NoResize;
453
    if (no_collapse)        window_flags |= ImGuiWindowFlags_NoCollapse;
454
    if (no_nav)             window_flags |= ImGuiWindowFlags_NoNav;
455
    if (no_background)      window_flags |= ImGuiWindowFlags_NoBackground;
456
    if (no_bring_to_front)  window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus;
457
    if (no_docking)         window_flags |= ImGuiWindowFlags_NoDocking;
458
    if (unsaved_document)   window_flags |= ImGuiWindowFlags_UnsavedDocument;
459
    if (no_close)           p_open = NULL; // Don't pass our bool* to Begin
460
461
    // We specify a default position/size in case there's no data in the .ini file.
462
    // We only do it to make the demo applications a little more welcoming, but typically this isn't required.
463
    const ImGuiViewport* main_viewport = ImGui::GetMainViewport();
464
    ImGui::SetNextWindowPos(ImVec2(main_viewport->WorkPos.x + 650, main_viewport->WorkPos.y + 20), ImGuiCond_FirstUseEver);
465
    ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver);
466
467
    // Main body of the Demo window starts here.
468
    if (!ImGui::Begin("Dear ImGui Demo", p_open, window_flags))
469
    {
470
        // Early out if the window is collapsed, as an optimization.
471
        ImGui::End();
472
        return;
473
    }
474
475
    // Most "big" widgets share a common width settings by default. See 'Demo->Layout->Widgets Width' for details.
476
    ImGui::PushItemWidth(ImGui::GetFontSize() * -12);           // e.g. Leave a fixed amount of width for labels (by passing a negative value), the rest goes to widgets.
477
    //ImGui::PushItemWidth(-ImGui::GetWindowWidth() * 0.35f);   // e.g. Use 2/3 of the space for widgets and 1/3 for labels (right align)
478
479
    // Menu Bar
480
    ShowDemoWindowMenuBar(&demo_data);
481
482
    ImGui::Text("dear imgui says hello! (%s) (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
483
    ImGui::Spacing();
484
485
    IMGUI_DEMO_MARKER("Help");
486
    if (ImGui::CollapsingHeader("Help"))
487
    {
488
        ImGui::SeparatorText("ABOUT THIS DEMO:");
489
        ImGui::BulletText("Sections below are demonstrating many aspects of the library.");
490
        ImGui::BulletText("The \"Examples\" menu above leads to more demo contents.");
491
        ImGui::BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n"
492
                          "and Metrics/Debugger (general purpose Dear ImGui debugging tool).");
493
494
        ImGui::SeparatorText("PROGRAMMER GUIDE:");
495
        ImGui::BulletText("See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!");
496
        ImGui::BulletText("See comments in imgui.cpp.");
497
        ImGui::BulletText("See example applications in the examples/ folder.");
498
        ImGui::BulletText("Read the FAQ at ");
499
        ImGui::SameLine(0, 0);
500
        ImGui::TextLinkOpenURL("https://www.dearimgui.com/faq/");
501
        ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls.");
502
        ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls.");
503
504
        ImGui::SeparatorText("USER GUIDE:");
505
        ImGui::ShowUserGuide();
506
    }
507
508
    IMGUI_DEMO_MARKER("Configuration");
509
    if (ImGui::CollapsingHeader("Configuration"))
510
    {
511
        ImGuiIO& io = ImGui::GetIO();
512
513
        if (ImGui::TreeNode("Configuration##2"))
514
        {
515
            ImGui::SeparatorText("General");
516
            ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard",    &io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard);
517
            ImGui::SameLine(); HelpMarker("Enable keyboard controls.");
518
            ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad",     &io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad);
519
            ImGui::SameLine(); HelpMarker("Enable gamepad controls. Require backend to set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details.");
520
            ImGui::CheckboxFlags("io.ConfigFlags: NoMouse",              &io.ConfigFlags, ImGuiConfigFlags_NoMouse);
521
            ImGui::SameLine(); HelpMarker("Instruct dear imgui to disable mouse inputs and interactions.");
522
523
            // The "NoMouse" option can get us stuck with a disabled mouse! Let's provide an alternative way to fix it:
524
            if (io.ConfigFlags & ImGuiConfigFlags_NoMouse)
525
            {
526
                if (fmodf((float)ImGui::GetTime(), 0.40f) < 0.20f)
527
                {
528
                    ImGui::SameLine();
529
                    ImGui::Text("<<PRESS SPACE TO DISABLE>>");
530
                }
531
                // Prevent both being checked
532
                if (ImGui::IsKeyPressed(ImGuiKey_Space) || (io.ConfigFlags & ImGuiConfigFlags_NoKeyboard))
533
                    io.ConfigFlags &= ~ImGuiConfigFlags_NoMouse;
534
            }
535
536
            ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange",  &io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange);
537
            ImGui::SameLine(); HelpMarker("Instruct backend to not alter mouse cursor shape and visibility.");
538
            ImGui::CheckboxFlags("io.ConfigFlags: NoKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NoKeyboard);
539
            ImGui::SameLine(); HelpMarker("Instruct dear imgui to disable keyboard inputs and interactions.");
540
541
            ImGui::Checkbox("io.ConfigInputTrickleEventQueue", &io.ConfigInputTrickleEventQueue);
542
            ImGui::SameLine(); HelpMarker("Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates.");
543
            ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor);
544
            ImGui::SameLine(); HelpMarker("Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something).");
545
546
            ImGui::SeparatorText("Keyboard/Gamepad Navigation");
547
            ImGui::Checkbox("io.ConfigNavSwapGamepadButtons", &io.ConfigNavSwapGamepadButtons);
548
            ImGui::Checkbox("io.ConfigNavMoveSetMousePos", &io.ConfigNavMoveSetMousePos);
549
            ImGui::SameLine(); HelpMarker("Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is difficult");
550
            ImGui::Checkbox("io.ConfigNavCaptureKeyboard", &io.ConfigNavCaptureKeyboard);
551
            ImGui::Checkbox("io.ConfigNavEscapeClearFocusItem", &io.ConfigNavEscapeClearFocusItem);
552
            ImGui::SameLine(); HelpMarker("Pressing Escape clears focused item.");
553
            ImGui::Checkbox("io.ConfigNavEscapeClearFocusWindow", &io.ConfigNavEscapeClearFocusWindow);
554
            ImGui::SameLine(); HelpMarker("Pressing Escape clears focused window.");
555
            ImGui::Checkbox("io.ConfigNavCursorVisibleAuto", &io.ConfigNavCursorVisibleAuto);
556
            ImGui::SameLine(); HelpMarker("Using directional navigation key makes the cursor visible. Mouse click hides the cursor.");
557
            ImGui::Checkbox("io.ConfigNavCursorVisibleAlways", &io.ConfigNavCursorVisibleAlways);
558
            ImGui::SameLine(); HelpMarker("Navigation cursor is always visible.");
559
560
            ImGui::SeparatorText("Docking");
561
            ImGui::CheckboxFlags("io.ConfigFlags: DockingEnable", &io.ConfigFlags, ImGuiConfigFlags_DockingEnable);
562
            ImGui::SameLine();
563
            if (io.ConfigDockingWithShift)
564
                HelpMarker("Drag from window title bar or their tab to dock/undock. Hold SHIFT to enable docking.\n\nDrag from window menu button (upper-left button) to undock an entire node (all windows).");
565
            else
566
                HelpMarker("Drag from window title bar or their tab to dock/undock. Hold SHIFT to disable docking.\n\nDrag from window menu button (upper-left button) to undock an entire node (all windows).");
567
            if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
568
            {
569
                ImGui::Indent();
570
                ImGui::Checkbox("io.ConfigDockingNoSplit", &io.ConfigDockingNoSplit);
571
                ImGui::SameLine(); HelpMarker("Simplified docking mode: disable window splitting, so docking is limited to merging multiple windows together into tab-bars.");
572
                ImGui::Checkbox("io.ConfigDockingWithShift", &io.ConfigDockingWithShift);
573
                ImGui::SameLine(); HelpMarker("Enable docking when holding Shift only (allow to drop in wider space, reduce visual noise)");
574
                ImGui::Checkbox("io.ConfigDockingAlwaysTabBar", &io.ConfigDockingAlwaysTabBar);
575
                ImGui::SameLine(); HelpMarker("Create a docking node and tab-bar on single floating windows.");
576
                ImGui::Checkbox("io.ConfigDockingTransparentPayload", &io.ConfigDockingTransparentPayload);
577
                ImGui::SameLine(); HelpMarker("Make window or viewport transparent when docking and only display docking boxes on the target viewport. Useful if rendering of multiple viewport cannot be synced. Best used with ConfigViewportsNoAutoMerge.");
578
                ImGui::Unindent();
579
            }
580
581
            ImGui::SeparatorText("Multi-viewports");
582
            ImGui::CheckboxFlags("io.ConfigFlags: ViewportsEnable", &io.ConfigFlags, ImGuiConfigFlags_ViewportsEnable);
583
            ImGui::SameLine(); HelpMarker("[beta] Enable beta multi-viewports support. See ImGuiPlatformIO for details.");
584
            if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
585
            {
586
                ImGui::Indent();
587
                ImGui::Checkbox("io.ConfigViewportsNoAutoMerge", &io.ConfigViewportsNoAutoMerge);
588
                ImGui::SameLine(); HelpMarker("Set to make all floating imgui windows always create their own viewport. Otherwise, they are merged into the main host viewports when overlapping it.");
589
                ImGui::Checkbox("io.ConfigViewportsNoTaskBarIcon", &io.ConfigViewportsNoTaskBarIcon);
590
                ImGui::SameLine(); HelpMarker("Toggling this at runtime is normally unsupported (most platform backends won't refresh the task bar icon state right away).");
591
                ImGui::Checkbox("io.ConfigViewportsNoDecoration", &io.ConfigViewportsNoDecoration);
592
                ImGui::SameLine(); HelpMarker("Toggling this at runtime is normally unsupported (most platform backends won't refresh the decoration right away).");
593
                ImGui::Checkbox("io.ConfigViewportsNoDefaultParent", &io.ConfigViewportsNoDefaultParent);
594
                ImGui::SameLine(); HelpMarker("Toggling this at runtime is normally unsupported (most platform backends won't refresh the parenting right away).");
595
                ImGui::Unindent();
596
            }
597
598
            ImGui::SeparatorText("Windows");
599
            ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges);
600
            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.");
601
            ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly);
602
            ImGui::Checkbox("io.ConfigWindowsCopyContentsWithCtrlC", &io.ConfigWindowsCopyContentsWithCtrlC); // [EXPERIMENTAL]
603
            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.");
604
            ImGui::Checkbox("io.ConfigScrollbarScrollByPage", &io.ConfigScrollbarScrollByPage);
605
            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.");
606
607
            ImGui::SeparatorText("Widgets");
608
            ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink);
609
            ImGui::SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting).");
610
            ImGui::Checkbox("io.ConfigInputTextEnterKeepActive", &io.ConfigInputTextEnterKeepActive);
611
            ImGui::SameLine(); HelpMarker("Pressing Enter will keep item active and select contents (single-line only).");
612
            ImGui::Checkbox("io.ConfigDragClickToInputText", &io.ConfigDragClickToInputText);
613
            ImGui::SameLine(); HelpMarker("Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving).");
614
            ImGui::Checkbox("io.ConfigMacOSXBehaviors", &io.ConfigMacOSXBehaviors);
615
            ImGui::SameLine(); HelpMarker("Swap Cmd<>Ctrl keys, enable various MacOS style behaviors.");
616
            ImGui::Text("Also see Style->Rendering for rendering options.");
617
618
            // Also read: https://github.com/ocornut/imgui/wiki/Error-Handling
619
            ImGui::SeparatorText("Error Handling");
620
621
            ImGui::Checkbox("io.ConfigErrorRecovery", &io.ConfigErrorRecovery);
622
            ImGui::SameLine(); HelpMarker(
623
                "Options to configure how we handle recoverable errors.\n"
624
                "- Error recovery is not perfect nor guaranteed! It is a feature to ease development.\n"
625
                "- You not are not supposed to rely on it in the course of a normal application run.\n"
626
                "- Possible usage: facilitate recovery from errors triggered from a scripting language or after specific exceptions handlers.\n"
627
                "- Always ensure that on programmers seat you have at minimum Asserts or Tooltips enabled when making direct imgui API call!"
628
                "Otherwise it would severely hinder your ability to catch and correct mistakes!");
629
            ImGui::Checkbox("io.ConfigErrorRecoveryEnableAssert", &io.ConfigErrorRecoveryEnableAssert);
630
            ImGui::Checkbox("io.ConfigErrorRecoveryEnableDebugLog", &io.ConfigErrorRecoveryEnableDebugLog);
631
            ImGui::Checkbox("io.ConfigErrorRecoveryEnableTooltip", &io.ConfigErrorRecoveryEnableTooltip);
632
            if (!io.ConfigErrorRecoveryEnableAssert && !io.ConfigErrorRecoveryEnableDebugLog && !io.ConfigErrorRecoveryEnableTooltip)
633
                io.ConfigErrorRecoveryEnableAssert = io.ConfigErrorRecoveryEnableDebugLog = io.ConfigErrorRecoveryEnableTooltip = true;
634
635
            // Also read: https://github.com/ocornut/imgui/wiki/Debug-Tools
636
            ImGui::SeparatorText("Debug");
637
            ImGui::Checkbox("io.ConfigDebugIsDebuggerPresent", &io.ConfigDebugIsDebuggerPresent);
638
            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.");
639
            ImGui::Checkbox("io.ConfigDebugHighlightIdConflicts", &io.ConfigDebugHighlightIdConflicts);
640
            ImGui::SameLine(); HelpMarker("Highlight and show an error message when multiple items have conflicting identifiers.");
641
            ImGui::BeginDisabled();
642
            ImGui::Checkbox("io.ConfigDebugBeginReturnValueOnce", &io.ConfigDebugBeginReturnValueOnce);
643
            ImGui::EndDisabled();
644
            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.");
645
            ImGui::Checkbox("io.ConfigDebugBeginReturnValueLoop", &io.ConfigDebugBeginReturnValueLoop);
646
            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.");
647
            ImGui::Checkbox("io.ConfigDebugIgnoreFocusLoss", &io.ConfigDebugIgnoreFocusLoss);
648
            ImGui::SameLine(); HelpMarker("Option to deactivate io.AddFocusEvent(false) handling. May facilitate interactions with a debugger when focus loss leads to clearing inputs data.");
649
            ImGui::Checkbox("io.ConfigDebugIniSettings", &io.ConfigDebugIniSettings);
650
            ImGui::SameLine(); HelpMarker("Option to save .ini data with extra comments (particularly helpful for Docking, but makes saving slower).");
651
652
            ImGui::TreePop();
653
            ImGui::Spacing();
654
        }
655
656
        IMGUI_DEMO_MARKER("Configuration/Backend Flags");
657
        if (ImGui::TreeNode("Backend Flags"))
658
        {
659
            HelpMarker(
660
                "Those flags are set by the backends (imgui_impl_xxx files) to specify their capabilities.\n"
661
                "Here we expose them as read-only fields to avoid breaking interactions with your backend.");
662
663
            // Make a local copy to avoid modifying actual backend flags.
664
            // FIXME: Maybe we need a BeginReadonly() equivalent to keep label bright?
665
            ImGui::BeginDisabled();
666
            ImGui::CheckboxFlags("io.BackendFlags: HasGamepad",             &io.BackendFlags, ImGuiBackendFlags_HasGamepad);
667
            ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors",        &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors);
668
            ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos",         &io.BackendFlags, ImGuiBackendFlags_HasSetMousePos);
669
            ImGui::CheckboxFlags("io.BackendFlags: PlatformHasViewports",   &io.BackendFlags, ImGuiBackendFlags_PlatformHasViewports);
670
            ImGui::CheckboxFlags("io.BackendFlags: HasMouseHoveredViewport",&io.BackendFlags, ImGuiBackendFlags_HasMouseHoveredViewport);
671
            ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset",   &io.BackendFlags, ImGuiBackendFlags_RendererHasVtxOffset);
672
            ImGui::CheckboxFlags("io.BackendFlags: RendererHasViewports",   &io.BackendFlags, ImGuiBackendFlags_RendererHasViewports);
673
            ImGui::EndDisabled();
674
675
            ImGui::TreePop();
676
            ImGui::Spacing();
677
        }
678
679
        IMGUI_DEMO_MARKER("Configuration/Style");
680
        if (ImGui::TreeNode("Style"))
681
        {
682
            ImGui::Checkbox("Style Editor", &demo_data.ShowStyleEditor);
683
            ImGui::SameLine();
684
            HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function.");
685
            ImGui::TreePop();
686
            ImGui::Spacing();
687
        }
688
689
        IMGUI_DEMO_MARKER("Configuration/Capture, Logging");
690
        if (ImGui::TreeNode("Capture/Logging"))
691
        {
692
            HelpMarker(
693
                "The logging API redirects all text output so you can easily capture the content of "
694
                "a window or a block. Tree nodes can be automatically expanded.\n"
695
                "Try opening any of the contents below in this window and then click one of the \"Log To\" button.");
696
            ImGui::LogButtons();
697
698
            HelpMarker("You can also call ImGui::LogText() to output directly to the log without a visual output.");
699
            if (ImGui::Button("Copy \"Hello, world!\" to clipboard"))
700
            {
701
                ImGui::LogToClipboard();
702
                ImGui::LogText("Hello, world!");
703
                ImGui::LogFinish();
704
            }
705
            ImGui::TreePop();
706
        }
707
    }
708
709
    IMGUI_DEMO_MARKER("Window options");
710
    if (ImGui::CollapsingHeader("Window options"))
711
    {
712
        if (ImGui::BeginTable("split", 3))
713
        {
714
            ImGui::TableNextColumn(); ImGui::Checkbox("No titlebar", &no_titlebar);
715
            ImGui::TableNextColumn(); ImGui::Checkbox("No scrollbar", &no_scrollbar);
716
            ImGui::TableNextColumn(); ImGui::Checkbox("No menu", &no_menu);
717
            ImGui::TableNextColumn(); ImGui::Checkbox("No move", &no_move);
718
            ImGui::TableNextColumn(); ImGui::Checkbox("No resize", &no_resize);
719
            ImGui::TableNextColumn(); ImGui::Checkbox("No collapse", &no_collapse);
720
            ImGui::TableNextColumn(); ImGui::Checkbox("No close", &no_close);
721
            ImGui::TableNextColumn(); ImGui::Checkbox("No nav", &no_nav);
722
            ImGui::TableNextColumn(); ImGui::Checkbox("No background", &no_background);
723
            ImGui::TableNextColumn(); ImGui::Checkbox("No bring to front", &no_bring_to_front);
724
            ImGui::TableNextColumn(); ImGui::Checkbox("No docking", &no_docking);
725
            ImGui::TableNextColumn(); ImGui::Checkbox("Unsaved document", &unsaved_document);
726
            ImGui::EndTable();
727
        }
728
    }
729
730
    // All demo contents
731
    ShowDemoWindowWidgets(&demo_data);
732
    ShowDemoWindowLayout();
733
    ShowDemoWindowPopups();
734
    ShowDemoWindowTables();
735
    ShowDemoWindowInputs();
736
737
    // End of ShowDemoWindow()
738
    ImGui::PopItemWidth();
739
    ImGui::End();
740
}
741
742
//-----------------------------------------------------------------------------
743
// [SECTION] ShowDemoWindowMenuBar()
744
//-----------------------------------------------------------------------------
745
746
static void ShowDemoWindowMenuBar(ImGuiDemoWindowData* demo_data)
747
{
748
    IMGUI_DEMO_MARKER("Menu");
749
    if (ImGui::BeginMenuBar())
750
    {
751
        if (ImGui::BeginMenu("Menu"))
752
        {
753
            IMGUI_DEMO_MARKER("Menu/File");
754
            ShowExampleMenuFile();
755
            ImGui::EndMenu();
756
        }
757
        if (ImGui::BeginMenu("Examples"))
758
        {
759
            IMGUI_DEMO_MARKER("Menu/Examples");
760
            ImGui::MenuItem("Main menu bar", NULL, &demo_data->ShowMainMenuBar);
761
762
            ImGui::SeparatorText("Mini apps");
763
            ImGui::MenuItem("Assets Browser", NULL, &demo_data->ShowAppAssetsBrowser);
764
            ImGui::MenuItem("Console", NULL, &demo_data->ShowAppConsole);
765
            ImGui::MenuItem("Custom rendering", NULL, &demo_data->ShowAppCustomRendering);
766
            ImGui::MenuItem("Documents", NULL, &demo_data->ShowAppDocuments);
767
            ImGui::MenuItem("Dockspace", NULL, &demo_data->ShowAppDockSpace);
768
            ImGui::MenuItem("Log", NULL, &demo_data->ShowAppLog);
769
            ImGui::MenuItem("Property editor", NULL, &demo_data->ShowAppPropertyEditor);
770
            ImGui::MenuItem("Simple layout", NULL, &demo_data->ShowAppLayout);
771
            ImGui::MenuItem("Simple overlay", NULL, &demo_data->ShowAppSimpleOverlay);
772
773
            ImGui::SeparatorText("Concepts");
774
            ImGui::MenuItem("Auto-resizing window", NULL, &demo_data->ShowAppAutoResize);
775
            ImGui::MenuItem("Constrained-resizing window", NULL, &demo_data->ShowAppConstrainedResize);
776
            ImGui::MenuItem("Fullscreen window", NULL, &demo_data->ShowAppFullscreen);
777
            ImGui::MenuItem("Long text display", NULL, &demo_data->ShowAppLongText);
778
            ImGui::MenuItem("Manipulating window titles", NULL, &demo_data->ShowAppWindowTitles);
779
780
            ImGui::EndMenu();
781
        }
782
        //if (ImGui::MenuItem("MenuItem")) {} // You can also use MenuItem() inside a menu bar!
783
        if (ImGui::BeginMenu("Tools"))
784
        {
785
            IMGUI_DEMO_MARKER("Menu/Tools");
786
            ImGuiIO& io = ImGui::GetIO();
787
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
788
            const bool has_debug_tools = true;
789
#else
790
            const bool has_debug_tools = false;
791
#endif
792
            ImGui::MenuItem("Metrics/Debugger", NULL, &demo_data->ShowMetrics, has_debug_tools);
793
            ImGui::MenuItem("Debug Log", NULL, &demo_data->ShowDebugLog, has_debug_tools);
794
            ImGui::MenuItem("ID Stack Tool", NULL, &demo_data->ShowIDStackTool, has_debug_tools);
795
            bool is_debugger_present = io.ConfigDebugIsDebuggerPresent;
796
            if (ImGui::MenuItem("Item Picker", NULL, false, has_debug_tools && is_debugger_present))
797
                ImGui::DebugStartItemPicker();
798
            if (!is_debugger_present)
799
                ImGui::SetItemTooltip("Requires io.ConfigDebugIsDebuggerPresent=true to be set.\n\nWe otherwise disable the menu option to avoid casual users crashing the application.\n\nYou can however always access the Item Picker in Metrics->Tools.");
800
            ImGui::MenuItem("Style Editor", NULL, &demo_data->ShowStyleEditor);
801
            ImGui::MenuItem("About Dear ImGui", NULL, &demo_data->ShowAbout);
802
803
            ImGui::SeparatorText("Debug Options");
804
            ImGui::MenuItem("Highlight ID Conflicts", NULL, &io.ConfigDebugHighlightIdConflicts, has_debug_tools);
805
            ImGui::EndMenu();
806
        }
807
        ImGui::EndMenuBar();
808
    }
809
}
810
811
//-----------------------------------------------------------------------------
812
// [SECTION] ShowDemoWindowWidgets()
813
//-----------------------------------------------------------------------------
814
815
static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data)
816
{
817
    IMGUI_DEMO_MARKER("Widgets");
818
    //ImGui::SetNextItemOpen(true, ImGuiCond_Once);
819
    if (!ImGui::CollapsingHeader("Widgets"))
820
        return;
821
822
    static bool disable_all = false; // The Checkbox for that is inside the "Disabled" section at the bottom
823
    if (disable_all)
824
        ImGui::BeginDisabled();
825
826
    IMGUI_DEMO_MARKER("Widgets/Basic");
827
    if (ImGui::TreeNode("Basic"))
828
    {
829
        ImGui::SeparatorText("General");
830
831
        IMGUI_DEMO_MARKER("Widgets/Basic/Button");
832
        static int clicked = 0;
833
        if (ImGui::Button("Button"))
834
            clicked++;
835
        if (clicked & 1)
836
        {
837
            ImGui::SameLine();
838
            ImGui::Text("Thanks for clicking me!");
839
        }
840
841
        IMGUI_DEMO_MARKER("Widgets/Basic/Checkbox");
842
        static bool check = true;
843
        ImGui::Checkbox("checkbox", &check);
844
845
        IMGUI_DEMO_MARKER("Widgets/Basic/RadioButton");
846
        static int e = 0;
847
        ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine();
848
        ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine();
849
        ImGui::RadioButton("radio c", &e, 2);
850
851
        // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style.
852
        IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Colored)");
853
        for (int i = 0; i < 7; i++)
854
        {
855
            if (i > 0)
856
                ImGui::SameLine();
857
            ImGui::PushID(i);
858
            ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.6f));
859
            ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.7f));
860
            ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.8f, 0.8f));
861
            ImGui::Button("Click");
862
            ImGui::PopStyleColor(3);
863
            ImGui::PopID();
864
        }
865
866
        // Use AlignTextToFramePadding() to align text baseline to the baseline of framed widgets elements
867
        // (otherwise a Text+SameLine+Button sequence will have the text a little too high by default!)
868
        // See 'Demo->Layout->Text Baseline Alignment' for details.
869
        ImGui::AlignTextToFramePadding();
870
        ImGui::Text("Hold to repeat:");
871
        ImGui::SameLine();
872
873
        // Arrow buttons with Repeater
874
        IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Repeating)");
875
        static int counter = 0;
876
        float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
877
        ImGui::PushItemFlag(ImGuiItemFlags_ButtonRepeat, true);
878
        if (ImGui::ArrowButton("##left", ImGuiDir_Left)) { counter--; }
879
        ImGui::SameLine(0.0f, spacing);
880
        if (ImGui::ArrowButton("##right", ImGuiDir_Right)) { counter++; }
881
        ImGui::PopItemFlag();
882
        ImGui::SameLine();
883
        ImGui::Text("%d", counter);
884
885
        ImGui::Button("Tooltip");
886
        ImGui::SetItemTooltip("I am a tooltip");
887
888
        ImGui::LabelText("label", "Value");
889
890
        ImGui::SeparatorText("Inputs");
891
892
        {
893
            // To wire InputText() with std::string or any other custom string type,
894
            // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file.
895
            IMGUI_DEMO_MARKER("Widgets/Basic/InputText");
896
            static char str0[128] = "Hello, world!";
897
            ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0));
898
            ImGui::SameLine(); HelpMarker(
899
                "USER:\n"
900
                "Hold SHIFT or use mouse to select text.\n"
901
                "CTRL+Left/Right to word jump.\n"
902
                "CTRL+A or Double-Click to select all.\n"
903
                "CTRL+X,CTRL+C,CTRL+V clipboard.\n"
904
                "CTRL+Z,CTRL+Y undo/redo.\n"
905
                "ESCAPE to revert.\n\n"
906
                "PROGRAMMER:\n"
907
                "You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() "
908
                "to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example (this is not demonstrated "
909
                "in imgui_demo.cpp).");
910
911
            static char str1[128] = "";
912
            ImGui::InputTextWithHint("input text (w/ hint)", "enter text here", str1, IM_ARRAYSIZE(str1));
913
914
            IMGUI_DEMO_MARKER("Widgets/Basic/InputInt, InputFloat");
915
            static int i0 = 123;
916
            ImGui::InputInt("input int", &i0);
917
918
            static float f0 = 0.001f;
919
            ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f");
920
921
            static double d0 = 999999.00000001;
922
            ImGui::InputDouble("input double", &d0, 0.01f, 1.0f, "%.8f");
923
924
            static float f1 = 1.e10f;
925
            ImGui::InputFloat("input scientific", &f1, 0.0f, 0.0f, "%e");
926
            ImGui::SameLine(); HelpMarker(
927
                "You can input value using the scientific notation,\n"
928
                "  e.g. \"1e+8\" becomes \"100000000\".");
929
930
            static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f };
931
            ImGui::InputFloat3("input float3", vec4a);
932
        }
933
934
        ImGui::SeparatorText("Drags");
935
936
        {
937
            IMGUI_DEMO_MARKER("Widgets/Basic/DragInt, DragFloat");
938
            static int i1 = 50, i2 = 42, i3 = 128;
939
            ImGui::DragInt("drag int", &i1, 1);
940
            ImGui::SameLine(); HelpMarker(
941
                "Click and drag to edit value.\n"
942
                "Hold SHIFT/ALT for faster/slower edit.\n"
943
                "Double-click or CTRL+click to input value.");
944
            ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp);
945
            ImGui::DragInt("drag int wrap 100..200", &i3, 1, 100, 200, "%d", ImGuiSliderFlags_WrapAround);
946
947
            static float f1 = 1.00f, f2 = 0.0067f;
948
            ImGui::DragFloat("drag float", &f1, 0.005f);
949
            ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns");
950
            //ImGui::DragFloat("drag wrap -1..1", &f3, 0.005f, -1.0f, 1.0f, NULL, ImGuiSliderFlags_WrapAround);
951
        }
952
953
        ImGui::SeparatorText("Sliders");
954
955
        {
956
            IMGUI_DEMO_MARKER("Widgets/Basic/SliderInt, SliderFloat");
957
            static int i1 = 0;
958
            ImGui::SliderInt("slider int", &i1, -1, 3);
959
            ImGui::SameLine(); HelpMarker("CTRL+click to input value.");
960
961
            static float f1 = 0.123f, f2 = 0.0f;
962
            ImGui::SliderFloat("slider float", &f1, 0.0f, 1.0f, "ratio = %.3f");
963
            ImGui::SliderFloat("slider float (log)", &f2, -10.0f, 10.0f, "%.4f", ImGuiSliderFlags_Logarithmic);
964
965
            IMGUI_DEMO_MARKER("Widgets/Basic/SliderAngle");
966
            static float angle = 0.0f;
967
            ImGui::SliderAngle("slider angle", &angle);
968
969
            // Using the format string to display a name instead of an integer.
970
            // Here we completely omit '%d' from the format string, so it'll only display a name.
971
            // This technique can also be used with DragInt().
972
            IMGUI_DEMO_MARKER("Widgets/Basic/Slider (enum)");
973
            enum Element { Element_Fire, Element_Earth, Element_Air, Element_Water, Element_COUNT };
974
            static int elem = Element_Fire;
975
            const char* elems_names[Element_COUNT] = { "Fire", "Earth", "Air", "Water" };
976
            const char* elem_name = (elem >= 0 && elem < Element_COUNT) ? elems_names[elem] : "Unknown";
977
            ImGui::SliderInt("slider enum", &elem, 0, Element_COUNT - 1, elem_name); // Use ImGuiSliderFlags_NoInput flag to disable CTRL+Click here.
978
            ImGui::SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer.");
979
        }
980
981
        ImGui::SeparatorText("Selectors/Pickers");
982
983
        {
984
            IMGUI_DEMO_MARKER("Widgets/Basic/ColorEdit3, ColorEdit4");
985
            static float col1[3] = { 1.0f, 0.0f, 0.2f };
986
            static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
987
            ImGui::ColorEdit3("color 1", col1);
988
            ImGui::SameLine(); HelpMarker(
989
                "Click on the color square to open a color picker.\n"
990
                "Click and hold to use drag and drop.\n"
991
                "Right-click on the color square to show options.\n"
992
                "CTRL+click on individual component to input value.\n");
993
994
            ImGui::ColorEdit4("color 2", col2);
995
        }
996
997
        {
998
            // Using the _simplified_ one-liner Combo() api here
999
            // See "Combo" section for examples of how to use the more flexible BeginCombo()/EndCombo() api.
1000
            IMGUI_DEMO_MARKER("Widgets/Basic/Combo");
1001
            const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" };
1002
            static int item_current = 0;
1003
            ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items));
1004
            ImGui::SameLine(); HelpMarker(
1005
                "Using the simplified one-liner Combo API here.\n"
1006
                "Refer to the \"Combo\" section below for an explanation of how to use the more flexible and general BeginCombo/EndCombo API.");
1007
        }
1008
1009
        {
1010
            // Using the _simplified_ one-liner ListBox() api here
1011
            // See "List boxes" section for examples of how to use the more flexible BeginListBox()/EndListBox() api.
1012
            IMGUI_DEMO_MARKER("Widgets/Basic/ListBox");
1013
            const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" };
1014
            static int item_current = 1;
1015
            ImGui::ListBox("listbox", &item_current, items, IM_ARRAYSIZE(items), 4);
1016
            ImGui::SameLine(); HelpMarker(
1017
                "Using the simplified one-liner ListBox API here.\n"
1018
                "Refer to the \"List boxes\" section below for an explanation of how to use the more flexible and general BeginListBox/EndListBox API.");
1019
        }
1020
1021
        ImGui::TreePop();
1022
    }
1023
1024
    IMGUI_DEMO_MARKER("Widgets/Tooltips");
1025
    if (ImGui::TreeNode("Tooltips"))
1026
    {
1027
        // Tooltips are windows following the mouse. They do not take focus away.
1028
        ImGui::SeparatorText("General");
1029
1030
        // Typical use cases:
1031
        // - Short-form (text only):      SetItemTooltip("Hello");
1032
        // - Short-form (any contents):   if (BeginItemTooltip()) { Text("Hello"); EndTooltip(); }
1033
1034
        // - Full-form (text only):       if (IsItemHovered(...)) { SetTooltip("Hello"); }
1035
        // - Full-form (any contents):    if (IsItemHovered(...) && BeginTooltip()) { Text("Hello"); EndTooltip(); }
1036
1037
        HelpMarker(
1038
            "Tooltip are typically created by using a IsItemHovered() + SetTooltip() sequence.\n\n"
1039
            "We provide a helper SetItemTooltip() function to perform the two with standards flags.");
1040
1041
        ImVec2 sz = ImVec2(-FLT_MIN, 0.0f);
1042
1043
        ImGui::Button("Basic", sz);
1044
        ImGui::SetItemTooltip("I am a tooltip");
1045
1046
        ImGui::Button("Fancy", sz);
1047
        if (ImGui::BeginItemTooltip())
1048
        {
1049
            ImGui::Text("I am a fancy tooltip");
1050
            static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
1051
            ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr));
1052
            ImGui::Text("Sin(time) = %f", sinf((float)ImGui::GetTime()));
1053
            ImGui::EndTooltip();
1054
        }
1055
1056
        ImGui::SeparatorText("Always On");
1057
1058
        // Showcase NOT relying on a IsItemHovered() to emit a tooltip.
1059
        // Here the tooltip is always emitted when 'always_on == true'.
1060
        static int always_on = 0;
1061
        ImGui::RadioButton("Off", &always_on, 0);
1062
        ImGui::SameLine();
1063
        ImGui::RadioButton("Always On (Simple)", &always_on, 1);
1064
        ImGui::SameLine();
1065
        ImGui::RadioButton("Always On (Advanced)", &always_on, 2);
1066
        if (always_on == 1)
1067
            ImGui::SetTooltip("I am following you around.");
1068
        else if (always_on == 2 && ImGui::BeginTooltip())
1069
        {
1070
            ImGui::ProgressBar(sinf((float)ImGui::GetTime()) * 0.5f + 0.5f, ImVec2(ImGui::GetFontSize() * 25, 0.0f));
1071
            ImGui::EndTooltip();
1072
        }
1073
1074
        ImGui::SeparatorText("Custom");
1075
1076
        HelpMarker(
1077
            "Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() is the preferred way to standardize"
1078
            "tooltip activation details across your application. You may however decide to use custom"
1079
            "flags for a specific tooltip instance.");
1080
1081
        // The following examples are passed for documentation purpose but may not be useful to most users.
1082
        // Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() will pull ImGuiHoveredFlags flags values from
1083
        // 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' depending on whether mouse or keyboard/gamepad is being used.
1084
        // With default settings, ImGuiHoveredFlags_ForTooltip is equivalent to ImGuiHoveredFlags_DelayShort + ImGuiHoveredFlags_Stationary.
1085
        ImGui::Button("Manual", sz);
1086
        if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip))
1087
            ImGui::SetTooltip("I am a manually emitted tooltip.");
1088
1089
        ImGui::Button("DelayNone", sz);
1090
        if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNone))
1091
            ImGui::SetTooltip("I am a tooltip with no delay.");
1092
1093
        ImGui::Button("DelayShort", sz);
1094
        if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort | ImGuiHoveredFlags_NoSharedDelay))
1095
            ImGui::SetTooltip("I am a tooltip with a short delay (%0.2f sec).", ImGui::GetStyle().HoverDelayShort);
1096
1097
        ImGui::Button("DelayLong", sz);
1098
        if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal | ImGuiHoveredFlags_NoSharedDelay))
1099
            ImGui::SetTooltip("I am a tooltip with a long delay (%0.2f sec).", ImGui::GetStyle().HoverDelayNormal);
1100
1101
        ImGui::Button("Stationary", sz);
1102
        if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary))
1103
            ImGui::SetTooltip("I am a tooltip requiring mouse to be stationary before activating.");
1104
1105
        // Using ImGuiHoveredFlags_ForTooltip will pull flags from 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav',
1106
        // which default value include the ImGuiHoveredFlags_AllowWhenDisabled flag.
1107
        ImGui::BeginDisabled();
1108
        ImGui::Button("Disabled item", sz);
1109
        if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip))
1110
            ImGui::SetTooltip("I am a a tooltip for a disabled item.");
1111
        ImGui::EndDisabled();
1112
1113
        ImGui::TreePop();
1114
    }
1115
1116
    // Testing ImGuiOnceUponAFrame helper.
1117
    //static ImGuiOnceUponAFrame once;
1118
    //for (int i = 0; i < 5; i++)
1119
    //    if (once)
1120
    //        ImGui::Text("This will be displayed only once.");
1121
1122
    IMGUI_DEMO_MARKER("Widgets/Tree Nodes");
1123
    if (ImGui::TreeNode("Tree Nodes"))
1124
    {
1125
        IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Basic trees");
1126
        if (ImGui::TreeNode("Basic trees"))
1127
        {
1128
            for (int i = 0; i < 5; i++)
1129
            {
1130
                // Use SetNextItemOpen() so set the default state of a node to be open. We could
1131
                // also use TreeNodeEx() with the ImGuiTreeNodeFlags_DefaultOpen flag to achieve the same thing!
1132
                if (i == 0)
1133
                    ImGui::SetNextItemOpen(true, ImGuiCond_Once);
1134
1135
                // Here we use PushID() to generate a unique base ID, and then the "" used as TreeNode id won't conflict.
1136
                // An alternative to using 'PushID() + TreeNode("", ...)' to generate a unique ID is to use 'TreeNode((void*)(intptr_t)i, ...)',
1137
                // aka generate a dummy pointer-sized value to be hashed. The demo below uses that technique. Both are fine.
1138
                ImGui::PushID(i);
1139
                if (ImGui::TreeNode("", "Child %d", i))
1140
                {
1141
                    ImGui::Text("blah blah");
1142
                    ImGui::SameLine();
1143
                    if (ImGui::SmallButton("button")) {}
1144
                    ImGui::TreePop();
1145
                }
1146
                ImGui::PopID();
1147
            }
1148
            ImGui::TreePop();
1149
        }
1150
1151
        IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Advanced, with Selectable nodes");
1152
        if (ImGui::TreeNode("Advanced, with Selectable nodes"))
1153
        {
1154
            HelpMarker(
1155
                "This is a more typical looking tree with selectable nodes.\n"
1156
                "Click to select, CTRL+Click to toggle, click on arrows or double-click to open.");
1157
            static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth;
1158
            static bool align_label_with_current_x_position = false;
1159
            static bool test_drag_and_drop = false;
1160
            ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnArrow",       &base_flags, ImGuiTreeNodeFlags_OpenOnArrow);
1161
            ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", &base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick);
1162
            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.");
1163
            ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth",     &base_flags, ImGuiTreeNodeFlags_SpanFullWidth);
1164
            ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanTextWidth",     &base_flags, ImGuiTreeNodeFlags_SpanTextWidth); ImGui::SameLine(); HelpMarker("Reduce hit area to the text label and a bit of margin.");
1165
            ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns",    &base_flags, ImGuiTreeNodeFlags_SpanAllColumns); ImGui::SameLine(); HelpMarker("For use in Tables only.");
1166
            ImGui::CheckboxFlags("ImGuiTreeNodeFlags_AllowOverlap",      &base_flags, ImGuiTreeNodeFlags_AllowOverlap);
1167
            ImGui::CheckboxFlags("ImGuiTreeNodeFlags_Framed",            &base_flags, ImGuiTreeNodeFlags_Framed); ImGui::SameLine(); HelpMarker("Draw frame with background (e.g. for CollapsingHeader)");
1168
            ImGui::CheckboxFlags("ImGuiTreeNodeFlags_NavLeftJumpsBackHere", &base_flags, ImGuiTreeNodeFlags_NavLeftJumpsBackHere);
1169
            ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position);
1170
            ImGui::Checkbox("Test tree node as drag source", &test_drag_and_drop);
1171
            ImGui::Text("Hello!");
1172
            if (align_label_with_current_x_position)
1173
                ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing());
1174
1175
            // 'selection_mask' is dumb representation of what may be user-side selection state.
1176
            //  You may retain selection state inside or outside your objects in whatever format you see fit.
1177
            // 'node_clicked' is temporary storage of what node we have clicked to process selection at the end
1178
            /// of the loop. May be a pointer to your own node type, etc.
1179
            static int selection_mask = (1 << 2);
1180
            int node_clicked = -1;
1181
            for (int i = 0; i < 6; i++)
1182
            {
1183
                // Disable the default "open on single-click behavior" + set Selected flag according to our selection.
1184
                // To alter selection we use IsItemClicked() && !IsItemToggledOpen(), so clicking on an arrow doesn't alter selection.
1185
                ImGuiTreeNodeFlags node_flags = base_flags;
1186
                const bool is_selected = (selection_mask & (1 << i)) != 0;
1187
                if (is_selected)
1188
                    node_flags |= ImGuiTreeNodeFlags_Selected;
1189
                if (i < 3)
1190
                {
1191
                    // Items 0..2 are Tree Node
1192
                    bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Node %d", i);
1193
                    if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen())
1194
                        node_clicked = i;
1195
                    if (test_drag_and_drop && ImGui::BeginDragDropSource())
1196
                    {
1197
                        ImGui::SetDragDropPayload("_TREENODE", NULL, 0);
1198
                        ImGui::Text("This is a drag and drop source");
1199
                        ImGui::EndDragDropSource();
1200
                    }
1201
                    if (i == 2 && (base_flags & ImGuiTreeNodeFlags_SpanTextWidth))
1202
                    {
1203
                        // Item 2 has an additional inline button to help demonstrate SpanTextWidth.
1204
                        ImGui::SameLine();
1205
                        if (ImGui::SmallButton("button")) {}
1206
                    }
1207
                    if (node_open)
1208
                    {
1209
                        ImGui::BulletText("Blah blah\nBlah Blah");
1210
                        ImGui::SameLine();
1211
                        ImGui::SmallButton("Button");
1212
                        ImGui::TreePop();
1213
                    }
1214
                }
1215
                else
1216
                {
1217
                    // Items 3..5 are Tree Leaves
1218
                    // The only reason we use TreeNode at all is to allow selection of the leaf. Otherwise we can
1219
                    // use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text().
1220
                    node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet
1221
                    ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i);
1222
                    if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen())
1223
                        node_clicked = i;
1224
                    if (test_drag_and_drop && ImGui::BeginDragDropSource())
1225
                    {
1226
                        ImGui::SetDragDropPayload("_TREENODE", NULL, 0);
1227
                        ImGui::Text("This is a drag and drop source");
1228
                        ImGui::EndDragDropSource();
1229
                    }
1230
                }
1231
            }
1232
            if (node_clicked != -1)
1233
            {
1234
                // Update selection state
1235
                // (process outside of tree loop to avoid visual inconsistencies during the clicking frame)
1236
                if (ImGui::GetIO().KeyCtrl)
1237
                    selection_mask ^= (1 << node_clicked);          // CTRL+click to toggle
1238
                else //if (!(selection_mask & (1 << node_clicked))) // Depending on selection behavior you want, may want to preserve selection when clicking on item that is part of the selection
1239
                    selection_mask = (1 << node_clicked);           // Click to single-select
1240
            }
1241
            if (align_label_with_current_x_position)
1242
                ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing());
1243
            ImGui::TreePop();
1244
        }
1245
        ImGui::TreePop();
1246
    }
1247
1248
    IMGUI_DEMO_MARKER("Widgets/Collapsing Headers");
1249
    if (ImGui::TreeNode("Collapsing Headers"))
1250
    {
1251
        static bool closable_group = true;
1252
        ImGui::Checkbox("Show 2nd header", &closable_group);
1253
        if (ImGui::CollapsingHeader("Header", ImGuiTreeNodeFlags_None))
1254
        {
1255
            ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
1256
            for (int i = 0; i < 5; i++)
1257
                ImGui::Text("Some content %d", i);
1258
        }
1259
        if (ImGui::CollapsingHeader("Header with a close button", &closable_group))
1260
        {
1261
            ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
1262
            for (int i = 0; i < 5; i++)
1263
                ImGui::Text("More content %d", i);
1264
        }
1265
        /*
1266
        if (ImGui::CollapsingHeader("Header with a bullet", ImGuiTreeNodeFlags_Bullet))
1267
            ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
1268
        */
1269
        ImGui::TreePop();
1270
    }
1271
1272
    IMGUI_DEMO_MARKER("Widgets/Bullets");
1273
    if (ImGui::TreeNode("Bullets"))
1274
    {
1275
        ImGui::BulletText("Bullet point 1");
1276
        ImGui::BulletText("Bullet point 2\nOn multiple lines");
1277
        if (ImGui::TreeNode("Tree node"))
1278
        {
1279
            ImGui::BulletText("Another bullet point");
1280
            ImGui::TreePop();
1281
        }
1282
        ImGui::Bullet(); ImGui::Text("Bullet point 3 (two calls)");
1283
        ImGui::Bullet(); ImGui::SmallButton("Button");
1284
        ImGui::TreePop();
1285
    }
1286
1287
    IMGUI_DEMO_MARKER("Widgets/Text");
1288
    if (ImGui::TreeNode("Text"))
1289
    {
1290
        IMGUI_DEMO_MARKER("Widgets/Text/Colored Text");
1291
        if (ImGui::TreeNode("Colorful Text"))
1292
        {
1293
            // Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility.
1294
            ImGui::TextColored(ImVec4(1.0f, 0.0f, 1.0f, 1.0f), "Pink");
1295
            ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Yellow");
1296
            ImGui::TextDisabled("Disabled");
1297
            ImGui::SameLine(); HelpMarker("The TextDisabled color is stored in ImGuiStyle.");
1298
            ImGui::TreePop();
1299
        }
1300
1301
        IMGUI_DEMO_MARKER("Widgets/Text/Word Wrapping");
1302
        if (ImGui::TreeNode("Word Wrapping"))
1303
        {
1304
            // Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility.
1305
            ImGui::TextWrapped(
1306
                "This text should automatically wrap on the edge of the window. The current implementation "
1307
                "for text wrapping follows simple rules suitable for English and possibly other languages.");
1308
            ImGui::Spacing();
1309
1310
            static float wrap_width = 200.0f;
1311
            ImGui::SliderFloat("Wrap width", &wrap_width, -20, 600, "%.0f");
1312
1313
            ImDrawList* draw_list = ImGui::GetWindowDrawList();
1314
            for (int n = 0; n < 2; n++)
1315
            {
1316
                ImGui::Text("Test paragraph %d:", n);
1317
                ImVec2 pos = ImGui::GetCursorScreenPos();
1318
                ImVec2 marker_min = ImVec2(pos.x + wrap_width, pos.y);
1319
                ImVec2 marker_max = ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight());
1320
                ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width);
1321
                if (n == 0)
1322
                    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);
1323
                else
1324
                    ImGui::Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee   ffffffff. gggggggg!hhhhhhhh");
1325
1326
                // Draw actual text bounding box, following by marker of our expected limit (should not overlap!)
1327
                draw_list->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 255, 0, 255));
1328
                draw_list->AddRectFilled(marker_min, marker_max, IM_COL32(255, 0, 255, 255));
1329
                ImGui::PopTextWrapPos();
1330
            }
1331
1332
            ImGui::TreePop();
1333
        }
1334
1335
        IMGUI_DEMO_MARKER("Widgets/Text/UTF-8 Text");
1336
        if (ImGui::TreeNode("UTF-8 Text"))
1337
        {
1338
            // UTF-8 test with Japanese characters
1339
            // (Needs a suitable font? Try "Google Noto" or "Arial Unicode". See docs/FONTS.md for details.)
1340
            // - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8
1341
            // - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. in Visual Studio, you
1342
            //   can save your source files as 'UTF-8 without signature').
1343
            // - FOR THIS DEMO FILE ONLY, BECAUSE WE WANT TO SUPPORT OLD COMPILERS, WE ARE *NOT* INCLUDING RAW UTF-8
1344
            //   CHARACTERS IN THIS SOURCE FILE. Instead we are encoding a few strings with hexadecimal constants.
1345
            //   Don't do this in your application! Please use u8"text in any language" in your application!
1346
            // Note that characters values are preserved even by InputText() if the font cannot be displayed,
1347
            // so you can safely copy & paste garbled characters into another application.
1348
            ImGui::TextWrapped(
1349
                "CJK text will only appear if the font was loaded with the appropriate CJK character ranges. "
1350
                "Call io.Fonts->AddFontFromFileTTF() manually to load extra character ranges. "
1351
                "Read docs/FONTS.md for details.");
1352
            ImGui::Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)");
1353
            ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)");
1354
            static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e";
1355
            //static char buf[32] = u8"NIHONGO"; // <- this is how you would write it with C++11, using real kanjis
1356
            ImGui::InputText("UTF-8 input", buf, IM_ARRAYSIZE(buf));
1357
            ImGui::TreePop();
1358
        }
1359
        ImGui::TreePop();
1360
    }
1361
1362
    IMGUI_DEMO_MARKER("Widgets/Images");
1363
    if (ImGui::TreeNode("Images"))
1364
    {
1365
        ImGuiIO& io = ImGui::GetIO();
1366
        ImGui::TextWrapped(
1367
            "Below we are displaying the font texture (which is the only texture we have access to in this demo). "
1368
            "Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. "
1369
            "Hover the texture for a zoomed view!");
1370
1371
        // Below we are displaying the font texture because it is the only texture we have access to inside the demo!
1372
        // Remember that ImTextureID is just storage for whatever you want it to be. It is essentially a value that
1373
        // will be passed to the rendering backend via the ImDrawCmd structure.
1374
        // If you use one of the default imgui_impl_XXXX.cpp rendering backend, they all have comments at the top
1375
        // of their respective source file to specify what they expect to be stored in ImTextureID, for example:
1376
        // - The imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer
1377
        // - The imgui_impl_opengl3.cpp renderer expect a GLuint OpenGL texture identifier, etc.
1378
        // More:
1379
        // - If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers
1380
        //   to ImGui::Image(), and gather width/height through your own functions, etc.
1381
        // - You can use ShowMetricsWindow() to inspect the draw data that are being passed to your renderer,
1382
        //   it will help you debug issues if you are confused about it.
1383
        // - Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage().
1384
        // - Read https://github.com/ocornut/imgui/blob/master/docs/FAQ.md
1385
        // - Read https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
1386
        ImTextureID my_tex_id = io.Fonts->TexID;
1387
        float my_tex_w = (float)io.Fonts->TexWidth;
1388
        float my_tex_h = (float)io.Fonts->TexHeight;
1389
        {
1390
            static bool use_text_color_for_tint = false;
1391
            ImGui::Checkbox("Use Text Color for Tint", &use_text_color_for_tint);
1392
            ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h);
1393
            ImVec2 pos = ImGui::GetCursorScreenPos();
1394
            ImVec2 uv_min = ImVec2(0.0f, 0.0f);                 // Top-left
1395
            ImVec2 uv_max = ImVec2(1.0f, 1.0f);                 // Lower-right
1396
            ImVec4 tint_col = use_text_color_for_tint ? ImGui::GetStyleColorVec4(ImGuiCol_Text) : ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint
1397
            ImVec4 border_col = ImGui::GetStyleColorVec4(ImGuiCol_Border);
1398
            ImGui::Image(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, tint_col, border_col);
1399
            if (ImGui::BeginItemTooltip())
1400
            {
1401
                float region_sz = 32.0f;
1402
                float region_x = io.MousePos.x - pos.x - region_sz * 0.5f;
1403
                float region_y = io.MousePos.y - pos.y - region_sz * 0.5f;
1404
                float zoom = 4.0f;
1405
                if (region_x < 0.0f) { region_x = 0.0f; }
1406
                else if (region_x > my_tex_w - region_sz) { region_x = my_tex_w - region_sz; }
1407
                if (region_y < 0.0f) { region_y = 0.0f; }
1408
                else if (region_y > my_tex_h - region_sz) { region_y = my_tex_h - region_sz; }
1409
                ImGui::Text("Min: (%.2f, %.2f)", region_x, region_y);
1410
                ImGui::Text("Max: (%.2f, %.2f)", region_x + region_sz, region_y + region_sz);
1411
                ImVec2 uv0 = ImVec2((region_x) / my_tex_w, (region_y) / my_tex_h);
1412
                ImVec2 uv1 = ImVec2((region_x + region_sz) / my_tex_w, (region_y + region_sz) / my_tex_h);
1413
                ImGui::Image(my_tex_id, ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, tint_col, border_col);
1414
                ImGui::EndTooltip();
1415
            }
1416
        }
1417
1418
        IMGUI_DEMO_MARKER("Widgets/Images/Textured buttons");
1419
        ImGui::TextWrapped("And now some textured buttons..");
1420
        static int pressed_count = 0;
1421
        for (int i = 0; i < 8; i++)
1422
        {
1423
            // UV coordinates are often (0.0f, 0.0f) and (1.0f, 1.0f) to display an entire textures.
1424
            // Here are trying to display only a 32x32 pixels area of the texture, hence the UV computation.
1425
            // Read about UV coordinates here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
1426
            ImGui::PushID(i);
1427
            if (i > 0)
1428
                ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(i - 1.0f, i - 1.0f));
1429
            ImVec2 size = ImVec2(32.0f, 32.0f);                         // Size of the image we want to make visible
1430
            ImVec2 uv0 = ImVec2(0.0f, 0.0f);                            // UV coordinates for lower-left
1431
            ImVec2 uv1 = ImVec2(32.0f / my_tex_w, 32.0f / my_tex_h);    // UV coordinates for (32,32) in our texture
1432
            ImVec4 bg_col = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);             // Black background
1433
            ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);           // No tint
1434
            if (ImGui::ImageButton("", my_tex_id, size, uv0, uv1, bg_col, tint_col))
1435
                pressed_count += 1;
1436
            if (i > 0)
1437
                ImGui::PopStyleVar();
1438
            ImGui::PopID();
1439
            ImGui::SameLine();
1440
        }
1441
        ImGui::NewLine();
1442
        ImGui::Text("Pressed %d times.", pressed_count);
1443
        ImGui::TreePop();
1444
    }
1445
1446
    IMGUI_DEMO_MARKER("Widgets/Combo");
1447
    if (ImGui::TreeNode("Combo"))
1448
    {
1449
        // Combo Boxes are also called "Dropdown" in other systems
1450
        // Expose flags as checkbox for the demo
1451
        static ImGuiComboFlags flags = 0;
1452
        ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", &flags, ImGuiComboFlags_PopupAlignLeft);
1453
        ImGui::SameLine(); HelpMarker("Only makes a difference if the popup is larger than the combo");
1454
        if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", &flags, ImGuiComboFlags_NoArrowButton))
1455
            flags &= ~ImGuiComboFlags_NoPreview;     // Clear incompatible flags
1456
        if (ImGui::CheckboxFlags("ImGuiComboFlags_NoPreview", &flags, ImGuiComboFlags_NoPreview))
1457
            flags &= ~(ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_WidthFitPreview); // Clear incompatible flags
1458
        if (ImGui::CheckboxFlags("ImGuiComboFlags_WidthFitPreview", &flags, ImGuiComboFlags_WidthFitPreview))
1459
            flags &= ~ImGuiComboFlags_NoPreview;
1460
1461
        // Override default popup height
1462
        if (ImGui::CheckboxFlags("ImGuiComboFlags_HeightSmall", &flags, ImGuiComboFlags_HeightSmall))
1463
            flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightSmall);
1464
        if (ImGui::CheckboxFlags("ImGuiComboFlags_HeightRegular", &flags, ImGuiComboFlags_HeightRegular))
1465
            flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightRegular);
1466
        if (ImGui::CheckboxFlags("ImGuiComboFlags_HeightLargest", &flags, ImGuiComboFlags_HeightLargest))
1467
            flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightLargest);
1468
1469
        // Using the generic BeginCombo() API, you have full control over how to display the combo contents.
1470
        // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
1471
        // stored in the object itself, etc.)
1472
        const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" };
1473
        static int item_selected_idx = 0; // Here we store our selection data as an index.
1474
1475
        // Pass in the preview value visible before opening the combo (it could technically be different contents or not pulled from items[])
1476
        const char* combo_preview_value = items[item_selected_idx];
1477
1478
        if (ImGui::BeginCombo("combo 1", combo_preview_value, flags))
1479
        {
1480
            for (int n = 0; n < IM_ARRAYSIZE(items); n++)
1481
            {
1482
                const bool is_selected = (item_selected_idx == n);
1483
                if (ImGui::Selectable(items[n], is_selected))
1484
                    item_selected_idx = n;
1485
1486
                // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
1487
                if (is_selected)
1488
                    ImGui::SetItemDefaultFocus();
1489
            }
1490
            ImGui::EndCombo();
1491
        }
1492
1493
        ImGui::Spacing();
1494
        ImGui::SeparatorText("One-liner variants");
1495
        HelpMarker("Flags above don't apply to this section.");
1496
1497
        // Simplified one-liner Combo() API, using values packed in a single constant string
1498
        // This is a convenience for when the selection set is small and known at compile-time.
1499
        static int item_current_2 = 0;
1500
        ImGui::Combo("combo 2 (one-liner)", &item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
1501
1502
        // Simplified one-liner Combo() using an array of const char*
1503
        // This is not very useful (may obsolete): prefer using BeginCombo()/EndCombo() for full control.
1504
        static int item_current_3 = -1; // If the selection isn't within 0..count, Combo won't display a preview
1505
        ImGui::Combo("combo 3 (array)", &item_current_3, items, IM_ARRAYSIZE(items));
1506
1507
        // Simplified one-liner Combo() using an accessor function
1508
        static int item_current_4 = 0;
1509
        ImGui::Combo("combo 4 (function)", &item_current_4, [](void* data, int n) { return ((const char**)data)[n]; }, items, IM_ARRAYSIZE(items));
1510
1511
        ImGui::TreePop();
1512
    }
1513
1514
    IMGUI_DEMO_MARKER("Widgets/List Boxes");
1515
    if (ImGui::TreeNode("List boxes"))
1516
    {
1517
        // BeginListBox() is essentially a thin wrapper to using BeginChild()/EndChild()
1518
        // using the ImGuiChildFlags_FrameStyle flag for stylistic changes + displaying a label.
1519
        // You may be tempted to simply use BeginChild() directly. However note that BeginChild() requires EndChild()
1520
        // to always be called (inconsistent with BeginListBox()/EndListBox()).
1521
1522
        // Using the generic BeginListBox() API, you have full control over how to display the combo contents.
1523
        // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
1524
        // stored in the object itself, etc.)
1525
        const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" };
1526
        static int item_selected_idx = 0; // Here we store our selected data as an index.
1527
1528
        static bool item_highlight = false;
1529
        int item_highlighted_idx = -1; // Here we store our highlighted data as an index.
1530
        ImGui::Checkbox("Highlight hovered item in second listbox", &item_highlight);
1531
1532
        if (ImGui::BeginListBox("listbox 1"))
1533
        {
1534
            for (int n = 0; n < IM_ARRAYSIZE(items); n++)
1535
            {
1536
                const bool is_selected = (item_selected_idx == n);
1537
                if (ImGui::Selectable(items[n], is_selected))
1538
                    item_selected_idx = n;
1539
1540
                if (item_highlight && ImGui::IsItemHovered())
1541
                    item_highlighted_idx = n;
1542
1543
                // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
1544
                if (is_selected)
1545
                    ImGui::SetItemDefaultFocus();
1546
            }
1547
            ImGui::EndListBox();
1548
        }
1549
        ImGui::SameLine(); HelpMarker("Here we are sharing selection state between both boxes.");
1550
1551
        // Custom size: use all width, 5 items tall
1552
        ImGui::Text("Full-width:");
1553
        if (ImGui::BeginListBox("##listbox 2", ImVec2(-FLT_MIN, 5 * ImGui::GetTextLineHeightWithSpacing())))
1554
        {
1555
            for (int n = 0; n < IM_ARRAYSIZE(items); n++)
1556
            {
1557
                bool is_selected = (item_selected_idx == n);
1558
                ImGuiSelectableFlags flags = (item_highlighted_idx == n) ? ImGuiSelectableFlags_Highlight : 0;
1559
                if (ImGui::Selectable(items[n], is_selected, flags))
1560
                    item_selected_idx = n;
1561
1562
                // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
1563
                if (is_selected)
1564
                    ImGui::SetItemDefaultFocus();
1565
            }
1566
            ImGui::EndListBox();
1567
        }
1568
1569
        ImGui::TreePop();
1570
    }
1571
1572
    IMGUI_DEMO_MARKER("Widgets/Selectables");
1573
    //ImGui::SetNextItemOpen(true, ImGuiCond_Once);
1574
    if (ImGui::TreeNode("Selectables"))
1575
    {
1576
        // Selectable() has 2 overloads:
1577
        // - The one taking "bool selected" as a read-only selection information.
1578
        //   When Selectable() has been clicked it returns true and you can alter selection state accordingly.
1579
        // - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases)
1580
        // The earlier is more flexible, as in real application your selection may be stored in many different ways
1581
        // and not necessarily inside a bool value (e.g. in flags within objects, as an external list, etc).
1582
        IMGUI_DEMO_MARKER("Widgets/Selectables/Basic");
1583
        if (ImGui::TreeNode("Basic"))
1584
        {
1585
            static bool selection[5] = { false, true, false, false };
1586
            ImGui::Selectable("1. I am selectable", &selection[0]);
1587
            ImGui::Selectable("2. I am selectable", &selection[1]);
1588
            ImGui::Selectable("3. I am selectable", &selection[2]);
1589
            if (ImGui::Selectable("4. I am double clickable", selection[3], ImGuiSelectableFlags_AllowDoubleClick))
1590
                if (ImGui::IsMouseDoubleClicked(0))
1591
                    selection[3] = !selection[3];
1592
            ImGui::TreePop();
1593
        }
1594
1595
        IMGUI_DEMO_MARKER("Widgets/Selectables/Rendering more items on the same line");
1596
        if (ImGui::TreeNode("Rendering more items on the same line"))
1597
        {
1598
            // (1) Using SetNextItemAllowOverlap()
1599
            // (2) Using the Selectable() override that takes "bool* p_selected" parameter, the bool value is toggled automatically.
1600
            static bool selected[3] = { false, false, false };
1601
            ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("main.c",    &selected[0]); ImGui::SameLine(); ImGui::SmallButton("Link 1");
1602
            ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("Hello.cpp", &selected[1]); ImGui::SameLine(); ImGui::SmallButton("Link 2");
1603
            ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("Hello.h",   &selected[2]); ImGui::SameLine(); ImGui::SmallButton("Link 3");
1604
            ImGui::TreePop();
1605
        }
1606
1607
        IMGUI_DEMO_MARKER("Widgets/Selectables/In Tables");
1608
        if (ImGui::TreeNode("In Tables"))
1609
        {
1610
            static bool selected[10] = {};
1611
1612
            if (ImGui::BeginTable("split1", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders))
1613
            {
1614
                for (int i = 0; i < 10; i++)
1615
                {
1616
                    char label[32];
1617
                    sprintf(label, "Item %d", i);
1618
                    ImGui::TableNextColumn();
1619
                    ImGui::Selectable(label, &selected[i]); // FIXME-TABLE: Selection overlap
1620
                }
1621
                ImGui::EndTable();
1622
            }
1623
            ImGui::Spacing();
1624
            if (ImGui::BeginTable("split2", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders))
1625
            {
1626
                for (int i = 0; i < 10; i++)
1627
                {
1628
                    char label[32];
1629
                    sprintf(label, "Item %d", i);
1630
                    ImGui::TableNextRow();
1631
                    ImGui::TableNextColumn();
1632
                    ImGui::Selectable(label, &selected[i], ImGuiSelectableFlags_SpanAllColumns);
1633
                    ImGui::TableNextColumn();
1634
                    ImGui::Text("Some other contents");
1635
                    ImGui::TableNextColumn();
1636
                    ImGui::Text("123456");
1637
                }
1638
                ImGui::EndTable();
1639
            }
1640
            ImGui::TreePop();
1641
        }
1642
1643
        IMGUI_DEMO_MARKER("Widgets/Selectables/Grid");
1644
        if (ImGui::TreeNode("Grid"))
1645
        {
1646
            static char selected[4][4] = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } };
1647
1648
            // Add in a bit of silly fun...
1649
            const float time = (float)ImGui::GetTime();
1650
            const bool winning_state = memchr(selected, 0, sizeof(selected)) == NULL; // If all cells are selected...
1651
            if (winning_state)
1652
                ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f + 0.5f * cosf(time * 2.0f), 0.5f + 0.5f * sinf(time * 3.0f)));
1653
1654
            for (int y = 0; y < 4; y++)
1655
                for (int x = 0; x < 4; x++)
1656
                {
1657
                    if (x > 0)
1658
                        ImGui::SameLine();
1659
                    ImGui::PushID(y * 4 + x);
1660
                    if (ImGui::Selectable("Sailor", selected[y][x] != 0, 0, ImVec2(50, 50)))
1661
                    {
1662
                        // Toggle clicked cell + toggle neighbors
1663
                        selected[y][x] ^= 1;
1664
                        if (x > 0) { selected[y][x - 1] ^= 1; }
1665
                        if (x < 3) { selected[y][x + 1] ^= 1; }
1666
                        if (y > 0) { selected[y - 1][x] ^= 1; }
1667
                        if (y < 3) { selected[y + 1][x] ^= 1; }
1668
                    }
1669
                    ImGui::PopID();
1670
                }
1671
1672
            if (winning_state)
1673
                ImGui::PopStyleVar();
1674
            ImGui::TreePop();
1675
        }
1676
        IMGUI_DEMO_MARKER("Widgets/Selectables/Alignment");
1677
        if (ImGui::TreeNode("Alignment"))
1678
        {
1679
            HelpMarker(
1680
                "By default, Selectables uses style.SelectableTextAlign but it can be overridden on a per-item "
1681
                "basis using PushStyleVar(). You'll probably want to always keep your default situation to "
1682
                "left-align otherwise it becomes difficult to layout multiple items on a same line");
1683
            static bool selected[3 * 3] = { true, false, true, false, true, false, true, false, true };
1684
            for (int y = 0; y < 3; y++)
1685
            {
1686
                for (int x = 0; x < 3; x++)
1687
                {
1688
                    ImVec2 alignment = ImVec2((float)x / 2.0f, (float)y / 2.0f);
1689
                    char name[32];
1690
                    sprintf(name, "(%.1f,%.1f)", alignment.x, alignment.y);
1691
                    if (x > 0) ImGui::SameLine();
1692
                    ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, alignment);
1693
                    ImGui::Selectable(name, &selected[3 * y + x], ImGuiSelectableFlags_None, ImVec2(80, 80));
1694
                    ImGui::PopStyleVar();
1695
                }
1696
            }
1697
            ImGui::TreePop();
1698
        }
1699
        ImGui::TreePop();
1700
    }
1701
1702
    ShowDemoWindowMultiSelect(demo_data);
1703
1704
    // To wire InputText() with std::string or any other custom string type,
1705
    // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file.
1706
    IMGUI_DEMO_MARKER("Widgets/Text Input");
1707
    if (ImGui::TreeNode("Text Input"))
1708
    {
1709
        IMGUI_DEMO_MARKER("Widgets/Text Input/Multi-line Text Input");
1710
        if (ImGui::TreeNode("Multi-line Text Input"))
1711
        {
1712
            // Note: we are using a fixed-sized buffer for simplicity here. See ImGuiInputTextFlags_CallbackResize
1713
            // and the code in misc/cpp/imgui_stdlib.h for how to setup InputText() for dynamically resizing strings.
1714
            static char text[1024 * 16] =
1715
                "/*\n"
1716
                " The Pentium F00F bug, shorthand for F0 0F C7 C8,\n"
1717
                " the hexadecimal encoding of one offending instruction,\n"
1718
                " more formally, the invalid operand with locked CMPXCHG8B\n"
1719
                " instruction bug, is a design flaw in the majority of\n"
1720
                " Intel Pentium, Pentium MMX, and Pentium OverDrive\n"
1721
                " processors (all in the P5 microarchitecture).\n"
1722
                "*/\n\n"
1723
                "label:\n"
1724
                "\tlock cmpxchg8b eax\n";
1725
1726
            static ImGuiInputTextFlags flags = ImGuiInputTextFlags_AllowTabInput;
1727
            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)");
1728
            ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly);
1729
            ImGui::CheckboxFlags("ImGuiInputTextFlags_AllowTabInput", &flags, ImGuiInputTextFlags_AllowTabInput);
1730
            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.");
1731
            ImGui::CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", &flags, ImGuiInputTextFlags_CtrlEnterForNewLine);
1732
            ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16), flags);
1733
            ImGui::TreePop();
1734
        }
1735
1736
        IMGUI_DEMO_MARKER("Widgets/Text Input/Filtered Text Input");
1737
        if (ImGui::TreeNode("Filtered Text Input"))
1738
        {
1739
            struct TextFilters
1740
            {
1741
                // Modify character input by altering 'data->Eventchar' (ImGuiInputTextFlags_CallbackCharFilter callback)
1742
                static int FilterCasingSwap(ImGuiInputTextCallbackData* data)
1743
                {
1744
                    if (data->EventChar >= 'a' && data->EventChar <= 'z')       { data->EventChar -= 'a' - 'A'; } // Lowercase becomes uppercase
1745
                    else if (data->EventChar >= 'A' && data->EventChar <= 'Z')  { data->EventChar += 'a' - 'A'; } // Uppercase becomes lowercase
1746
                    return 0;
1747
                }
1748
1749
                // Return 0 (pass) if the character is 'i' or 'm' or 'g' or 'u' or 'i', otherwise return 1 (filter out)
1750
                static int FilterImGuiLetters(ImGuiInputTextCallbackData* data)
1751
                {
1752
                    if (data->EventChar < 256 && strchr("imgui", (char)data->EventChar))
1753
                        return 0;
1754
                    return 1;
1755
                }
1756
            };
1757
1758
            static char buf1[32] = ""; ImGui::InputText("default",     buf1, 32);
1759
            static char buf2[32] = ""; ImGui::InputText("decimal",     buf2, 32, ImGuiInputTextFlags_CharsDecimal);
1760
            static char buf3[32] = ""; ImGui::InputText("hexadecimal", buf3, 32, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase);
1761
            static char buf4[32] = ""; ImGui::InputText("uppercase",   buf4, 32, ImGuiInputTextFlags_CharsUppercase);
1762
            static char buf5[32] = ""; ImGui::InputText("no blank",    buf5, 32, ImGuiInputTextFlags_CharsNoBlank);
1763
            static char buf6[32] = ""; ImGui::InputText("casing swap", buf6, 32, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterCasingSwap); // Use CharFilter callback to replace characters.
1764
            static char buf7[32] = ""; ImGui::InputText("\"imgui\"",   buf7, 32, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters); // Use CharFilter callback to disable some characters.
1765
            ImGui::TreePop();
1766
        }
1767
1768
        IMGUI_DEMO_MARKER("Widgets/Text Input/Password input");
1769
        if (ImGui::TreeNode("Password Input"))
1770
        {
1771
            static char password[64] = "password123";
1772
            ImGui::InputText("password", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password);
1773
            ImGui::SameLine(); HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n");
1774
            ImGui::InputTextWithHint("password (w/ hint)", "<password>", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password);
1775
            ImGui::InputText("password (clear)", password, IM_ARRAYSIZE(password));
1776
            ImGui::TreePop();
1777
        }
1778
1779
        IMGUI_DEMO_MARKER("Widgets/Text Input/Completion, History, Edit Callbacks");
1780
        if (ImGui::TreeNode("Completion, History, Edit Callbacks"))
1781
        {
1782
            struct Funcs
1783
            {
1784
                static int MyCallback(ImGuiInputTextCallbackData* data)
1785
                {
1786
                    if (data->EventFlag == ImGuiInputTextFlags_CallbackCompletion)
1787
                    {
1788
                        data->InsertChars(data->CursorPos, "..");
1789
                    }
1790
                    else if (data->EventFlag == ImGuiInputTextFlags_CallbackHistory)
1791
                    {
1792
                        if (data->EventKey == ImGuiKey_UpArrow)
1793
                        {
1794
                            data->DeleteChars(0, data->BufTextLen);
1795
                            data->InsertChars(0, "Pressed Up!");
1796
                            data->SelectAll();
1797
                        }
1798
                        else if (data->EventKey == ImGuiKey_DownArrow)
1799
                        {
1800
                            data->DeleteChars(0, data->BufTextLen);
1801
                            data->InsertChars(0, "Pressed Down!");
1802
                            data->SelectAll();
1803
                        }
1804
                    }
1805
                    else if (data->EventFlag == ImGuiInputTextFlags_CallbackEdit)
1806
                    {
1807
                        // Toggle casing of first character
1808
                        char c = data->Buf[0];
1809
                        if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) data->Buf[0] ^= 32;
1810
                        data->BufDirty = true;
1811
1812
                        // Increment a counter
1813
                        int* p_int = (int*)data->UserData;
1814
                        *p_int = *p_int + 1;
1815
                    }
1816
                    return 0;
1817
                }
1818
            };
1819
            static char buf1[64];
1820
            ImGui::InputText("Completion", buf1, 64, ImGuiInputTextFlags_CallbackCompletion, Funcs::MyCallback);
1821
            ImGui::SameLine(); HelpMarker(
1822
                "Here we append \"..\" each time Tab is pressed. "
1823
                "See 'Examples>Console' for a more meaningful demonstration of using this callback.");
1824
1825
            static char buf2[64];
1826
            ImGui::InputText("History", buf2, 64, ImGuiInputTextFlags_CallbackHistory, Funcs::MyCallback);
1827
            ImGui::SameLine(); HelpMarker(
1828
                "Here we replace and select text each time Up/Down are pressed. "
1829
                "See 'Examples>Console' for a more meaningful demonstration of using this callback.");
1830
1831
            static char buf3[64];
1832
            static int edit_count = 0;
1833
            ImGui::InputText("Edit", buf3, 64, ImGuiInputTextFlags_CallbackEdit, Funcs::MyCallback, (void*)&edit_count);
1834
            ImGui::SameLine(); HelpMarker(
1835
                "Here we toggle the casing of the first character on every edit + count edits.");
1836
            ImGui::SameLine(); ImGui::Text("(%d)", edit_count);
1837
1838
            ImGui::TreePop();
1839
        }
1840
1841
        IMGUI_DEMO_MARKER("Widgets/Text Input/Resize Callback");
1842
        if (ImGui::TreeNode("Resize Callback"))
1843
        {
1844
            // To wire InputText() with std::string or any other custom string type,
1845
            // you can use the ImGuiInputTextFlags_CallbackResize flag + create a custom ImGui::InputText() wrapper
1846
            // using your preferred type. See misc/cpp/imgui_stdlib.h for an implementation of this using std::string.
1847
            HelpMarker(
1848
                "Using ImGuiInputTextFlags_CallbackResize to wire your custom string type to InputText().\n\n"
1849
                "See misc/cpp/imgui_stdlib.h for an implementation of this for std::string.");
1850
            struct Funcs
1851
            {
1852
                static int MyResizeCallback(ImGuiInputTextCallbackData* data)
1853
                {
1854
                    if (data->EventFlag == ImGuiInputTextFlags_CallbackResize)
1855
                    {
1856
                        ImVector<char>* my_str = (ImVector<char>*)data->UserData;
1857
                        IM_ASSERT(my_str->begin() == data->Buf);
1858
                        my_str->resize(data->BufSize); // NB: On resizing calls, generally data->BufSize == data->BufTextLen + 1
1859
                        data->Buf = my_str->begin();
1860
                    }
1861
                    return 0;
1862
                }
1863
1864
                // Note: Because ImGui:: is a namespace you would typically add your own function into the namespace.
1865
                // For example, you code may declare a function 'ImGui::InputText(const char* label, MyString* my_str)'
1866
                static bool MyInputTextMultiline(const char* label, ImVector<char>* my_str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0)
1867
                {
1868
                    IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
1869
                    return ImGui::InputTextMultiline(label, my_str->begin(), (size_t)my_str->size(), size, flags | ImGuiInputTextFlags_CallbackResize, Funcs::MyResizeCallback, (void*)my_str);
1870
                }
1871
            };
1872
1873
            // For this demo we are using ImVector as a string container.
1874
            // Note that because we need to store a terminating zero character, our size/capacity are 1 more
1875
            // than usually reported by a typical string class.
1876
            static ImVector<char> my_str;
1877
            if (my_str.empty())
1878
                my_str.push_back(0);
1879
            Funcs::MyInputTextMultiline("##MyStr", &my_str, ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16));
1880
            ImGui::Text("Data: %p\nSize: %d\nCapacity: %d", (void*)my_str.begin(), my_str.size(), my_str.capacity());
1881
            ImGui::TreePop();
1882
        }
1883
1884
        IMGUI_DEMO_MARKER("Widgets/Text Input/Miscellaneous");
1885
        if (ImGui::TreeNode("Miscellaneous"))
1886
        {
1887
            static char buf1[16];
1888
            static ImGuiInputTextFlags flags = ImGuiInputTextFlags_EscapeClearsAll;
1889
            ImGui::CheckboxFlags("ImGuiInputTextFlags_EscapeClearsAll", &flags, ImGuiInputTextFlags_EscapeClearsAll);
1890
            ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly);
1891
            ImGui::CheckboxFlags("ImGuiInputTextFlags_NoUndoRedo", &flags, ImGuiInputTextFlags_NoUndoRedo);
1892
            ImGui::InputText("Hello", buf1, IM_ARRAYSIZE(buf1), flags);
1893
            ImGui::TreePop();
1894
        }
1895
1896
        ImGui::TreePop();
1897
    }
1898
1899
    // Tabs
1900
    IMGUI_DEMO_MARKER("Widgets/Tabs");
1901
    if (ImGui::TreeNode("Tabs"))
1902
    {
1903
        IMGUI_DEMO_MARKER("Widgets/Tabs/Basic");
1904
        if (ImGui::TreeNode("Basic"))
1905
        {
1906
            ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None;
1907
            if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
1908
            {
1909
                if (ImGui::BeginTabItem("Avocado"))
1910
                {
1911
                    ImGui::Text("This is the Avocado tab!\nblah blah blah blah blah");
1912
                    ImGui::EndTabItem();
1913
                }
1914
                if (ImGui::BeginTabItem("Broccoli"))
1915
                {
1916
                    ImGui::Text("This is the Broccoli tab!\nblah blah blah blah blah");
1917
                    ImGui::EndTabItem();
1918
                }
1919
                if (ImGui::BeginTabItem("Cucumber"))
1920
                {
1921
                    ImGui::Text("This is the Cucumber tab!\nblah blah blah blah blah");
1922
                    ImGui::EndTabItem();
1923
                }
1924
                ImGui::EndTabBar();
1925
            }
1926
            ImGui::Separator();
1927
            ImGui::TreePop();
1928
        }
1929
1930
        IMGUI_DEMO_MARKER("Widgets/Tabs/Advanced & Close Button");
1931
        if (ImGui::TreeNode("Advanced & Close Button"))
1932
        {
1933
            // Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0).
1934
            static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable;
1935
            ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", &tab_bar_flags, ImGuiTabBarFlags_Reorderable);
1936
            ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", &tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs);
1937
            ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton);
1938
            ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", &tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton);
1939
            ImGui::CheckboxFlags("ImGuiTabBarFlags_DrawSelectedOverline", &tab_bar_flags, ImGuiTabBarFlags_DrawSelectedOverline);
1940
            if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0)
1941
                tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_;
1942
            if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown))
1943
                tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown);
1944
            if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll))
1945
                tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll);
1946
1947
            // Tab Bar
1948
            ImGui::AlignTextToFramePadding();
1949
            ImGui::Text("Opened:");
1950
            const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" };
1951
            static bool opened[4] = { true, true, true, true }; // Persistent user state
1952
            for (int n = 0; n < IM_ARRAYSIZE(opened); n++)
1953
            {
1954
                ImGui::SameLine();
1955
                ImGui::Checkbox(names[n], &opened[n]);
1956
            }
1957
1958
            // Passing a bool* to BeginTabItem() is similar to passing one to Begin():
1959
            // the underlying bool will be set to false when the tab is closed.
1960
            if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
1961
            {
1962
                for (int n = 0; n < IM_ARRAYSIZE(opened); n++)
1963
                    if (opened[n] && ImGui::BeginTabItem(names[n], &opened[n], ImGuiTabItemFlags_None))
1964
                    {
1965
                        ImGui::Text("This is the %s tab!", names[n]);
1966
                        if (n & 1)
1967
                            ImGui::Text("I am an odd tab.");
1968
                        ImGui::EndTabItem();
1969
                    }
1970
                ImGui::EndTabBar();
1971
            }
1972
            ImGui::Separator();
1973
            ImGui::TreePop();
1974
        }
1975
1976
        IMGUI_DEMO_MARKER("Widgets/Tabs/TabItemButton & Leading-Trailing flags");
1977
        if (ImGui::TreeNode("TabItemButton & Leading/Trailing flags"))
1978
        {
1979
            static ImVector<int> active_tabs;
1980
            static int next_tab_id = 0;
1981
            if (next_tab_id == 0) // Initialize with some default tabs
1982
                for (int i = 0; i < 3; i++)
1983
                    active_tabs.push_back(next_tab_id++);
1984
1985
            // TabItemButton() and Leading/Trailing flags are distinct features which we will demo together.
1986
            // (It is possible to submit regular tabs with Leading/Trailing flags, or TabItemButton tabs without Leading/Trailing flags...
1987
            // but they tend to make more sense together)
1988
            static bool show_leading_button = true;
1989
            static bool show_trailing_button = true;
1990
            ImGui::Checkbox("Show Leading TabItemButton()", &show_leading_button);
1991
            ImGui::Checkbox("Show Trailing TabItemButton()", &show_trailing_button);
1992
1993
            // Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs
1994
            static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_FittingPolicyResizeDown;
1995
            ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton);
1996
            if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown))
1997
                tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown);
1998
            if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll))
1999
                tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll);
2000
2001
            if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
2002
            {
2003
                // Demo a Leading TabItemButton(): click the "?" button to open a menu
2004
                if (show_leading_button)
2005
                    if (ImGui::TabItemButton("?", ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_NoTooltip))
2006
                        ImGui::OpenPopup("MyHelpMenu");
2007
                if (ImGui::BeginPopup("MyHelpMenu"))
2008
                {
2009
                    ImGui::Selectable("Hello!");
2010
                    ImGui::EndPopup();
2011
                }
2012
2013
                // Demo Trailing Tabs: click the "+" button to add a new tab.
2014
                // (In your app you may want to use a font icon instead of the "+")
2015
                // We submit it before the regular tabs, but thanks to the ImGuiTabItemFlags_Trailing flag it will always appear at the end.
2016
                if (show_trailing_button)
2017
                    if (ImGui::TabItemButton("+", ImGuiTabItemFlags_Trailing | ImGuiTabItemFlags_NoTooltip))
2018
                        active_tabs.push_back(next_tab_id++); // Add new tab
2019
2020
                // Submit our regular tabs
2021
                for (int n = 0; n < active_tabs.Size; )
2022
                {
2023
                    bool open = true;
2024
                    char name[16];
2025
                    snprintf(name, IM_ARRAYSIZE(name), "%04d", active_tabs[n]);
2026
                    if (ImGui::BeginTabItem(name, &open, ImGuiTabItemFlags_None))
2027
                    {
2028
                        ImGui::Text("This is the %s tab!", name);
2029
                        ImGui::EndTabItem();
2030
                    }
2031
2032
                    if (!open)
2033
                        active_tabs.erase(active_tabs.Data + n);
2034
                    else
2035
                        n++;
2036
                }
2037
2038
                ImGui::EndTabBar();
2039
            }
2040
            ImGui::Separator();
2041
            ImGui::TreePop();
2042
        }
2043
        ImGui::TreePop();
2044
    }
2045
2046
    // Plot/Graph widgets are not very good.
2047
    // Consider using a third-party library such as ImPlot: https://github.com/epezent/implot
2048
    // (see others https://github.com/ocornut/imgui/wiki/Useful-Extensions)
2049
    IMGUI_DEMO_MARKER("Widgets/Plotting");
2050
    if (ImGui::TreeNode("Plotting"))
2051
    {
2052
        static bool animate = true;
2053
        ImGui::Checkbox("Animate", &animate);
2054
2055
        // Plot as lines and plot as histogram
2056
        static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
2057
        ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr));
2058
        ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0, 80.0f));
2059
        //ImGui::SameLine(); HelpMarker("Consider using ImPlot instead!");
2060
2061
        // Fill an array of contiguous float values to plot
2062
        // Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float
2063
        // and the sizeof() of your structure in the "stride" parameter.
2064
        static float values[90] = {};
2065
        static int values_offset = 0;
2066
        static double refresh_time = 0.0;
2067
        if (!animate || refresh_time == 0.0)
2068
            refresh_time = ImGui::GetTime();
2069
        while (refresh_time < ImGui::GetTime()) // Create data at fixed 60 Hz rate for the demo
2070
        {
2071
            static float phase = 0.0f;
2072
            values[values_offset] = cosf(phase);
2073
            values_offset = (values_offset + 1) % IM_ARRAYSIZE(values);
2074
            phase += 0.10f * values_offset;
2075
            refresh_time += 1.0f / 60.0f;
2076
        }
2077
2078
        // Plots can display overlay texts
2079
        // (in this example, we will display an average value)
2080
        {
2081
            float average = 0.0f;
2082
            for (int n = 0; n < IM_ARRAYSIZE(values); n++)
2083
                average += values[n];
2084
            average /= (float)IM_ARRAYSIZE(values);
2085
            char overlay[32];
2086
            sprintf(overlay, "avg %f", average);
2087
            ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, overlay, -1.0f, 1.0f, ImVec2(0, 80.0f));
2088
        }
2089
2090
        // Use functions to generate output
2091
        // FIXME: This is actually VERY awkward because current plot API only pass in indices.
2092
        // We probably want an API passing floats and user provide sample rate/count.
2093
        struct Funcs
2094
        {
2095
            static float Sin(void*, int i) { return sinf(i * 0.1f); }
2096
            static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; }
2097
        };
2098
        static int func_type = 0, display_count = 70;
2099
        ImGui::SeparatorText("Functions");
2100
        ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
2101
        ImGui::Combo("func", &func_type, "Sin\0Saw\0");
2102
        ImGui::SameLine();
2103
        ImGui::SliderInt("Sample count", &display_count, 1, 400);
2104
        float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw;
2105
        ImGui::PlotLines("Lines##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
2106
        ImGui::PlotHistogram("Histogram##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
2107
        ImGui::Separator();
2108
2109
        ImGui::Text("Need better plotting and graphing? Consider using ImPlot:");
2110
        ImGui::TextLinkOpenURL("https://github.com/epezent/implot");
2111
        ImGui::Separator();
2112
2113
        ImGui::TreePop();
2114
    }
2115
2116
    IMGUI_DEMO_MARKER("Widgets/Progress Bars");
2117
    if (ImGui::TreeNode("Progress Bars"))
2118
    {
2119
        // Animate a simple progress bar
2120
        static float progress = 0.0f, progress_dir = 1.0f;
2121
        progress += progress_dir * 0.4f * ImGui::GetIO().DeltaTime;
2122
        if (progress >= +1.1f) { progress = +1.1f; progress_dir *= -1.0f; }
2123
        if (progress <= -0.1f) { progress = -0.1f; progress_dir *= -1.0f; }
2124
2125
        // Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width,
2126
        // or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth.
2127
        ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f));
2128
        ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
2129
        ImGui::Text("Progress Bar");
2130
2131
        float progress_saturated = IM_CLAMP(progress, 0.0f, 1.0f);
2132
        char buf[32];
2133
        sprintf(buf, "%d/%d", (int)(progress_saturated * 1753), 1753);
2134
        ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), buf);
2135
2136
        // Pass an animated negative value, e.g. -1.0f * (float)ImGui::GetTime() is the recommended value.
2137
        // Adjust the factor if you want to adjust the animation speed.
2138
        ImGui::ProgressBar(-1.0f * (float)ImGui::GetTime(), ImVec2(0.0f, 0.0f), "Searching..");
2139
        ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
2140
        ImGui::Text("Indeterminate");
2141
2142
        ImGui::TreePop();
2143
    }
2144
2145
    IMGUI_DEMO_MARKER("Widgets/Color");
2146
    if (ImGui::TreeNode("Color/Picker Widgets"))
2147
    {
2148
        static ImVec4 color = ImVec4(114.0f / 255.0f, 144.0f / 255.0f, 154.0f / 255.0f, 200.0f / 255.0f);
2149
2150
        static bool alpha_preview = true;
2151
        static bool alpha_half_preview = false;
2152
        static bool drag_and_drop = true;
2153
        static bool options_menu = true;
2154
        static bool hdr = false;
2155
        ImGui::SeparatorText("Options");
2156
        ImGui::Checkbox("With Alpha Preview", &alpha_preview);
2157
        ImGui::Checkbox("With Half Alpha Preview", &alpha_half_preview);
2158
        ImGui::Checkbox("With Drag and Drop", &drag_and_drop);
2159
        ImGui::Checkbox("With Options Menu", &options_menu); ImGui::SameLine(); HelpMarker("Right-click on the individual color widget to show options.");
2160
        ImGui::Checkbox("With HDR", &hdr); ImGui::SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets.");
2161
        ImGuiColorEditFlags misc_flags = (hdr ? ImGuiColorEditFlags_HDR : 0) | (drag_and_drop ? 0 : ImGuiColorEditFlags_NoDragDrop) | (alpha_half_preview ? ImGuiColorEditFlags_AlphaPreviewHalf : (alpha_preview ? ImGuiColorEditFlags_AlphaPreview : 0)) | (options_menu ? 0 : ImGuiColorEditFlags_NoOptions);
2162
2163
        IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit");
2164
        ImGui::SeparatorText("Inline color editor");
2165
        ImGui::Text("Color widget:");
2166
        ImGui::SameLine(); HelpMarker(
2167
            "Click on the color square to open a color picker.\n"
2168
            "CTRL+click on individual component to input value.\n");
2169
        ImGui::ColorEdit3("MyColor##1", (float*)&color, misc_flags);
2170
2171
        IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (HSV, with Alpha)");
2172
        ImGui::Text("Color widget HSV with Alpha:");
2173
        ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_DisplayHSV | misc_flags);
2174
2175
        IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (float display)");
2176
        ImGui::Text("Color widget with Float Display:");
2177
        ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | misc_flags);
2178
2179
        IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with Picker)");
2180
        ImGui::Text("Color button with Picker:");
2181
        ImGui::SameLine(); HelpMarker(
2182
            "With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\n"
2183
            "With the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only "
2184
            "be used for the tooltip and picker popup.");
2185
        ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | misc_flags);
2186
2187
        IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with custom Picker popup)");
2188
        ImGui::Text("Color button with Custom Picker Popup:");
2189
2190
        // Generate a default palette. The palette will persist and can be edited.
2191
        static bool saved_palette_init = true;
2192
        static ImVec4 saved_palette[32] = {};
2193
        if (saved_palette_init)
2194
        {
2195
            for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++)
2196
            {
2197
                ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f,
2198
                    saved_palette[n].x, saved_palette[n].y, saved_palette[n].z);
2199
                saved_palette[n].w = 1.0f; // Alpha
2200
            }
2201
            saved_palette_init = false;
2202
        }
2203
2204
        static ImVec4 backup_color;
2205
        bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags);
2206
        ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x);
2207
        open_popup |= ImGui::Button("Palette");
2208
        if (open_popup)
2209
        {
2210
            ImGui::OpenPopup("mypicker");
2211
            backup_color = color;
2212
        }
2213
        if (ImGui::BeginPopup("mypicker"))
2214
        {
2215
            ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!");
2216
            ImGui::Separator();
2217
            ImGui::ColorPicker4("##picker", (float*)&color, misc_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview);
2218
            ImGui::SameLine();
2219
2220
            ImGui::BeginGroup(); // Lock X position
2221
            ImGui::Text("Current");
2222
            ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40));
2223
            ImGui::Text("Previous");
2224
            if (ImGui::ColorButton("##previous", backup_color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40)))
2225
                color = backup_color;
2226
            ImGui::Separator();
2227
            ImGui::Text("Palette");
2228
            for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++)
2229
            {
2230
                ImGui::PushID(n);
2231
                if ((n % 8) != 0)
2232
                    ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y);
2233
2234
                ImGuiColorEditFlags palette_button_flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip;
2235
                if (ImGui::ColorButton("##palette", saved_palette[n], palette_button_flags, ImVec2(20, 20)))
2236
                    color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha!
2237
2238
                // Allow user to drop colors into each palette entry. Note that ColorButton() is already a
2239
                // drag source by default, unless specifying the ImGuiColorEditFlags_NoDragDrop flag.
2240
                if (ImGui::BeginDragDropTarget())
2241
                {
2242
                    if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
2243
                        memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3);
2244
                    if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F))
2245
                        memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4);
2246
                    ImGui::EndDragDropTarget();
2247
                }
2248
2249
                ImGui::PopID();
2250
            }
2251
            ImGui::EndGroup();
2252
            ImGui::EndPopup();
2253
        }
2254
2255
        IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (simple)");
2256
        ImGui::Text("Color button only:");
2257
        static bool no_border = false;
2258
        ImGui::Checkbox("ImGuiColorEditFlags_NoBorder", &no_border);
2259
        ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, misc_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80));
2260
2261
        IMGUI_DEMO_MARKER("Widgets/Color/ColorPicker");
2262
        ImGui::SeparatorText("Color picker");
2263
        static bool alpha = true;
2264
        static bool alpha_bar = true;
2265
        static bool side_preview = true;
2266
        static bool ref_color = false;
2267
        static ImVec4 ref_color_v(1.0f, 0.0f, 1.0f, 0.5f);
2268
        static int display_mode = 0;
2269
        static int picker_mode = 0;
2270
        ImGui::Checkbox("With Alpha", &alpha);
2271
        ImGui::Checkbox("With Alpha Bar", &alpha_bar);
2272
        ImGui::Checkbox("With Side Preview", &side_preview);
2273
        if (side_preview)
2274
        {
2275
            ImGui::SameLine();
2276
            ImGui::Checkbox("With Ref Color", &ref_color);
2277
            if (ref_color)
2278
            {
2279
                ImGui::SameLine();
2280
                ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | misc_flags);
2281
            }
2282
        }
2283
        ImGui::Combo("Display Mode", &display_mode, "Auto/Current\0None\0RGB Only\0HSV Only\0Hex Only\0");
2284
        ImGui::SameLine(); HelpMarker(
2285
            "ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, "
2286
            "but the user can change it with a right-click on those inputs.\n\nColorPicker defaults to displaying RGB+HSV+Hex "
2287
            "if you don't specify a display mode.\n\nYou can change the defaults using SetColorEditOptions().");
2288
        ImGui::SameLine(); HelpMarker("When not specified explicitly (Auto/Current mode), user can right-click the picker to change mode.");
2289
        ImGuiColorEditFlags flags = misc_flags;
2290
        if (!alpha)            flags |= ImGuiColorEditFlags_NoAlpha;        // This is by default if you call ColorPicker3() instead of ColorPicker4()
2291
        if (alpha_bar)         flags |= ImGuiColorEditFlags_AlphaBar;
2292
        if (!side_preview)     flags |= ImGuiColorEditFlags_NoSidePreview;
2293
        if (picker_mode == 1)  flags |= ImGuiColorEditFlags_PickerHueBar;
2294
        if (picker_mode == 2)  flags |= ImGuiColorEditFlags_PickerHueWheel;
2295
        if (display_mode == 1) flags |= ImGuiColorEditFlags_NoInputs;       // Disable all RGB/HSV/Hex displays
2296
        if (display_mode == 2) flags |= ImGuiColorEditFlags_DisplayRGB;     // Override display mode
2297
        if (display_mode == 3) flags |= ImGuiColorEditFlags_DisplayHSV;
2298
        if (display_mode == 4) flags |= ImGuiColorEditFlags_DisplayHex;
2299
        ImGui::ColorPicker4("MyColor##4", (float*)&color, flags, ref_color ? &ref_color_v.x : NULL);
2300
2301
        ImGui::Text("Set defaults in code:");
2302
        ImGui::SameLine(); HelpMarker(
2303
            "SetColorEditOptions() is designed to allow you to set boot-time default.\n"
2304
            "We don't have Push/Pop functions because you can force options on a per-widget basis if needed,"
2305
            "and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid"
2306
            "encouraging you to persistently save values that aren't forward-compatible.");
2307
        if (ImGui::Button("Default: Uint8 + HSV + Hue Bar"))
2308
            ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_PickerHueBar);
2309
        if (ImGui::Button("Default: Float + HDR + Hue Wheel"))
2310
            ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel);
2311
2312
        // Always display a small version of both types of pickers
2313
        // (that's in order to make it more visible in the demo to people who are skimming quickly through it)
2314
        ImGui::Text("Both types:");
2315
        float w = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.y) * 0.40f;
2316
        ImGui::SetNextItemWidth(w);
2317
        ImGui::ColorPicker3("##MyColor##5", (float*)&color, ImGuiColorEditFlags_PickerHueBar | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha);
2318
        ImGui::SameLine();
2319
        ImGui::SetNextItemWidth(w);
2320
        ImGui::ColorPicker3("##MyColor##6", (float*)&color, ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha);
2321
2322
        // HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0)
2323
        static ImVec4 color_hsv(0.23f, 1.0f, 1.0f, 1.0f); // Stored as HSV!
2324
        ImGui::Spacing();
2325
        ImGui::Text("HSV encoded colors");
2326
        ImGui::SameLine(); HelpMarker(
2327
            "By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV"
2328
            "allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV. This comes with the"
2329
            "added benefit that you can manipulate hue values with the picker even when saturation or value are zero.");
2330
        ImGui::Text("Color widget with InputHSV:");
2331
        ImGui::ColorEdit4("HSV shown as RGB##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float);
2332
        ImGui::ColorEdit4("HSV shown as HSV##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float);
2333
        ImGui::DragFloat4("Raw HSV values", (float*)&color_hsv, 0.01f, 0.0f, 1.0f);
2334
2335
        ImGui::TreePop();
2336
    }
2337
2338
    IMGUI_DEMO_MARKER("Widgets/Drag and Slider Flags");
2339
    if (ImGui::TreeNode("Drag/Slider Flags"))
2340
    {
2341
        // Demonstrate using advanced flags for DragXXX and SliderXXX functions. Note that the flags are the same!
2342
        static ImGuiSliderFlags flags = ImGuiSliderFlags_None;
2343
        ImGui::CheckboxFlags("ImGuiSliderFlags_AlwaysClamp", &flags, ImGuiSliderFlags_AlwaysClamp);
2344
        ImGui::CheckboxFlags("ImGuiSliderFlags_ClampOnInput", &flags, ImGuiSliderFlags_ClampOnInput);
2345
        ImGui::SameLine(); HelpMarker("Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds.");
2346
        ImGui::CheckboxFlags("ImGuiSliderFlags_ClampZeroRange", &flags, ImGuiSliderFlags_ClampZeroRange);
2347
        ImGui::SameLine(); HelpMarker("Clamp even if min==max==0.0f. Otherwise DragXXX functions don't clamp.");
2348
        ImGui::CheckboxFlags("ImGuiSliderFlags_Logarithmic", &flags, ImGuiSliderFlags_Logarithmic);
2349
        ImGui::SameLine(); HelpMarker("Enable logarithmic editing (more precision for small values).");
2350
        ImGui::CheckboxFlags("ImGuiSliderFlags_NoRoundToFormat", &flags, ImGuiSliderFlags_NoRoundToFormat);
2351
        ImGui::SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits).");
2352
        ImGui::CheckboxFlags("ImGuiSliderFlags_NoInput", &flags, ImGuiSliderFlags_NoInput);
2353
        ImGui::SameLine(); HelpMarker("Disable CTRL+Click or Enter key allowing to input text directly into the widget.");
2354
        ImGui::CheckboxFlags("ImGuiSliderFlags_WrapAround", &flags, ImGuiSliderFlags_WrapAround);
2355
        ImGui::SameLine(); HelpMarker("Enable wrapping around from max to min and from min to max (only supported by DragXXX() functions)");
2356
2357
        // Drags
2358
        static float drag_f = 0.5f;
2359
        static int drag_i = 50;
2360
        ImGui::Text("Underlying float value: %f", drag_f);
2361
        ImGui::DragFloat("DragFloat (0 -> 1)", &drag_f, 0.005f, 0.0f, 1.0f, "%.3f", flags);
2362
        ImGui::DragFloat("DragFloat (0 -> +inf)", &drag_f, 0.005f, 0.0f, FLT_MAX, "%.3f", flags);
2363
        ImGui::DragFloat("DragFloat (-inf -> 1)", &drag_f, 0.005f, -FLT_MAX, 1.0f, "%.3f", flags);
2364
        ImGui::DragFloat("DragFloat (-inf -> +inf)", &drag_f, 0.005f, -FLT_MAX, +FLT_MAX, "%.3f", flags);
2365
        //ImGui::DragFloat("DragFloat (0 -> 0)", &drag_f, 0.005f, 0.0f, 0.0f, "%.3f", flags);           // To test ClampZeroRange
2366
        //ImGui::DragFloat("DragFloat (100 -> 100)", &drag_f, 0.005f, 100.0f, 100.0f, "%.3f", flags);
2367
        ImGui::DragInt("DragInt (0 -> 100)", &drag_i, 0.5f, 0, 100, "%d", flags);
2368
2369
        // Sliders
2370
        static float slider_f = 0.5f;
2371
        static int slider_i = 50;
2372
        const ImGuiSliderFlags flags_for_sliders = flags & ~ImGuiSliderFlags_WrapAround;
2373
        ImGui::Text("Underlying float value: %f", slider_f);
2374
        ImGui::SliderFloat("SliderFloat (0 -> 1)", &slider_f, 0.0f, 1.0f, "%.3f", flags_for_sliders);
2375
        ImGui::SliderInt("SliderInt (0 -> 100)", &slider_i, 0, 100, "%d", flags_for_sliders);
2376
2377
        ImGui::TreePop();
2378
    }
2379
2380
    IMGUI_DEMO_MARKER("Widgets/Range Widgets");
2381
    if (ImGui::TreeNode("Range Widgets"))
2382
    {
2383
        static float begin = 10, end = 90;
2384
        static int begin_i = 100, end_i = 1000;
2385
        ImGui::DragFloatRange2("range float", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%", ImGuiSliderFlags_AlwaysClamp);
2386
        ImGui::DragIntRange2("range int", &begin_i, &end_i, 5, 0, 1000, "Min: %d units", "Max: %d units");
2387
        ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %d units", "Max: %d units");
2388
        ImGui::TreePop();
2389
    }
2390
2391
    IMGUI_DEMO_MARKER("Widgets/Data Types");
2392
    if (ImGui::TreeNode("Data Types"))
2393
    {
2394
        // DragScalar/InputScalar/SliderScalar functions allow various data types
2395
        // - signed/unsigned
2396
        // - 8/16/32/64-bits
2397
        // - integer/float/double
2398
        // To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum
2399
        // to pass the type, and passing all arguments by pointer.
2400
        // This is the reason the test code below creates local variables to hold "zero" "one" etc. for each type.
2401
        // In practice, if you frequently use a given type that is not covered by the normal API entry points,
2402
        // you can wrap it yourself inside a 1 line function which can take typed argument as value instead of void*,
2403
        // and then pass their address to the generic function. For example:
2404
        //   bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld")
2405
        //   {
2406
        //      return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format);
2407
        //   }
2408
2409
        // Setup limits (as helper variables so we can take their address, as explained above)
2410
        // Note: SliderScalar() functions have a maximum usable range of half the natural type maximum, hence the /2.
2411
        #ifndef LLONG_MIN
2412
        ImS64 LLONG_MIN = -9223372036854775807LL - 1;
2413
        ImS64 LLONG_MAX = 9223372036854775807LL;
2414
        ImU64 ULLONG_MAX = (2ULL * 9223372036854775807LL + 1);
2415
        #endif
2416
        const char    s8_zero  = 0,   s8_one  = 1,   s8_fifty  = 50, s8_min  = -128,        s8_max = 127;
2417
        const ImU8    u8_zero  = 0,   u8_one  = 1,   u8_fifty  = 50, u8_min  = 0,           u8_max = 255;
2418
        const short   s16_zero = 0,   s16_one = 1,   s16_fifty = 50, s16_min = -32768,      s16_max = 32767;
2419
        const ImU16   u16_zero = 0,   u16_one = 1,   u16_fifty = 50, u16_min = 0,           u16_max = 65535;
2420
        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;
2421
        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;
2422
        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;
2423
        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;
2424
        const float   f32_zero = 0.f, f32_one = 1.f, f32_lo_a = -10000000000.0f, f32_hi_a = +10000000000.0f;
2425
        const double  f64_zero = 0.,  f64_one = 1.,  f64_lo_a = -1000000000000000.0, f64_hi_a = +1000000000000000.0;
2426
2427
        // State
2428
        static char   s8_v  = 127;
2429
        static ImU8   u8_v  = 255;
2430
        static short  s16_v = 32767;
2431
        static ImU16  u16_v = 65535;
2432
        static ImS32  s32_v = -1;
2433
        static ImU32  u32_v = (ImU32)-1;
2434
        static ImS64  s64_v = -1;
2435
        static ImU64  u64_v = (ImU64)-1;
2436
        static float  f32_v = 0.123f;
2437
        static double f64_v = 90000.01234567890123456789;
2438
2439
        const float drag_speed = 0.2f;
2440
        static bool drag_clamp = false;
2441
        IMGUI_DEMO_MARKER("Widgets/Data Types/Drags");
2442
        ImGui::SeparatorText("Drags");
2443
        ImGui::Checkbox("Clamp integers to 0..50", &drag_clamp);
2444
        ImGui::SameLine(); HelpMarker(
2445
            "As with every widget in dear imgui, we never modify values unless there is a user interaction.\n"
2446
            "You can override the clamping limits by using CTRL+Click to input a value.");
2447
        ImGui::DragScalar("drag s8",        ImGuiDataType_S8,     &s8_v,  drag_speed, drag_clamp ? &s8_zero  : NULL, drag_clamp ? &s8_fifty  : NULL);
2448
        ImGui::DragScalar("drag u8",        ImGuiDataType_U8,     &u8_v,  drag_speed, drag_clamp ? &u8_zero  : NULL, drag_clamp ? &u8_fifty  : NULL, "%u ms");
2449
        ImGui::DragScalar("drag s16",       ImGuiDataType_S16,    &s16_v, drag_speed, drag_clamp ? &s16_zero : NULL, drag_clamp ? &s16_fifty : NULL);
2450
        ImGui::DragScalar("drag u16",       ImGuiDataType_U16,    &u16_v, drag_speed, drag_clamp ? &u16_zero : NULL, drag_clamp ? &u16_fifty : NULL, "%u ms");
2451
        ImGui::DragScalar("drag s32",       ImGuiDataType_S32,    &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL);
2452
        ImGui::DragScalar("drag s32 hex",   ImGuiDataType_S32,    &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL, "0x%08X");
2453
        ImGui::DragScalar("drag u32",       ImGuiDataType_U32,    &u32_v, drag_speed, drag_clamp ? &u32_zero : NULL, drag_clamp ? &u32_fifty : NULL, "%u ms");
2454
        ImGui::DragScalar("drag s64",       ImGuiDataType_S64,    &s64_v, drag_speed, drag_clamp ? &s64_zero : NULL, drag_clamp ? &s64_fifty : NULL);
2455
        ImGui::DragScalar("drag u64",       ImGuiDataType_U64,    &u64_v, drag_speed, drag_clamp ? &u64_zero : NULL, drag_clamp ? &u64_fifty : NULL);
2456
        ImGui::DragScalar("drag float",     ImGuiDataType_Float,  &f32_v, 0.005f,  &f32_zero, &f32_one, "%f");
2457
        ImGui::DragScalar("drag float log", ImGuiDataType_Float,  &f32_v, 0.005f,  &f32_zero, &f32_one, "%f", ImGuiSliderFlags_Logarithmic);
2458
        ImGui::DragScalar("drag double",    ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, NULL,     "%.10f grams");
2459
        ImGui::DragScalar("drag double log",ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", ImGuiSliderFlags_Logarithmic);
2460
2461
        IMGUI_DEMO_MARKER("Widgets/Data Types/Sliders");
2462
        ImGui::SeparatorText("Sliders");
2463
        ImGui::SliderScalar("slider s8 full",       ImGuiDataType_S8,     &s8_v,  &s8_min,   &s8_max,   "%d");
2464
        ImGui::SliderScalar("slider u8 full",       ImGuiDataType_U8,     &u8_v,  &u8_min,   &u8_max,   "%u");
2465
        ImGui::SliderScalar("slider s16 full",      ImGuiDataType_S16,    &s16_v, &s16_min,  &s16_max,  "%d");
2466
        ImGui::SliderScalar("slider u16 full",      ImGuiDataType_U16,    &u16_v, &u16_min,  &u16_max,  "%u");
2467
        ImGui::SliderScalar("slider s32 low",       ImGuiDataType_S32,    &s32_v, &s32_zero, &s32_fifty,"%d");
2468
        ImGui::SliderScalar("slider s32 high",      ImGuiDataType_S32,    &s32_v, &s32_hi_a, &s32_hi_b, "%d");
2469
        ImGui::SliderScalar("slider s32 full",      ImGuiDataType_S32,    &s32_v, &s32_min,  &s32_max,  "%d");
2470
        ImGui::SliderScalar("slider s32 hex",       ImGuiDataType_S32,    &s32_v, &s32_zero, &s32_fifty, "0x%04X");
2471
        ImGui::SliderScalar("slider u32 low",       ImGuiDataType_U32,    &u32_v, &u32_zero, &u32_fifty,"%u");
2472
        ImGui::SliderScalar("slider u32 high",      ImGuiDataType_U32,    &u32_v, &u32_hi_a, &u32_hi_b, "%u");
2473
        ImGui::SliderScalar("slider u32 full",      ImGuiDataType_U32,    &u32_v, &u32_min,  &u32_max,  "%u");
2474
        ImGui::SliderScalar("slider s64 low",       ImGuiDataType_S64,    &s64_v, &s64_zero, &s64_fifty,"%" PRId64);
2475
        ImGui::SliderScalar("slider s64 high",      ImGuiDataType_S64,    &s64_v, &s64_hi_a, &s64_hi_b, "%" PRId64);
2476
        ImGui::SliderScalar("slider s64 full",      ImGuiDataType_S64,    &s64_v, &s64_min,  &s64_max,  "%" PRId64);
2477
        ImGui::SliderScalar("slider u64 low",       ImGuiDataType_U64,    &u64_v, &u64_zero, &u64_fifty,"%" PRIu64 " ms");
2478
        ImGui::SliderScalar("slider u64 high",      ImGuiDataType_U64,    &u64_v, &u64_hi_a, &u64_hi_b, "%" PRIu64 " ms");
2479
        ImGui::SliderScalar("slider u64 full",      ImGuiDataType_U64,    &u64_v, &u64_min,  &u64_max,  "%" PRIu64 " ms");
2480
        ImGui::SliderScalar("slider float low",     ImGuiDataType_Float,  &f32_v, &f32_zero, &f32_one);
2481
        ImGui::SliderScalar("slider float low log", ImGuiDataType_Float,  &f32_v, &f32_zero, &f32_one,  "%.10f", ImGuiSliderFlags_Logarithmic);
2482
        ImGui::SliderScalar("slider float high",    ImGuiDataType_Float,  &f32_v, &f32_lo_a, &f32_hi_a, "%e");
2483
        ImGui::SliderScalar("slider double low",    ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one,  "%.10f grams");
2484
        ImGui::SliderScalar("slider double low log",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one,  "%.10f", ImGuiSliderFlags_Logarithmic);
2485
        ImGui::SliderScalar("slider double high",   ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams");
2486
2487
        ImGui::SeparatorText("Sliders (reverse)");
2488
        ImGui::SliderScalar("slider s8 reverse",    ImGuiDataType_S8,   &s8_v,  &s8_max,    &s8_min,   "%d");
2489
        ImGui::SliderScalar("slider u8 reverse",    ImGuiDataType_U8,   &u8_v,  &u8_max,    &u8_min,   "%u");
2490
        ImGui::SliderScalar("slider s32 reverse",   ImGuiDataType_S32,  &s32_v, &s32_fifty, &s32_zero, "%d");
2491
        ImGui::SliderScalar("slider u32 reverse",   ImGuiDataType_U32,  &u32_v, &u32_fifty, &u32_zero, "%u");
2492
        ImGui::SliderScalar("slider s64 reverse",   ImGuiDataType_S64,  &s64_v, &s64_fifty, &s64_zero, "%" PRId64);
2493
        ImGui::SliderScalar("slider u64 reverse",   ImGuiDataType_U64,  &u64_v, &u64_fifty, &u64_zero, "%" PRIu64 " ms");
2494
2495
        IMGUI_DEMO_MARKER("Widgets/Data Types/Inputs");
2496
        static bool inputs_step = true;
2497
        static ImGuiInputTextFlags flags = ImGuiInputTextFlags_None;
2498
        ImGui::SeparatorText("Inputs");
2499
        ImGui::Checkbox("Show step buttons", &inputs_step);
2500
        ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly);
2501
        ImGui::CheckboxFlags("ImGuiInputTextFlags_ParseEmptyRefVal", &flags, ImGuiInputTextFlags_ParseEmptyRefVal);
2502
        ImGui::CheckboxFlags("ImGuiInputTextFlags_DisplayEmptyRefVal", &flags, ImGuiInputTextFlags_DisplayEmptyRefVal);
2503
        ImGui::InputScalar("input s8",      ImGuiDataType_S8,     &s8_v,  inputs_step ? &s8_one  : NULL, NULL, "%d", flags);
2504
        ImGui::InputScalar("input u8",      ImGuiDataType_U8,     &u8_v,  inputs_step ? &u8_one  : NULL, NULL, "%u", flags);
2505
        ImGui::InputScalar("input s16",     ImGuiDataType_S16,    &s16_v, inputs_step ? &s16_one : NULL, NULL, "%d", flags);
2506
        ImGui::InputScalar("input u16",     ImGuiDataType_U16,    &u16_v, inputs_step ? &u16_one : NULL, NULL, "%u", flags);
2507
        ImGui::InputScalar("input s32",     ImGuiDataType_S32,    &s32_v, inputs_step ? &s32_one : NULL, NULL, "%d", flags);
2508
        ImGui::InputScalar("input s32 hex", ImGuiDataType_S32,    &s32_v, inputs_step ? &s32_one : NULL, NULL, "%04X", flags);
2509
        ImGui::InputScalar("input u32",     ImGuiDataType_U32,    &u32_v, inputs_step ? &u32_one : NULL, NULL, "%u", flags);
2510
        ImGui::InputScalar("input u32 hex", ImGuiDataType_U32,    &u32_v, inputs_step ? &u32_one : NULL, NULL, "%08X", flags);
2511
        ImGui::InputScalar("input s64",     ImGuiDataType_S64,    &s64_v, inputs_step ? &s64_one : NULL, NULL, NULL, flags);
2512
        ImGui::InputScalar("input u64",     ImGuiDataType_U64,    &u64_v, inputs_step ? &u64_one : NULL, NULL, NULL, flags);
2513
        ImGui::InputScalar("input float",   ImGuiDataType_Float,  &f32_v, inputs_step ? &f32_one : NULL, NULL, NULL, flags);
2514
        ImGui::InputScalar("input double",  ImGuiDataType_Double, &f64_v, inputs_step ? &f64_one : NULL, NULL, NULL, flags);
2515
2516
        ImGui::TreePop();
2517
    }
2518
2519
    IMGUI_DEMO_MARKER("Widgets/Multi-component Widgets");
2520
    if (ImGui::TreeNode("Multi-component Widgets"))
2521
    {
2522
        static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f };
2523
        static int vec4i[4] = { 1, 5, 100, 255 };
2524
2525
        ImGui::SeparatorText("2-wide");
2526
        ImGui::InputFloat2("input float2", vec4f);
2527
        ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f);
2528
        ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f);
2529
        ImGui::InputInt2("input int2", vec4i);
2530
        ImGui::DragInt2("drag int2", vec4i, 1, 0, 255);
2531
        ImGui::SliderInt2("slider int2", vec4i, 0, 255);
2532
2533
        ImGui::SeparatorText("3-wide");
2534
        ImGui::InputFloat3("input float3", vec4f);
2535
        ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f);
2536
        ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f);
2537
        ImGui::InputInt3("input int3", vec4i);
2538
        ImGui::DragInt3("drag int3", vec4i, 1, 0, 255);
2539
        ImGui::SliderInt3("slider int3", vec4i, 0, 255);
2540
2541
        ImGui::SeparatorText("4-wide");
2542
        ImGui::InputFloat4("input float4", vec4f);
2543
        ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f);
2544
        ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f);
2545
        ImGui::InputInt4("input int4", vec4i);
2546
        ImGui::DragInt4("drag int4", vec4i, 1, 0, 255);
2547
        ImGui::SliderInt4("slider int4", vec4i, 0, 255);
2548
2549
        ImGui::TreePop();
2550
    }
2551
2552
    IMGUI_DEMO_MARKER("Widgets/Vertical Sliders");
2553
    if (ImGui::TreeNode("Vertical Sliders"))
2554
    {
2555
        const float spacing = 4;
2556
        ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
2557
2558
        static int int_value = 0;
2559
        ImGui::VSliderInt("##int", ImVec2(18, 160), &int_value, 0, 5);
2560
        ImGui::SameLine();
2561
2562
        static float values[7] = { 0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f };
2563
        ImGui::PushID("set1");
2564
        for (int i = 0; i < 7; i++)
2565
        {
2566
            if (i > 0) ImGui::SameLine();
2567
            ImGui::PushID(i);
2568
            ImGui::PushStyleColor(ImGuiCol_FrameBg, (ImVec4)ImColor::HSV(i / 7.0f, 0.5f, 0.5f));
2569
            ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.5f));
2570
            ImGui::PushStyleColor(ImGuiCol_FrameBgActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.5f));
2571
            ImGui::PushStyleColor(ImGuiCol_SliderGrab, (ImVec4)ImColor::HSV(i / 7.0f, 0.9f, 0.9f));
2572
            ImGui::VSliderFloat("##v", ImVec2(18, 160), &values[i], 0.0f, 1.0f, "");
2573
            if (ImGui::IsItemActive() || ImGui::IsItemHovered())
2574
                ImGui::SetTooltip("%.3f", values[i]);
2575
            ImGui::PopStyleColor(4);
2576
            ImGui::PopID();
2577
        }
2578
        ImGui::PopID();
2579
2580
        ImGui::SameLine();
2581
        ImGui::PushID("set2");
2582
        static float values2[4] = { 0.20f, 0.80f, 0.40f, 0.25f };
2583
        const int rows = 3;
2584
        const ImVec2 small_slider_size(18, (float)(int)((160.0f - (rows - 1) * spacing) / rows));
2585
        for (int nx = 0; nx < 4; nx++)
2586
        {
2587
            if (nx > 0) ImGui::SameLine();
2588
            ImGui::BeginGroup();
2589
            for (int ny = 0; ny < rows; ny++)
2590
            {
2591
                ImGui::PushID(nx * rows + ny);
2592
                ImGui::VSliderFloat("##v", small_slider_size, &values2[nx], 0.0f, 1.0f, "");
2593
                if (ImGui::IsItemActive() || ImGui::IsItemHovered())
2594
                    ImGui::SetTooltip("%.3f", values2[nx]);
2595
                ImGui::PopID();
2596
            }
2597
            ImGui::EndGroup();
2598
        }
2599
        ImGui::PopID();
2600
2601
        ImGui::SameLine();
2602
        ImGui::PushID("set3");
2603
        for (int i = 0; i < 4; i++)
2604
        {
2605
            if (i > 0) ImGui::SameLine();
2606
            ImGui::PushID(i);
2607
            ImGui::PushStyleVar(ImGuiStyleVar_GrabMinSize, 40);
2608
            ImGui::VSliderFloat("##v", ImVec2(40, 160), &values[i], 0.0f, 1.0f, "%.2f\nsec");
2609
            ImGui::PopStyleVar();
2610
            ImGui::PopID();
2611
        }
2612
        ImGui::PopID();
2613
        ImGui::PopStyleVar();
2614
        ImGui::TreePop();
2615
    }
2616
2617
    IMGUI_DEMO_MARKER("Widgets/Drag and drop");
2618
    if (ImGui::TreeNode("Drag and Drop"))
2619
    {
2620
        IMGUI_DEMO_MARKER("Widgets/Drag and drop/Standard widgets");
2621
        if (ImGui::TreeNode("Drag and drop in standard widgets"))
2622
        {
2623
            // ColorEdit widgets automatically act as drag source and drag target.
2624
            // They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F
2625
            // to allow your own widgets to use colors in their drag and drop interaction.
2626
            // Also see 'Demo->Widgets->Color/Picker Widgets->Palette' demo.
2627
            HelpMarker("You can drag from the color squares.");
2628
            static float col1[3] = { 1.0f, 0.0f, 0.2f };
2629
            static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
2630
            ImGui::ColorEdit3("color 1", col1);
2631
            ImGui::ColorEdit4("color 2", col2);
2632
            ImGui::TreePop();
2633
        }
2634
2635
        IMGUI_DEMO_MARKER("Widgets/Drag and drop/Copy-swap items");
2636
        if (ImGui::TreeNode("Drag and drop to copy/swap items"))
2637
        {
2638
            enum Mode
2639
            {
2640
                Mode_Copy,
2641
                Mode_Move,
2642
                Mode_Swap
2643
            };
2644
            static int mode = 0;
2645
            if (ImGui::RadioButton("Copy", mode == Mode_Copy)) { mode = Mode_Copy; } ImGui::SameLine();
2646
            if (ImGui::RadioButton("Move", mode == Mode_Move)) { mode = Mode_Move; } ImGui::SameLine();
2647
            if (ImGui::RadioButton("Swap", mode == Mode_Swap)) { mode = Mode_Swap; }
2648
            static const char* names[9] =
2649
            {
2650
                "Bobby", "Beatrice", "Betty",
2651
                "Brianna", "Barry", "Bernard",
2652
                "Bibi", "Blaine", "Bryn"
2653
            };
2654
            for (int n = 0; n < IM_ARRAYSIZE(names); n++)
2655
            {
2656
                ImGui::PushID(n);
2657
                if ((n % 3) != 0)
2658
                    ImGui::SameLine();
2659
                ImGui::Button(names[n], ImVec2(60, 60));
2660
2661
                // Our buttons are both drag sources and drag targets here!
2662
                if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None))
2663
                {
2664
                    // Set payload to carry the index of our item (could be anything)
2665
                    ImGui::SetDragDropPayload("DND_DEMO_CELL", &n, sizeof(int));
2666
2667
                    // Display preview (could be anything, e.g. when dragging an image we could decide to display
2668
                    // the filename and a small preview of the image, etc.)
2669
                    if (mode == Mode_Copy) { ImGui::Text("Copy %s", names[n]); }
2670
                    if (mode == Mode_Move) { ImGui::Text("Move %s", names[n]); }
2671
                    if (mode == Mode_Swap) { ImGui::Text("Swap %s", names[n]); }
2672
                    ImGui::EndDragDropSource();
2673
                }
2674
                if (ImGui::BeginDragDropTarget())
2675
                {
2676
                    if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DND_DEMO_CELL"))
2677
                    {
2678
                        IM_ASSERT(payload->DataSize == sizeof(int));
2679
                        int payload_n = *(const int*)payload->Data;
2680
                        if (mode == Mode_Copy)
2681
                        {
2682
                            names[n] = names[payload_n];
2683
                        }
2684
                        if (mode == Mode_Move)
2685
                        {
2686
                            names[n] = names[payload_n];
2687
                            names[payload_n] = "";
2688
                        }
2689
                        if (mode == Mode_Swap)
2690
                        {
2691
                            const char* tmp = names[n];
2692
                            names[n] = names[payload_n];
2693
                            names[payload_n] = tmp;
2694
                        }
2695
                    }
2696
                    ImGui::EndDragDropTarget();
2697
                }
2698
                ImGui::PopID();
2699
            }
2700
            ImGui::TreePop();
2701
        }
2702
2703
        IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Drag to reorder items (simple)");
2704
        if (ImGui::TreeNode("Drag to reorder items (simple)"))
2705
        {
2706
            // FIXME: there is temporary (usually single-frame) ID Conflict during reordering as a same item may be submitting twice.
2707
            // This code was always slightly faulty but in a way which was not easily noticeable.
2708
            // Until we fix this, enable ImGuiItemFlags_AllowDuplicateId to disable detecting the issue.
2709
            ImGui::PushItemFlag(ImGuiItemFlags_AllowDuplicateId, true);
2710
2711
            // Simple reordering
2712
            HelpMarker(
2713
                "We don't use the drag and drop api at all here! "
2714
                "Instead we query when the item is held but not hovered, and order items accordingly.");
2715
            static const char* item_names[] = { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" };
2716
            for (int n = 0; n < IM_ARRAYSIZE(item_names); n++)
2717
            {
2718
                const char* item = item_names[n];
2719
                ImGui::Selectable(item);
2720
2721
                if (ImGui::IsItemActive() && !ImGui::IsItemHovered())
2722
                {
2723
                    int n_next = n + (ImGui::GetMouseDragDelta(0).y < 0.f ? -1 : 1);
2724
                    if (n_next >= 0 && n_next < IM_ARRAYSIZE(item_names))
2725
                    {
2726
                        item_names[n] = item_names[n_next];
2727
                        item_names[n_next] = item;
2728
                        ImGui::ResetMouseDragDelta();
2729
                    }
2730
                }
2731
            }
2732
2733
            ImGui::PopItemFlag();
2734
            ImGui::TreePop();
2735
        }
2736
2737
        IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Tooltip at target location");
2738
        if (ImGui::TreeNode("Tooltip at target location"))
2739
        {
2740
            for (int n = 0; n < 2; n++)
2741
            {
2742
                // Drop targets
2743
                ImGui::Button(n ? "drop here##1" : "drop here##0");
2744
                if (ImGui::BeginDragDropTarget())
2745
                {
2746
                    ImGuiDragDropFlags drop_target_flags = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoPreviewTooltip;
2747
                    if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, drop_target_flags))
2748
                    {
2749
                        IM_UNUSED(payload);
2750
                        ImGui::SetMouseCursor(ImGuiMouseCursor_NotAllowed);
2751
                        ImGui::SetTooltip("Cannot drop here!");
2752
                    }
2753
                    ImGui::EndDragDropTarget();
2754
                }
2755
2756
                // Drop source
2757
                static ImVec4 col4 = { 1.0f, 0.0f, 0.2f, 1.0f };
2758
                if (n == 0)
2759
                    ImGui::ColorButton("drag me", col4);
2760
2761
            }
2762
            ImGui::TreePop();
2763
        }
2764
2765
        ImGui::TreePop();
2766
    }
2767
2768
    IMGUI_DEMO_MARKER("Widgets/Querying Item Status (Edited,Active,Hovered etc.)");
2769
    if (ImGui::TreeNode("Querying Item Status (Edited/Active/Hovered etc.)"))
2770
    {
2771
        // Select an item type
2772
        const char* item_names[] =
2773
        {
2774
            "Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputTextMultiline", "InputFloat",
2775
            "InputFloat3", "ColorEdit4", "Selectable", "MenuItem", "TreeNode", "TreeNode (w/ double-click)", "Combo", "ListBox"
2776
        };
2777
        static int item_type = 4;
2778
        static bool item_disabled = false;
2779
        ImGui::Combo("Item Type", &item_type, item_names, IM_ARRAYSIZE(item_names), IM_ARRAYSIZE(item_names));
2780
        ImGui::SameLine();
2781
        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().");
2782
        ImGui::Checkbox("Item Disabled",  &item_disabled);
2783
2784
        // Submit selected items so we can query their status in the code following it.
2785
        bool ret = false;
2786
        static bool b = false;
2787
        static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f };
2788
        static char str[16] = {};
2789
        if (item_disabled)
2790
            ImGui::BeginDisabled(true);
2791
        if (item_type == 0) { ImGui::Text("ITEM: Text"); }                                              // Testing text items with no identifier/interaction
2792
        if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); }                                    // Testing button
2793
        if (item_type == 2) { ImGui::PushItemFlag(ImGuiItemFlags_ButtonRepeat, true); ret = ImGui::Button("ITEM: Button"); ImGui::PopItemFlag(); } // Testing button (with repeater)
2794
        if (item_type == 3) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); }                            // Testing checkbox
2795
        if (item_type == 4) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); }   // Testing basic item
2796
        if (item_type == 5) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_ARRAYSIZE(str)); }  // Testing input text (which handles tabbing)
2797
        if (item_type == 6) { ret = ImGui::InputTextMultiline("ITEM: InputTextMultiline", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which uses a child window)
2798
        if (item_type == 7) { ret = ImGui::InputFloat("ITEM: InputFloat", col4f, 1.0f); }               // Testing +/- buttons on scalar input
2799
        if (item_type == 8) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); }                   // Testing multi-component items (IsItemXXX flags are reported merged)
2800
        if (item_type == 9) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); }                     // Testing multi-component items (IsItemXXX flags are reported merged)
2801
        if (item_type == 10){ ret = ImGui::Selectable("ITEM: Selectable"); }                            // Testing selectable item
2802
        if (item_type == 11){ ret = ImGui::MenuItem("ITEM: MenuItem"); }                                // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy)
2803
        if (item_type == 12){ ret = ImGui::TreeNode("ITEM: TreeNode"); if (ret) ImGui::TreePop(); }     // Testing tree node
2804
        if (item_type == 13){ ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy.
2805
        if (item_type == 14){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::Combo("ITEM: Combo", &current, items, IM_ARRAYSIZE(items)); }
2806
        if (item_type == 15){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", &current, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); }
2807
2808
        bool hovered_delay_none = ImGui::IsItemHovered();
2809
        bool hovered_delay_stationary = ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary);
2810
        bool hovered_delay_short = ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort);
2811
        bool hovered_delay_normal = ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal);
2812
        bool hovered_delay_tooltip = ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip); // = Normal + Stationary
2813
2814
        // Display the values of IsItemHovered() and other common item state functions.
2815
        // Note that the ImGuiHoveredFlags_XXX flags can be combined.
2816
        // Because BulletText is an item itself and that would affect the output of IsItemXXX functions,
2817
        // we query every state in a single call to avoid storing them and to simplify the code.
2818
        ImGui::BulletText(
2819
            "Return value = %d\n"
2820
            "IsItemFocused() = %d\n"
2821
            "IsItemHovered() = %d\n"
2822
            "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n"
2823
            "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n"
2824
            "IsItemHovered(_AllowWhenOverlappedByItem) = %d\n"
2825
            "IsItemHovered(_AllowWhenOverlappedByWindow) = %d\n"
2826
            "IsItemHovered(_AllowWhenDisabled) = %d\n"
2827
            "IsItemHovered(_RectOnly) = %d\n"
2828
            "IsItemActive() = %d\n"
2829
            "IsItemEdited() = %d\n"
2830
            "IsItemActivated() = %d\n"
2831
            "IsItemDeactivated() = %d\n"
2832
            "IsItemDeactivatedAfterEdit() = %d\n"
2833
            "IsItemVisible() = %d\n"
2834
            "IsItemClicked() = %d\n"
2835
            "IsItemToggledOpen() = %d\n"
2836
            "GetItemRectMin() = (%.1f, %.1f)\n"
2837
            "GetItemRectMax() = (%.1f, %.1f)\n"
2838
            "GetItemRectSize() = (%.1f, %.1f)",
2839
            ret,
2840
            ImGui::IsItemFocused(),
2841
            ImGui::IsItemHovered(),
2842
            ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2843
            ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
2844
            ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlappedByItem),
2845
            ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlappedByWindow),
2846
            ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled),
2847
            ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly),
2848
            ImGui::IsItemActive(),
2849
            ImGui::IsItemEdited(),
2850
            ImGui::IsItemActivated(),
2851
            ImGui::IsItemDeactivated(),
2852
            ImGui::IsItemDeactivatedAfterEdit(),
2853
            ImGui::IsItemVisible(),
2854
            ImGui::IsItemClicked(),
2855
            ImGui::IsItemToggledOpen(),
2856
            ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y,
2857
            ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y,
2858
            ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y
2859
        );
2860
        ImGui::BulletText(
2861
            "with Hovering Delay or Stationary test:\n"
2862
            "IsItemHovered() = = %d\n"
2863
            "IsItemHovered(_Stationary) = %d\n"
2864
            "IsItemHovered(_DelayShort) = %d\n"
2865
            "IsItemHovered(_DelayNormal) = %d\n"
2866
            "IsItemHovered(_Tooltip) = %d",
2867
            hovered_delay_none, hovered_delay_stationary, hovered_delay_short, hovered_delay_normal, hovered_delay_tooltip);
2868
2869
        if (item_disabled)
2870
            ImGui::EndDisabled();
2871
2872
        char buf[1] = "";
2873
        ImGui::InputText("unused", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_ReadOnly);
2874
        ImGui::SameLine();
2875
        HelpMarker("This widget is only here to be able to tab-out of the widgets above and see e.g. Deactivated() status.");
2876
2877
        ImGui::TreePop();
2878
    }
2879
2880
    IMGUI_DEMO_MARKER("Widgets/Querying Window Status (Focused,Hovered etc.)");
2881
    if (ImGui::TreeNode("Querying Window Status (Focused/Hovered etc.)"))
2882
    {
2883
        static bool embed_all_inside_a_child_window = false;
2884
        ImGui::Checkbox("Embed everything inside a child window for testing _RootWindow flag.", &embed_all_inside_a_child_window);
2885
        if (embed_all_inside_a_child_window)
2886
            ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20.0f), ImGuiChildFlags_Borders);
2887
2888
        // Testing IsWindowFocused() function with its various flags.
2889
        ImGui::BulletText(
2890
            "IsWindowFocused() = %d\n"
2891
            "IsWindowFocused(_ChildWindows) = %d\n"
2892
            "IsWindowFocused(_ChildWindows|_NoPopupHierarchy) = %d\n"
2893
            "IsWindowFocused(_ChildWindows|_DockHierarchy) = %d\n"
2894
            "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n"
2895
            "IsWindowFocused(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n"
2896
            "IsWindowFocused(_ChildWindows|_RootWindow|_DockHierarchy) = %d\n"
2897
            "IsWindowFocused(_RootWindow) = %d\n"
2898
            "IsWindowFocused(_RootWindow|_NoPopupHierarchy) = %d\n"
2899
            "IsWindowFocused(_RootWindow|_DockHierarchy) = %d\n"
2900
            "IsWindowFocused(_AnyWindow) = %d\n",
2901
            ImGui::IsWindowFocused(),
2902
            ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows),
2903
            ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_NoPopupHierarchy),
2904
            ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_DockHierarchy),
2905
            ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow),
2906
            ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy),
2907
            ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_DockHierarchy),
2908
            ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow),
2909
            ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy),
2910
            ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_DockHierarchy),
2911
            ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow));
2912
2913
        // Testing IsWindowHovered() function with its various flags.
2914
        ImGui::BulletText(
2915
            "IsWindowHovered() = %d\n"
2916
            "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n"
2917
            "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n"
2918
            "IsWindowHovered(_ChildWindows) = %d\n"
2919
            "IsWindowHovered(_ChildWindows|_NoPopupHierarchy) = %d\n"
2920
            "IsWindowHovered(_ChildWindows|_DockHierarchy) = %d\n"
2921
            "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n"
2922
            "IsWindowHovered(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n"
2923
            "IsWindowHovered(_ChildWindows|_RootWindow|_DockHierarchy) = %d\n"
2924
            "IsWindowHovered(_RootWindow) = %d\n"
2925
            "IsWindowHovered(_RootWindow|_NoPopupHierarchy) = %d\n"
2926
            "IsWindowHovered(_RootWindow|_DockHierarchy) = %d\n"
2927
            "IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n"
2928
            "IsWindowHovered(_AnyWindow) = %d\n"
2929
            "IsWindowHovered(_Stationary) = %d\n",
2930
            ImGui::IsWindowHovered(),
2931
            ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2932
            ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
2933
            ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows),
2934
            ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy),
2935
            ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_DockHierarchy),
2936
            ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow),
2937
            ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy),
2938
            ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_DockHierarchy),
2939
            ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow),
2940
            ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy),
2941
            ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_DockHierarchy),
2942
            ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2943
            ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow),
2944
            ImGui::IsWindowHovered(ImGuiHoveredFlags_Stationary));
2945
2946
        ImGui::BeginChild("child", ImVec2(0, 50), ImGuiChildFlags_Borders);
2947
        ImGui::Text("This is another child window for testing the _ChildWindows flag.");
2948
        ImGui::EndChild();
2949
        if (embed_all_inside_a_child_window)
2950
            ImGui::EndChild();
2951
2952
        // Calling IsItemHovered() after begin returns the hovered status of the title bar.
2953
        // This is useful in particular if you want to create a context menu associated to the title bar of a window.
2954
        // This will also work when docked into a Tab (the Tab replace the Title Bar and guarantee the same properties).
2955
        static bool test_window = false;
2956
        ImGui::Checkbox("Hovered/Active tests after Begin() for title bar testing", &test_window);
2957
        if (test_window)
2958
        {
2959
            // FIXME-DOCK: This window cannot be docked within the ImGui Demo window, this will cause a feedback loop and get them stuck.
2960
            // Could we fix this through an ImGuiWindowClass feature? Or an API call to tag our parent as "don't skip items"?
2961
            ImGui::Begin("Title bar Hovered/Active tests", &test_window);
2962
            if (ImGui::BeginPopupContextItem()) // <-- This is using IsItemHovered()
2963
            {
2964
                if (ImGui::MenuItem("Close")) { test_window = false; }
2965
                ImGui::EndPopup();
2966
            }
2967
            ImGui::Text(
2968
                "IsItemHovered() after begin = %d (== is title bar hovered)\n"
2969
                "IsItemActive() after begin = %d (== is window being clicked/moved)\n",
2970
                ImGui::IsItemHovered(), ImGui::IsItemActive());
2971
            ImGui::End();
2972
        }
2973
2974
        ImGui::TreePop();
2975
    }
2976
2977
    // Demonstrate BeginDisabled/EndDisabled using a checkbox located at the bottom of the section (which is a bit odd:
2978
    // logically we'd have this checkbox at the top of the section, but we don't want this feature to steal that space)
2979
    if (disable_all)
2980
        ImGui::EndDisabled();
2981
2982
    IMGUI_DEMO_MARKER("Widgets/Disable Block");
2983
    if (ImGui::TreeNode("Disable block"))
2984
    {
2985
        ImGui::Checkbox("Disable entire section above", &disable_all);
2986
        ImGui::SameLine(); HelpMarker("Demonstrate using BeginDisabled()/EndDisabled() across this section.");
2987
        ImGui::TreePop();
2988
    }
2989
2990
    IMGUI_DEMO_MARKER("Widgets/Text Filter");
2991
    if (ImGui::TreeNode("Text Filter"))
2992
    {
2993
        // Helper class to easy setup a text filter.
2994
        // You may want to implement a more feature-full filtering scheme in your own application.
2995
        HelpMarker("Not a widget per-se, but ImGuiTextFilter is a helper to perform simple filtering on text strings.");
2996
        static ImGuiTextFilter filter;
2997
        ImGui::Text("Filter usage:\n"
2998
            "  \"\"         display all lines\n"
2999
            "  \"xxx\"      display lines containing \"xxx\"\n"
3000
            "  \"xxx,yyy\"  display lines containing \"xxx\" or \"yyy\"\n"
3001
            "  \"-xxx\"     hide lines containing \"xxx\"");
3002
        filter.Draw();
3003
        const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" };
3004
        for (int i = 0; i < IM_ARRAYSIZE(lines); i++)
3005
            if (filter.PassFilter(lines[i]))
3006
                ImGui::BulletText("%s", lines[i]);
3007
        ImGui::TreePop();
3008
    }
3009
}
3010
3011
static const char* ExampleNames[] =
3012
{
3013
    "Artichoke", "Arugula", "Asparagus", "Avocado", "Bamboo Shoots", "Bean Sprouts", "Beans", "Beet", "Belgian Endive", "Bell Pepper",
3014
    "Bitter Gourd", "Bok Choy", "Broccoli", "Brussels Sprouts", "Burdock Root", "Cabbage", "Calabash", "Capers", "Carrot", "Cassava",
3015
    "Cauliflower", "Celery", "Celery Root", "Celcuce", "Chayote", "Chinese Broccoli", "Corn", "Cucumber"
3016
};
3017
3018
// Extra functions to add deletion support to ImGuiSelectionBasicStorage
3019
struct ExampleSelectionWithDeletion : ImGuiSelectionBasicStorage
3020
{
3021
    // Find which item should be Focused after deletion.
3022
    // Call _before_ item submission. Retunr an index in the before-deletion item list, your item loop should call SetKeyboardFocusHere() on it.
3023
    // The subsequent ApplyDeletionPostLoop() code will use it to apply Selection.
3024
    // - We cannot provide this logic in core Dear ImGui because we don't have access to selection data.
3025
    // - We don't actually manipulate the ImVector<> here, only in ApplyDeletionPostLoop(), but using similar API for consistency and flexibility.
3026
    // - 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.
3027
    // FIXME-MULTISELECT: Doesn't take account of the possibility focus target will be moved during deletion. Need refocus or scroll offset.
3028
    int ApplyDeletionPreLoop(ImGuiMultiSelectIO* ms_io, int items_count)
3029
    {
3030
        if (Size == 0)
3031
            return -1;
3032
3033
        // If focused item is not selected...
3034
        const int focused_idx = (int)ms_io->NavIdItem;  // Index of currently focused item
3035
        if (ms_io->NavIdSelected == false)  // This is merely a shortcut, == Contains(adapter->IndexToStorage(items, focused_idx))
3036
        {
3037
            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.
3038
            return focused_idx;             // Request to focus same item after deletion.
3039
        }
3040
3041
        // If focused item is selected: land on first unselected item after focused item.
3042
        for (int idx = focused_idx + 1; idx < items_count; idx++)
3043
            if (!Contains(GetStorageIdFromIndex(idx)))
3044
                return idx;
3045
3046
        // If focused item is selected: otherwise return last unselected item before focused item.
3047
        for (int idx = IM_MIN(focused_idx, items_count) - 1; idx >= 0; idx--)
3048
            if (!Contains(GetStorageIdFromIndex(idx)))
3049
                return idx;
3050
3051
        return -1;
3052
    }
3053
3054
    // Rewrite item list (delete items) + update selection.
3055
    // - Call after EndMultiSelect()
3056
    // - We cannot provide this logic in core Dear ImGui because we don't have access to your items, nor to selection data.
3057
    template<typename ITEM_TYPE>
3058
    void ApplyDeletionPostLoop(ImGuiMultiSelectIO* ms_io, ImVector<ITEM_TYPE>& items, int item_curr_idx_to_select)
3059
    {
3060
        // Rewrite item list (delete items) + convert old selection index (before deletion) to new selection index (after selection).
3061
        // If NavId was not part of selection, we will stay on same item.
3062
        ImVector<ITEM_TYPE> new_items;
3063
        new_items.reserve(items.Size - Size);
3064
        int item_next_idx_to_select = -1;
3065
        for (int idx = 0; idx < items.Size; idx++)
3066
        {
3067
            if (!Contains(GetStorageIdFromIndex(idx)))
3068
                new_items.push_back(items[idx]);
3069
            if (item_curr_idx_to_select == idx)
3070
                item_next_idx_to_select = new_items.Size - 1;
3071
        }
3072
        items.swap(new_items);
3073
3074
        // Update selection
3075
        Clear();
3076
        if (item_next_idx_to_select != -1 && ms_io->NavIdSelected)
3077
            SetItemSelected(GetStorageIdFromIndex(item_next_idx_to_select), true);
3078
    }
3079
};
3080
3081
// Example: Implement dual list box storage and interface
3082
struct ExampleDualListBox
3083
{
3084
    ImVector<ImGuiID>           Items[2];               // ID is index into ExampleName[]
3085
    ImGuiSelectionBasicStorage  Selections[2];          // Store ExampleItemId into selection
3086
    bool                        OptKeepSorted = true;
3087
3088
    void MoveAll(int src, int dst)
3089
    {
3090
        IM_ASSERT((src == 0 && dst == 1) || (src == 1 && dst == 0));
3091
        for (ImGuiID item_id : Items[src])
3092
            Items[dst].push_back(item_id);
3093
        Items[src].clear();
3094
        SortItems(dst);
3095
        Selections[src].Swap(Selections[dst]);
3096
        Selections[src].Clear();
3097
    }
3098
    void MoveSelected(int src, int dst)
3099
    {
3100
        for (int src_n = 0; src_n < Items[src].Size; src_n++)
3101
        {
3102
            ImGuiID item_id = Items[src][src_n];
3103
            if (!Selections[src].Contains(item_id))
3104
                continue;
3105
            Items[src].erase(&Items[src][src_n]); // FIXME-OPT: Could be implemented more optimally (rebuild src items and swap)
3106
            Items[dst].push_back(item_id);
3107
            src_n--;
3108
        }
3109
        if (OptKeepSorted)
3110
            SortItems(dst);
3111
        Selections[src].Swap(Selections[dst]);
3112
        Selections[src].Clear();
3113
    }
3114
    void ApplySelectionRequests(ImGuiMultiSelectIO* ms_io, int side)
3115
    {
3116
        // In this example we store item id in selection (instead of item index)
3117
        Selections[side].UserData = Items[side].Data;
3118
        Selections[side].AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { ImGuiID* items = (ImGuiID*)self->UserData; return items[idx]; };
3119
        Selections[side].ApplyRequests(ms_io);
3120
    }
3121
    static int IMGUI_CDECL CompareItemsByValue(const void* lhs, const void* rhs)
3122
    {
3123
        const int* a = (const int*)lhs;
3124
        const int* b = (const int*)rhs;
3125
        return (*a - *b) > 0 ? +1 : -1;
3126
    }
3127
    void SortItems(int n)
3128
    {
3129
        qsort(Items[n].Data, (size_t)Items[n].Size, sizeof(Items[n][0]), CompareItemsByValue);
3130
    }
3131
    void Show()
3132
    {
3133
        //ImGui::Checkbox("Sorted", &OptKeepSorted);
3134
        if (ImGui::BeginTable("split", 3, ImGuiTableFlags_None))
3135
        {
3136
            ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch);    // Left side
3137
            ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed);      // Buttons
3138
            ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch);    // Right side
3139
            ImGui::TableNextRow();
3140
3141
            int request_move_selected = -1;
3142
            int request_move_all = -1;
3143
            float child_height_0 = 0.0f;
3144
            for (int side = 0; side < 2; side++)
3145
            {
3146
                // FIXME-MULTISELECT: Dual List Box: Add context menus
3147
                // FIXME-NAV: Using ImGuiWindowFlags_NavFlattened exhibit many issues.
3148
                ImVector<ImGuiID>& items = Items[side];
3149
                ImGuiSelectionBasicStorage& selection = Selections[side];
3150
3151
                ImGui::TableSetColumnIndex((side == 0) ? 0 : 2);
3152
                ImGui::Text("%s (%d)", (side == 0) ? "Available" : "Basket", items.Size);
3153
3154
                // Submit scrolling range to avoid glitches on moving/deletion
3155
                const float items_height = ImGui::GetTextLineHeightWithSpacing();
3156
                ImGui::SetNextWindowContentSize(ImVec2(0.0f, items.Size * items_height));
3157
3158
                bool child_visible;
3159
                if (side == 0)
3160
                {
3161
                    // Left child is resizable
3162
                    ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetFrameHeightWithSpacing() * 4), ImVec2(FLT_MAX, FLT_MAX));
3163
                    child_visible = ImGui::BeginChild("0", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY);
3164
                    child_height_0 = ImGui::GetWindowSize().y;
3165
                }
3166
                else
3167
                {
3168
                    // Right child use same height as left one
3169
                    child_visible = ImGui::BeginChild("1", ImVec2(-FLT_MIN, child_height_0), ImGuiChildFlags_FrameStyle);
3170
                }
3171
                if (child_visible)
3172
                {
3173
                    ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_None;
3174
                    ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size);
3175
                    ApplySelectionRequests(ms_io, side);
3176
3177
                    for (int item_n = 0; item_n < items.Size; item_n++)
3178
                    {
3179
                        ImGuiID item_id = items[item_n];
3180
                        bool item_is_selected = selection.Contains(item_id);
3181
                        ImGui::SetNextItemSelectionUserData(item_n);
3182
                        ImGui::Selectable(ExampleNames[item_id], item_is_selected, ImGuiSelectableFlags_AllowDoubleClick);
3183
                        if (ImGui::IsItemFocused())
3184
                        {
3185
                            // FIXME-MULTISELECT: Dual List Box: Transfer focus
3186
                            if (ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_KeypadEnter))
3187
                                request_move_selected = side;
3188
                            if (ImGui::IsMouseDoubleClicked(0)) // FIXME-MULTISELECT: Double-click on multi-selection?
3189
                                request_move_selected = side;
3190
                        }
3191
                    }
3192
3193
                    ms_io = ImGui::EndMultiSelect();
3194
                    ApplySelectionRequests(ms_io, side);
3195
                }
3196
                ImGui::EndChild();
3197
            }
3198
3199
            // Buttons columns
3200
            ImGui::TableSetColumnIndex(1);
3201
            ImGui::NewLine();
3202
            //ImVec2 button_sz = { ImGui::CalcTextSize(">>").x + ImGui::GetStyle().FramePadding.x * 2.0f, ImGui::GetFrameHeight() + padding.y * 2.0f };
3203
            ImVec2 button_sz = { ImGui::GetFrameHeight(), ImGui::GetFrameHeight() };
3204
3205
            // (Using BeginDisabled()/EndDisabled() works but feels distracting given how it is currently visualized)
3206
            if (ImGui::Button(">>", button_sz))
3207
                request_move_all = 0;
3208
            if (ImGui::Button(">", button_sz))
3209
                request_move_selected = 0;
3210
            if (ImGui::Button("<", button_sz))
3211
                request_move_selected = 1;
3212
            if (ImGui::Button("<<", button_sz))
3213
                request_move_all = 1;
3214
3215
            // Process requests
3216
            if (request_move_all != -1)
3217
                MoveAll(request_move_all, request_move_all ^ 1);
3218
            if (request_move_selected != -1)
3219
                MoveSelected(request_move_selected, request_move_selected ^ 1);
3220
3221
            // FIXME-MULTISELECT: Support action from outside
3222
            /*
3223
            if (OptKeepSorted == false)
3224
            {
3225
                ImGui::NewLine();
3226
                if (ImGui::ArrowButton("MoveUp", ImGuiDir_Up)) {}
3227
                if (ImGui::ArrowButton("MoveDown", ImGuiDir_Down)) {}
3228
            }
3229
            */
3230
3231
            ImGui::EndTable();
3232
        }
3233
    }
3234
};
3235
3236
//-----------------------------------------------------------------------------
3237
// [SECTION] ShowDemoWindowMultiSelect()
3238
//-----------------------------------------------------------------------------
3239
// Multi-selection demos
3240
// Also read: https://github.com/ocornut/imgui/wiki/Multi-Select
3241
//-----------------------------------------------------------------------------
3242
3243
static void ShowDemoWindowMultiSelect(ImGuiDemoWindowData* demo_data)
3244
{
3245
    IMGUI_DEMO_MARKER("Widgets/Selection State & Multi-Select");
3246
    if (ImGui::TreeNode("Selection State & Multi-Select"))
3247
    {
3248
        HelpMarker("Selections can be built using Selectable(), TreeNode() or other widgets. Selection state is owned by application code/data.");
3249
3250
        // Without any fancy API: manage single-selection yourself.
3251
        IMGUI_DEMO_MARKER("Widgets/Selection State/Single-Select");
3252
        if (ImGui::TreeNode("Single-Select"))
3253
        {
3254
            static int selected = -1;
3255
            for (int n = 0; n < 5; n++)
3256
            {
3257
                char buf[32];
3258
                sprintf(buf, "Object %d", n);
3259
                if (ImGui::Selectable(buf, selected == n))
3260
                    selected = n;
3261
            }
3262
            ImGui::TreePop();
3263
        }
3264
3265
        // Demonstrate implementation a most-basic form of multi-selection manually
3266
        // This doesn't support the SHIFT modifier which requires BeginMultiSelect()!
3267
        IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (manual/simplified, without BeginMultiSelect)");
3268
        if (ImGui::TreeNode("Multi-Select (manual/simplified, without BeginMultiSelect)"))
3269
        {
3270
            HelpMarker("Hold CTRL and click to select multiple items.");
3271
            static bool selection[5] = { false, false, false, false, false };
3272
            for (int n = 0; n < 5; n++)
3273
            {
3274
                char buf[32];
3275
                sprintf(buf, "Object %d", n);
3276
                if (ImGui::Selectable(buf, selection[n]))
3277
                {
3278
                    if (!ImGui::GetIO().KeyCtrl) // Clear selection when CTRL is not held
3279
                        memset(selection, 0, sizeof(selection));
3280
                    selection[n] ^= 1; // Toggle current item
3281
                }
3282
            }
3283
            ImGui::TreePop();
3284
        }
3285
3286
        // Demonstrate handling proper multi-selection using the BeginMultiSelect/EndMultiSelect API.
3287
        // SHIFT+Click w/ CTRL and other standard features are supported.
3288
        // We use the ImGuiSelectionBasicStorage helper which you may freely reimplement.
3289
        IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select");
3290
        if (ImGui::TreeNode("Multi-Select"))
3291
        {
3292
            ImGui::Text("Supported features:");
3293
            ImGui::BulletText("Keyboard navigation (arrows, page up/down, home/end, space).");
3294
            ImGui::BulletText("Ctrl modifier to preserve and toggle selection.");
3295
            ImGui::BulletText("Shift modifier for range selection.");
3296
            ImGui::BulletText("CTRL+A to select all.");
3297
            ImGui::BulletText("Escape to clear selection.");
3298
            ImGui::BulletText("Click and drag to box-select.");
3299
            ImGui::Text("Tip: Use 'Demo->Tools->Debug Log->Selection' to see selection requests as they happen.");
3300
3301
            // Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection
3302
            const int ITEMS_COUNT = 50;
3303
            static ImGuiSelectionBasicStorage selection;
3304
            ImGui::Text("Selection: %d/%d", selection.Size, ITEMS_COUNT);
3305
3306
            // The BeginChild() has no purpose for selection logic, other that offering a scrolling region.
3307
            if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
3308
            {
3309
                ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
3310
                ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT);
3311
                selection.ApplyRequests(ms_io);
3312
3313
                for (int n = 0; n < ITEMS_COUNT; n++)
3314
                {
3315
                    char label[64];
3316
                    sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_ARRAYSIZE(ExampleNames)]);
3317
                    bool item_is_selected = selection.Contains((ImGuiID)n);
3318
                    ImGui::SetNextItemSelectionUserData(n);
3319
                    ImGui::Selectable(label, item_is_selected);
3320
                }
3321
3322
                ms_io = ImGui::EndMultiSelect();
3323
                selection.ApplyRequests(ms_io);
3324
            }
3325
            ImGui::EndChild();
3326
            ImGui::TreePop();
3327
        }
3328
3329
        // Demonstrate using the clipper with BeginMultiSelect()/EndMultiSelect()
3330
        IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (with clipper)");
3331
        if (ImGui::TreeNode("Multi-Select (with clipper)"))
3332
        {
3333
            // Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection
3334
            static ImGuiSelectionBasicStorage selection;
3335
3336
            ImGui::Text("Added features:");
3337
            ImGui::BulletText("Using ImGuiListClipper.");
3338
3339
            const int ITEMS_COUNT = 10000;
3340
            ImGui::Text("Selection: %d/%d", selection.Size, ITEMS_COUNT);
3341
            if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
3342
            {
3343
                ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
3344
                ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT);
3345
                selection.ApplyRequests(ms_io);
3346
3347
                ImGuiListClipper clipper;
3348
                clipper.Begin(ITEMS_COUNT);
3349
                if (ms_io->RangeSrcItem != -1)
3350
                    clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped.
3351
                while (clipper.Step())
3352
                {
3353
                    for (int n = clipper.DisplayStart; n < clipper.DisplayEnd; n++)
3354
                    {
3355
                        char label[64];
3356
                        sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_ARRAYSIZE(ExampleNames)]);
3357
                        bool item_is_selected = selection.Contains((ImGuiID)n);
3358
                        ImGui::SetNextItemSelectionUserData(n);
3359
                        ImGui::Selectable(label, item_is_selected);
3360
                    }
3361
                }
3362
3363
                ms_io = ImGui::EndMultiSelect();
3364
                selection.ApplyRequests(ms_io);
3365
            }
3366
            ImGui::EndChild();
3367
            ImGui::TreePop();
3368
        }
3369
3370
        // Demonstrate dynamic item list + deletion support using the BeginMultiSelect/EndMultiSelect API.
3371
        // In order to support Deletion without any glitches you need to:
3372
        // - (1) If items are submitted in their own scrolling area, submit contents size SetNextWindowContentSize() ahead of time to prevent one-frame readjustment of scrolling.
3373
        // - (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.
3374
        // - (3) BeginXXXX process
3375
        // - (4) Focus process
3376
        // - (5) EndXXXX process
3377
        IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (with deletion)");
3378
        if (ImGui::TreeNode("Multi-Select (with deletion)"))
3379
        {
3380
            // Storing items data separately from selection data.
3381
            // (you may decide to store selection data inside your item (aka intrusive storage) if you don't need multiple views over same items)
3382
            // Use a custom selection.Adapter: store item identifier in Selection (instead of index)
3383
            static ImVector<ImGuiID> items;
3384
            static ExampleSelectionWithDeletion selection;
3385
            selection.UserData = (void*)&items;
3386
            selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { ImVector<ImGuiID>* p_items = (ImVector<ImGuiID>*)self->UserData; return (*p_items)[idx]; }; // Index -> ID
3387
3388
            ImGui::Text("Added features:");
3389
            ImGui::BulletText("Dynamic list with Delete key support.");
3390
            ImGui::Text("Selection size: %d/%d", selection.Size, items.Size);
3391
3392
            // Initialize default list with 50 items + button to add/remove items.
3393
            static ImGuiID items_next_id = 0;
3394
            if (items_next_id == 0)
3395
                for (ImGuiID n = 0; n < 50; n++)
3396
                    items.push_back(items_next_id++);
3397
            if (ImGui::SmallButton("Add 20 items"))     { for (int n = 0; n < 20; n++) { items.push_back(items_next_id++); } }
3398
            ImGui::SameLine();
3399
            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(); } }
3400
3401
            // (1) Extra to support deletion: Submit scrolling range to avoid glitches on deletion
3402
            const float items_height = ImGui::GetTextLineHeightWithSpacing();
3403
            ImGui::SetNextWindowContentSize(ImVec2(0.0f, items.Size * items_height));
3404
3405
            if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
3406
            {
3407
                ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
3408
                ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size);
3409
                selection.ApplyRequests(ms_io);
3410
3411
                const bool want_delete = ImGui::Shortcut(ImGuiKey_Delete, ImGuiInputFlags_Repeat) && (selection.Size > 0);
3412
                const int item_curr_idx_to_focus = want_delete ? selection.ApplyDeletionPreLoop(ms_io, items.Size) : -1;
3413
3414
                for (int n = 0; n < items.Size; n++)
3415
                {
3416
                    const ImGuiID item_id = items[n];
3417
                    char label[64];
3418
                    sprintf(label, "Object %05u: %s", item_id, ExampleNames[item_id % IM_ARRAYSIZE(ExampleNames)]);
3419
3420
                    bool item_is_selected = selection.Contains(item_id);
3421
                    ImGui::SetNextItemSelectionUserData(n);
3422
                    ImGui::Selectable(label, item_is_selected);
3423
                    if (item_curr_idx_to_focus == n)
3424
                        ImGui::SetKeyboardFocusHere(-1);
3425
                }
3426
3427
                // Apply multi-select requests
3428
                ms_io = ImGui::EndMultiSelect();
3429
                selection.ApplyRequests(ms_io);
3430
                if (want_delete)
3431
                    selection.ApplyDeletionPostLoop(ms_io, items, item_curr_idx_to_focus);
3432
            }
3433
            ImGui::EndChild();
3434
            ImGui::TreePop();
3435
        }
3436
3437
        // Implement a Dual List Box (#6648)
3438
        IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (dual list box)");
3439
        if (ImGui::TreeNode("Multi-Select (dual list box)"))
3440
        {
3441
            // Init default state
3442
            static ExampleDualListBox dlb;
3443
            if (dlb.Items[0].Size == 0 && dlb.Items[1].Size == 0)
3444
                for (int item_id = 0; item_id < IM_ARRAYSIZE(ExampleNames); item_id++)
3445
                    dlb.Items[0].push_back((ImGuiID)item_id);
3446
3447
            // Show
3448
            dlb.Show();
3449
3450
            ImGui::TreePop();
3451
        }
3452
3453
        // Demonstrate using the clipper with BeginMultiSelect()/EndMultiSelect()
3454
        IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (in a table)");
3455
        if (ImGui::TreeNode("Multi-Select (in a table)"))
3456
        {
3457
            static ImGuiSelectionBasicStorage selection;
3458
3459
            const int ITEMS_COUNT = 10000;
3460
            ImGui::Text("Selection: %d/%d", selection.Size, ITEMS_COUNT);
3461
            if (ImGui::BeginTable("##Basket", 2, ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter))
3462
            {
3463
                ImGui::TableSetupColumn("Object");
3464
                ImGui::TableSetupColumn("Action");
3465
                ImGui::TableSetupScrollFreeze(0, 1);
3466
                ImGui::TableHeadersRow();
3467
3468
                ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
3469
                ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT);
3470
                selection.ApplyRequests(ms_io);
3471
3472
                ImGuiListClipper clipper;
3473
                clipper.Begin(ITEMS_COUNT);
3474
                if (ms_io->RangeSrcItem != -1)
3475
                    clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped.
3476
                while (clipper.Step())
3477
                {
3478
                    for (int n = clipper.DisplayStart; n < clipper.DisplayEnd; n++)
3479
                    {
3480
                        ImGui::TableNextRow();
3481
                        ImGui::TableNextColumn();
3482
                        char label[64];
3483
                        sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_ARRAYSIZE(ExampleNames)]);
3484
                        bool item_is_selected = selection.Contains((ImGuiID)n);
3485
                        ImGui::SetNextItemSelectionUserData(n);
3486
                        ImGui::Selectable(label, item_is_selected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap);
3487
                        ImGui::TableNextColumn();
3488
                        ImGui::SmallButton("hello");
3489
                    }
3490
                }
3491
3492
                ms_io = ImGui::EndMultiSelect();
3493
                selection.ApplyRequests(ms_io);
3494
                ImGui::EndTable();
3495
            }
3496
            ImGui::TreePop();
3497
        }
3498
3499
        IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (checkboxes)");
3500
        if (ImGui::TreeNode("Multi-Select (checkboxes)"))
3501
        {
3502
            ImGui::Text("In a list of checkboxes (not selectable):");
3503
            ImGui::BulletText("Using _NoAutoSelect + _NoAutoClear flags.");
3504
            ImGui::BulletText("Shift+Click to check multiple boxes.");
3505
            ImGui::BulletText("Shift+Keyboard to copy current value to other boxes.");
3506
3507
            // If you have an array of checkboxes, you may want to use NoAutoSelect + NoAutoClear and the ImGuiSelectionExternalStorage helper.
3508
            static bool items[20] = {};
3509
            static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_NoAutoSelect | ImGuiMultiSelectFlags_NoAutoClear | ImGuiMultiSelectFlags_ClearOnEscape;
3510
            ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoSelect", &flags, ImGuiMultiSelectFlags_NoAutoSelect);
3511
            ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoClear", &flags, ImGuiMultiSelectFlags_NoAutoClear);
3512
            ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect2d", &flags, ImGuiMultiSelectFlags_BoxSelect2d); // Cannot use ImGuiMultiSelectFlags_BoxSelect1d as checkboxes are varying width.
3513
3514
            if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeY))
3515
            {
3516
                ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, -1, IM_ARRAYSIZE(items));
3517
                ImGuiSelectionExternalStorage storage_wrapper;
3518
                storage_wrapper.UserData = (void*)items;
3519
                storage_wrapper.AdapterSetItemSelected = [](ImGuiSelectionExternalStorage* self, int n, bool selected) { bool* array = (bool*)self->UserData; array[n] = selected; };
3520
                storage_wrapper.ApplyRequests(ms_io);
3521
                for (int n = 0; n < 20; n++)
3522
                {
3523
                    char label[32];
3524
                    sprintf(label, "Item %d", n);
3525
                    ImGui::SetNextItemSelectionUserData(n);
3526
                    ImGui::Checkbox(label, &items[n]);
3527
                }
3528
                ms_io = ImGui::EndMultiSelect();
3529
                storage_wrapper.ApplyRequests(ms_io);
3530
            }
3531
            ImGui::EndChild();
3532
3533
            ImGui::TreePop();
3534
        }
3535
3536
        // Demonstrate individual selection scopes in same window
3537
        IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (multiple scopes)");
3538
        if (ImGui::TreeNode("Multi-Select (multiple scopes)"))
3539
        {
3540
            // Use default select: Pass index to SetNextItemSelectionUserData(), store index in Selection
3541
            const int SCOPES_COUNT = 3;
3542
            const int ITEMS_COUNT = 8; // Per scope
3543
            static ImGuiSelectionBasicStorage selections_data[SCOPES_COUNT];
3544
3545
            // Use ImGuiMultiSelectFlags_ScopeRect to not affect other selections in same window.
3546
            static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ScopeRect | ImGuiMultiSelectFlags_ClearOnEscape;// | ImGuiMultiSelectFlags_ClearOnClickVoid;
3547
            if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeWindow", &flags, ImGuiMultiSelectFlags_ScopeWindow) && (flags & ImGuiMultiSelectFlags_ScopeWindow))
3548
                flags &= ~ImGuiMultiSelectFlags_ScopeRect;
3549
            if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeRect", &flags, ImGuiMultiSelectFlags_ScopeRect) && (flags & ImGuiMultiSelectFlags_ScopeRect))
3550
                flags &= ~ImGuiMultiSelectFlags_ScopeWindow;
3551
            ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnClickVoid", &flags, ImGuiMultiSelectFlags_ClearOnClickVoid);
3552
            ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect1d", &flags, ImGuiMultiSelectFlags_BoxSelect1d);
3553
3554
            for (int selection_scope_n = 0; selection_scope_n < SCOPES_COUNT; selection_scope_n++)
3555
            {
3556
                ImGui::PushID(selection_scope_n);
3557
                ImGuiSelectionBasicStorage* selection = &selections_data[selection_scope_n];
3558
                ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection->Size, ITEMS_COUNT);
3559
                selection->ApplyRequests(ms_io);
3560
3561
                ImGui::SeparatorText("Selection scope");
3562
                ImGui::Text("Selection size: %d/%d", selection->Size, ITEMS_COUNT);
3563
3564
                for (int n = 0; n < ITEMS_COUNT; n++)
3565
                {
3566
                    char label[64];
3567
                    sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_ARRAYSIZE(ExampleNames)]);
3568
                    bool item_is_selected = selection->Contains((ImGuiID)n);
3569
                    ImGui::SetNextItemSelectionUserData(n);
3570
                    ImGui::Selectable(label, item_is_selected);
3571
                }
3572
3573
                // Apply multi-select requests
3574
                ms_io = ImGui::EndMultiSelect();
3575
                selection->ApplyRequests(ms_io);
3576
                ImGui::PopID();
3577
            }
3578
            ImGui::TreePop();
3579
        }
3580
3581
        // See ShowExampleAppAssetsBrowser()
3582
        if (ImGui::TreeNode("Multi-Select (tiled assets browser)"))
3583
        {
3584
            ImGui::Checkbox("Assets Browser", &demo_data->ShowAppAssetsBrowser);
3585
            ImGui::Text("(also access from 'Examples->Assets Browser' in menu)");
3586
            ImGui::TreePop();
3587
        }
3588
3589
        // Demonstrate supporting multiple-selection in a tree.
3590
        // - We don't use linear indices for selection user data, but our ExampleTreeNode* pointer directly!
3591
        //   This showcase how SetNextItemSelectionUserData() never assume indices!
3592
        // - The difficulty here is to "interpolate" from RangeSrcItem to RangeDstItem in the SetAll/SetRange request.
3593
        //   We want this interpolation to match what the user sees: in visible order, skipping closed nodes.
3594
        //   This is implemented by our TreeGetNextNodeInVisibleOrder() user-space helper.
3595
        // - Important: In a real codebase aiming to implement full-featured selectable tree with custom filtering, you
3596
        //   are more likely to build an array mapping sequential indices to visible tree nodes, since your
3597
        //   filtering/search + clipping process will benefit from it. Having this will make this interpolation much easier.
3598
        // - Consider this a prototype: we are working toward simplifying some of it.
3599
        IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (trees)");
3600
        if (ImGui::TreeNode("Multi-Select (trees)"))
3601
        {
3602
            HelpMarker(
3603
                "This is rather advanced and experimental. If you are getting started with multi-select,"
3604
                "please don't start by looking at how to use it for a tree!\n\n"
3605
                "Future versions will try to simplify and formalize some of this.");
3606
3607
            struct ExampleTreeFuncs
3608
            {
3609
                static void DrawNode(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection)
3610
                {
3611
                    ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;
3612
                    tree_node_flags |= ImGuiTreeNodeFlags_NavLeftJumpsBackHere; // Enable pressing left to jump to parent
3613
                    if (node->Childs.Size == 0)
3614
                        tree_node_flags |= ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_Leaf;
3615
                    if (selection->Contains((ImGuiID)node->UID))
3616
                        tree_node_flags |= ImGuiTreeNodeFlags_Selected;
3617
3618
                    // Using SetNextItemStorageID() to specify storage id, so we can easily peek into
3619
                    // the storage holding open/close stage, using our TreeNodeGetOpen/TreeNodeSetOpen() functions.
3620
                    ImGui::SetNextItemSelectionUserData((ImGuiSelectionUserData)(intptr_t)node);
3621
                    ImGui::SetNextItemStorageID((ImGuiID)node->UID);
3622
                    if (ImGui::TreeNodeEx(node->Name, tree_node_flags))
3623
                    {
3624
                        for (ExampleTreeNode* child : node->Childs)
3625
                            DrawNode(child, selection);
3626
                        ImGui::TreePop();
3627
                    }
3628
                    else if (ImGui::IsItemToggledOpen())
3629
                    {
3630
                        TreeCloseAndUnselectChildNodes(node, selection);
3631
                    }
3632
                }
3633
3634
                static bool TreeNodeGetOpen(ExampleTreeNode* node)
3635
                {
3636
                    return ImGui::GetStateStorage()->GetBool((ImGuiID)node->UID);
3637
                }
3638
3639
                static void TreeNodeSetOpen(ExampleTreeNode* node, bool open)
3640
                {
3641
                    ImGui::GetStateStorage()->SetBool((ImGuiID)node->UID, open);
3642
                }
3643
3644
                // When closing a node: 1) close and unselect all child nodes, 2) select parent if any child was selected.
3645
                // FIXME: This is currently handled by user logic but I'm hoping to eventually provide tree node
3646
                // features to do this automatically, e.g. a ImGuiTreeNodeFlags_AutoCloseChildNodes etc.
3647
                static int TreeCloseAndUnselectChildNodes(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection, int depth = 0)
3648
                {
3649
                    // Recursive close (the test for depth == 0 is because we call this on a node that was just closed!)
3650
                    int unselected_count = selection->Contains((ImGuiID)node->UID) ? 1 : 0;
3651
                    if (depth == 0 || TreeNodeGetOpen(node))
3652
                    {
3653
                        for (ExampleTreeNode* child : node->Childs)
3654
                            unselected_count += TreeCloseAndUnselectChildNodes(child, selection, depth + 1);
3655
                        TreeNodeSetOpen(node, false);
3656
                    }
3657
3658
                    // Select root node if any of its child was selected, otherwise unselect
3659
                    selection->SetItemSelected((ImGuiID)node->UID, (depth == 0 && unselected_count > 0));
3660
                    return unselected_count;
3661
                }
3662
3663
                // Apply multi-selection requests
3664
                static void ApplySelectionRequests(ImGuiMultiSelectIO* ms_io, ExampleTreeNode* tree, ImGuiSelectionBasicStorage* selection)
3665
                {
3666
                    for (ImGuiSelectionRequest& req : ms_io->Requests)
3667
                    {
3668
                        if (req.Type == ImGuiSelectionRequestType_SetAll)
3669
                        {
3670
                            if (req.Selected)
3671
                                TreeSetAllInOpenNodes(tree, selection, req.Selected);
3672
                            else
3673
                                selection->Clear();
3674
                        }
3675
                        else if (req.Type == ImGuiSelectionRequestType_SetRange)
3676
                        {
3677
                            ExampleTreeNode* first_node = (ExampleTreeNode*)(intptr_t)req.RangeFirstItem;
3678
                            ExampleTreeNode* last_node = (ExampleTreeNode*)(intptr_t)req.RangeLastItem;
3679
                            for (ExampleTreeNode* node = first_node; node != NULL; node = TreeGetNextNodeInVisibleOrder(node, last_node))
3680
                                selection->SetItemSelected((ImGuiID)node->UID, req.Selected);
3681
                        }
3682
                    }
3683
                }
3684
3685
                static void TreeSetAllInOpenNodes(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection, bool selected)
3686
                {
3687
                    if (node->Parent != NULL) // Root node isn't visible nor selectable in our scheme
3688
                        selection->SetItemSelected((ImGuiID)node->UID, selected);
3689
                    if (node->Parent == NULL || TreeNodeGetOpen(node))
3690
                        for (ExampleTreeNode* child : node->Childs)
3691
                            TreeSetAllInOpenNodes(child, selection, selected);
3692
                }
3693
3694
                // Interpolate in *user-visible order* AND only *over opened nodes*.
3695
                // If you have a sequential mapping tables (e.g. generated after a filter/search pass) this would be simpler.
3696
                // Here the tricks are that:
3697
                // - we store/maintain ExampleTreeNode::IndexInParent which allows implementing a linear iterator easily, without searches, without recursion.
3698
                //   this could be replaced by a search in parent, aka 'int index_in_parent = curr_node->Parent->Childs.find_index(curr_node)'
3699
                //   which would only be called when crossing from child to a parent, aka not too much.
3700
                // - we call SetNextItemStorageID() before our TreeNode() calls with an ID which doesn't relate to UI stack,
3701
                //   making it easier to call TreeNodeGetOpen()/TreeNodeSetOpen() from any location.
3702
                static ExampleTreeNode* TreeGetNextNodeInVisibleOrder(ExampleTreeNode* curr_node, ExampleTreeNode* last_node)
3703
                {
3704
                    // Reached last node
3705
                    if (curr_node == last_node)
3706
                        return NULL;
3707
3708
                    // Recurse into childs. Query storage to tell if the node is open.
3709
                    if (curr_node->Childs.Size > 0 && TreeNodeGetOpen(curr_node))
3710
                        return curr_node->Childs[0];
3711
3712
                    // Next sibling, then into our own parent
3713
                    while (curr_node->Parent != NULL)
3714
                    {
3715
                        if (curr_node->IndexInParent + 1 < curr_node->Parent->Childs.Size)
3716
                            return curr_node->Parent->Childs[curr_node->IndexInParent + 1];
3717
                        curr_node = curr_node->Parent;
3718
                    }
3719
                    return NULL;
3720
                }
3721
3722
            }; // ExampleTreeFuncs
3723
3724
            static ImGuiSelectionBasicStorage selection;
3725
            if (demo_data->DemoTree == NULL)
3726
                demo_data->DemoTree = ExampleTree_CreateDemoTree(); // Create tree once
3727
            ImGui::Text("Selection size: %d", selection.Size);
3728
3729
            if (ImGui::BeginChild("##Tree", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
3730
            {
3731
                ExampleTreeNode* tree = demo_data->DemoTree;
3732
                ImGuiMultiSelectFlags ms_flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect2d;
3733
                ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(ms_flags, selection.Size, -1);
3734
                ExampleTreeFuncs::ApplySelectionRequests(ms_io, tree, &selection);
3735
                for (ExampleTreeNode* node : tree->Childs)
3736
                    ExampleTreeFuncs::DrawNode(node, &selection);
3737
                ms_io = ImGui::EndMultiSelect();
3738
                ExampleTreeFuncs::ApplySelectionRequests(ms_io, tree, &selection);
3739
            }
3740
            ImGui::EndChild();
3741
3742
            ImGui::TreePop();
3743
        }
3744
3745
        // Advanced demonstration of BeginMultiSelect()
3746
        // - Showcase clipping.
3747
        // - Showcase deletion.
3748
        // - Showcase basic drag and drop.
3749
        // - Showcase TreeNode variant (note that tree node don't expand in the demo: supporting expanding tree nodes + clipping a separate thing).
3750
        // - Showcase using inside a table.
3751
        IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (advanced)");
3752
        //ImGui::SetNextItemOpen(true, ImGuiCond_Once);
3753
        if (ImGui::TreeNode("Multi-Select (advanced)"))
3754
        {
3755
            // Options
3756
            enum WidgetType { WidgetType_Selectable, WidgetType_TreeNode };
3757
            static bool use_clipper = true;
3758
            static bool use_deletion = true;
3759
            static bool use_drag_drop = true;
3760
            static bool show_in_table = false;
3761
            static bool show_color_button = true;
3762
            static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
3763
            static WidgetType widget_type = WidgetType_Selectable;
3764
3765
            if (ImGui::TreeNode("Options"))
3766
            {
3767
                if (ImGui::RadioButton("Selectables", widget_type == WidgetType_Selectable)) { widget_type = WidgetType_Selectable; }
3768
                ImGui::SameLine();
3769
                if (ImGui::RadioButton("Tree nodes", widget_type == WidgetType_TreeNode)) { widget_type = WidgetType_TreeNode; }
3770
                ImGui::SameLine();
3771
                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.");
3772
                ImGui::Checkbox("Enable clipper", &use_clipper);
3773
                ImGui::Checkbox("Enable deletion", &use_deletion);
3774
                ImGui::Checkbox("Enable drag & drop", &use_drag_drop);
3775
                ImGui::Checkbox("Show in a table", &show_in_table);
3776
                ImGui::Checkbox("Show color button", &show_color_button);
3777
                ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SingleSelect", &flags, ImGuiMultiSelectFlags_SingleSelect);
3778
                ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoSelectAll", &flags, ImGuiMultiSelectFlags_NoSelectAll);
3779
                ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoRangeSelect", &flags, ImGuiMultiSelectFlags_NoRangeSelect);
3780
                ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoSelect", &flags, ImGuiMultiSelectFlags_NoAutoSelect);
3781
                ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoClear", &flags, ImGuiMultiSelectFlags_NoAutoClear);
3782
                ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoClearOnReselect", &flags, ImGuiMultiSelectFlags_NoAutoClearOnReselect);
3783
                ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect1d", &flags, ImGuiMultiSelectFlags_BoxSelect1d);
3784
                ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect2d", &flags, ImGuiMultiSelectFlags_BoxSelect2d);
3785
                ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelectNoScroll", &flags, ImGuiMultiSelectFlags_BoxSelectNoScroll);
3786
                ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnEscape", &flags, ImGuiMultiSelectFlags_ClearOnEscape);
3787
                ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnClickVoid", &flags, ImGuiMultiSelectFlags_ClearOnClickVoid);
3788
                if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeWindow", &flags, ImGuiMultiSelectFlags_ScopeWindow) && (flags & ImGuiMultiSelectFlags_ScopeWindow))
3789
                    flags &= ~ImGuiMultiSelectFlags_ScopeRect;
3790
                if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeRect", &flags, ImGuiMultiSelectFlags_ScopeRect) && (flags & ImGuiMultiSelectFlags_ScopeRect))
3791
                    flags &= ~ImGuiMultiSelectFlags_ScopeWindow;
3792
                if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SelectOnClick", &flags, ImGuiMultiSelectFlags_SelectOnClick) && (flags & ImGuiMultiSelectFlags_SelectOnClick))
3793
                    flags &= ~ImGuiMultiSelectFlags_SelectOnClickRelease;
3794
                if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SelectOnClickRelease", &flags, ImGuiMultiSelectFlags_SelectOnClickRelease) && (flags & ImGuiMultiSelectFlags_SelectOnClickRelease))
3795
                    flags &= ~ImGuiMultiSelectFlags_SelectOnClick;
3796
                ImGui::SameLine(); HelpMarker("Allow dragging an unselected item without altering selection.");
3797
                ImGui::TreePop();
3798
            }
3799
3800
            // Initialize default list with 1000 items.
3801
            // Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection
3802
            static ImVector<int> items;
3803
            static int items_next_id = 0;
3804
            if (items_next_id == 0) { for (int n = 0; n < 1000; n++) { items.push_back(items_next_id++); } }
3805
            static ExampleSelectionWithDeletion selection;
3806
            static bool request_deletion_from_menu = false; // Queue deletion triggered from context menu
3807
3808
            ImGui::Text("Selection size: %d/%d", selection.Size, items.Size);
3809
3810
            const float items_height = (widget_type == WidgetType_TreeNode) ? ImGui::GetTextLineHeight() : ImGui::GetTextLineHeightWithSpacing();
3811
            ImGui::SetNextWindowContentSize(ImVec2(0.0f, items.Size * items_height));
3812
            if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
3813
            {
3814
                ImVec2 color_button_sz(ImGui::GetFontSize(), ImGui::GetFontSize());
3815
                if (widget_type == WidgetType_TreeNode)
3816
                    ImGui::PushStyleVarY(ImGuiStyleVar_ItemSpacing, 0.0f);
3817
3818
                ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size);
3819
                selection.ApplyRequests(ms_io);
3820
3821
                const bool want_delete = (ImGui::Shortcut(ImGuiKey_Delete, ImGuiInputFlags_Repeat) && (selection.Size > 0)) || request_deletion_from_menu;
3822
                const int item_curr_idx_to_focus = want_delete ? selection.ApplyDeletionPreLoop(ms_io, items.Size) : -1;
3823
                request_deletion_from_menu = false;
3824
3825
                if (show_in_table)
3826
                {
3827
                    if (widget_type == WidgetType_TreeNode)
3828
                        ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(0.0f, 0.0f));
3829
                    ImGui::BeginTable("##Split", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_NoPadOuterX);
3830
                    ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 0.70f);
3831
                    ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 0.30f);
3832
                    //ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacingY, 0.0f);
3833
                }
3834
3835
                ImGuiListClipper clipper;
3836
                if (use_clipper)
3837
                {
3838
                    clipper.Begin(items.Size);
3839
                    if (item_curr_idx_to_focus != -1)
3840
                        clipper.IncludeItemByIndex(item_curr_idx_to_focus); // Ensure focused item is not clipped.
3841
                    if (ms_io->RangeSrcItem != -1)
3842
                        clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped.
3843
                }
3844
3845
                while (!use_clipper || clipper.Step())
3846
                {
3847
                    const int item_begin = use_clipper ? clipper.DisplayStart : 0;
3848
                    const int item_end = use_clipper ? clipper.DisplayEnd : items.Size;
3849
                    for (int n = item_begin; n < item_end; n++)
3850
                    {
3851
                        if (show_in_table)
3852
                            ImGui::TableNextColumn();
3853
3854
                        const int item_id = items[n];
3855
                        const char* item_category = ExampleNames[item_id % IM_ARRAYSIZE(ExampleNames)];
3856
                        char label[64];
3857
                        sprintf(label, "Object %05d: %s", item_id, item_category);
3858
3859
                        // IMPORTANT: for deletion refocus to work we need object ID to be stable,
3860
                        // aka not depend on their index in the list. Here we use our persistent item_id
3861
                        // instead of index to build a unique ID that will persist.
3862
                        // (If we used PushID(index) instead, focus wouldn't be restored correctly after deletion).
3863
                        ImGui::PushID(item_id);
3864
3865
                        // Emit a color button, to test that Shift+LeftArrow landing on an item that is not part
3866
                        // of the selection scope doesn't erroneously alter our selection.
3867
                        if (show_color_button)
3868
                        {
3869
                            ImU32 dummy_col = (ImU32)((unsigned int)n * 0xC250B74B) | IM_COL32_A_MASK;
3870
                            ImGui::ColorButton("##", ImColor(dummy_col), ImGuiColorEditFlags_NoTooltip, color_button_sz);
3871
                            ImGui::SameLine();
3872
                        }
3873
3874
                        // Submit item
3875
                        bool item_is_selected = selection.Contains((ImGuiID)n);
3876
                        bool item_is_open = false;
3877
                        ImGui::SetNextItemSelectionUserData(n);
3878
                        if (widget_type == WidgetType_Selectable)
3879
                        {
3880
                            ImGui::Selectable(label, item_is_selected, ImGuiSelectableFlags_None);
3881
                        }
3882
                        else if (widget_type == WidgetType_TreeNode)
3883
                        {
3884
                            ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;
3885
                            if (item_is_selected)
3886
                                tree_node_flags |= ImGuiTreeNodeFlags_Selected;
3887
                            item_is_open = ImGui::TreeNodeEx(label, tree_node_flags);
3888
                        }
3889
3890
                        // Focus (for after deletion)
3891
                        if (item_curr_idx_to_focus == n)
3892
                            ImGui::SetKeyboardFocusHere(-1);
3893
3894
                        // Drag and Drop
3895
                        if (use_drag_drop && ImGui::BeginDragDropSource())
3896
                        {
3897
                            // Create payload with full selection OR single unselected item.
3898
                            // (the later is only possible when using ImGuiMultiSelectFlags_SelectOnClickRelease)
3899
                            if (ImGui::GetDragDropPayload() == NULL)
3900
                            {
3901
                                ImVector<int> payload_items;
3902
                                void* it = NULL;
3903
                                ImGuiID id = 0;
3904
                                if (!item_is_selected)
3905
                                    payload_items.push_back(item_id);
3906
                                else
3907
                                    while (selection.GetNextSelectedItem(&it, &id))
3908
                                        payload_items.push_back((int)id);
3909
                                ImGui::SetDragDropPayload("MULTISELECT_DEMO_ITEMS", payload_items.Data, (size_t)payload_items.size_in_bytes());
3910
                            }
3911
3912
                            // Display payload content in tooltip
3913
                            const ImGuiPayload* payload = ImGui::GetDragDropPayload();
3914
                            const int* payload_items = (int*)payload->Data;
3915
                            const int payload_count = (int)payload->DataSize / (int)sizeof(int);
3916
                            if (payload_count == 1)
3917
                                ImGui::Text("Object %05d: %s", payload_items[0], ExampleNames[payload_items[0] % IM_ARRAYSIZE(ExampleNames)]);
3918
                            else
3919
                                ImGui::Text("Dragging %d objects", payload_count);
3920
3921
                            ImGui::EndDragDropSource();
3922
                        }
3923
3924
                        if (widget_type == WidgetType_TreeNode && item_is_open)
3925
                            ImGui::TreePop();
3926
3927
                        // Right-click: context menu
3928
                        if (ImGui::BeginPopupContextItem())
3929
                        {
3930
                            ImGui::BeginDisabled(!use_deletion || selection.Size == 0);
3931
                            sprintf(label, "Delete %d item(s)###DeleteSelected", selection.Size);
3932
                            if (ImGui::Selectable(label))
3933
                                request_deletion_from_menu = true;
3934
                            ImGui::EndDisabled();
3935
                            ImGui::Selectable("Close");
3936
                            ImGui::EndPopup();
3937
                        }
3938
3939
                        // Demo content within a table
3940
                        if (show_in_table)
3941
                        {
3942
                            ImGui::TableNextColumn();
3943
                            ImGui::SetNextItemWidth(-FLT_MIN);
3944
                            ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
3945
                            ImGui::InputText("###NoLabel", (char*)(void*)item_category, strlen(item_category), ImGuiInputTextFlags_ReadOnly);
3946
                            ImGui::PopStyleVar();
3947
                        }
3948
3949
                        ImGui::PopID();
3950
                    }
3951
                    if (!use_clipper)
3952
                        break;
3953
                }
3954
3955
                if (show_in_table)
3956
                {
3957
                    ImGui::EndTable();
3958
                    if (widget_type == WidgetType_TreeNode)
3959
                        ImGui::PopStyleVar();
3960
                }
3961
3962
                // Apply multi-select requests
3963
                ms_io = ImGui::EndMultiSelect();
3964
                selection.ApplyRequests(ms_io);
3965
                if (want_delete)
3966
                    selection.ApplyDeletionPostLoop(ms_io, items, item_curr_idx_to_focus);
3967
3968
                if (widget_type == WidgetType_TreeNode)
3969
                    ImGui::PopStyleVar();
3970
            }
3971
            ImGui::EndChild();
3972
            ImGui::TreePop();
3973
        }
3974
        ImGui::TreePop();
3975
    }
3976
}
3977
3978
//-----------------------------------------------------------------------------
3979
// [SECTION] ShowDemoWindowLayout()
3980
//-----------------------------------------------------------------------------
3981
3982
static void ShowDemoWindowLayout()
3983
{
3984
    IMGUI_DEMO_MARKER("Layout");
3985
    if (!ImGui::CollapsingHeader("Layout & Scrolling"))
3986
        return;
3987
3988
    IMGUI_DEMO_MARKER("Layout/Child windows");
3989
    if (ImGui::TreeNode("Child windows"))
3990
    {
3991
        ImGui::SeparatorText("Child windows");
3992
3993
        HelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window.");
3994
        static bool disable_mouse_wheel = false;
3995
        static bool disable_menu = false;
3996
        ImGui::Checkbox("Disable Mouse Wheel", &disable_mouse_wheel);
3997
        ImGui::Checkbox("Disable Menu", &disable_menu);
3998
3999
        // Child 1: no border, enable horizontal scrollbar
4000
        {
4001
            ImGuiWindowFlags window_flags = ImGuiWindowFlags_HorizontalScrollbar;
4002
            if (disable_mouse_wheel)
4003
                window_flags |= ImGuiWindowFlags_NoScrollWithMouse;
4004
            ImGui::BeginChild("ChildL", ImVec2(ImGui::GetContentRegionAvail().x * 0.5f, 260), ImGuiChildFlags_None, window_flags);
4005
            for (int i = 0; i < 100; i++)
4006
                ImGui::Text("%04d: scrollable region", i);
4007
            ImGui::EndChild();
4008
        }
4009
4010
        ImGui::SameLine();
4011
4012
        // Child 2: rounded border
4013
        {
4014
            ImGuiWindowFlags window_flags = ImGuiWindowFlags_None;
4015
            if (disable_mouse_wheel)
4016
                window_flags |= ImGuiWindowFlags_NoScrollWithMouse;
4017
            if (!disable_menu)
4018
                window_flags |= ImGuiWindowFlags_MenuBar;
4019
            ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f);
4020
            ImGui::BeginChild("ChildR", ImVec2(0, 260), ImGuiChildFlags_Borders, window_flags);
4021
            if (!disable_menu && ImGui::BeginMenuBar())
4022
            {
4023
                if (ImGui::BeginMenu("Menu"))
4024
                {
4025
                    ShowExampleMenuFile();
4026
                    ImGui::EndMenu();
4027
                }
4028
                ImGui::EndMenuBar();
4029
            }
4030
            if (ImGui::BeginTable("split", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings))
4031
            {
4032
                for (int i = 0; i < 100; i++)
4033
                {
4034
                    char buf[32];
4035
                    sprintf(buf, "%03d", i);
4036
                    ImGui::TableNextColumn();
4037
                    ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f));
4038
                }
4039
                ImGui::EndTable();
4040
            }
4041
            ImGui::EndChild();
4042
            ImGui::PopStyleVar();
4043
        }
4044
4045
        // Child 3: manual-resize
4046
        ImGui::SeparatorText("Manual-resize");
4047
        {
4048
            HelpMarker("Drag bottom border to resize. Double-click bottom border to auto-fit to vertical contents.");
4049
            //if (ImGui::Button("Set Height to 200"))
4050
            //    ImGui::SetNextWindowSize(ImVec2(-FLT_MIN, 200.0f));
4051
4052
            ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyleColorVec4(ImGuiCol_FrameBg));
4053
            if (ImGui::BeginChild("ResizableChild", ImVec2(-FLT_MIN, ImGui::GetTextLineHeightWithSpacing() * 8), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeY))
4054
                for (int n = 0; n < 10; n++)
4055
                    ImGui::Text("Line %04d", n);
4056
            ImGui::PopStyleColor();
4057
            ImGui::EndChild();
4058
        }
4059
4060
        // Child 4: auto-resizing height with a limit
4061
        ImGui::SeparatorText("Auto-resize with constraints");
4062
        {
4063
            static int draw_lines = 3;
4064
            static int max_height_in_lines = 10;
4065
            ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
4066
            ImGui::DragInt("Lines Count", &draw_lines, 0.2f);
4067
            ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
4068
            ImGui::DragInt("Max Height (in Lines)", &max_height_in_lines, 0.2f);
4069
4070
            ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 1), ImVec2(FLT_MAX, ImGui::GetTextLineHeightWithSpacing() * max_height_in_lines));
4071
            if (ImGui::BeginChild("ConstrainedChild", ImVec2(-FLT_MIN, 0.0f), ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeY))
4072
                for (int n = 0; n < draw_lines; n++)
4073
                    ImGui::Text("Line %04d", n);
4074
            ImGui::EndChild();
4075
        }
4076
4077
        ImGui::SeparatorText("Misc/Advanced");
4078
4079
        // Demonstrate a few extra things
4080
        // - Changing ImGuiCol_ChildBg (which is transparent black in default styles)
4081
        // - Using SetCursorPos() to position child window (the child window is an item from the POV of parent window)
4082
        //   You can also call SetNextWindowPos() to position the child window. The parent window will effectively
4083
        //   layout from this position.
4084
        // - Using ImGui::GetItemRectMin/Max() to query the "item" state (because the child window is an item from
4085
        //   the POV of the parent window). See 'Demo->Querying Status (Edited/Active/Hovered etc.)' for details.
4086
        {
4087
            static int offset_x = 0;
4088
            static bool override_bg_color = true;
4089
            static ImGuiChildFlags child_flags = ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY;
4090
            ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
4091
            ImGui::DragInt("Offset X", &offset_x, 1.0f, -1000, 1000);
4092
            ImGui::Checkbox("Override ChildBg color", &override_bg_color);
4093
            ImGui::CheckboxFlags("ImGuiChildFlags_Borders", &child_flags, ImGuiChildFlags_Borders);
4094
            ImGui::CheckboxFlags("ImGuiChildFlags_AlwaysUseWindowPadding", &child_flags, ImGuiChildFlags_AlwaysUseWindowPadding);
4095
            ImGui::CheckboxFlags("ImGuiChildFlags_ResizeX", &child_flags, ImGuiChildFlags_ResizeX);
4096
            ImGui::CheckboxFlags("ImGuiChildFlags_ResizeY", &child_flags, ImGuiChildFlags_ResizeY);
4097
            ImGui::CheckboxFlags("ImGuiChildFlags_FrameStyle", &child_flags, ImGuiChildFlags_FrameStyle);
4098
            ImGui::SameLine(); HelpMarker("Style the child window like a framed item: use FrameBg, FrameRounding, FrameBorderSize, FramePadding instead of ChildBg, ChildRounding, ChildBorderSize, WindowPadding.");
4099
            if (child_flags & ImGuiChildFlags_FrameStyle)
4100
                override_bg_color = false;
4101
4102
            ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (float)offset_x);
4103
            if (override_bg_color)
4104
                ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(255, 0, 0, 100));
4105
            ImGui::BeginChild("Red", ImVec2(200, 100), child_flags, ImGuiWindowFlags_None);
4106
            if (override_bg_color)
4107
                ImGui::PopStyleColor();
4108
4109
            for (int n = 0; n < 50; n++)
4110
                ImGui::Text("Some test %d", n);
4111
            ImGui::EndChild();
4112
            bool child_is_hovered = ImGui::IsItemHovered();
4113
            ImVec2 child_rect_min = ImGui::GetItemRectMin();
4114
            ImVec2 child_rect_max = ImGui::GetItemRectMax();
4115
            ImGui::Text("Hovered: %d", child_is_hovered);
4116
            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);
4117
        }
4118
4119
        ImGui::TreePop();
4120
    }
4121
4122
    IMGUI_DEMO_MARKER("Layout/Widgets Width");
4123
    if (ImGui::TreeNode("Widgets Width"))
4124
    {
4125
        static float f = 0.0f;
4126
        static bool show_indented_items = true;
4127
        ImGui::Checkbox("Show indented items", &show_indented_items);
4128
4129
        // Use SetNextItemWidth() to set the width of a single upcoming item.
4130
        // Use PushItemWidth()/PopItemWidth() to set the width of a group of items.
4131
        // In real code use you'll probably want to choose width values that are proportional to your font size
4132
        // e.g. Using '20.0f * GetFontSize()' as width instead of '200.0f', etc.
4133
4134
        ImGui::Text("SetNextItemWidth/PushItemWidth(100)");
4135
        ImGui::SameLine(); HelpMarker("Fixed width.");
4136
        ImGui::PushItemWidth(100);
4137
        ImGui::DragFloat("float##1b", &f);
4138
        if (show_indented_items)
4139
        {
4140
            ImGui::Indent();
4141
            ImGui::DragFloat("float (indented)##1b", &f);
4142
            ImGui::Unindent();
4143
        }
4144
        ImGui::PopItemWidth();
4145
4146
        ImGui::Text("SetNextItemWidth/PushItemWidth(-100)");
4147
        ImGui::SameLine(); HelpMarker("Align to right edge minus 100");
4148
        ImGui::PushItemWidth(-100);
4149
        ImGui::DragFloat("float##2a", &f);
4150
        if (show_indented_items)
4151
        {
4152
            ImGui::Indent();
4153
            ImGui::DragFloat("float (indented)##2b", &f);
4154
            ImGui::Unindent();
4155
        }
4156
        ImGui::PopItemWidth();
4157
4158
        ImGui::Text("SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)");
4159
        ImGui::SameLine(); HelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)");
4160
        ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * 0.5f);
4161
        ImGui::DragFloat("float##3a", &f);
4162
        if (show_indented_items)
4163
        {
4164
            ImGui::Indent();
4165
            ImGui::DragFloat("float (indented)##3b", &f);
4166
            ImGui::Unindent();
4167
        }
4168
        ImGui::PopItemWidth();
4169
4170
        ImGui::Text("SetNextItemWidth/PushItemWidth(-GetContentRegionAvail().x * 0.5f)");
4171
        ImGui::SameLine(); HelpMarker("Align to right edge minus half");
4172
        ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.5f);
4173
        ImGui::DragFloat("float##4a", &f);
4174
        if (show_indented_items)
4175
        {
4176
            ImGui::Indent();
4177
            ImGui::DragFloat("float (indented)##4b", &f);
4178
            ImGui::Unindent();
4179
        }
4180
        ImGui::PopItemWidth();
4181
4182
        // Demonstrate using PushItemWidth to surround three items.
4183
        // Calling SetNextItemWidth() before each of them would have the same effect.
4184
        ImGui::Text("SetNextItemWidth/PushItemWidth(-FLT_MIN)");
4185
        ImGui::SameLine(); HelpMarker("Align to right edge");
4186
        ImGui::PushItemWidth(-FLT_MIN);
4187
        ImGui::DragFloat("##float5a", &f);
4188
        if (show_indented_items)
4189
        {
4190
            ImGui::Indent();
4191
            ImGui::DragFloat("float (indented)##5b", &f);
4192
            ImGui::Unindent();
4193
        }
4194
        ImGui::PopItemWidth();
4195
4196
        ImGui::TreePop();
4197
    }
4198
4199
    IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout");
4200
    if (ImGui::TreeNode("Basic Horizontal Layout"))
4201
    {
4202
        ImGui::TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)");
4203
4204
        // Text
4205
        IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine");
4206
        ImGui::Text("Two items: Hello"); ImGui::SameLine();
4207
        ImGui::TextColored(ImVec4(1, 1, 0, 1), "Sailor");
4208
4209
        // Adjust spacing
4210
        ImGui::Text("More spacing: Hello"); ImGui::SameLine(0, 20);
4211
        ImGui::TextColored(ImVec4(1, 1, 0, 1), "Sailor");
4212
4213
        // Button
4214
        ImGui::AlignTextToFramePadding();
4215
        ImGui::Text("Normal buttons"); ImGui::SameLine();
4216
        ImGui::Button("Banana"); ImGui::SameLine();
4217
        ImGui::Button("Apple"); ImGui::SameLine();
4218
        ImGui::Button("Corniflower");
4219
4220
        // Button
4221
        ImGui::Text("Small buttons"); ImGui::SameLine();
4222
        ImGui::SmallButton("Like this one"); ImGui::SameLine();
4223
        ImGui::Text("can fit within a text block.");
4224
4225
        // Aligned to arbitrary position. Easy/cheap column.
4226
        IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (with offset)");
4227
        ImGui::Text("Aligned");
4228
        ImGui::SameLine(150); ImGui::Text("x=150");
4229
        ImGui::SameLine(300); ImGui::Text("x=300");
4230
        ImGui::Text("Aligned");
4231
        ImGui::SameLine(150); ImGui::SmallButton("x=150");
4232
        ImGui::SameLine(300); ImGui::SmallButton("x=300");
4233
4234
        // Checkbox
4235
        IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (more)");
4236
        static bool c1 = false, c2 = false, c3 = false, c4 = false;
4237
        ImGui::Checkbox("My", &c1); ImGui::SameLine();
4238
        ImGui::Checkbox("Tailor", &c2); ImGui::SameLine();
4239
        ImGui::Checkbox("Is", &c3); ImGui::SameLine();
4240
        ImGui::Checkbox("Rich", &c4);
4241
4242
        // Various
4243
        static float f0 = 1.0f, f1 = 2.0f, f2 = 3.0f;
4244
        ImGui::PushItemWidth(80);
4245
        const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD" };
4246
        static int item = -1;
4247
        ImGui::Combo("Combo", &item, items, IM_ARRAYSIZE(items)); ImGui::SameLine();
4248
        ImGui::SliderFloat("X", &f0, 0.0f, 5.0f); ImGui::SameLine();
4249
        ImGui::SliderFloat("Y", &f1, 0.0f, 5.0f); ImGui::SameLine();
4250
        ImGui::SliderFloat("Z", &f2, 0.0f, 5.0f);
4251
        ImGui::PopItemWidth();
4252
4253
        ImGui::PushItemWidth(80);
4254
        ImGui::Text("Lists:");
4255
        static int selection[4] = { 0, 1, 2, 3 };
4256
        for (int i = 0; i < 4; i++)
4257
        {
4258
            if (i > 0) ImGui::SameLine();
4259
            ImGui::PushID(i);
4260
            ImGui::ListBox("", &selection[i], items, IM_ARRAYSIZE(items));
4261
            ImGui::PopID();
4262
            //ImGui::SetItemTooltip("ListBox %d hovered", i);
4263
        }
4264
        ImGui::PopItemWidth();
4265
4266
        // Dummy
4267
        IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Dummy");
4268
        ImVec2 button_sz(40, 40);
4269
        ImGui::Button("A", button_sz); ImGui::SameLine();
4270
        ImGui::Dummy(button_sz); ImGui::SameLine();
4271
        ImGui::Button("B", button_sz);
4272
4273
        // Manually wrapping
4274
        // (we should eventually provide this as an automatic layout feature, but for now you can do it manually)
4275
        IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Manual wrapping");
4276
        ImGui::Text("Manual wrapping:");
4277
        ImGuiStyle& style = ImGui::GetStyle();
4278
        int buttons_count = 20;
4279
        float window_visible_x2 = ImGui::GetCursorScreenPos().x + ImGui::GetContentRegionAvail().x;
4280
        for (int n = 0; n < buttons_count; n++)
4281
        {
4282
            ImGui::PushID(n);
4283
            ImGui::Button("Box", button_sz);
4284
            float last_button_x2 = ImGui::GetItemRectMax().x;
4285
            float next_button_x2 = last_button_x2 + style.ItemSpacing.x + button_sz.x; // Expected position if next button was on same line
4286
            if (n + 1 < buttons_count && next_button_x2 < window_visible_x2)
4287
                ImGui::SameLine();
4288
            ImGui::PopID();
4289
        }
4290
4291
        ImGui::TreePop();
4292
    }
4293
4294
    IMGUI_DEMO_MARKER("Layout/Groups");
4295
    if (ImGui::TreeNode("Groups"))
4296
    {
4297
        HelpMarker(
4298
            "BeginGroup() basically locks the horizontal position for new line. "
4299
            "EndGroup() bundles the whole group so that you can use \"item\" functions such as "
4300
            "IsItemHovered()/IsItemActive() or SameLine() etc. on the whole group.");
4301
        ImGui::BeginGroup();
4302
        {
4303
            ImGui::BeginGroup();
4304
            ImGui::Button("AAA");
4305
            ImGui::SameLine();
4306
            ImGui::Button("BBB");
4307
            ImGui::SameLine();
4308
            ImGui::BeginGroup();
4309
            ImGui::Button("CCC");
4310
            ImGui::Button("DDD");
4311
            ImGui::EndGroup();
4312
            ImGui::SameLine();
4313
            ImGui::Button("EEE");
4314
            ImGui::EndGroup();
4315
            ImGui::SetItemTooltip("First group hovered");
4316
        }
4317
        // Capture the group size and create widgets using the same size
4318
        ImVec2 size = ImGui::GetItemRectSize();
4319
        const float values[5] = { 0.5f, 0.20f, 0.80f, 0.60f, 0.25f };
4320
        ImGui::PlotHistogram("##values", values, IM_ARRAYSIZE(values), 0, NULL, 0.0f, 1.0f, size);
4321
4322
        ImGui::Button("ACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y));
4323
        ImGui::SameLine();
4324
        ImGui::Button("REACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y));
4325
        ImGui::EndGroup();
4326
        ImGui::SameLine();
4327
4328
        ImGui::Button("LEVERAGE\nBUZZWORD", size);
4329
        ImGui::SameLine();
4330
4331
        if (ImGui::BeginListBox("List", size))
4332
        {
4333
            ImGui::Selectable("Selected", true);
4334
            ImGui::Selectable("Not Selected", false);
4335
            ImGui::EndListBox();
4336
        }
4337
4338
        ImGui::TreePop();
4339
    }
4340
4341
    IMGUI_DEMO_MARKER("Layout/Text Baseline Alignment");
4342
    if (ImGui::TreeNode("Text Baseline Alignment"))
4343
    {
4344
        {
4345
            ImGui::BulletText("Text baseline:");
4346
            ImGui::SameLine(); HelpMarker(
4347
                "This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. "
4348
                "Lines only composed of text or \"small\" widgets use less vertical space than lines with framed widgets.");
4349
            ImGui::Indent();
4350
4351
            ImGui::Text("KO Blahblah"); ImGui::SameLine();
4352
            ImGui::Button("Some framed item"); ImGui::SameLine();
4353
            HelpMarker("Baseline of button will look misaligned with text..");
4354
4355
            // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets.
4356
            // (because we don't know what's coming after the Text() statement, we need to move the text baseline
4357
            // down by FramePadding.y ahead of time)
4358
            ImGui::AlignTextToFramePadding();
4359
            ImGui::Text("OK Blahblah"); ImGui::SameLine();
4360
            ImGui::Button("Some framed item##2"); ImGui::SameLine();
4361
            HelpMarker("We call AlignTextToFramePadding() to vertically align the text baseline by +FramePadding.y");
4362
4363
            // SmallButton() uses the same vertical padding as Text
4364
            ImGui::Button("TEST##1"); ImGui::SameLine();
4365
            ImGui::Text("TEST"); ImGui::SameLine();
4366
            ImGui::SmallButton("TEST##2");
4367
4368
            // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets.
4369
            ImGui::AlignTextToFramePadding();
4370
            ImGui::Text("Text aligned to framed item"); ImGui::SameLine();
4371
            ImGui::Button("Item##1"); ImGui::SameLine();
4372
            ImGui::Text("Item"); ImGui::SameLine();
4373
            ImGui::SmallButton("Item##2"); ImGui::SameLine();
4374
            ImGui::Button("Item##3");
4375
4376
            ImGui::Unindent();
4377
        }
4378
4379
        ImGui::Spacing();
4380
4381
        {
4382
            ImGui::BulletText("Multi-line text:");
4383
            ImGui::Indent();
4384
            ImGui::Text("One\nTwo\nThree"); ImGui::SameLine();
4385
            ImGui::Text("Hello\nWorld"); ImGui::SameLine();
4386
            ImGui::Text("Banana");
4387
4388
            ImGui::Text("Banana"); ImGui::SameLine();
4389
            ImGui::Text("Hello\nWorld"); ImGui::SameLine();
4390
            ImGui::Text("One\nTwo\nThree");
4391
4392
            ImGui::Button("HOP##1"); ImGui::SameLine();
4393
            ImGui::Text("Banana"); ImGui::SameLine();
4394
            ImGui::Text("Hello\nWorld"); ImGui::SameLine();
4395
            ImGui::Text("Banana");
4396
4397
            ImGui::Button("HOP##2"); ImGui::SameLine();
4398
            ImGui::Text("Hello\nWorld"); ImGui::SameLine();
4399
            ImGui::Text("Banana");
4400
            ImGui::Unindent();
4401
        }
4402
4403
        ImGui::Spacing();
4404
4405
        {
4406
            ImGui::BulletText("Misc items:");
4407
            ImGui::Indent();
4408
4409
            // SmallButton() sets FramePadding to zero. Text baseline is aligned to match baseline of previous Button.
4410
            ImGui::Button("80x80", ImVec2(80, 80));
4411
            ImGui::SameLine();
4412
            ImGui::Button("50x50", ImVec2(50, 50));
4413
            ImGui::SameLine();
4414
            ImGui::Button("Button()");
4415
            ImGui::SameLine();
4416
            ImGui::SmallButton("SmallButton()");
4417
4418
            // Tree
4419
            const float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
4420
            ImGui::Button("Button##1");
4421
            ImGui::SameLine(0.0f, spacing);
4422
            if (ImGui::TreeNode("Node##1"))
4423
            {
4424
                // Placeholder tree data
4425
                for (int i = 0; i < 6; i++)
4426
                    ImGui::BulletText("Item %d..", i);
4427
                ImGui::TreePop();
4428
            }
4429
4430
            // Vertically align text node a bit lower so it'll be vertically centered with upcoming widget.
4431
            // Otherwise you can use SmallButton() (smaller fit).
4432
            ImGui::AlignTextToFramePadding();
4433
4434
            // Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add
4435
            // other contents below the node.
4436
            bool node_open = ImGui::TreeNode("Node##2");
4437
            ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##2");
4438
            if (node_open)
4439
            {
4440
                // Placeholder tree data
4441
                for (int i = 0; i < 6; i++)
4442
                    ImGui::BulletText("Item %d..", i);
4443
                ImGui::TreePop();
4444
            }
4445
4446
            // Bullet
4447
            ImGui::Button("Button##3");
4448
            ImGui::SameLine(0.0f, spacing);
4449
            ImGui::BulletText("Bullet text");
4450
4451
            ImGui::AlignTextToFramePadding();
4452
            ImGui::BulletText("Node");
4453
            ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##4");
4454
            ImGui::Unindent();
4455
        }
4456
4457
        ImGui::TreePop();
4458
    }
4459
4460
    IMGUI_DEMO_MARKER("Layout/Scrolling");
4461
    if (ImGui::TreeNode("Scrolling"))
4462
    {
4463
        // Vertical scroll functions
4464
        IMGUI_DEMO_MARKER("Layout/Scrolling/Vertical");
4465
        HelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given vertical position.");
4466
4467
        static int track_item = 50;
4468
        static bool enable_track = true;
4469
        static bool enable_extra_decorations = false;
4470
        static float scroll_to_off_px = 0.0f;
4471
        static float scroll_to_pos_px = 200.0f;
4472
4473
        ImGui::Checkbox("Decoration", &enable_extra_decorations);
4474
4475
        ImGui::Checkbox("Track", &enable_track);
4476
        ImGui::PushItemWidth(100);
4477
        ImGui::SameLine(140); enable_track |= ImGui::DragInt("##item", &track_item, 0.25f, 0, 99, "Item = %d");
4478
4479
        bool scroll_to_off = ImGui::Button("Scroll Offset");
4480
        ImGui::SameLine(140); scroll_to_off |= ImGui::DragFloat("##off", &scroll_to_off_px, 1.00f, 0, FLT_MAX, "+%.0f px");
4481
4482
        bool scroll_to_pos = ImGui::Button("Scroll To Pos");
4483
        ImGui::SameLine(140); scroll_to_pos |= ImGui::DragFloat("##pos", &scroll_to_pos_px, 1.00f, -10, FLT_MAX, "X/Y = %.0f px");
4484
        ImGui::PopItemWidth();
4485
4486
        if (scroll_to_off || scroll_to_pos)
4487
            enable_track = false;
4488
4489
        ImGuiStyle& style = ImGui::GetStyle();
4490
        float child_w = (ImGui::GetContentRegionAvail().x - 4 * style.ItemSpacing.x) / 5;
4491
        if (child_w < 1.0f)
4492
            child_w = 1.0f;
4493
        ImGui::PushID("##VerticalScrolling");
4494
        for (int i = 0; i < 5; i++)
4495
        {
4496
            if (i > 0) ImGui::SameLine();
4497
            ImGui::BeginGroup();
4498
            const char* names[] = { "Top", "25%", "Center", "75%", "Bottom" };
4499
            ImGui::TextUnformatted(names[i]);
4500
4501
            const ImGuiWindowFlags child_flags = enable_extra_decorations ? ImGuiWindowFlags_MenuBar : 0;
4502
            const ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i);
4503
            const bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(child_w, 200.0f), ImGuiChildFlags_Borders, child_flags);
4504
            if (ImGui::BeginMenuBar())
4505
            {
4506
                ImGui::TextUnformatted("abc");
4507
                ImGui::EndMenuBar();
4508
            }
4509
            if (scroll_to_off)
4510
                ImGui::SetScrollY(scroll_to_off_px);
4511
            if (scroll_to_pos)
4512
                ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_pos_px, i * 0.25f);
4513
            if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items
4514
            {
4515
                for (int item = 0; item < 100; item++)
4516
                {
4517
                    if (enable_track && item == track_item)
4518
                    {
4519
                        ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item);
4520
                        ImGui::SetScrollHereY(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom
4521
                    }
4522
                    else
4523
                    {
4524
                        ImGui::Text("Item %d", item);
4525
                    }
4526
                }
4527
            }
4528
            float scroll_y = ImGui::GetScrollY();
4529
            float scroll_max_y = ImGui::GetScrollMaxY();
4530
            ImGui::EndChild();
4531
            ImGui::Text("%.0f/%.0f", scroll_y, scroll_max_y);
4532
            ImGui::EndGroup();
4533
        }
4534
        ImGui::PopID();
4535
4536
        // Horizontal scroll functions
4537
        IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal");
4538
        ImGui::Spacing();
4539
        HelpMarker(
4540
            "Use SetScrollHereX() or SetScrollFromPosX() to scroll to a given horizontal position.\n\n"
4541
            "Because the clipping rectangle of most window hides half worth of WindowPadding on the "
4542
            "left/right, using SetScrollFromPosX(+1) will usually result in clipped text whereas the "
4543
            "equivalent SetScrollFromPosY(+1) wouldn't.");
4544
        ImGui::PushID("##HorizontalScrolling");
4545
        for (int i = 0; i < 5; i++)
4546
        {
4547
            float child_height = ImGui::GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0f;
4548
            ImGuiWindowFlags child_flags = ImGuiWindowFlags_HorizontalScrollbar | (enable_extra_decorations ? ImGuiWindowFlags_AlwaysVerticalScrollbar : 0);
4549
            ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i);
4550
            bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(-100, child_height), ImGuiChildFlags_Borders, child_flags);
4551
            if (scroll_to_off)
4552
                ImGui::SetScrollX(scroll_to_off_px);
4553
            if (scroll_to_pos)
4554
                ImGui::SetScrollFromPosX(ImGui::GetCursorStartPos().x + scroll_to_pos_px, i * 0.25f);
4555
            if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items
4556
            {
4557
                for (int item = 0; item < 100; item++)
4558
                {
4559
                    if (item > 0)
4560
                        ImGui::SameLine();
4561
                    if (enable_track && item == track_item)
4562
                    {
4563
                        ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item);
4564
                        ImGui::SetScrollHereX(i * 0.25f); // 0.0f:left, 0.5f:center, 1.0f:right
4565
                    }
4566
                    else
4567
                    {
4568
                        ImGui::Text("Item %d", item);
4569
                    }
4570
                }
4571
            }
4572
            float scroll_x = ImGui::GetScrollX();
4573
            float scroll_max_x = ImGui::GetScrollMaxX();
4574
            ImGui::EndChild();
4575
            ImGui::SameLine();
4576
            const char* names[] = { "Left", "25%", "Center", "75%", "Right" };
4577
            ImGui::Text("%s\n%.0f/%.0f", names[i], scroll_x, scroll_max_x);
4578
            ImGui::Spacing();
4579
        }
4580
        ImGui::PopID();
4581
4582
        // Miscellaneous Horizontal Scrolling Demo
4583
        IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal (more)");
4584
        HelpMarker(
4585
            "Horizontal scrolling for a window is enabled via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\n"
4586
            "You may want to also explicitly specify content width by using SetNextWindowContentWidth() before Begin().");
4587
        static int lines = 7;
4588
        ImGui::SliderInt("Lines", &lines, 1, 15);
4589
        ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
4590
        ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f));
4591
        ImVec2 scrolling_child_size = ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30);
4592
        ImGui::BeginChild("scrolling", scrolling_child_size, ImGuiChildFlags_Borders, ImGuiWindowFlags_HorizontalScrollbar);
4593
        for (int line = 0; line < lines; line++)
4594
        {
4595
            // Display random stuff. For the sake of this trivial demo we are using basic Button() + SameLine()
4596
            // If you want to create your own time line for a real application you may be better off manipulating
4597
            // the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets
4598
            // yourself. You may also want to use the lower-level ImDrawList API.
4599
            int num_buttons = 10 + ((line & 1) ? line * 9 : line * 3);
4600
            for (int n = 0; n < num_buttons; n++)
4601
            {
4602
                if (n > 0) ImGui::SameLine();
4603
                ImGui::PushID(n + line * 1000);
4604
                char num_buf[16];
4605
                sprintf(num_buf, "%d", n);
4606
                const char* label = (!(n % 15)) ? "FizzBuzz" : (!(n % 3)) ? "Fizz" : (!(n % 5)) ? "Buzz" : num_buf;
4607
                float hue = n * 0.05f;
4608
                ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(hue, 0.6f, 0.6f));
4609
                ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(hue, 0.7f, 0.7f));
4610
                ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(hue, 0.8f, 0.8f));
4611
                ImGui::Button(label, ImVec2(40.0f + sinf((float)(line + n)) * 20.0f, 0.0f));
4612
                ImGui::PopStyleColor(3);
4613
                ImGui::PopID();
4614
            }
4615
        }
4616
        float scroll_x = ImGui::GetScrollX();
4617
        float scroll_max_x = ImGui::GetScrollMaxX();
4618
        ImGui::EndChild();
4619
        ImGui::PopStyleVar(2);
4620
        float scroll_x_delta = 0.0f;
4621
        ImGui::SmallButton("<<");
4622
        if (ImGui::IsItemActive())
4623
            scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f;
4624
        ImGui::SameLine();
4625
        ImGui::Text("Scroll from code"); ImGui::SameLine();
4626
        ImGui::SmallButton(">>");
4627
        if (ImGui::IsItemActive())
4628
            scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f;
4629
        ImGui::SameLine();
4630
        ImGui::Text("%.0f/%.0f", scroll_x, scroll_max_x);
4631
        if (scroll_x_delta != 0.0f)
4632
        {
4633
            // Demonstrate a trick: you can use Begin to set yourself in the context of another window
4634
            // (here we are already out of your child window)
4635
            ImGui::BeginChild("scrolling");
4636
            ImGui::SetScrollX(ImGui::GetScrollX() + scroll_x_delta);
4637
            ImGui::EndChild();
4638
        }
4639
        ImGui::Spacing();
4640
4641
        static bool show_horizontal_contents_size_demo_window = false;
4642
        ImGui::Checkbox("Show Horizontal contents size demo window", &show_horizontal_contents_size_demo_window);
4643
4644
        if (show_horizontal_contents_size_demo_window)
4645
        {
4646
            static bool show_h_scrollbar = true;
4647
            static bool show_button = true;
4648
            static bool show_tree_nodes = true;
4649
            static bool show_text_wrapped = false;
4650
            static bool show_columns = true;
4651
            static bool show_tab_bar = true;
4652
            static bool show_child = false;
4653
            static bool explicit_content_size = false;
4654
            static float contents_size_x = 300.0f;
4655
            if (explicit_content_size)
4656
                ImGui::SetNextWindowContentSize(ImVec2(contents_size_x, 0.0f));
4657
            ImGui::Begin("Horizontal contents size demo window", &show_horizontal_contents_size_demo_window, show_h_scrollbar ? ImGuiWindowFlags_HorizontalScrollbar : 0);
4658
            IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal contents size demo window");
4659
            ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 0));
4660
            ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 0));
4661
            HelpMarker(
4662
                "Test how different widgets react and impact the work rectangle growing when horizontal scrolling is enabled.\n\n"
4663
                "Use 'Metrics->Tools->Show windows rectangles' to visualize rectangles.");
4664
            ImGui::Checkbox("H-scrollbar", &show_h_scrollbar);
4665
            ImGui::Checkbox("Button", &show_button);            // Will grow contents size (unless explicitly overwritten)
4666
            ImGui::Checkbox("Tree nodes", &show_tree_nodes);    // Will grow contents size and display highlight over full width
4667
            ImGui::Checkbox("Text wrapped", &show_text_wrapped);// Will grow and use contents size
4668
            ImGui::Checkbox("Columns", &show_columns);          // Will use contents size
4669
            ImGui::Checkbox("Tab bar", &show_tab_bar);          // Will use contents size
4670
            ImGui::Checkbox("Child", &show_child);              // Will grow and use contents size
4671
            ImGui::Checkbox("Explicit content size", &explicit_content_size);
4672
            ImGui::Text("Scroll %.1f/%.1f %.1f/%.1f", ImGui::GetScrollX(), ImGui::GetScrollMaxX(), ImGui::GetScrollY(), ImGui::GetScrollMaxY());
4673
            if (explicit_content_size)
4674
            {
4675
                ImGui::SameLine();
4676
                ImGui::SetNextItemWidth(100);
4677
                ImGui::DragFloat("##csx", &contents_size_x);
4678
                ImVec2 p = ImGui::GetCursorScreenPos();
4679
                ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + 10, p.y + 10), IM_COL32_WHITE);
4680
                ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(p.x + contents_size_x - 10, p.y), ImVec2(p.x + contents_size_x, p.y + 10), IM_COL32_WHITE);
4681
                ImGui::Dummy(ImVec2(0, 10));
4682
            }
4683
            ImGui::PopStyleVar(2);
4684
            ImGui::Separator();
4685
            if (show_button)
4686
            {
4687
                ImGui::Button("this is a 300-wide button", ImVec2(300, 0));
4688
            }
4689
            if (show_tree_nodes)
4690
            {
4691
                bool open = true;
4692
                if (ImGui::TreeNode("this is a tree node"))
4693
                {
4694
                    if (ImGui::TreeNode("another one of those tree node..."))
4695
                    {
4696
                        ImGui::Text("Some tree contents");
4697
                        ImGui::TreePop();
4698
                    }
4699
                    ImGui::TreePop();
4700
                }
4701
                ImGui::CollapsingHeader("CollapsingHeader", &open);
4702
            }
4703
            if (show_text_wrapped)
4704
            {
4705
                ImGui::TextWrapped("This text should automatically wrap on the edge of the work rectangle.");
4706
            }
4707
            if (show_columns)
4708
            {
4709
                ImGui::Text("Tables:");
4710
                if (ImGui::BeginTable("table", 4, ImGuiTableFlags_Borders))
4711
                {
4712
                    for (int n = 0; n < 4; n++)
4713
                    {
4714
                        ImGui::TableNextColumn();
4715
                        ImGui::Text("Width %.2f", ImGui::GetContentRegionAvail().x);
4716
                    }
4717
                    ImGui::EndTable();
4718
                }
4719
                ImGui::Text("Columns:");
4720
                ImGui::Columns(4);
4721
                for (int n = 0; n < 4; n++)
4722
                {
4723
                    ImGui::Text("Width %.2f", ImGui::GetColumnWidth());
4724
                    ImGui::NextColumn();
4725
                }
4726
                ImGui::Columns(1);
4727
            }
4728
            if (show_tab_bar && ImGui::BeginTabBar("Hello"))
4729
            {
4730
                if (ImGui::BeginTabItem("OneOneOne")) { ImGui::EndTabItem(); }
4731
                if (ImGui::BeginTabItem("TwoTwoTwo")) { ImGui::EndTabItem(); }
4732
                if (ImGui::BeginTabItem("ThreeThreeThree")) { ImGui::EndTabItem(); }
4733
                if (ImGui::BeginTabItem("FourFourFour")) { ImGui::EndTabItem(); }
4734
                ImGui::EndTabBar();
4735
            }
4736
            if (show_child)
4737
            {
4738
                ImGui::BeginChild("child", ImVec2(0, 0), ImGuiChildFlags_Borders);
4739
                ImGui::EndChild();
4740
            }
4741
            ImGui::End();
4742
        }
4743
4744
        ImGui::TreePop();
4745
    }
4746
4747
    IMGUI_DEMO_MARKER("Layout/Text Clipping");
4748
    if (ImGui::TreeNode("Text Clipping"))
4749
    {
4750
        static ImVec2 size(100.0f, 100.0f);
4751
        static ImVec2 offset(30.0f, 30.0f);
4752
        ImGui::DragFloat2("size", (float*)&size, 0.5f, 1.0f, 200.0f, "%.0f");
4753
        ImGui::TextWrapped("(Click and drag to scroll)");
4754
4755
        HelpMarker(
4756
            "(Left) Using ImGui::PushClipRect():\n"
4757
            "Will alter ImGui hit-testing logic + ImDrawList rendering.\n"
4758
            "(use this if you want your clipping rectangle to affect interactions)\n\n"
4759
            "(Center) Using ImDrawList::PushClipRect():\n"
4760
            "Will alter ImDrawList rendering only.\n"
4761
            "(use this as a shortcut if you are only using ImDrawList calls)\n\n"
4762
            "(Right) Using ImDrawList::AddText() with a fine ClipRect:\n"
4763
            "Will alter only this specific ImDrawList::AddText() rendering.\n"
4764
            "This is often used internally to avoid altering the clipping rectangle and minimize draw calls.");
4765
4766
        for (int n = 0; n < 3; n++)
4767
        {
4768
            if (n > 0)
4769
                ImGui::SameLine();
4770
4771
            ImGui::PushID(n);
4772
            ImGui::InvisibleButton("##canvas", size);
4773
            if (ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left))
4774
            {
4775
                offset.x += ImGui::GetIO().MouseDelta.x;
4776
                offset.y += ImGui::GetIO().MouseDelta.y;
4777
            }
4778
            ImGui::PopID();
4779
            if (!ImGui::IsItemVisible()) // Skip rendering as ImDrawList elements are not clipped.
4780
                continue;
4781
4782
            const ImVec2 p0 = ImGui::GetItemRectMin();
4783
            const ImVec2 p1 = ImGui::GetItemRectMax();
4784
            const char* text_str = "Line 1 hello\nLine 2 clip me!";
4785
            const ImVec2 text_pos = ImVec2(p0.x + offset.x, p0.y + offset.y);
4786
            ImDrawList* draw_list = ImGui::GetWindowDrawList();
4787
            switch (n)
4788
            {
4789
            case 0:
4790
                ImGui::PushClipRect(p0, p1, true);
4791
                draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
4792
                draw_list->AddText(text_pos, IM_COL32_WHITE, text_str);
4793
                ImGui::PopClipRect();
4794
                break;
4795
            case 1:
4796
                draw_list->PushClipRect(p0, p1, true);
4797
                draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
4798
                draw_list->AddText(text_pos, IM_COL32_WHITE, text_str);
4799
                draw_list->PopClipRect();
4800
                break;
4801
            case 2:
4802
                ImVec4 clip_rect(p0.x, p0.y, p1.x, p1.y); // AddText() takes a ImVec4* here so let's convert.
4803
                draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
4804
                draw_list->AddText(ImGui::GetFont(), ImGui::GetFontSize(), text_pos, IM_COL32_WHITE, text_str, NULL, 0.0f, &clip_rect);
4805
                break;
4806
            }
4807
        }
4808
4809
        ImGui::TreePop();
4810
    }
4811
4812
    IMGUI_DEMO_MARKER("Layout/Overlap Mode");
4813
    if (ImGui::TreeNode("Overlap Mode"))
4814
    {
4815
        static bool enable_allow_overlap = true;
4816
4817
        HelpMarker(
4818
            "Hit-testing is by default performed in item submission order, which generally is perceived as 'back-to-front'.\n\n"
4819
            "By using SetNextItemAllowOverlap() you can notify that an item may be overlapped by another. "
4820
            "Doing so alters the hovering logic: items using AllowOverlap mode requires an extra frame to accept hovered state.");
4821
        ImGui::Checkbox("Enable AllowOverlap", &enable_allow_overlap);
4822
4823
        ImVec2 button1_pos = ImGui::GetCursorScreenPos();
4824
        ImVec2 button2_pos = ImVec2(button1_pos.x + 50.0f, button1_pos.y + 50.0f);
4825
        if (enable_allow_overlap)
4826
            ImGui::SetNextItemAllowOverlap();
4827
        ImGui::Button("Button 1", ImVec2(80, 80));
4828
        ImGui::SetCursorScreenPos(button2_pos);
4829
        ImGui::Button("Button 2", ImVec2(80, 80));
4830
4831
        // This is typically used with width-spanning items.
4832
        // (note that Selectable() has a dedicated flag ImGuiSelectableFlags_AllowOverlap, which is a shortcut
4833
        // for using SetNextItemAllowOverlap(). For demo purpose we use SetNextItemAllowOverlap() here.)
4834
        if (enable_allow_overlap)
4835
            ImGui::SetNextItemAllowOverlap();
4836
        ImGui::Selectable("Some Selectable", false);
4837
        ImGui::SameLine();
4838
        ImGui::SmallButton("++");
4839
4840
        ImGui::TreePop();
4841
    }
4842
}
4843
4844
//-----------------------------------------------------------------------------
4845
// [SECTION] ShowDemoWindowPopups()
4846
//-----------------------------------------------------------------------------
4847
4848
static void ShowDemoWindowPopups()
4849
{
4850
    IMGUI_DEMO_MARKER("Popups");
4851
    if (!ImGui::CollapsingHeader("Popups & Modal windows"))
4852
        return;
4853
4854
    // The properties of popups windows are:
4855
    // - They block normal mouse hovering detection outside them. (*)
4856
    // - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE.
4857
    // - Their visibility state (~bool) is held internally by Dear ImGui instead of being held by the programmer as
4858
    //   we are used to with regular Begin() calls. User can manipulate the visibility state by calling OpenPopup().
4859
    // (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even
4860
    //     when normally blocked by a popup.
4861
    // Those three properties are connected. The library needs to hold their visibility state BECAUSE it can close
4862
    // popups at any time.
4863
4864
    // Typical use for regular windows:
4865
    //   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();
4866
    // Typical use for popups:
4867
    //   if (ImGui::Button("Open")) ImGui::OpenPopup("MyPopup"); if (ImGui::BeginPopup("MyPopup") { [...] EndPopup(); }
4868
4869
    // With popups we have to go through a library call (here OpenPopup) to manipulate the visibility state.
4870
    // This may be a bit confusing at first but it should quickly make sense. Follow on the examples below.
4871
4872
    IMGUI_DEMO_MARKER("Popups/Popups");
4873
    if (ImGui::TreeNode("Popups"))
4874
    {
4875
        ImGui::TextWrapped(
4876
            "When a popup is active, it inhibits interacting with windows that are behind the popup. "
4877
            "Clicking outside the popup closes it.");
4878
4879
        static int selected_fish = -1;
4880
        const char* names[] = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" };
4881
        static bool toggles[] = { true, false, false, false, false };
4882
4883
        // Simple selection popup (if you want to show the current selection inside the Button itself,
4884
        // you may want to build a string using the "###" operator to preserve a constant ID with a variable label)
4885
        if (ImGui::Button("Select.."))
4886
            ImGui::OpenPopup("my_select_popup");
4887
        ImGui::SameLine();
4888
        ImGui::TextUnformatted(selected_fish == -1 ? "<None>" : names[selected_fish]);
4889
        if (ImGui::BeginPopup("my_select_popup"))
4890
        {
4891
            ImGui::SeparatorText("Aquarium");
4892
            for (int i = 0; i < IM_ARRAYSIZE(names); i++)
4893
                if (ImGui::Selectable(names[i]))
4894
                    selected_fish = i;
4895
            ImGui::EndPopup();
4896
        }
4897
4898
        // Showing a menu with toggles
4899
        if (ImGui::Button("Toggle.."))
4900
            ImGui::OpenPopup("my_toggle_popup");
4901
        if (ImGui::BeginPopup("my_toggle_popup"))
4902
        {
4903
            for (int i = 0; i < IM_ARRAYSIZE(names); i++)
4904
                ImGui::MenuItem(names[i], "", &toggles[i]);
4905
            if (ImGui::BeginMenu("Sub-menu"))
4906
            {
4907
                ImGui::MenuItem("Click me");
4908
                ImGui::EndMenu();
4909
            }
4910
4911
            ImGui::Separator();
4912
            ImGui::Text("Tooltip here");
4913
            ImGui::SetItemTooltip("I am a tooltip over a popup");
4914
4915
            if (ImGui::Button("Stacked Popup"))
4916
                ImGui::OpenPopup("another popup");
4917
            if (ImGui::BeginPopup("another popup"))
4918
            {
4919
                for (int i = 0; i < IM_ARRAYSIZE(names); i++)
4920
                    ImGui::MenuItem(names[i], "", &toggles[i]);
4921
                if (ImGui::BeginMenu("Sub-menu"))
4922
                {
4923
                    ImGui::MenuItem("Click me");
4924
                    if (ImGui::Button("Stacked Popup"))
4925
                        ImGui::OpenPopup("another popup");
4926
                    if (ImGui::BeginPopup("another popup"))
4927
                    {
4928
                        ImGui::Text("I am the last one here.");
4929
                        ImGui::EndPopup();
4930
                    }
4931
                    ImGui::EndMenu();
4932
                }
4933
                ImGui::EndPopup();
4934
            }
4935
            ImGui::EndPopup();
4936
        }
4937
4938
        // Call the more complete ShowExampleMenuFile which we use in various places of this demo
4939
        if (ImGui::Button("With a menu.."))
4940
            ImGui::OpenPopup("my_file_popup");
4941
        if (ImGui::BeginPopup("my_file_popup", ImGuiWindowFlags_MenuBar))
4942
        {
4943
            if (ImGui::BeginMenuBar())
4944
            {
4945
                if (ImGui::BeginMenu("File"))
4946
                {
4947
                    ShowExampleMenuFile();
4948
                    ImGui::EndMenu();
4949
                }
4950
                if (ImGui::BeginMenu("Edit"))
4951
                {
4952
                    ImGui::MenuItem("Dummy");
4953
                    ImGui::EndMenu();
4954
                }
4955
                ImGui::EndMenuBar();
4956
            }
4957
            ImGui::Text("Hello from popup!");
4958
            ImGui::Button("This is a dummy button..");
4959
            ImGui::EndPopup();
4960
        }
4961
4962
        ImGui::TreePop();
4963
    }
4964
4965
    IMGUI_DEMO_MARKER("Popups/Context menus");
4966
    if (ImGui::TreeNode("Context menus"))
4967
    {
4968
        HelpMarker("\"Context\" functions are simple helpers to associate a Popup to a given Item or Window identifier.");
4969
4970
        // BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing:
4971
        //     if (id == 0)
4972
        //         id = GetItemID(); // Use last item id
4973
        //     if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right))
4974
        //         OpenPopup(id);
4975
        //     return BeginPopup(id);
4976
        // For advanced uses you may want to replicate and customize this code.
4977
        // See more details in BeginPopupContextItem().
4978
4979
        // Example 1
4980
        // When used after an item that has an ID (e.g. Button), we can skip providing an ID to BeginPopupContextItem(),
4981
        // and BeginPopupContextItem() will use the last item ID as the popup ID.
4982
        {
4983
            const char* names[5] = { "Label1", "Label2", "Label3", "Label4", "Label5" };
4984
            static int selected = -1;
4985
            for (int n = 0; n < 5; n++)
4986
            {
4987
                if (ImGui::Selectable(names[n], selected == n))
4988
                    selected = n;
4989
                if (ImGui::BeginPopupContextItem()) // <-- use last item id as popup id
4990
                {
4991
                    selected = n;
4992
                    ImGui::Text("This a popup for \"%s\"!", names[n]);
4993
                    if (ImGui::Button("Close"))
4994
                        ImGui::CloseCurrentPopup();
4995
                    ImGui::EndPopup();
4996
                }
4997
                ImGui::SetItemTooltip("Right-click to open popup");
4998
            }
4999
        }
5000
5001
        // Example 2
5002
        // Popup on a Text() element which doesn't have an identifier: we need to provide an identifier to BeginPopupContextItem().
5003
        // Using an explicit identifier is also convenient if you want to activate the popups from different locations.
5004
        {
5005
            HelpMarker("Text() elements don't have stable identifiers so we need to provide one.");
5006
            static float value = 0.5f;
5007
            ImGui::Text("Value = %.3f <-- (1) right-click this text", value);
5008
            if (ImGui::BeginPopupContextItem("my popup"))
5009
            {
5010
                if (ImGui::Selectable("Set to zero")) value = 0.0f;
5011
                if (ImGui::Selectable("Set to PI")) value = 3.1415f;
5012
                ImGui::SetNextItemWidth(-FLT_MIN);
5013
                ImGui::DragFloat("##Value", &value, 0.1f, 0.0f, 0.0f);
5014
                ImGui::EndPopup();
5015
            }
5016
5017
            // We can also use OpenPopupOnItemClick() to toggle the visibility of a given popup.
5018
            // Here we make it that right-clicking this other text element opens the same popup as above.
5019
            // The popup itself will be submitted by the code above.
5020
            ImGui::Text("(2) Or right-click this text");
5021
            ImGui::OpenPopupOnItemClick("my popup", ImGuiPopupFlags_MouseButtonRight);
5022
5023
            // Back to square one: manually open the same popup.
5024
            if (ImGui::Button("(3) Or click this button"))
5025
                ImGui::OpenPopup("my popup");
5026
        }
5027
5028
        // Example 3
5029
        // When using BeginPopupContextItem() with an implicit identifier (NULL == use last item ID),
5030
        // we need to make sure your item identifier is stable.
5031
        // In this example we showcase altering the item label while preserving its identifier, using the ### operator (see FAQ).
5032
        {
5033
            HelpMarker("Showcase using a popup ID linked to item ID, with the item having a changing label + stable ID using the ### operator.");
5034
            static char name[32] = "Label1";
5035
            char buf[64];
5036
            sprintf(buf, "Button: %s###Button", name); // ### operator override ID ignoring the preceding label
5037
            ImGui::Button(buf);
5038
            if (ImGui::BeginPopupContextItem())
5039
            {
5040
                ImGui::Text("Edit name:");
5041
                ImGui::InputText("##edit", name, IM_ARRAYSIZE(name));
5042
                if (ImGui::Button("Close"))
5043
                    ImGui::CloseCurrentPopup();
5044
                ImGui::EndPopup();
5045
            }
5046
            ImGui::SameLine(); ImGui::Text("(<-- right-click here)");
5047
        }
5048
5049
        ImGui::TreePop();
5050
    }
5051
5052
    IMGUI_DEMO_MARKER("Popups/Modals");
5053
    if (ImGui::TreeNode("Modals"))
5054
    {
5055
        ImGui::TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside.");
5056
5057
        if (ImGui::Button("Delete.."))
5058
            ImGui::OpenPopup("Delete?");
5059
5060
        // Always center this window when appearing
5061
        ImVec2 center = ImGui::GetMainViewport()->GetCenter();
5062
        ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
5063
5064
        if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize))
5065
        {
5066
            ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!");
5067
            ImGui::Separator();
5068
5069
            //static int unused_i = 0;
5070
            //ImGui::Combo("Combo", &unused_i, "Delete\0Delete harder\0");
5071
5072
            static bool dont_ask_me_next_time = false;
5073
            ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
5074
            ImGui::Checkbox("Don't ask me next time", &dont_ask_me_next_time);
5075
            ImGui::PopStyleVar();
5076
5077
            if (ImGui::Button("OK", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); }
5078
            ImGui::SetItemDefaultFocus();
5079
            ImGui::SameLine();
5080
            if (ImGui::Button("Cancel", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); }
5081
            ImGui::EndPopup();
5082
        }
5083
5084
        if (ImGui::Button("Stacked modals.."))
5085
            ImGui::OpenPopup("Stacked 1");
5086
        if (ImGui::BeginPopupModal("Stacked 1", NULL, ImGuiWindowFlags_MenuBar))
5087
        {
5088
            if (ImGui::BeginMenuBar())
5089
            {
5090
                if (ImGui::BeginMenu("File"))
5091
                {
5092
                    if (ImGui::MenuItem("Some menu item")) {}
5093
                    ImGui::EndMenu();
5094
                }
5095
                ImGui::EndMenuBar();
5096
            }
5097
            ImGui::Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it.");
5098
5099
            // Testing behavior of widgets stacking their own regular popups over the modal.
5100
            static int item = 1;
5101
            static float color[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
5102
            ImGui::Combo("Combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
5103
            ImGui::ColorEdit4("Color", color);
5104
5105
            if (ImGui::Button("Add another modal.."))
5106
                ImGui::OpenPopup("Stacked 2");
5107
5108
            // Also demonstrate passing a bool* to BeginPopupModal(), this will create a regular close button which
5109
            // will close the popup. Note that the visibility state of popups is owned by imgui, so the input value
5110
            // of the bool actually doesn't matter here.
5111
            bool unused_open = true;
5112
            if (ImGui::BeginPopupModal("Stacked 2", &unused_open))
5113
            {
5114
                ImGui::Text("Hello from Stacked The Second!");
5115
                ImGui::ColorEdit4("Color", color); // Allow opening another nested popup
5116
                if (ImGui::Button("Close"))
5117
                    ImGui::CloseCurrentPopup();
5118
                ImGui::EndPopup();
5119
            }
5120
5121
            if (ImGui::Button("Close"))
5122
                ImGui::CloseCurrentPopup();
5123
            ImGui::EndPopup();
5124
        }
5125
5126
        ImGui::TreePop();
5127
    }
5128
5129
    IMGUI_DEMO_MARKER("Popups/Menus inside a regular window");
5130
    if (ImGui::TreeNode("Menus inside a regular window"))
5131
    {
5132
        ImGui::TextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!");
5133
        ImGui::Separator();
5134
5135
        ImGui::MenuItem("Menu item", "CTRL+M");
5136
        if (ImGui::BeginMenu("Menu inside a regular window"))
5137
        {
5138
            ShowExampleMenuFile();
5139
            ImGui::EndMenu();
5140
        }
5141
        ImGui::Separator();
5142
        ImGui::TreePop();
5143
    }
5144
}
5145
5146
// Dummy data structure that we use for the Table demo.
5147
// (pre-C++11 doesn't allow us to instantiate ImVector<MyItem> template if this structure is defined inside the demo function)
5148
namespace
5149
{
5150
// We are passing our own identifier to TableSetupColumn() to facilitate identifying columns in the sorting code.
5151
// This identifier will be passed down into ImGuiTableSortSpec::ColumnUserID.
5152
// But it is possible to omit the user id parameter of TableSetupColumn() and just use the column index instead! (ImGuiTableSortSpec::ColumnIndex)
5153
// If you don't use sorting, you will generally never care about giving column an ID!
5154
enum MyItemColumnID
5155
{
5156
    MyItemColumnID_ID,
5157
    MyItemColumnID_Name,
5158
    MyItemColumnID_Action,
5159
    MyItemColumnID_Quantity,
5160
    MyItemColumnID_Description
5161
};
5162
5163
struct MyItem
5164
{
5165
    int         ID;
5166
    const char* Name;
5167
    int         Quantity;
5168
5169
    // We have a problem which is affecting _only this demo_ and should not affect your code:
5170
    // As we don't rely on std:: or other third-party library to compile dear imgui, we only have reliable access to qsort(),
5171
    // however qsort doesn't allow passing user data to comparing function.
5172
    // As a workaround, we are storing the sort specs in a static/global for the comparing function to access.
5173
    // In your own use case you would probably pass the sort specs to your sorting/comparing functions directly and not use a global.
5174
    // We could technically call ImGui::TableGetSortSpecs() in CompareWithSortSpecs(), but considering that this function is called
5175
    // very often by the sorting algorithm it would be a little wasteful.
5176
    static const ImGuiTableSortSpecs* s_current_sort_specs;
5177
5178
    static void SortWithSortSpecs(ImGuiTableSortSpecs* sort_specs, MyItem* items, int items_count)
5179
    {
5180
        s_current_sort_specs = sort_specs; // Store in variable accessible by the sort function.
5181
        if (items_count > 1)
5182
            qsort(items, (size_t)items_count, sizeof(items[0]), MyItem::CompareWithSortSpecs);
5183
        s_current_sort_specs = NULL;
5184
    }
5185
5186
    // Compare function to be used by qsort()
5187
    static int IMGUI_CDECL CompareWithSortSpecs(const void* lhs, const void* rhs)
5188
    {
5189
        const MyItem* a = (const MyItem*)lhs;
5190
        const MyItem* b = (const MyItem*)rhs;
5191
        for (int n = 0; n < s_current_sort_specs->SpecsCount; n++)
5192
        {
5193
            // Here we identify columns using the ColumnUserID value that we ourselves passed to TableSetupColumn()
5194
            // We could also choose to identify columns based on their index (sort_spec->ColumnIndex), which is simpler!
5195
            const ImGuiTableColumnSortSpecs* sort_spec = &s_current_sort_specs->Specs[n];
5196
            int delta = 0;
5197
            switch (sort_spec->ColumnUserID)
5198
            {
5199
            case MyItemColumnID_ID:             delta = (a->ID - b->ID);                break;
5200
            case MyItemColumnID_Name:           delta = (strcmp(a->Name, b->Name));     break;
5201
            case MyItemColumnID_Quantity:       delta = (a->Quantity - b->Quantity);    break;
5202
            case MyItemColumnID_Description:    delta = (strcmp(a->Name, b->Name));     break;
5203
            default: IM_ASSERT(0); break;
5204
            }
5205
            if (delta > 0)
5206
                return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? +1 : -1;
5207
            if (delta < 0)
5208
                return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? -1 : +1;
5209
        }
5210
5211
        // qsort() is instable so always return a way to differenciate items.
5212
        // Your own compare function may want to avoid fallback on implicit sort specs.
5213
        // e.g. a Name compare if it wasn't already part of the sort specs.
5214
        return (a->ID - b->ID);
5215
    }
5216
};
5217
const ImGuiTableSortSpecs* MyItem::s_current_sort_specs = NULL;
5218
}
5219
5220
// Make the UI compact because there are so many fields
5221
static void PushStyleCompact()
5222
{
5223
    ImGuiStyle& style = ImGui::GetStyle();
5224
    ImGui::PushStyleVarY(ImGuiStyleVar_FramePadding, (float)(int)(style.FramePadding.y * 0.60f));
5225
    ImGui::PushStyleVarY(ImGuiStyleVar_ItemSpacing, (float)(int)(style.ItemSpacing.y * 0.60f));
5226
}
5227
5228
static void PopStyleCompact()
5229
{
5230
    ImGui::PopStyleVar(2);
5231
}
5232
5233
// Show a combo box with a choice of sizing policies
5234
static void EditTableSizingFlags(ImGuiTableFlags* p_flags)
5235
{
5236
    struct EnumDesc { ImGuiTableFlags Value; const char* Name; const char* Tooltip; };
5237
    static const EnumDesc policies[] =
5238
    {
5239
        { 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." },
5240
        { ImGuiTableFlags_SizingFixedFit,     "ImGuiTableFlags_SizingFixedFit",     "Columns default to _WidthFixed (if resizable) or _WidthAuto (if not resizable), matching contents width." },
5241
        { ImGuiTableFlags_SizingFixedSame,    "ImGuiTableFlags_SizingFixedSame",    "Columns are all the same width, matching the maximum contents width.\nImplicitly disable ImGuiTableFlags_Resizable and enable ImGuiTableFlags_NoKeepColumnsVisible." },
5242
        { ImGuiTableFlags_SizingStretchProp,  "ImGuiTableFlags_SizingStretchProp",  "Columns default to _WidthStretch with weights proportional to their widths." },
5243
        { ImGuiTableFlags_SizingStretchSame,  "ImGuiTableFlags_SizingStretchSame",  "Columns default to _WidthStretch with same weights." }
5244
    };
5245
    int idx;
5246
    for (idx = 0; idx < IM_ARRAYSIZE(policies); idx++)
5247
        if (policies[idx].Value == (*p_flags & ImGuiTableFlags_SizingMask_))
5248
            break;
5249
    const char* preview_text = (idx < IM_ARRAYSIZE(policies)) ? policies[idx].Name + (idx > 0 ? strlen("ImGuiTableFlags") : 0) : "";
5250
    if (ImGui::BeginCombo("Sizing Policy", preview_text))
5251
    {
5252
        for (int n = 0; n < IM_ARRAYSIZE(policies); n++)
5253
            if (ImGui::Selectable(policies[n].Name, idx == n))
5254
                *p_flags = (*p_flags & ~ImGuiTableFlags_SizingMask_) | policies[n].Value;
5255
        ImGui::EndCombo();
5256
    }
5257
    ImGui::SameLine();
5258
    ImGui::TextDisabled("(?)");
5259
    if (ImGui::BeginItemTooltip())
5260
    {
5261
        ImGui::PushTextWrapPos(ImGui::GetFontSize() * 50.0f);
5262
        for (int m = 0; m < IM_ARRAYSIZE(policies); m++)
5263
        {
5264
            ImGui::Separator();
5265
            ImGui::Text("%s:", policies[m].Name);
5266
            ImGui::Separator();
5267
            ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetStyle().IndentSpacing * 0.5f);
5268
            ImGui::TextUnformatted(policies[m].Tooltip);
5269
        }
5270
        ImGui::PopTextWrapPos();
5271
        ImGui::EndTooltip();
5272
    }
5273
}
5274
5275
static void EditTableColumnsFlags(ImGuiTableColumnFlags* p_flags)
5276
{
5277
    ImGui::CheckboxFlags("_Disabled", p_flags, ImGuiTableColumnFlags_Disabled); ImGui::SameLine(); HelpMarker("Master disable flag (also hide from context menu)");
5278
    ImGui::CheckboxFlags("_DefaultHide", p_flags, ImGuiTableColumnFlags_DefaultHide);
5279
    ImGui::CheckboxFlags("_DefaultSort", p_flags, ImGuiTableColumnFlags_DefaultSort);
5280
    if (ImGui::CheckboxFlags("_WidthStretch", p_flags, ImGuiTableColumnFlags_WidthStretch))
5281
        *p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthStretch);
5282
    if (ImGui::CheckboxFlags("_WidthFixed", p_flags, ImGuiTableColumnFlags_WidthFixed))
5283
        *p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthFixed);
5284
    ImGui::CheckboxFlags("_NoResize", p_flags, ImGuiTableColumnFlags_NoResize);
5285
    ImGui::CheckboxFlags("_NoReorder", p_flags, ImGuiTableColumnFlags_NoReorder);
5286
    ImGui::CheckboxFlags("_NoHide", p_flags, ImGuiTableColumnFlags_NoHide);
5287
    ImGui::CheckboxFlags("_NoClip", p_flags, ImGuiTableColumnFlags_NoClip);
5288
    ImGui::CheckboxFlags("_NoSort", p_flags, ImGuiTableColumnFlags_NoSort);
5289
    ImGui::CheckboxFlags("_NoSortAscending", p_flags, ImGuiTableColumnFlags_NoSortAscending);
5290
    ImGui::CheckboxFlags("_NoSortDescending", p_flags, ImGuiTableColumnFlags_NoSortDescending);
5291
    ImGui::CheckboxFlags("_NoHeaderLabel", p_flags, ImGuiTableColumnFlags_NoHeaderLabel);
5292
    ImGui::CheckboxFlags("_NoHeaderWidth", p_flags, ImGuiTableColumnFlags_NoHeaderWidth);
5293
    ImGui::CheckboxFlags("_PreferSortAscending", p_flags, ImGuiTableColumnFlags_PreferSortAscending);
5294
    ImGui::CheckboxFlags("_PreferSortDescending", p_flags, ImGuiTableColumnFlags_PreferSortDescending);
5295
    ImGui::CheckboxFlags("_IndentEnable", p_flags, ImGuiTableColumnFlags_IndentEnable); ImGui::SameLine(); HelpMarker("Default for column 0");
5296
    ImGui::CheckboxFlags("_IndentDisable", p_flags, ImGuiTableColumnFlags_IndentDisable); ImGui::SameLine(); HelpMarker("Default for column >0");
5297
    ImGui::CheckboxFlags("_AngledHeader", p_flags, ImGuiTableColumnFlags_AngledHeader);
5298
}
5299
5300
static void ShowTableColumnsStatusFlags(ImGuiTableColumnFlags flags)
5301
{
5302
    ImGui::CheckboxFlags("_IsEnabled", &flags, ImGuiTableColumnFlags_IsEnabled);
5303
    ImGui::CheckboxFlags("_IsVisible", &flags, ImGuiTableColumnFlags_IsVisible);
5304
    ImGui::CheckboxFlags("_IsSorted", &flags, ImGuiTableColumnFlags_IsSorted);
5305
    ImGui::CheckboxFlags("_IsHovered", &flags, ImGuiTableColumnFlags_IsHovered);
5306
}
5307
5308
//-----------------------------------------------------------------------------
5309
// [SECTION] ShowDemoWindowTables()
5310
//-----------------------------------------------------------------------------
5311
5312
static void ShowDemoWindowTables()
5313
{
5314
    //ImGui::SetNextItemOpen(true, ImGuiCond_Once);
5315
    IMGUI_DEMO_MARKER("Tables");
5316
    if (!ImGui::CollapsingHeader("Tables & Columns"))
5317
        return;
5318
5319
    // Using those as a base value to create width/height that are factor of the size of our font
5320
    const float TEXT_BASE_WIDTH = ImGui::CalcTextSize("A").x;
5321
    const float TEXT_BASE_HEIGHT = ImGui::GetTextLineHeightWithSpacing();
5322
5323
    ImGui::PushID("Tables");
5324
5325
    int open_action = -1;
5326
    if (ImGui::Button("Expand all"))
5327
        open_action = 1;
5328
    ImGui::SameLine();
5329
    if (ImGui::Button("Collapse all"))
5330
        open_action = 0;
5331
    ImGui::SameLine();
5332
5333
    // Options
5334
    static bool disable_indent = false;
5335
    ImGui::Checkbox("Disable tree indentation", &disable_indent);
5336
    ImGui::SameLine();
5337
    HelpMarker("Disable the indenting of tree nodes so demo tables can use the full window width.");
5338
    ImGui::Separator();
5339
    if (disable_indent)
5340
        ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0.0f);
5341
5342
    // About Styling of tables
5343
    // Most settings are configured on a per-table basis via the flags passed to BeginTable() and TableSetupColumns APIs.
5344
    // There are however a few settings that a shared and part of the ImGuiStyle structure:
5345
    //   style.CellPadding                          // Padding within each cell
5346
    //   style.Colors[ImGuiCol_TableHeaderBg]       // Table header background
5347
    //   style.Colors[ImGuiCol_TableBorderStrong]   // Table outer and header borders
5348
    //   style.Colors[ImGuiCol_TableBorderLight]    // Table inner borders
5349
    //   style.Colors[ImGuiCol_TableRowBg]          // Table row background when ImGuiTableFlags_RowBg is enabled (even rows)
5350
    //   style.Colors[ImGuiCol_TableRowBgAlt]       // Table row background when ImGuiTableFlags_RowBg is enabled (odds rows)
5351
5352
    // Demos
5353
    if (open_action != -1)
5354
        ImGui::SetNextItemOpen(open_action != 0);
5355
    IMGUI_DEMO_MARKER("Tables/Basic");
5356
    if (ImGui::TreeNode("Basic"))
5357
    {
5358
        // Here we will showcase three different ways to output a table.
5359
        // They are very simple variations of a same thing!
5360
5361
        // [Method 1] Using TableNextRow() to create a new row, and TableSetColumnIndex() to select the column.
5362
        // In many situations, this is the most flexible and easy to use pattern.
5363
        HelpMarker("Using TableNextRow() + calling TableSetColumnIndex() _before_ each cell, in a loop.");
5364
        if (ImGui::BeginTable("table1", 3))
5365
        {
5366
            for (int row = 0; row < 4; row++)
5367
            {
5368
                ImGui::TableNextRow();
5369
                for (int column = 0; column < 3; column++)
5370
                {
5371
                    ImGui::TableSetColumnIndex(column);
5372
                    ImGui::Text("Row %d Column %d", row, column);
5373
                }
5374
            }
5375
            ImGui::EndTable();
5376
        }
5377
5378
        // [Method 2] Using TableNextColumn() called multiple times, instead of using a for loop + TableSetColumnIndex().
5379
        // This is generally more convenient when you have code manually submitting the contents of each column.
5380
        HelpMarker("Using TableNextRow() + calling TableNextColumn() _before_ each cell, manually.");
5381
        if (ImGui::BeginTable("table2", 3))
5382
        {
5383
            for (int row = 0; row < 4; row++)
5384
            {
5385
                ImGui::TableNextRow();
5386
                ImGui::TableNextColumn();
5387
                ImGui::Text("Row %d", row);
5388
                ImGui::TableNextColumn();
5389
                ImGui::Text("Some contents");
5390
                ImGui::TableNextColumn();
5391
                ImGui::Text("123.456");
5392
            }
5393
            ImGui::EndTable();
5394
        }
5395
5396
        // [Method 3] We call TableNextColumn() _before_ each cell. We never call TableNextRow(),
5397
        // as TableNextColumn() will automatically wrap around and create new rows as needed.
5398
        // This is generally more convenient when your cells all contains the same type of data.
5399
        HelpMarker(
5400
            "Only using TableNextColumn(), which tends to be convenient for tables where every cell contains "
5401
            "the same type of contents.\n This is also more similar to the old NextColumn() function of the "
5402
            "Columns API, and provided to facilitate the Columns->Tables API transition.");
5403
        if (ImGui::BeginTable("table3", 3))
5404
        {
5405
            for (int item = 0; item < 14; item++)
5406
            {
5407
                ImGui::TableNextColumn();
5408
                ImGui::Text("Item %d", item);
5409
            }
5410
            ImGui::EndTable();
5411
        }
5412
5413
        ImGui::TreePop();
5414
    }
5415
5416
    if (open_action != -1)
5417
        ImGui::SetNextItemOpen(open_action != 0);
5418
    IMGUI_DEMO_MARKER("Tables/Borders, background");
5419
    if (ImGui::TreeNode("Borders, background"))
5420
    {
5421
        // Expose a few Borders related flags interactively
5422
        enum ContentsType { CT_Text, CT_FillButton };
5423
        static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg;
5424
        static bool display_headers = false;
5425
        static int contents_type = CT_Text;
5426
5427
        PushStyleCompact();
5428
        ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg);
5429
        ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags, ImGuiTableFlags_Borders);
5430
        ImGui::SameLine(); HelpMarker("ImGuiTableFlags_Borders\n = ImGuiTableFlags_BordersInnerV\n | ImGuiTableFlags_BordersOuterV\n | ImGuiTableFlags_BordersInnerH\n | ImGuiTableFlags_BordersOuterH");
5431
        ImGui::Indent();
5432
5433
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags, ImGuiTableFlags_BordersH);
5434
        ImGui::Indent();
5435
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterH", &flags, ImGuiTableFlags_BordersOuterH);
5436
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerH", &flags, ImGuiTableFlags_BordersInnerH);
5437
        ImGui::Unindent();
5438
5439
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV);
5440
        ImGui::Indent();
5441
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags, ImGuiTableFlags_BordersOuterV);
5442
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags, ImGuiTableFlags_BordersInnerV);
5443
        ImGui::Unindent();
5444
5445
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuter", &flags, ImGuiTableFlags_BordersOuter);
5446
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersInner", &flags, ImGuiTableFlags_BordersInner);
5447
        ImGui::Unindent();
5448
5449
        ImGui::AlignTextToFramePadding(); ImGui::Text("Cell contents:");
5450
        ImGui::SameLine(); ImGui::RadioButton("Text", &contents_type, CT_Text);
5451
        ImGui::SameLine(); ImGui::RadioButton("FillButton", &contents_type, CT_FillButton);
5452
        ImGui::Checkbox("Display headers", &display_headers);
5453
        ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers");
5454
        PopStyleCompact();
5455
5456
        if (ImGui::BeginTable("table1", 3, flags))
5457
        {
5458
            // Display headers so we can inspect their interaction with borders
5459
            // (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)
5460
            if (display_headers)
5461
            {
5462
                ImGui::TableSetupColumn("One");
5463
                ImGui::TableSetupColumn("Two");
5464
                ImGui::TableSetupColumn("Three");
5465
                ImGui::TableHeadersRow();
5466
            }
5467
5468
            for (int row = 0; row < 5; row++)
5469
            {
5470
                ImGui::TableNextRow();
5471
                for (int column = 0; column < 3; column++)
5472
                {
5473
                    ImGui::TableSetColumnIndex(column);
5474
                    char buf[32];
5475
                    sprintf(buf, "Hello %d,%d", column, row);
5476
                    if (contents_type == CT_Text)
5477
                        ImGui::TextUnformatted(buf);
5478
                    else if (contents_type == CT_FillButton)
5479
                        ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f));
5480
                }
5481
            }
5482
            ImGui::EndTable();
5483
        }
5484
        ImGui::TreePop();
5485
    }
5486
5487
    if (open_action != -1)
5488
        ImGui::SetNextItemOpen(open_action != 0);
5489
    IMGUI_DEMO_MARKER("Tables/Resizable, stretch");
5490
    if (ImGui::TreeNode("Resizable, stretch"))
5491
    {
5492
        // By default, if we don't enable ScrollX the sizing policy for each column is "Stretch"
5493
        // All columns maintain a sizing weight, and they will occupy all available width.
5494
        static ImGuiTableFlags flags = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody;
5495
        PushStyleCompact();
5496
        ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
5497
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV);
5498
        ImGui::SameLine(); HelpMarker(
5499
            "Using the _Resizable flag automatically enables the _BordersInnerV flag as well, "
5500
            "this is why the resize borders are still showing when unchecking this.");
5501
        PopStyleCompact();
5502
5503
        if (ImGui::BeginTable("table1", 3, flags))
5504
        {
5505
            for (int row = 0; row < 5; row++)
5506
            {
5507
                ImGui::TableNextRow();
5508
                for (int column = 0; column < 3; column++)
5509
                {
5510
                    ImGui::TableSetColumnIndex(column);
5511
                    ImGui::Text("Hello %d,%d", column, row);
5512
                }
5513
            }
5514
            ImGui::EndTable();
5515
        }
5516
        ImGui::TreePop();
5517
    }
5518
5519
    if (open_action != -1)
5520
        ImGui::SetNextItemOpen(open_action != 0);
5521
    IMGUI_DEMO_MARKER("Tables/Resizable, fixed");
5522
    if (ImGui::TreeNode("Resizable, fixed"))
5523
    {
5524
        // Here we use ImGuiTableFlags_SizingFixedFit (even though _ScrollX is not set)
5525
        // So columns will adopt the "Fixed" policy and will maintain a fixed width regardless of the whole available width (unless table is small)
5526
        // If there is not enough available width to fit all columns, they will however be resized down.
5527
        // FIXME-TABLE: Providing a stretch-on-init would make sense especially for tables which don't have saved settings
5528
        HelpMarker(
5529
            "Using _Resizable + _SizingFixedFit flags.\n"
5530
            "Fixed-width columns generally makes more sense if you want to use horizontal scrolling.\n\n"
5531
            "Double-click a column border to auto-fit the column to its contents.");
5532
        PushStyleCompact();
5533
        static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody;
5534
        ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX);
5535
        PopStyleCompact();
5536
5537
        if (ImGui::BeginTable("table1", 3, flags))
5538
        {
5539
            for (int row = 0; row < 5; row++)
5540
            {
5541
                ImGui::TableNextRow();
5542
                for (int column = 0; column < 3; column++)
5543
                {
5544
                    ImGui::TableSetColumnIndex(column);
5545
                    ImGui::Text("Hello %d,%d", column, row);
5546
                }
5547
            }
5548
            ImGui::EndTable();
5549
        }
5550
        ImGui::TreePop();
5551
    }
5552
5553
    if (open_action != -1)
5554
        ImGui::SetNextItemOpen(open_action != 0);
5555
    IMGUI_DEMO_MARKER("Tables/Resizable, mixed");
5556
    if (ImGui::TreeNode("Resizable, mixed"))
5557
    {
5558
        HelpMarker(
5559
            "Using TableSetupColumn() to alter resizing policy on a per-column basis.\n\n"
5560
            "When combining Fixed and Stretch columns, generally you only want one, maybe two trailing columns to use _WidthStretch.");
5561
        static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
5562
5563
        if (ImGui::BeginTable("table1", 3, flags))
5564
        {
5565
            ImGui::TableSetupColumn("AAA", ImGuiTableColumnFlags_WidthFixed);
5566
            ImGui::TableSetupColumn("BBB", ImGuiTableColumnFlags_WidthFixed);
5567
            ImGui::TableSetupColumn("CCC", ImGuiTableColumnFlags_WidthStretch);
5568
            ImGui::TableHeadersRow();
5569
            for (int row = 0; row < 5; row++)
5570
            {
5571
                ImGui::TableNextRow();
5572
                for (int column = 0; column < 3; column++)
5573
                {
5574
                    ImGui::TableSetColumnIndex(column);
5575
                    ImGui::Text("%s %d,%d", (column == 2) ? "Stretch" : "Fixed", column, row);
5576
                }
5577
            }
5578
            ImGui::EndTable();
5579
        }
5580
        if (ImGui::BeginTable("table2", 6, flags))
5581
        {
5582
            ImGui::TableSetupColumn("AAA", ImGuiTableColumnFlags_WidthFixed);
5583
            ImGui::TableSetupColumn("BBB", ImGuiTableColumnFlags_WidthFixed);
5584
            ImGui::TableSetupColumn("CCC", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_DefaultHide);
5585
            ImGui::TableSetupColumn("DDD", ImGuiTableColumnFlags_WidthStretch);
5586
            ImGui::TableSetupColumn("EEE", ImGuiTableColumnFlags_WidthStretch);
5587
            ImGui::TableSetupColumn("FFF", ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_DefaultHide);
5588
            ImGui::TableHeadersRow();
5589
            for (int row = 0; row < 5; row++)
5590
            {
5591
                ImGui::TableNextRow();
5592
                for (int column = 0; column < 6; column++)
5593
                {
5594
                    ImGui::TableSetColumnIndex(column);
5595
                    ImGui::Text("%s %d,%d", (column >= 3) ? "Stretch" : "Fixed", column, row);
5596
                }
5597
            }
5598
            ImGui::EndTable();
5599
        }
5600
        ImGui::TreePop();
5601
    }
5602
5603
    if (open_action != -1)
5604
        ImGui::SetNextItemOpen(open_action != 0);
5605
    IMGUI_DEMO_MARKER("Tables/Reorderable, hideable, with headers");
5606
    if (ImGui::TreeNode("Reorderable, hideable, with headers"))
5607
    {
5608
        HelpMarker(
5609
            "Click and drag column headers to reorder columns.\n\n"
5610
            "Right-click on a header to open a context menu.");
5611
        static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV;
5612
        PushStyleCompact();
5613
        ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
5614
        ImGui::CheckboxFlags("ImGuiTableFlags_Reorderable", &flags, ImGuiTableFlags_Reorderable);
5615
        ImGui::CheckboxFlags("ImGuiTableFlags_Hideable", &flags, ImGuiTableFlags_Hideable);
5616
        ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody);
5617
        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)");
5618
        ImGui::CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", &flags, ImGuiTableFlags_HighlightHoveredColumn);
5619
        PopStyleCompact();
5620
5621
        if (ImGui::BeginTable("table1", 3, flags))
5622
        {
5623
            // Submit columns name with TableSetupColumn() and call TableHeadersRow() to create a row with a header in each column.
5624
            // (Later we will show how TableSetupColumn() has other uses, optional flags, sizing weight etc.)
5625
            ImGui::TableSetupColumn("One");
5626
            ImGui::TableSetupColumn("Two");
5627
            ImGui::TableSetupColumn("Three");
5628
            ImGui::TableHeadersRow();
5629
            for (int row = 0; row < 6; row++)
5630
            {
5631
                ImGui::TableNextRow();
5632
                for (int column = 0; column < 3; column++)
5633
                {
5634
                    ImGui::TableSetColumnIndex(column);
5635
                    ImGui::Text("Hello %d,%d", column, row);
5636
                }
5637
            }
5638
            ImGui::EndTable();
5639
        }
5640
5641
        // Use outer_size.x == 0.0f instead of default to make the table as tight as possible
5642
        // (only valid when no scrolling and no stretch column)
5643
        if (ImGui::BeginTable("table2", 3, flags | ImGuiTableFlags_SizingFixedFit, ImVec2(0.0f, 0.0f)))
5644
        {
5645
            ImGui::TableSetupColumn("One");
5646
            ImGui::TableSetupColumn("Two");
5647
            ImGui::TableSetupColumn("Three");
5648
            ImGui::TableHeadersRow();
5649
            for (int row = 0; row < 6; row++)
5650
            {
5651
                ImGui::TableNextRow();
5652
                for (int column = 0; column < 3; column++)
5653
                {
5654
                    ImGui::TableSetColumnIndex(column);
5655
                    ImGui::Text("Fixed %d,%d", column, row);
5656
                }
5657
            }
5658
            ImGui::EndTable();
5659
        }
5660
        ImGui::TreePop();
5661
    }
5662
5663
    if (open_action != -1)
5664
        ImGui::SetNextItemOpen(open_action != 0);
5665
    IMGUI_DEMO_MARKER("Tables/Padding");
5666
    if (ImGui::TreeNode("Padding"))
5667
    {
5668
        // First example: showcase use of padding flags and effect of BorderOuterV/BorderInnerV on X padding.
5669
        // We don't expose BorderOuterH/BorderInnerH here because they have no effect on X padding.
5670
        HelpMarker(
5671
            "We often want outer padding activated when any using features which makes the edges of a column visible:\n"
5672
            "e.g.:\n"
5673
            "- BorderOuterV\n"
5674
            "- any form of row selection\n"
5675
            "Because of this, activating BorderOuterV sets the default to PadOuterX. "
5676
            "Using PadOuterX or NoPadOuterX you can override the default.\n\n"
5677
            "Actual padding values are using style.CellPadding.\n\n"
5678
            "In this demo we don't show horizontal borders to emphasize how they don't affect default horizontal padding.");
5679
5680
        static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV;
5681
        PushStyleCompact();
5682
        ImGui::CheckboxFlags("ImGuiTableFlags_PadOuterX", &flags1, ImGuiTableFlags_PadOuterX);
5683
        ImGui::SameLine(); HelpMarker("Enable outer-most padding (default if ImGuiTableFlags_BordersOuterV is set)");
5684
        ImGui::CheckboxFlags("ImGuiTableFlags_NoPadOuterX", &flags1, ImGuiTableFlags_NoPadOuterX);
5685
        ImGui::SameLine(); HelpMarker("Disable outer-most padding (default if ImGuiTableFlags_BordersOuterV is not set)");
5686
        ImGui::CheckboxFlags("ImGuiTableFlags_NoPadInnerX", &flags1, ImGuiTableFlags_NoPadInnerX);
5687
        ImGui::SameLine(); HelpMarker("Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off)");
5688
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags1, ImGuiTableFlags_BordersOuterV);
5689
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags1, ImGuiTableFlags_BordersInnerV);
5690
        static bool show_headers = false;
5691
        ImGui::Checkbox("show_headers", &show_headers);
5692
        PopStyleCompact();
5693
5694
        if (ImGui::BeginTable("table_padding", 3, flags1))
5695
        {
5696
            if (show_headers)
5697
            {
5698
                ImGui::TableSetupColumn("One");
5699
                ImGui::TableSetupColumn("Two");
5700
                ImGui::TableSetupColumn("Three");
5701
                ImGui::TableHeadersRow();
5702
            }
5703
5704
            for (int row = 0; row < 5; row++)
5705
            {
5706
                ImGui::TableNextRow();
5707
                for (int column = 0; column < 3; column++)
5708
                {
5709
                    ImGui::TableSetColumnIndex(column);
5710
                    if (row == 0)
5711
                    {
5712
                        ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x);
5713
                    }
5714
                    else
5715
                    {
5716
                        char buf[32];
5717
                        sprintf(buf, "Hello %d,%d", column, row);
5718
                        ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f));
5719
                    }
5720
                    //if (ImGui::TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered)
5721
                    //    ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, IM_COL32(0, 100, 0, 255));
5722
                }
5723
            }
5724
            ImGui::EndTable();
5725
        }
5726
5727
        // Second example: set style.CellPadding to (0.0) or a custom value.
5728
        // FIXME-TABLE: Vertical border effectively not displayed the same way as horizontal one...
5729
        HelpMarker("Setting style.CellPadding to (0,0) or a custom value.");
5730
        static ImGuiTableFlags flags2 = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg;
5731
        static ImVec2 cell_padding(0.0f, 0.0f);
5732
        static bool show_widget_frame_bg = true;
5733
5734
        PushStyleCompact();
5735
        ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags2, ImGuiTableFlags_Borders);
5736
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags2, ImGuiTableFlags_BordersH);
5737
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags2, ImGuiTableFlags_BordersV);
5738
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersInner", &flags2, ImGuiTableFlags_BordersInner);
5739
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuter", &flags2, ImGuiTableFlags_BordersOuter);
5740
        ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags2, ImGuiTableFlags_RowBg);
5741
        ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags2, ImGuiTableFlags_Resizable);
5742
        ImGui::Checkbox("show_widget_frame_bg", &show_widget_frame_bg);
5743
        ImGui::SliderFloat2("CellPadding", &cell_padding.x, 0.0f, 10.0f, "%.0f");
5744
        PopStyleCompact();
5745
5746
        ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, cell_padding);
5747
        if (ImGui::BeginTable("table_padding_2", 3, flags2))
5748
        {
5749
            static char text_bufs[3 * 5][16]; // Mini text storage for 3x5 cells
5750
            static bool init = true;
5751
            if (!show_widget_frame_bg)
5752
                ImGui::PushStyleColor(ImGuiCol_FrameBg, 0);
5753
            for (int cell = 0; cell < 3 * 5; cell++)
5754
            {
5755
                ImGui::TableNextColumn();
5756
                if (init)
5757
                    strcpy(text_bufs[cell], "edit me");
5758
                ImGui::SetNextItemWidth(-FLT_MIN);
5759
                ImGui::PushID(cell);
5760
                ImGui::InputText("##cell", text_bufs[cell], IM_ARRAYSIZE(text_bufs[cell]));
5761
                ImGui::PopID();
5762
            }
5763
            if (!show_widget_frame_bg)
5764
                ImGui::PopStyleColor();
5765
            init = false;
5766
            ImGui::EndTable();
5767
        }
5768
        ImGui::PopStyleVar();
5769
5770
        ImGui::TreePop();
5771
    }
5772
5773
    if (open_action != -1)
5774
        ImGui::SetNextItemOpen(open_action != 0);
5775
    IMGUI_DEMO_MARKER("Tables/Explicit widths");
5776
    if (ImGui::TreeNode("Sizing policies"))
5777
    {
5778
        static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody;
5779
        PushStyleCompact();
5780
        ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags1, ImGuiTableFlags_Resizable);
5781
        ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags1, ImGuiTableFlags_NoHostExtendX);
5782
        PopStyleCompact();
5783
5784
        static ImGuiTableFlags sizing_policy_flags[4] = { ImGuiTableFlags_SizingFixedFit, ImGuiTableFlags_SizingFixedSame, ImGuiTableFlags_SizingStretchProp, ImGuiTableFlags_SizingStretchSame };
5785
        for (int table_n = 0; table_n < 4; table_n++)
5786
        {
5787
            ImGui::PushID(table_n);
5788
            ImGui::SetNextItemWidth(TEXT_BASE_WIDTH * 30);
5789
            EditTableSizingFlags(&sizing_policy_flags[table_n]);
5790
5791
            // To make it easier to understand the different sizing policy,
5792
            // For each policy: we display one table where the columns have equal contents width,
5793
            // and one where the columns have different contents width.
5794
            if (ImGui::BeginTable("table1", 3, sizing_policy_flags[table_n] | flags1))
5795
            {
5796
                for (int row = 0; row < 3; row++)
5797
                {
5798
                    ImGui::TableNextRow();
5799
                    ImGui::TableNextColumn(); ImGui::Text("Oh dear");
5800
                    ImGui::TableNextColumn(); ImGui::Text("Oh dear");
5801
                    ImGui::TableNextColumn(); ImGui::Text("Oh dear");
5802
                }
5803
                ImGui::EndTable();
5804
            }
5805
            if (ImGui::BeginTable("table2", 3, sizing_policy_flags[table_n] | flags1))
5806
            {
5807
                for (int row = 0; row < 3; row++)
5808
                {
5809
                    ImGui::TableNextRow();
5810
                    ImGui::TableNextColumn(); ImGui::Text("AAAA");
5811
                    ImGui::TableNextColumn(); ImGui::Text("BBBBBBBB");
5812
                    ImGui::TableNextColumn(); ImGui::Text("CCCCCCCCCCCC");
5813
                }
5814
                ImGui::EndTable();
5815
            }
5816
            ImGui::PopID();
5817
        }
5818
5819
        ImGui::Spacing();
5820
        ImGui::TextUnformatted("Advanced");
5821
        ImGui::SameLine();
5822
        HelpMarker(
5823
            "This section allows you to interact and see the effect of various sizing policies "
5824
            "depending on whether Scroll is enabled and the contents of your columns.");
5825
5826
        enum ContentsType { CT_ShowWidth, CT_ShortText, CT_LongText, CT_Button, CT_FillButton, CT_InputText };
5827
        static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable;
5828
        static int contents_type = CT_ShowWidth;
5829
        static int column_count = 3;
5830
5831
        PushStyleCompact();
5832
        ImGui::PushID("Advanced");
5833
        ImGui::PushItemWidth(TEXT_BASE_WIDTH * 30);
5834
        EditTableSizingFlags(&flags);
5835
        ImGui::Combo("Contents", &contents_type, "Show width\0Short Text\0Long Text\0Button\0Fill Button\0InputText\0");
5836
        if (contents_type == CT_FillButton)
5837
        {
5838
            ImGui::SameLine();
5839
            HelpMarker(
5840
                "Be mindful that using right-alignment (e.g. size.x = -FLT_MIN) creates a feedback loop "
5841
                "where contents width can feed into auto-column width can feed into contents width.");
5842
        }
5843
        ImGui::DragInt("Columns", &column_count, 0.1f, 1, 64, "%d", ImGuiSliderFlags_AlwaysClamp);
5844
        ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
5845
        ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths);
5846
        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.");
5847
        ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX);
5848
        ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
5849
        ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip);
5850
        ImGui::PopItemWidth();
5851
        ImGui::PopID();
5852
        PopStyleCompact();
5853
5854
        if (ImGui::BeginTable("table2", column_count, flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 7)))
5855
        {
5856
            for (int cell = 0; cell < 10 * column_count; cell++)
5857
            {
5858
                ImGui::TableNextColumn();
5859
                int column = ImGui::TableGetColumnIndex();
5860
                int row = ImGui::TableGetRowIndex();
5861
5862
                ImGui::PushID(cell);
5863
                char label[32];
5864
                static char text_buf[32] = "";
5865
                sprintf(label, "Hello %d,%d", column, row);
5866
                switch (contents_type)
5867
                {
5868
                case CT_ShortText:  ImGui::TextUnformatted(label); break;
5869
                case CT_LongText:   ImGui::Text("Some %s text %d,%d\nOver two lines..", column == 0 ? "long" : "longeeer", column, row); break;
5870
                case CT_ShowWidth:  ImGui::Text("W: %.1f", ImGui::GetContentRegionAvail().x); break;
5871
                case CT_Button:     ImGui::Button(label); break;
5872
                case CT_FillButton: ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f)); break;
5873
                case CT_InputText:  ImGui::SetNextItemWidth(-FLT_MIN); ImGui::InputText("##", text_buf, IM_ARRAYSIZE(text_buf)); break;
5874
                }
5875
                ImGui::PopID();
5876
            }
5877
            ImGui::EndTable();
5878
        }
5879
        ImGui::TreePop();
5880
    }
5881
5882
    if (open_action != -1)
5883
        ImGui::SetNextItemOpen(open_action != 0);
5884
    IMGUI_DEMO_MARKER("Tables/Vertical scrolling, with clipping");
5885
    if (ImGui::TreeNode("Vertical scrolling, with clipping"))
5886
    {
5887
        HelpMarker(
5888
            "Here we activate ScrollY, which will create a child window container to allow hosting scrollable contents.\n\n"
5889
            "We also demonstrate using ImGuiListClipper to virtualize the submission of many items.");
5890
        static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
5891
5892
        PushStyleCompact();
5893
        ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
5894
        PopStyleCompact();
5895
5896
        // When using ScrollX or ScrollY we need to specify a size for our table container!
5897
        // Otherwise by default the table will fit all available space, like a BeginChild() call.
5898
        ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 8);
5899
        if (ImGui::BeginTable("table_scrolly", 3, flags, outer_size))
5900
        {
5901
            ImGui::TableSetupScrollFreeze(0, 1); // Make top row always visible
5902
            ImGui::TableSetupColumn("One", ImGuiTableColumnFlags_None);
5903
            ImGui::TableSetupColumn("Two", ImGuiTableColumnFlags_None);
5904
            ImGui::TableSetupColumn("Three", ImGuiTableColumnFlags_None);
5905
            ImGui::TableHeadersRow();
5906
5907
            // Demonstrate using clipper for large vertical lists
5908
            ImGuiListClipper clipper;
5909
            clipper.Begin(1000);
5910
            while (clipper.Step())
5911
            {
5912
                for (int row = clipper.DisplayStart; row < clipper.DisplayEnd; row++)
5913
                {
5914
                    ImGui::TableNextRow();
5915
                    for (int column = 0; column < 3; column++)
5916
                    {
5917
                        ImGui::TableSetColumnIndex(column);
5918
                        ImGui::Text("Hello %d,%d", column, row);
5919
                    }
5920
                }
5921
            }
5922
            ImGui::EndTable();
5923
        }
5924
        ImGui::TreePop();
5925
    }
5926
5927
    if (open_action != -1)
5928
        ImGui::SetNextItemOpen(open_action != 0);
5929
    IMGUI_DEMO_MARKER("Tables/Horizontal scrolling");
5930
    if (ImGui::TreeNode("Horizontal scrolling"))
5931
    {
5932
        HelpMarker(
5933
            "When ScrollX is enabled, the default sizing policy becomes ImGuiTableFlags_SizingFixedFit, "
5934
            "as automatically stretching columns doesn't make much sense with horizontal scrolling.\n\n"
5935
            "Also note that as of the current version, you will almost always want to enable ScrollY along with ScrollX, "
5936
            "because the container window won't automatically extend vertically to fix contents "
5937
            "(this may be improved in future versions).");
5938
        static ImGuiTableFlags flags = ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
5939
        static int freeze_cols = 1;
5940
        static int freeze_rows = 1;
5941
5942
        PushStyleCompact();
5943
        ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
5944
        ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX);
5945
        ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
5946
        ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
5947
        ImGui::DragInt("freeze_cols", &freeze_cols, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
5948
        ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
5949
        ImGui::DragInt("freeze_rows", &freeze_rows, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
5950
        PopStyleCompact();
5951
5952
        // When using ScrollX or ScrollY we need to specify a size for our table container!
5953
        // Otherwise by default the table will fit all available space, like a BeginChild() call.
5954
        ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 8);
5955
        if (ImGui::BeginTable("table_scrollx", 7, flags, outer_size))
5956
        {
5957
            ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows);
5958
            ImGui::TableSetupColumn("Line #", ImGuiTableColumnFlags_NoHide); // Make the first column not hideable to match our use of TableSetupScrollFreeze()
5959
            ImGui::TableSetupColumn("One");
5960
            ImGui::TableSetupColumn("Two");
5961
            ImGui::TableSetupColumn("Three");
5962
            ImGui::TableSetupColumn("Four");
5963
            ImGui::TableSetupColumn("Five");
5964
            ImGui::TableSetupColumn("Six");
5965
            ImGui::TableHeadersRow();
5966
            for (int row = 0; row < 20; row++)
5967
            {
5968
                ImGui::TableNextRow();
5969
                for (int column = 0; column < 7; column++)
5970
                {
5971
                    // Both TableNextColumn() and TableSetColumnIndex() return true when a column is visible or performing width measurement.
5972
                    // Because here we know that:
5973
                    // - A) all our columns are contributing the same to row height
5974
                    // - B) column 0 is always visible,
5975
                    // We only always submit this one column and can skip others.
5976
                    // More advanced per-column clipping behaviors may benefit from polling the status flags via TableGetColumnFlags().
5977
                    if (!ImGui::TableSetColumnIndex(column) && column > 0)
5978
                        continue;
5979
                    if (column == 0)
5980
                        ImGui::Text("Line %d", row);
5981
                    else
5982
                        ImGui::Text("Hello world %d,%d", column, row);
5983
                }
5984
            }
5985
            ImGui::EndTable();
5986
        }
5987
5988
        ImGui::Spacing();
5989
        ImGui::TextUnformatted("Stretch + ScrollX");
5990
        ImGui::SameLine();
5991
        HelpMarker(
5992
            "Showcase using Stretch columns + ScrollX together: "
5993
            "this is rather unusual and only makes sense when specifying an 'inner_width' for the table!\n"
5994
            "Without an explicit value, inner_width is == outer_size.x and therefore using Stretch columns "
5995
            "along with ScrollX doesn't make sense.");
5996
        static ImGuiTableFlags flags2 = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody;
5997
        static float inner_width = 1000.0f;
5998
        PushStyleCompact();
5999
        ImGui::PushID("flags3");
6000
        ImGui::PushItemWidth(TEXT_BASE_WIDTH * 30);
6001
        ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags2, ImGuiTableFlags_ScrollX);
6002
        ImGui::DragFloat("inner_width", &inner_width, 1.0f, 0.0f, FLT_MAX, "%.1f");
6003
        ImGui::PopItemWidth();
6004
        ImGui::PopID();
6005
        PopStyleCompact();
6006
        if (ImGui::BeginTable("table2", 7, flags2, outer_size, inner_width))
6007
        {
6008
            for (int cell = 0; cell < 20 * 7; cell++)
6009
            {
6010
                ImGui::TableNextColumn();
6011
                ImGui::Text("Hello world %d,%d", ImGui::TableGetColumnIndex(), ImGui::TableGetRowIndex());
6012
            }
6013
            ImGui::EndTable();
6014
        }
6015
        ImGui::TreePop();
6016
    }
6017
6018
    if (open_action != -1)
6019
        ImGui::SetNextItemOpen(open_action != 0);
6020
    IMGUI_DEMO_MARKER("Tables/Columns flags");
6021
    if (ImGui::TreeNode("Columns flags"))
6022
    {
6023
        // Create a first table just to show all the options/flags we want to make visible in our example!
6024
        const int column_count = 3;
6025
        const char* column_names[column_count] = { "One", "Two", "Three" };
6026
        static ImGuiTableColumnFlags column_flags[column_count] = { ImGuiTableColumnFlags_DefaultSort, ImGuiTableColumnFlags_None, ImGuiTableColumnFlags_DefaultHide };
6027
        static ImGuiTableColumnFlags column_flags_out[column_count] = { 0, 0, 0 }; // Output from TableGetColumnFlags()
6028
6029
        if (ImGui::BeginTable("table_columns_flags_checkboxes", column_count, ImGuiTableFlags_None))
6030
        {
6031
            PushStyleCompact();
6032
            for (int column = 0; column < column_count; column++)
6033
            {
6034
                ImGui::TableNextColumn();
6035
                ImGui::PushID(column);
6036
                ImGui::AlignTextToFramePadding(); // FIXME-TABLE: Workaround for wrong text baseline propagation across columns
6037
                ImGui::Text("'%s'", column_names[column]);
6038
                ImGui::Spacing();
6039
                ImGui::Text("Input flags:");
6040
                EditTableColumnsFlags(&column_flags[column]);
6041
                ImGui::Spacing();
6042
                ImGui::Text("Output flags:");
6043
                ImGui::BeginDisabled();
6044
                ShowTableColumnsStatusFlags(column_flags_out[column]);
6045
                ImGui::EndDisabled();
6046
                ImGui::PopID();
6047
            }
6048
            PopStyleCompact();
6049
            ImGui::EndTable();
6050
        }
6051
6052
        // Create the real table we care about for the example!
6053
        // We use a scrolling table to be able to showcase the difference between the _IsEnabled and _IsVisible flags above,
6054
        // otherwise in a non-scrolling table columns are always visible (unless using ImGuiTableFlags_NoKeepColumnsVisible
6055
        // + resizing the parent window down).
6056
        const ImGuiTableFlags flags
6057
            = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY
6058
            | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV
6059
            | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable;
6060
        ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 9);
6061
        if (ImGui::BeginTable("table_columns_flags", column_count, flags, outer_size))
6062
        {
6063
            bool has_angled_header = false;
6064
            for (int column = 0; column < column_count; column++)
6065
            {
6066
                has_angled_header |= (column_flags[column] & ImGuiTableColumnFlags_AngledHeader) != 0;
6067
                ImGui::TableSetupColumn(column_names[column], column_flags[column]);
6068
            }
6069
            if (has_angled_header)
6070
                ImGui::TableAngledHeadersRow();
6071
            ImGui::TableHeadersRow();
6072
            for (int column = 0; column < column_count; column++)
6073
                column_flags_out[column] = ImGui::TableGetColumnFlags(column);
6074
            float indent_step = (float)((int)TEXT_BASE_WIDTH / 2);
6075
            for (int row = 0; row < 8; row++)
6076
            {
6077
                // Add some indentation to demonstrate usage of per-column IndentEnable/IndentDisable flags.
6078
                ImGui::Indent(indent_step);
6079
                ImGui::TableNextRow();
6080
                for (int column = 0; column < column_count; column++)
6081
                {
6082
                    ImGui::TableSetColumnIndex(column);
6083
                    ImGui::Text("%s %s", (column == 0) ? "Indented" : "Hello", ImGui::TableGetColumnName(column));
6084
                }
6085
            }
6086
            ImGui::Unindent(indent_step * 8.0f);
6087
6088
            ImGui::EndTable();
6089
        }
6090
        ImGui::TreePop();
6091
    }
6092
6093
    if (open_action != -1)
6094
        ImGui::SetNextItemOpen(open_action != 0);
6095
    IMGUI_DEMO_MARKER("Tables/Columns widths");
6096
    if (ImGui::TreeNode("Columns widths"))
6097
    {
6098
        HelpMarker("Using TableSetupColumn() to setup default width.");
6099
6100
        static ImGuiTableFlags flags1 = ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBodyUntilResize;
6101
        PushStyleCompact();
6102
        ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags1, ImGuiTableFlags_Resizable);
6103
        ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags1, ImGuiTableFlags_NoBordersInBodyUntilResize);
6104
        PopStyleCompact();
6105
        if (ImGui::BeginTable("table1", 3, flags1))
6106
        {
6107
            // We could also set ImGuiTableFlags_SizingFixedFit on the table and all columns will default to ImGuiTableColumnFlags_WidthFixed.
6108
            ImGui::TableSetupColumn("one", ImGuiTableColumnFlags_WidthFixed, 100.0f); // Default to 100.0f
6109
            ImGui::TableSetupColumn("two", ImGuiTableColumnFlags_WidthFixed, 200.0f); // Default to 200.0f
6110
            ImGui::TableSetupColumn("three", ImGuiTableColumnFlags_WidthFixed);       // Default to auto
6111
            ImGui::TableHeadersRow();
6112
            for (int row = 0; row < 4; row++)
6113
            {
6114
                ImGui::TableNextRow();
6115
                for (int column = 0; column < 3; column++)
6116
                {
6117
                    ImGui::TableSetColumnIndex(column);
6118
                    if (row == 0)
6119
                        ImGui::Text("(w: %5.1f)", ImGui::GetContentRegionAvail().x);
6120
                    else
6121
                        ImGui::Text("Hello %d,%d", column, row);
6122
                }
6123
            }
6124
            ImGui::EndTable();
6125
        }
6126
6127
        HelpMarker(
6128
            "Using TableSetupColumn() to setup explicit width.\n\nUnless _NoKeepColumnsVisible is set, "
6129
            "fixed columns with set width may still be shrunk down if there's not enough space in the host.");
6130
6131
        static ImGuiTableFlags flags2 = ImGuiTableFlags_None;
6132
        PushStyleCompact();
6133
        ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags2, ImGuiTableFlags_NoKeepColumnsVisible);
6134
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags2, ImGuiTableFlags_BordersInnerV);
6135
        ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags2, ImGuiTableFlags_BordersOuterV);
6136
        PopStyleCompact();
6137
        if (ImGui::BeginTable("table2", 4, flags2))
6138
        {
6139
            // We could also set ImGuiTableFlags_SizingFixedFit on the table and then all columns
6140
            // will default to ImGuiTableColumnFlags_WidthFixed.
6141
            ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 100.0f);
6142
            ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f);
6143
            ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 30.0f);
6144
            ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f);
6145
            for (int row = 0; row < 5; row++)
6146
            {
6147
                ImGui::TableNextRow();
6148
                for (int column = 0; column < 4; column++)
6149
                {
6150
                    ImGui::TableSetColumnIndex(column);
6151
                    if (row == 0)
6152
                        ImGui::Text("(w: %5.1f)", ImGui::GetContentRegionAvail().x);
6153
                    else
6154
                        ImGui::Text("Hello %d,%d", column, row);
6155
                }
6156
            }
6157
            ImGui::EndTable();
6158
        }
6159
        ImGui::TreePop();
6160
    }
6161
6162
    if (open_action != -1)
6163
        ImGui::SetNextItemOpen(open_action != 0);
6164
    IMGUI_DEMO_MARKER("Tables/Nested tables");
6165
    if (ImGui::TreeNode("Nested tables"))
6166
    {
6167
        HelpMarker("This demonstrates embedding a table into another table cell.");
6168
6169
        if (ImGui::BeginTable("table_nested1", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
6170
        {
6171
            ImGui::TableSetupColumn("A0");
6172
            ImGui::TableSetupColumn("A1");
6173
            ImGui::TableHeadersRow();
6174
6175
            ImGui::TableNextColumn();
6176
            ImGui::Text("A0 Row 0");
6177
            {
6178
                float rows_height = TEXT_BASE_HEIGHT * 2;
6179
                if (ImGui::BeginTable("table_nested2", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
6180
                {
6181
                    ImGui::TableSetupColumn("B0");
6182
                    ImGui::TableSetupColumn("B1");
6183
                    ImGui::TableHeadersRow();
6184
6185
                    ImGui::TableNextRow(ImGuiTableRowFlags_None, rows_height);
6186
                    ImGui::TableNextColumn();
6187
                    ImGui::Text("B0 Row 0");
6188
                    ImGui::TableNextColumn();
6189
                    ImGui::Text("B1 Row 0");
6190
                    ImGui::TableNextRow(ImGuiTableRowFlags_None, rows_height);
6191
                    ImGui::TableNextColumn();
6192
                    ImGui::Text("B0 Row 1");
6193
                    ImGui::TableNextColumn();
6194
                    ImGui::Text("B1 Row 1");
6195
6196
                    ImGui::EndTable();
6197
                }
6198
            }
6199
            ImGui::TableNextColumn(); ImGui::Text("A1 Row 0");
6200
            ImGui::TableNextColumn(); ImGui::Text("A0 Row 1");
6201
            ImGui::TableNextColumn(); ImGui::Text("A1 Row 1");
6202
            ImGui::EndTable();
6203
        }
6204
        ImGui::TreePop();
6205
    }
6206
6207
    if (open_action != -1)
6208
        ImGui::SetNextItemOpen(open_action != 0);
6209
    IMGUI_DEMO_MARKER("Tables/Row height");
6210
    if (ImGui::TreeNode("Row height"))
6211
    {
6212
        HelpMarker(
6213
            "You can pass a 'min_row_height' to TableNextRow().\n\nRows are padded with 'style.CellPadding.y' on top and bottom, "
6214
            "so effectively the minimum row height will always be >= 'style.CellPadding.y * 2.0f'.\n\n"
6215
            "We cannot honor a _maximum_ row height as that would require a unique clipping rectangle per row.");
6216
        if (ImGui::BeginTable("table_row_height", 1, ImGuiTableFlags_Borders))
6217
        {
6218
            for (int row = 0; row < 8; row++)
6219
            {
6220
                float min_row_height = (float)(int)(TEXT_BASE_HEIGHT * 0.30f * row);
6221
                ImGui::TableNextRow(ImGuiTableRowFlags_None, min_row_height);
6222
                ImGui::TableNextColumn();
6223
                ImGui::Text("min_row_height = %.2f", min_row_height);
6224
            }
6225
            ImGui::EndTable();
6226
        }
6227
6228
        HelpMarker(
6229
            "Showcase using SameLine(0,0) to share Current Line Height between cells.\n\n"
6230
            "Please note that Tables Row Height is not the same thing as Current Line Height, "
6231
            "as a table cell may contains multiple lines.");
6232
        if (ImGui::BeginTable("table_share_lineheight", 2, ImGuiTableFlags_Borders))
6233
        {
6234
            ImGui::TableNextRow();
6235
            ImGui::TableNextColumn();
6236
            ImGui::ColorButton("##1", ImVec4(0.13f, 0.26f, 0.40f, 1.0f), ImGuiColorEditFlags_None, ImVec2(40, 40));
6237
            ImGui::TableNextColumn();
6238
            ImGui::Text("Line 1");
6239
            ImGui::Text("Line 2");
6240
6241
            ImGui::TableNextRow();
6242
            ImGui::TableNextColumn();
6243
            ImGui::ColorButton("##2", ImVec4(0.13f, 0.26f, 0.40f, 1.0f), ImGuiColorEditFlags_None, ImVec2(40, 40));
6244
            ImGui::TableNextColumn();
6245
            ImGui::SameLine(0.0f, 0.0f); // Reuse line height from previous column
6246
            ImGui::Text("Line 1, with SameLine(0,0)");
6247
            ImGui::Text("Line 2");
6248
6249
            ImGui::EndTable();
6250
        }
6251
6252
        HelpMarker("Showcase altering CellPadding.y between rows. Note that CellPadding.x is locked for the entire table.");
6253
        if (ImGui::BeginTable("table_changing_cellpadding_y", 1, ImGuiTableFlags_Borders))
6254
        {
6255
            ImGuiStyle& style = ImGui::GetStyle();
6256
            for (int row = 0; row < 8; row++)
6257
            {
6258
                if ((row % 3) == 2)
6259
                    ImGui::PushStyleVarY(ImGuiStyleVar_CellPadding, 20.0f);
6260
                ImGui::TableNextRow(ImGuiTableRowFlags_None);
6261
                ImGui::TableNextColumn();
6262
                ImGui::Text("CellPadding.y = %.2f", style.CellPadding.y);
6263
                if ((row % 3) == 2)
6264
                    ImGui::PopStyleVar();
6265
            }
6266
            ImGui::EndTable();
6267
        }
6268
6269
        ImGui::TreePop();
6270
    }
6271
6272
    if (open_action != -1)
6273
        ImGui::SetNextItemOpen(open_action != 0);
6274
    IMGUI_DEMO_MARKER("Tables/Outer size");
6275
    if (ImGui::TreeNode("Outer size"))
6276
    {
6277
        // Showcasing use of ImGuiTableFlags_NoHostExtendX and ImGuiTableFlags_NoHostExtendY
6278
        // Important to that note how the two flags have slightly different behaviors!
6279
        ImGui::Text("Using NoHostExtendX and NoHostExtendY:");
6280
        PushStyleCompact();
6281
        static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_ContextMenuInBody | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX;
6282
        ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX);
6283
        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.");
6284
        ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendY", &flags, ImGuiTableFlags_NoHostExtendY);
6285
        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.");
6286
        PopStyleCompact();
6287
6288
        ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 5.5f);
6289
        if (ImGui::BeginTable("table1", 3, flags, outer_size))
6290
        {
6291
            for (int row = 0; row < 10; row++)
6292
            {
6293
                ImGui::TableNextRow();
6294
                for (int column = 0; column < 3; column++)
6295
                {
6296
                    ImGui::TableNextColumn();
6297
                    ImGui::Text("Cell %d,%d", column, row);
6298
                }
6299
            }
6300
            ImGui::EndTable();
6301
        }
6302
        ImGui::SameLine();
6303
        ImGui::Text("Hello!");
6304
6305
        ImGui::Spacing();
6306
6307
        ImGui::Text("Using explicit size:");
6308
        if (ImGui::BeginTable("table2", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(TEXT_BASE_WIDTH * 30, 0.0f)))
6309
        {
6310
            for (int row = 0; row < 5; row++)
6311
            {
6312
                ImGui::TableNextRow();
6313
                for (int column = 0; column < 3; column++)
6314
                {
6315
                    ImGui::TableNextColumn();
6316
                    ImGui::Text("Cell %d,%d", column, row);
6317
                }
6318
            }
6319
            ImGui::EndTable();
6320
        }
6321
        ImGui::SameLine();
6322
        if (ImGui::BeginTable("table3", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(TEXT_BASE_WIDTH * 30, 0.0f)))
6323
        {
6324
            for (int row = 0; row < 3; row++)
6325
            {
6326
                ImGui::TableNextRow(0, TEXT_BASE_HEIGHT * 1.5f);
6327
                for (int column = 0; column < 3; column++)
6328
                {
6329
                    ImGui::TableNextColumn();
6330
                    ImGui::Text("Cell %d,%d", column, row);
6331
                }
6332
            }
6333
            ImGui::EndTable();
6334
        }
6335
6336
        ImGui::TreePop();
6337
    }
6338
6339
    if (open_action != -1)
6340
        ImGui::SetNextItemOpen(open_action != 0);
6341
    IMGUI_DEMO_MARKER("Tables/Background color");
6342
    if (ImGui::TreeNode("Background color"))
6343
    {
6344
        static ImGuiTableFlags flags = ImGuiTableFlags_RowBg;
6345
        static int row_bg_type = 1;
6346
        static int row_bg_target = 1;
6347
        static int cell_bg_type = 1;
6348
6349
        PushStyleCompact();
6350
        ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags, ImGuiTableFlags_Borders);
6351
        ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg);
6352
        ImGui::SameLine(); HelpMarker("ImGuiTableFlags_RowBg automatically sets RowBg0 to alternative colors pulled from the Style.");
6353
        ImGui::Combo("row bg type", (int*)&row_bg_type, "None\0Red\0Gradient\0");
6354
        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.");
6355
        ImGui::Combo("cell bg type", (int*)&cell_bg_type, "None\0Blue\0"); ImGui::SameLine(); HelpMarker("We are colorizing cells to B1->C2 here.");
6356
        IM_ASSERT(row_bg_type >= 0 && row_bg_type <= 2);
6357
        IM_ASSERT(row_bg_target >= 0 && row_bg_target <= 1);
6358
        IM_ASSERT(cell_bg_type >= 0 && cell_bg_type <= 1);
6359
        PopStyleCompact();
6360
6361
        if (ImGui::BeginTable("table1", 5, flags))
6362
        {
6363
            for (int row = 0; row < 6; row++)
6364
            {
6365
                ImGui::TableNextRow();
6366
6367
                // Demonstrate setting a row background color with 'ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBgX, ...)'
6368
                // 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.
6369
                if (row_bg_type != 0)
6370
                {
6371
                    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?
6372
                    ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0 + row_bg_target, row_bg_color);
6373
                }
6374
6375
                // Fill cells
6376
                for (int column = 0; column < 5; column++)
6377
                {
6378
                    ImGui::TableSetColumnIndex(column);
6379
                    ImGui::Text("%c%c", 'A' + row, '0' + column);
6380
6381
                    // Change background of Cells B1->C2
6382
                    // Demonstrate setting a cell background color with 'ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ...)'
6383
                    // (the CellBg color will be blended over the RowBg and ColumnBg colors)
6384
                    // We can also pass a column number as a third parameter to TableSetBgColor() and do this outside the column loop.
6385
                    if (row >= 1 && row <= 2 && column >= 1 && column <= 2 && cell_bg_type == 1)
6386
                    {
6387
                        ImU32 cell_bg_color = ImGui::GetColorU32(ImVec4(0.3f, 0.3f, 0.7f, 0.65f));
6388
                        ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, cell_bg_color);
6389
                    }
6390
                }
6391
            }
6392
            ImGui::EndTable();
6393
        }
6394
        ImGui::TreePop();
6395
    }
6396
6397
    if (open_action != -1)
6398
        ImGui::SetNextItemOpen(open_action != 0);
6399
    IMGUI_DEMO_MARKER("Tables/Tree view");
6400
    if (ImGui::TreeNode("Tree view"))
6401
    {
6402
        static ImGuiTableFlags flags = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody;
6403
6404
        static ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAllColumns;
6405
        ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth",  &tree_node_flags, ImGuiTreeNodeFlags_SpanFullWidth);
6406
        ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanTextWidth",  &tree_node_flags, ImGuiTreeNodeFlags_SpanTextWidth);
6407
        ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &tree_node_flags, ImGuiTreeNodeFlags_SpanAllColumns);
6408
6409
        HelpMarker("See \"Columns flags\" section to configure how indentation is applied to individual columns.");
6410
        if (ImGui::BeginTable("3ways", 3, flags))
6411
        {
6412
            // The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On
6413
            ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_NoHide);
6414
            ImGui::TableSetupColumn("Size", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f);
6415
            ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 18.0f);
6416
            ImGui::TableHeadersRow();
6417
6418
            // Simple storage to output a dummy file-system.
6419
            struct MyTreeNode
6420
            {
6421
                const char*     Name;
6422
                const char*     Type;
6423
                int             Size;
6424
                int             ChildIdx;
6425
                int             ChildCount;
6426
                static void DisplayNode(const MyTreeNode* node, const MyTreeNode* all_nodes)
6427
                {
6428
                    ImGui::TableNextRow();
6429
                    ImGui::TableNextColumn();
6430
                    const bool is_folder = (node->ChildCount > 0);
6431
                    if (is_folder)
6432
                    {
6433
                        bool open = ImGui::TreeNodeEx(node->Name, tree_node_flags);
6434
                        ImGui::TableNextColumn();
6435
                        ImGui::TextDisabled("--");
6436
                        ImGui::TableNextColumn();
6437
                        ImGui::TextUnformatted(node->Type);
6438
                        if (open)
6439
                        {
6440
                            for (int child_n = 0; child_n < node->ChildCount; child_n++)
6441
                                DisplayNode(&all_nodes[node->ChildIdx + child_n], all_nodes);
6442
                            ImGui::TreePop();
6443
                        }
6444
                    }
6445
                    else
6446
                    {
6447
                        ImGui::TreeNodeEx(node->Name, tree_node_flags | ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_NoTreePushOnOpen);
6448
                        ImGui::TableNextColumn();
6449
                        ImGui::Text("%d", node->Size);
6450
                        ImGui::TableNextColumn();
6451
                        ImGui::TextUnformatted(node->Type);
6452
                    }
6453
                }
6454
            };
6455
            static const MyTreeNode nodes[] =
6456
            {
6457
                { "Root",                         "Folder",       -1,       1, 3    }, // 0
6458
                { "Music",                        "Folder",       -1,       4, 2    }, // 1
6459
                { "Textures",                     "Folder",       -1,       6, 3    }, // 2
6460
                { "desktop.ini",                  "System file",  1024,    -1,-1    }, // 3
6461
                { "File1_a.wav",                  "Audio file",   123000,  -1,-1    }, // 4
6462
                { "File1_b.wav",                  "Audio file",   456000,  -1,-1    }, // 5
6463
                { "Image001.png",                 "Image file",   203128,  -1,-1    }, // 6
6464
                { "Copy of Image001.png",         "Image file",   203256,  -1,-1    }, // 7
6465
                { "Copy of Image001 (Final2).png","Image file",   203512,  -1,-1    }, // 8
6466
            };
6467
6468
            MyTreeNode::DisplayNode(&nodes[0], nodes);
6469
6470
            ImGui::EndTable();
6471
        }
6472
        ImGui::TreePop();
6473
    }
6474
6475
    if (open_action != -1)
6476
        ImGui::SetNextItemOpen(open_action != 0);
6477
    IMGUI_DEMO_MARKER("Tables/Item width");
6478
    if (ImGui::TreeNode("Item width"))
6479
    {
6480
        HelpMarker(
6481
            "Showcase using PushItemWidth() and how it is preserved on a per-column basis.\n\n"
6482
            "Note that on auto-resizing non-resizable fixed columns, querying the content width for "
6483
            "e.g. right-alignment doesn't make sense.");
6484
        if (ImGui::BeginTable("table_item_width", 3, ImGuiTableFlags_Borders))
6485
        {
6486
            ImGui::TableSetupColumn("small");
6487
            ImGui::TableSetupColumn("half");
6488
            ImGui::TableSetupColumn("right-align");
6489
            ImGui::TableHeadersRow();
6490
6491
            for (int row = 0; row < 3; row++)
6492
            {
6493
                ImGui::TableNextRow();
6494
                if (row == 0)
6495
                {
6496
                    // Setup ItemWidth once (instead of setting up every time, which is also possible but less efficient)
6497
                    ImGui::TableSetColumnIndex(0);
6498
                    ImGui::PushItemWidth(TEXT_BASE_WIDTH * 3.0f); // Small
6499
                    ImGui::TableSetColumnIndex(1);
6500
                    ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.5f);
6501
                    ImGui::TableSetColumnIndex(2);
6502
                    ImGui::PushItemWidth(-FLT_MIN); // Right-aligned
6503
                }
6504
6505
                // Draw our contents
6506
                static float dummy_f = 0.0f;
6507
                ImGui::PushID(row);
6508
                ImGui::TableSetColumnIndex(0);
6509
                ImGui::SliderFloat("float0", &dummy_f, 0.0f, 1.0f);
6510
                ImGui::TableSetColumnIndex(1);
6511
                ImGui::SliderFloat("float1", &dummy_f, 0.0f, 1.0f);
6512
                ImGui::TableSetColumnIndex(2);
6513
                ImGui::SliderFloat("##float2", &dummy_f, 0.0f, 1.0f); // No visible label since right-aligned
6514
                ImGui::PopID();
6515
            }
6516
            ImGui::EndTable();
6517
        }
6518
        ImGui::TreePop();
6519
    }
6520
6521
    // Demonstrate using TableHeader() calls instead of TableHeadersRow()
6522
    if (open_action != -1)
6523
        ImGui::SetNextItemOpen(open_action != 0);
6524
    IMGUI_DEMO_MARKER("Tables/Custom headers");
6525
    if (ImGui::TreeNode("Custom headers"))
6526
    {
6527
        const int COLUMNS_COUNT = 3;
6528
        if (ImGui::BeginTable("table_custom_headers", COLUMNS_COUNT, ImGuiTableFlags_Borders | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
6529
        {
6530
            ImGui::TableSetupColumn("Apricot");
6531
            ImGui::TableSetupColumn("Banana");
6532
            ImGui::TableSetupColumn("Cherry");
6533
6534
            // Dummy entire-column selection storage
6535
            // FIXME: It would be nice to actually demonstrate full-featured selection using those checkbox.
6536
            static bool column_selected[3] = {};
6537
6538
            // Instead of calling TableHeadersRow() we'll submit custom headers ourselves.
6539
            // (A different approach is also possible:
6540
            //    - Specify ImGuiTableColumnFlags_NoHeaderLabel in some TableSetupColumn() call.
6541
            //    - Call TableHeadersRow() normally. This will submit TableHeader() with no name.
6542
            //    - Then call TableSetColumnIndex() to position yourself in the column and submit your stuff e.g. Checkbox().)
6543
            ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
6544
            for (int column = 0; column < COLUMNS_COUNT; column++)
6545
            {
6546
                ImGui::TableSetColumnIndex(column);
6547
                const char* column_name = ImGui::TableGetColumnName(column); // Retrieve name passed to TableSetupColumn()
6548
                ImGui::PushID(column);
6549
                ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
6550
                ImGui::Checkbox("##checkall", &column_selected[column]);
6551
                ImGui::PopStyleVar();
6552
                ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
6553
                ImGui::TableHeader(column_name);
6554
                ImGui::PopID();
6555
            }
6556
6557
            // Submit table contents
6558
            for (int row = 0; row < 5; row++)
6559
            {
6560
                ImGui::TableNextRow();
6561
                for (int column = 0; column < 3; column++)
6562
                {
6563
                    char buf[32];
6564
                    sprintf(buf, "Cell %d,%d", column, row);
6565
                    ImGui::TableSetColumnIndex(column);
6566
                    ImGui::Selectable(buf, column_selected[column]);
6567
                }
6568
            }
6569
            ImGui::EndTable();
6570
        }
6571
        ImGui::TreePop();
6572
    }
6573
6574
    // Demonstrate using ImGuiTableColumnFlags_AngledHeader flag to create angled headers
6575
    if (open_action != -1)
6576
        ImGui::SetNextItemOpen(open_action != 0);
6577
    IMGUI_DEMO_MARKER("Tables/Angled headers");
6578
    if (ImGui::TreeNode("Angled headers"))
6579
    {
6580
        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" };
6581
        const int columns_count = IM_ARRAYSIZE(column_names);
6582
        const int rows_count = 12;
6583
6584
        static ImGuiTableFlags table_flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_Hideable | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_HighlightHoveredColumn;
6585
        static ImGuiTableColumnFlags column_flags = ImGuiTableColumnFlags_AngledHeader | ImGuiTableColumnFlags_WidthFixed;
6586
        static bool bools[columns_count * rows_count] = {}; // Dummy storage selection storage
6587
        static int frozen_cols = 1;
6588
        static int frozen_rows = 2;
6589
        ImGui::CheckboxFlags("_ScrollX", &table_flags, ImGuiTableFlags_ScrollX);
6590
        ImGui::CheckboxFlags("_ScrollY", &table_flags, ImGuiTableFlags_ScrollY);
6591
        ImGui::CheckboxFlags("_Resizable", &table_flags, ImGuiTableFlags_Resizable);
6592
        ImGui::CheckboxFlags("_Sortable", &table_flags, ImGuiTableFlags_Sortable);
6593
        ImGui::CheckboxFlags("_NoBordersInBody", &table_flags, ImGuiTableFlags_NoBordersInBody);
6594
        ImGui::CheckboxFlags("_HighlightHoveredColumn", &table_flags, ImGuiTableFlags_HighlightHoveredColumn);
6595
        ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
6596
        ImGui::SliderInt("Frozen columns", &frozen_cols, 0, 2);
6597
        ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
6598
        ImGui::SliderInt("Frozen rows", &frozen_rows, 0, 2);
6599
        ImGui::CheckboxFlags("Disable header contributing to column width", &column_flags, ImGuiTableColumnFlags_NoHeaderWidth);
6600
6601
        if (ImGui::TreeNode("Style settings"))
6602
        {
6603
            ImGui::SameLine();
6604
            HelpMarker("Giving access to some ImGuiStyle value in this demo for convenience.");
6605
            ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
6606
            ImGui::SliderAngle("style.TableAngledHeadersAngle", &ImGui::GetStyle().TableAngledHeadersAngle, -50.0f, +50.0f);
6607
            ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
6608
            ImGui::SliderFloat2("style.TableAngledHeadersTextAlign", (float*)&ImGui::GetStyle().TableAngledHeadersTextAlign, 0.0f, 1.0f, "%.2f");
6609
            ImGui::TreePop();
6610
        }
6611
6612
        if (ImGui::BeginTable("table_angled_headers", columns_count, table_flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 12)))
6613
        {
6614
            ImGui::TableSetupColumn(column_names[0], ImGuiTableColumnFlags_NoHide | ImGuiTableColumnFlags_NoReorder);
6615
            for (int n = 1; n < columns_count; n++)
6616
                ImGui::TableSetupColumn(column_names[n], column_flags);
6617
            ImGui::TableSetupScrollFreeze(frozen_cols, frozen_rows);
6618
6619
            ImGui::TableAngledHeadersRow(); // Draw angled headers for all columns with the ImGuiTableColumnFlags_AngledHeader flag.
6620
            ImGui::TableHeadersRow();       // Draw remaining headers and allow access to context-menu and other functions.
6621
            for (int row = 0; row < rows_count; row++)
6622
            {
6623
                ImGui::PushID(row);
6624
                ImGui::TableNextRow();
6625
                ImGui::TableSetColumnIndex(0);
6626
                ImGui::AlignTextToFramePadding();
6627
                ImGui::Text("Track %d", row);
6628
                for (int column = 1; column < columns_count; column++)
6629
                    if (ImGui::TableSetColumnIndex(column))
6630
                    {
6631
                        ImGui::PushID(column);
6632
                        ImGui::Checkbox("", &bools[row * columns_count + column]);
6633
                        ImGui::PopID();
6634
                    }
6635
                ImGui::PopID();
6636
            }
6637
            ImGui::EndTable();
6638
        }
6639
        ImGui::TreePop();
6640
    }
6641
6642
    // Demonstrate creating custom context menus inside columns,
6643
    // while playing it nice with context menus provided by TableHeadersRow()/TableHeader()
6644
    if (open_action != -1)
6645
        ImGui::SetNextItemOpen(open_action != 0);
6646
    IMGUI_DEMO_MARKER("Tables/Context menus");
6647
    if (ImGui::TreeNode("Context menus"))
6648
    {
6649
        HelpMarker(
6650
            "By default, right-clicking over a TableHeadersRow()/TableHeader() line will open the default context-menu.\n"
6651
            "Using ImGuiTableFlags_ContextMenuInBody we also allow right-clicking over columns body.");
6652
        static ImGuiTableFlags flags1 = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_ContextMenuInBody;
6653
6654
        PushStyleCompact();
6655
        ImGui::CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", &flags1, ImGuiTableFlags_ContextMenuInBody);
6656
        PopStyleCompact();
6657
6658
        // Context Menus: first example
6659
        // [1.1] Right-click on the TableHeadersRow() line to open the default table context menu.
6660
        // [1.2] Right-click in columns also open the default table context menu (if ImGuiTableFlags_ContextMenuInBody is set)
6661
        const int COLUMNS_COUNT = 3;
6662
        if (ImGui::BeginTable("table_context_menu", COLUMNS_COUNT, flags1))
6663
        {
6664
            ImGui::TableSetupColumn("One");
6665
            ImGui::TableSetupColumn("Two");
6666
            ImGui::TableSetupColumn("Three");
6667
6668
            // [1.1]] Right-click on the TableHeadersRow() line to open the default table context menu.
6669
            ImGui::TableHeadersRow();
6670
6671
            // Submit dummy contents
6672
            for (int row = 0; row < 4; row++)
6673
            {
6674
                ImGui::TableNextRow();
6675
                for (int column = 0; column < COLUMNS_COUNT; column++)
6676
                {
6677
                    ImGui::TableSetColumnIndex(column);
6678
                    ImGui::Text("Cell %d,%d", column, row);
6679
                }
6680
            }
6681
            ImGui::EndTable();
6682
        }
6683
6684
        // Context Menus: second example
6685
        // [2.1] Right-click on the TableHeadersRow() line to open the default table context menu.
6686
        // [2.2] Right-click on the ".." to open a custom popup
6687
        // [2.3] Right-click in columns to open another custom popup
6688
        HelpMarker(
6689
            "Demonstrate mixing table context menu (over header), item context button (over button) "
6690
            "and custom per-colunm context menu (over column body).");
6691
        ImGuiTableFlags flags2 = ImGuiTableFlags_Resizable | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders;
6692
        if (ImGui::BeginTable("table_context_menu_2", COLUMNS_COUNT, flags2))
6693
        {
6694
            ImGui::TableSetupColumn("One");
6695
            ImGui::TableSetupColumn("Two");
6696
            ImGui::TableSetupColumn("Three");
6697
6698
            // [2.1] Right-click on the TableHeadersRow() line to open the default table context menu.
6699
            ImGui::TableHeadersRow();
6700
            for (int row = 0; row < 4; row++)
6701
            {
6702
                ImGui::TableNextRow();
6703
                for (int column = 0; column < COLUMNS_COUNT; column++)
6704
                {
6705
                    // Submit dummy contents
6706
                    ImGui::TableSetColumnIndex(column);
6707
                    ImGui::Text("Cell %d,%d", column, row);
6708
                    ImGui::SameLine();
6709
6710
                    // [2.2] Right-click on the ".." to open a custom popup
6711
                    ImGui::PushID(row * COLUMNS_COUNT + column);
6712
                    ImGui::SmallButton("..");
6713
                    if (ImGui::BeginPopupContextItem())
6714
                    {
6715
                        ImGui::Text("This is the popup for Button(\"..\") in Cell %d,%d", column, row);
6716
                        if (ImGui::Button("Close"))
6717
                            ImGui::CloseCurrentPopup();
6718
                        ImGui::EndPopup();
6719
                    }
6720
                    ImGui::PopID();
6721
                }
6722
            }
6723
6724
            // [2.3] Right-click anywhere in columns to open another custom popup
6725
            // (instead of testing for !IsAnyItemHovered() we could also call OpenPopup() with ImGuiPopupFlags_NoOpenOverExistingPopup
6726
            // to manage popup priority as the popups triggers, here "are we hovering a column" are overlapping)
6727
            int hovered_column = -1;
6728
            for (int column = 0; column < COLUMNS_COUNT + 1; column++)
6729
            {
6730
                ImGui::PushID(column);
6731
                if (ImGui::TableGetColumnFlags(column) & ImGuiTableColumnFlags_IsHovered)
6732
                    hovered_column = column;
6733
                if (hovered_column == column && !ImGui::IsAnyItemHovered() && ImGui::IsMouseReleased(1))
6734
                    ImGui::OpenPopup("MyPopup");
6735
                if (ImGui::BeginPopup("MyPopup"))
6736
                {
6737
                    if (column == COLUMNS_COUNT)
6738
                        ImGui::Text("This is a custom popup for unused space after the last column.");
6739
                    else
6740
                        ImGui::Text("This is a custom popup for Column %d", column);
6741
                    if (ImGui::Button("Close"))
6742
                        ImGui::CloseCurrentPopup();
6743
                    ImGui::EndPopup();
6744
                }
6745
                ImGui::PopID();
6746
            }
6747
6748
            ImGui::EndTable();
6749
            ImGui::Text("Hovered column: %d", hovered_column);
6750
        }
6751
        ImGui::TreePop();
6752
    }
6753
6754
    // Demonstrate creating multiple tables with the same ID
6755
    if (open_action != -1)
6756
        ImGui::SetNextItemOpen(open_action != 0);
6757
    IMGUI_DEMO_MARKER("Tables/Synced instances");
6758
    if (ImGui::TreeNode("Synced instances"))
6759
    {
6760
        HelpMarker("Multiple tables with the same identifier will share their settings, width, visibility, order etc.");
6761
6762
        static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoSavedSettings;
6763
        ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
6764
        ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
6765
        ImGui::CheckboxFlags("ImGuiTableFlags_SizingFixedFit", &flags, ImGuiTableFlags_SizingFixedFit);
6766
        ImGui::CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", &flags, ImGuiTableFlags_HighlightHoveredColumn);
6767
        for (int n = 0; n < 3; n++)
6768
        {
6769
            char buf[32];
6770
            sprintf(buf, "Synced Table %d", n);
6771
            bool open = ImGui::CollapsingHeader(buf, ImGuiTreeNodeFlags_DefaultOpen);
6772
            if (open && ImGui::BeginTable("Table", 3, flags, ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 5)))
6773
            {
6774
                ImGui::TableSetupColumn("One");
6775
                ImGui::TableSetupColumn("Two");
6776
                ImGui::TableSetupColumn("Three");
6777
                ImGui::TableHeadersRow();
6778
                const int cell_count = (n == 1) ? 27 : 9; // Make second table have a scrollbar to verify that additional decoration is not affecting column positions.
6779
                for (int cell = 0; cell < cell_count; cell++)
6780
                {
6781
                    ImGui::TableNextColumn();
6782
                    ImGui::Text("this cell %d", cell);
6783
                }
6784
                ImGui::EndTable();
6785
            }
6786
        }
6787
        ImGui::TreePop();
6788
    }
6789
6790
    // Demonstrate using Sorting facilities
6791
    // This is a simplified version of the "Advanced" example, where we mostly focus on the code necessary to handle sorting.
6792
    // Note that the "Advanced" example also showcase manually triggering a sort (e.g. if item quantities have been modified)
6793
    static const char* template_items_names[] =
6794
    {
6795
        "Banana", "Apple", "Cherry", "Watermelon", "Grapefruit", "Strawberry", "Mango",
6796
        "Kiwi", "Orange", "Pineapple", "Blueberry", "Plum", "Coconut", "Pear", "Apricot"
6797
    };
6798
    if (open_action != -1)
6799
        ImGui::SetNextItemOpen(open_action != 0);
6800
    IMGUI_DEMO_MARKER("Tables/Sorting");
6801
    if (ImGui::TreeNode("Sorting"))
6802
    {
6803
        // Create item list
6804
        static ImVector<MyItem> items;
6805
        if (items.Size == 0)
6806
        {
6807
            items.resize(50, MyItem());
6808
            for (int n = 0; n < items.Size; n++)
6809
            {
6810
                const int template_n = n % IM_ARRAYSIZE(template_items_names);
6811
                MyItem& item = items[n];
6812
                item.ID = n;
6813
                item.Name = template_items_names[template_n];
6814
                item.Quantity = (n * n - n) % 20; // Assign default quantities
6815
            }
6816
        }
6817
6818
        // Options
6819
        static ImGuiTableFlags flags =
6820
            ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti
6821
            | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_NoBordersInBody
6822
            | ImGuiTableFlags_ScrollY;
6823
        PushStyleCompact();
6824
        ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti);
6825
        ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).");
6826
        ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate);
6827
        ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).");
6828
        PopStyleCompact();
6829
6830
        if (ImGui::BeginTable("table_sorting", 4, flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 15), 0.0f))
6831
        {
6832
            // Declare columns
6833
            // We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications.
6834
            // This is so our sort function can identify a column given our own identifier. We could also identify them based on their index!
6835
            // Demonstrate using a mixture of flags among available sort-related flags:
6836
            // - ImGuiTableColumnFlags_DefaultSort
6837
            // - ImGuiTableColumnFlags_NoSort / ImGuiTableColumnFlags_NoSortAscending / ImGuiTableColumnFlags_NoSortDescending
6838
            // - ImGuiTableColumnFlags_PreferSortAscending / ImGuiTableColumnFlags_PreferSortDescending
6839
            ImGui::TableSetupColumn("ID",       ImGuiTableColumnFlags_DefaultSort          | ImGuiTableColumnFlags_WidthFixed,   0.0f, MyItemColumnID_ID);
6840
            ImGui::TableSetupColumn("Name",                                                  ImGuiTableColumnFlags_WidthFixed,   0.0f, MyItemColumnID_Name);
6841
            ImGui::TableSetupColumn("Action",   ImGuiTableColumnFlags_NoSort               | ImGuiTableColumnFlags_WidthFixed,   0.0f, MyItemColumnID_Action);
6842
            ImGui::TableSetupColumn("Quantity", ImGuiTableColumnFlags_PreferSortDescending | ImGuiTableColumnFlags_WidthStretch, 0.0f, MyItemColumnID_Quantity);
6843
            ImGui::TableSetupScrollFreeze(0, 1); // Make row always visible
6844
            ImGui::TableHeadersRow();
6845
6846
            // Sort our data if sort specs have been changed!
6847
            if (ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs())
6848
                if (sort_specs->SpecsDirty)
6849
                {
6850
                    MyItem::SortWithSortSpecs(sort_specs, items.Data, items.Size);
6851
                    sort_specs->SpecsDirty = false;
6852
                }
6853
6854
            // Demonstrate using clipper for large vertical lists
6855
            ImGuiListClipper clipper;
6856
            clipper.Begin(items.Size);
6857
            while (clipper.Step())
6858
                for (int row_n = clipper.DisplayStart; row_n < clipper.DisplayEnd; row_n++)
6859
                {
6860
                    // Display a data item
6861
                    MyItem* item = &items[row_n];
6862
                    ImGui::PushID(item->ID);
6863
                    ImGui::TableNextRow();
6864
                    ImGui::TableNextColumn();
6865
                    ImGui::Text("%04d", item->ID);
6866
                    ImGui::TableNextColumn();
6867
                    ImGui::TextUnformatted(item->Name);
6868
                    ImGui::TableNextColumn();
6869
                    ImGui::SmallButton("None");
6870
                    ImGui::TableNextColumn();
6871
                    ImGui::Text("%d", item->Quantity);
6872
                    ImGui::PopID();
6873
                }
6874
            ImGui::EndTable();
6875
        }
6876
        ImGui::TreePop();
6877
    }
6878
6879
    // In this example we'll expose most table flags and settings.
6880
    // For specific flags and settings refer to the corresponding section for more detailed explanation.
6881
    // This section is mostly useful to experiment with combining certain flags or settings with each others.
6882
    //ImGui::SetNextItemOpen(true, ImGuiCond_Once); // [DEBUG]
6883
    if (open_action != -1)
6884
        ImGui::SetNextItemOpen(open_action != 0);
6885
    IMGUI_DEMO_MARKER("Tables/Advanced");
6886
    if (ImGui::TreeNode("Advanced"))
6887
    {
6888
        static ImGuiTableFlags flags =
6889
            ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable
6890
            | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti
6891
            | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBody
6892
            | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY
6893
            | ImGuiTableFlags_SizingFixedFit;
6894
        static ImGuiTableColumnFlags columns_base_flags = ImGuiTableColumnFlags_None;
6895
6896
        enum ContentsType { CT_Text, CT_Button, CT_SmallButton, CT_FillButton, CT_Selectable, CT_SelectableSpanRow };
6897
        static int contents_type = CT_SelectableSpanRow;
6898
        const char* contents_type_names[] = { "Text", "Button", "SmallButton", "FillButton", "Selectable", "Selectable (span row)" };
6899
        static int freeze_cols = 1;
6900
        static int freeze_rows = 1;
6901
        static int items_count = IM_ARRAYSIZE(template_items_names) * 2;
6902
        static ImVec2 outer_size_value = ImVec2(0.0f, TEXT_BASE_HEIGHT * 12);
6903
        static float row_min_height = 0.0f; // Auto
6904
        static float inner_width_with_scroll = 0.0f; // Auto-extend
6905
        static bool outer_size_enabled = true;
6906
        static bool show_headers = true;
6907
        static bool show_wrapped_text = false;
6908
        //static ImGuiTextFilter filter;
6909
        //ImGui::SetNextItemOpen(true, ImGuiCond_Once); // FIXME-TABLE: Enabling this results in initial clipped first pass on table which tend to affect column sizing
6910
        if (ImGui::TreeNode("Options"))
6911
        {
6912
            // Make the UI compact because there are so many fields
6913
            PushStyleCompact();
6914
            ImGui::PushItemWidth(TEXT_BASE_WIDTH * 28.0f);
6915
6916
            if (ImGui::TreeNodeEx("Features:", ImGuiTreeNodeFlags_DefaultOpen))
6917
            {
6918
                ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
6919
                ImGui::CheckboxFlags("ImGuiTableFlags_Reorderable", &flags, ImGuiTableFlags_Reorderable);
6920
                ImGui::CheckboxFlags("ImGuiTableFlags_Hideable", &flags, ImGuiTableFlags_Hideable);
6921
                ImGui::CheckboxFlags("ImGuiTableFlags_Sortable", &flags, ImGuiTableFlags_Sortable);
6922
                ImGui::CheckboxFlags("ImGuiTableFlags_NoSavedSettings", &flags, ImGuiTableFlags_NoSavedSettings);
6923
                ImGui::CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", &flags, ImGuiTableFlags_ContextMenuInBody);
6924
                ImGui::TreePop();
6925
            }
6926
6927
            if (ImGui::TreeNodeEx("Decorations:", ImGuiTreeNodeFlags_DefaultOpen))
6928
            {
6929
                ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg);
6930
                ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV);
6931
                ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags, ImGuiTableFlags_BordersOuterV);
6932
                ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags, ImGuiTableFlags_BordersInnerV);
6933
                ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags, ImGuiTableFlags_BordersH);
6934
                ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterH", &flags, ImGuiTableFlags_BordersOuterH);
6935
                ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerH", &flags, ImGuiTableFlags_BordersInnerH);
6936
                ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers");
6937
                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)");
6938
                ImGui::TreePop();
6939
            }
6940
6941
            if (ImGui::TreeNodeEx("Sizing:", ImGuiTreeNodeFlags_DefaultOpen))
6942
            {
6943
                EditTableSizingFlags(&flags);
6944
                ImGui::SameLine(); HelpMarker("In the Advanced demo we override the policy of each column so those table-wide settings have less effect that typical.");
6945
                ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX);
6946
                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.");
6947
                ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendY", &flags, ImGuiTableFlags_NoHostExtendY);
6948
                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.");
6949
                ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags, ImGuiTableFlags_NoKeepColumnsVisible);
6950
                ImGui::SameLine(); HelpMarker("Only available if ScrollX is disabled.");
6951
                ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths);
6952
                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.");
6953
                ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip);
6954
                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.");
6955
                ImGui::TreePop();
6956
            }
6957
6958
            if (ImGui::TreeNodeEx("Padding:", ImGuiTreeNodeFlags_DefaultOpen))
6959
            {
6960
                ImGui::CheckboxFlags("ImGuiTableFlags_PadOuterX", &flags, ImGuiTableFlags_PadOuterX);
6961
                ImGui::CheckboxFlags("ImGuiTableFlags_NoPadOuterX", &flags, ImGuiTableFlags_NoPadOuterX);
6962
                ImGui::CheckboxFlags("ImGuiTableFlags_NoPadInnerX", &flags, ImGuiTableFlags_NoPadInnerX);
6963
                ImGui::TreePop();
6964
            }
6965
6966
            if (ImGui::TreeNodeEx("Scrolling:", ImGuiTreeNodeFlags_DefaultOpen))
6967
            {
6968
                ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX);
6969
                ImGui::SameLine();
6970
                ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
6971
                ImGui::DragInt("freeze_cols", &freeze_cols, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
6972
                ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
6973
                ImGui::SameLine();
6974
                ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
6975
                ImGui::DragInt("freeze_rows", &freeze_rows, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
6976
                ImGui::TreePop();
6977
            }
6978
6979
            if (ImGui::TreeNodeEx("Sorting:", ImGuiTreeNodeFlags_DefaultOpen))
6980
            {
6981
                ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti);
6982
                ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).");
6983
                ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate);
6984
                ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).");
6985
                ImGui::TreePop();
6986
            }
6987
6988
            if (ImGui::TreeNodeEx("Headers:", ImGuiTreeNodeFlags_DefaultOpen))
6989
            {
6990
                ImGui::Checkbox("show_headers", &show_headers);
6991
                ImGui::CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", &flags, ImGuiTableFlags_HighlightHoveredColumn);
6992
                ImGui::CheckboxFlags("ImGuiTableColumnFlags_AngledHeader", &columns_base_flags, ImGuiTableColumnFlags_AngledHeader);
6993
                ImGui::SameLine(); HelpMarker("Enable AngledHeader on all columns. Best enabled on selected narrow columns (see \"Angled headers\" section of the demo).");
6994
                ImGui::TreePop();
6995
            }
6996
6997
            if (ImGui::TreeNodeEx("Other:", ImGuiTreeNodeFlags_DefaultOpen))
6998
            {
6999
                ImGui::Checkbox("show_wrapped_text", &show_wrapped_text);
7000
7001
                ImGui::DragFloat2("##OuterSize", &outer_size_value.x);
7002
                ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
7003
                ImGui::Checkbox("outer_size", &outer_size_enabled);
7004
                ImGui::SameLine();
7005
                HelpMarker("If scrolling is disabled (ScrollX and ScrollY not set):\n"
7006
                    "- The table is output directly in the parent window.\n"
7007
                    "- OuterSize.x < 0.0f will right-align the table.\n"
7008
                    "- OuterSize.x = 0.0f will narrow fit the table unless there are any Stretch columns.\n"
7009
                    "- OuterSize.y then becomes the minimum size for the table, which will extend vertically if there are more rows (unless NoHostExtendY is set).");
7010
7011
                // From a user point of view we will tend to use 'inner_width' differently depending on whether our table is embedding scrolling.
7012
                // To facilitate toying with this demo we will actually pass 0.0f to the BeginTable() when ScrollX is disabled.
7013
                ImGui::DragFloat("inner_width (when ScrollX active)", &inner_width_with_scroll, 1.0f, 0.0f, FLT_MAX);
7014
7015
                ImGui::DragFloat("row_min_height", &row_min_height, 1.0f, 0.0f, FLT_MAX);
7016
                ImGui::SameLine(); HelpMarker("Specify height of the Selectable item.");
7017
7018
                ImGui::DragInt("items_count", &items_count, 0.1f, 0, 9999);
7019
                ImGui::Combo("items_type (first column)", &contents_type, contents_type_names, IM_ARRAYSIZE(contents_type_names));
7020
                //filter.Draw("filter");
7021
                ImGui::TreePop();
7022
            }
7023
7024
            ImGui::PopItemWidth();
7025
            PopStyleCompact();
7026
            ImGui::Spacing();
7027
            ImGui::TreePop();
7028
        }
7029
7030
        // Update item list if we changed the number of items
7031
        static ImVector<MyItem> items;
7032
        static ImVector<int> selection;
7033
        static bool items_need_sort = false;
7034
        if (items.Size != items_count)
7035
        {
7036
            items.resize(items_count, MyItem());
7037
            for (int n = 0; n < items_count; n++)
7038
            {
7039
                const int template_n = n % IM_ARRAYSIZE(template_items_names);
7040
                MyItem& item = items[n];
7041
                item.ID = n;
7042
                item.Name = template_items_names[template_n];
7043
                item.Quantity = (template_n == 3) ? 10 : (template_n == 4) ? 20 : 0; // Assign default quantities
7044
            }
7045
        }
7046
7047
        const ImDrawList* parent_draw_list = ImGui::GetWindowDrawList();
7048
        const int parent_draw_list_draw_cmd_count = parent_draw_list->CmdBuffer.Size;
7049
        ImVec2 table_scroll_cur, table_scroll_max; // For debug display
7050
        const ImDrawList* table_draw_list = NULL;  // "
7051
7052
        // Submit table
7053
        const float inner_width_to_use = (flags & ImGuiTableFlags_ScrollX) ? inner_width_with_scroll : 0.0f;
7054
        if (ImGui::BeginTable("table_advanced", 6, flags, outer_size_enabled ? outer_size_value : ImVec2(0, 0), inner_width_to_use))
7055
        {
7056
            // Declare columns
7057
            // We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications.
7058
            // This is so our sort function can identify a column given our own identifier. We could also identify them based on their index!
7059
            ImGui::TableSetupColumn("ID",           columns_base_flags | ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoHide, 0.0f, MyItemColumnID_ID);
7060
            ImGui::TableSetupColumn("Name",         columns_base_flags | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Name);
7061
            ImGui::TableSetupColumn("Action",       columns_base_flags | ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Action);
7062
            ImGui::TableSetupColumn("Quantity",     columns_base_flags | ImGuiTableColumnFlags_PreferSortDescending, 0.0f, MyItemColumnID_Quantity);
7063
            ImGui::TableSetupColumn("Description",  columns_base_flags | ((flags & ImGuiTableFlags_NoHostExtendX) ? 0 : ImGuiTableColumnFlags_WidthStretch), 0.0f, MyItemColumnID_Description);
7064
            ImGui::TableSetupColumn("Hidden",       columns_base_flags |  ImGuiTableColumnFlags_DefaultHide | ImGuiTableColumnFlags_NoSort);
7065
            ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows);
7066
7067
            // Sort our data if sort specs have been changed!
7068
            ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs();
7069
            if (sort_specs && sort_specs->SpecsDirty)
7070
                items_need_sort = true;
7071
            if (sort_specs && items_need_sort && items.Size > 1)
7072
            {
7073
                MyItem::SortWithSortSpecs(sort_specs, items.Data, items.Size);
7074
                sort_specs->SpecsDirty = false;
7075
            }
7076
            items_need_sort = false;
7077
7078
            // Take note of whether we are currently sorting based on the Quantity field,
7079
            // we will use this to trigger sorting when we know the data of this column has been modified.
7080
            const bool sorts_specs_using_quantity = (ImGui::TableGetColumnFlags(3) & ImGuiTableColumnFlags_IsSorted) != 0;
7081
7082
            // Show headers
7083
            if (show_headers && (columns_base_flags & ImGuiTableColumnFlags_AngledHeader) != 0)
7084
                ImGui::TableAngledHeadersRow();
7085
            if (show_headers)
7086
                ImGui::TableHeadersRow();
7087
7088
            // Show data
7089
            // FIXME-TABLE FIXME-NAV: How we can get decent up/down even though we have the buttons here?
7090
#if 1
7091
            // Demonstrate using clipper for large vertical lists
7092
            ImGuiListClipper clipper;
7093
            clipper.Begin(items.Size);
7094
            while (clipper.Step())
7095
            {
7096
                for (int row_n = clipper.DisplayStart; row_n < clipper.DisplayEnd; row_n++)
7097
#else
7098
            // Without clipper
7099
            {
7100
                for (int row_n = 0; row_n < items.Size; row_n++)
7101
#endif
7102
                {
7103
                    MyItem* item = &items[row_n];
7104
                    //if (!filter.PassFilter(item->Name))
7105
                    //    continue;
7106
7107
                    const bool item_is_selected = selection.contains(item->ID);
7108
                    ImGui::PushID(item->ID);
7109
                    ImGui::TableNextRow(ImGuiTableRowFlags_None, row_min_height);
7110
7111
                    // For the demo purpose we can select among different type of items submitted in the first column
7112
                    ImGui::TableSetColumnIndex(0);
7113
                    char label[32];
7114
                    sprintf(label, "%04d", item->ID);
7115
                    if (contents_type == CT_Text)
7116
                        ImGui::TextUnformatted(label);
7117
                    else if (contents_type == CT_Button)
7118
                        ImGui::Button(label);
7119
                    else if (contents_type == CT_SmallButton)
7120
                        ImGui::SmallButton(label);
7121
                    else if (contents_type == CT_FillButton)
7122
                        ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f));
7123
                    else if (contents_type == CT_Selectable || contents_type == CT_SelectableSpanRow)
7124
                    {
7125
                        ImGuiSelectableFlags selectable_flags = (contents_type == CT_SelectableSpanRow) ? ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap : ImGuiSelectableFlags_None;
7126
                        if (ImGui::Selectable(label, item_is_selected, selectable_flags, ImVec2(0, row_min_height)))
7127
                        {
7128
                            if (ImGui::GetIO().KeyCtrl)
7129
                            {
7130
                                if (item_is_selected)
7131
                                    selection.find_erase_unsorted(item->ID);
7132
                                else
7133
                                    selection.push_back(item->ID);
7134
                            }
7135
                            else
7136
                            {
7137
                                selection.clear();
7138
                                selection.push_back(item->ID);
7139
                            }
7140
                        }
7141
                    }
7142
7143
                    if (ImGui::TableSetColumnIndex(1))
7144
                        ImGui::TextUnformatted(item->Name);
7145
7146
                    // Here we demonstrate marking our data set as needing to be sorted again if we modified a quantity,
7147
                    // and we are currently sorting on the column showing the Quantity.
7148
                    // To avoid triggering a sort while holding the button, we only trigger it when the button has been released.
7149
                    // You will probably need some extra logic if you want to automatically sort when a specific entry changes.
7150
                    if (ImGui::TableSetColumnIndex(2))
7151
                    {
7152
                        if (ImGui::SmallButton("Chop")) { item->Quantity += 1; }
7153
                        if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) { items_need_sort = true; }
7154
                        ImGui::SameLine();
7155
                        if (ImGui::SmallButton("Eat")) { item->Quantity -= 1; }
7156
                        if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) { items_need_sort = true; }
7157
                    }
7158
7159
                    if (ImGui::TableSetColumnIndex(3))
7160
                        ImGui::Text("%d", item->Quantity);
7161
7162
                    ImGui::TableSetColumnIndex(4);
7163
                    if (show_wrapped_text)
7164
                        ImGui::TextWrapped("Lorem ipsum dolor sit amet");
7165
                    else
7166
                        ImGui::Text("Lorem ipsum dolor sit amet");
7167
7168
                    if (ImGui::TableSetColumnIndex(5))
7169
                        ImGui::Text("1234");
7170
7171
                    ImGui::PopID();
7172
                }
7173
            }
7174
7175
            // Store some info to display debug details below
7176
            table_scroll_cur = ImVec2(ImGui::GetScrollX(), ImGui::GetScrollY());
7177
            table_scroll_max = ImVec2(ImGui::GetScrollMaxX(), ImGui::GetScrollMaxY());
7178
            table_draw_list = ImGui::GetWindowDrawList();
7179
            ImGui::EndTable();
7180
        }
7181
        static bool show_debug_details = false;
7182
        ImGui::Checkbox("Debug details", &show_debug_details);
7183
        if (show_debug_details && table_draw_list)
7184
        {
7185
            ImGui::SameLine(0.0f, 0.0f);
7186
            const int table_draw_list_draw_cmd_count = table_draw_list->CmdBuffer.Size;
7187
            if (table_draw_list == parent_draw_list)
7188
                ImGui::Text(": DrawCmd: +%d (in same window)",
7189
                    table_draw_list_draw_cmd_count - parent_draw_list_draw_cmd_count);
7190
            else
7191
                ImGui::Text(": DrawCmd: +%d (in child window), Scroll: (%.f/%.f) (%.f/%.f)",
7192
                    table_draw_list_draw_cmd_count - 1, table_scroll_cur.x, table_scroll_max.x, table_scroll_cur.y, table_scroll_max.y);
7193
        }
7194
        ImGui::TreePop();
7195
    }
7196
7197
    ImGui::PopID();
7198
7199
    ShowDemoWindowColumns();
7200
7201
    if (disable_indent)
7202
        ImGui::PopStyleVar();
7203
}
7204
7205
// Demonstrate old/legacy Columns API!
7206
// [2020: Columns are under-featured and not maintained. Prefer using the more flexible and powerful BeginTable() API!]
7207
static void ShowDemoWindowColumns()
7208
{
7209
    IMGUI_DEMO_MARKER("Columns (legacy API)");
7210
    bool open = ImGui::TreeNode("Legacy Columns API");
7211
    ImGui::SameLine();
7212
    HelpMarker("Columns() is an old API! Prefer using the more flexible and powerful BeginTable() API!");
7213
    if (!open)
7214
        return;
7215
7216
    // Basic columns
7217
    IMGUI_DEMO_MARKER("Columns (legacy API)/Basic");
7218
    if (ImGui::TreeNode("Basic"))
7219
    {
7220
        ImGui::Text("Without border:");
7221
        ImGui::Columns(3, "mycolumns3", false);  // 3-ways, no border
7222
        ImGui::Separator();
7223
        for (int n = 0; n < 14; n++)
7224
        {
7225
            char label[32];
7226
            sprintf(label, "Item %d", n);
7227
            if (ImGui::Selectable(label)) {}
7228
            //if (ImGui::Button(label, ImVec2(-FLT_MIN,0.0f))) {}
7229
            ImGui::NextColumn();
7230
        }
7231
        ImGui::Columns(1);
7232
        ImGui::Separator();
7233
7234
        ImGui::Text("With border:");
7235
        ImGui::Columns(4, "mycolumns"); // 4-ways, with border
7236
        ImGui::Separator();
7237
        ImGui::Text("ID"); ImGui::NextColumn();
7238
        ImGui::Text("Name"); ImGui::NextColumn();
7239
        ImGui::Text("Path"); ImGui::NextColumn();
7240
        ImGui::Text("Hovered"); ImGui::NextColumn();
7241
        ImGui::Separator();
7242
        const char* names[3] = { "One", "Two", "Three" };
7243
        const char* paths[3] = { "/path/one", "/path/two", "/path/three" };
7244
        static int selected = -1;
7245
        for (int i = 0; i < 3; i++)
7246
        {
7247
            char label[32];
7248
            sprintf(label, "%04d", i);
7249
            if (ImGui::Selectable(label, selected == i, ImGuiSelectableFlags_SpanAllColumns))
7250
                selected = i;
7251
            bool hovered = ImGui::IsItemHovered();
7252
            ImGui::NextColumn();
7253
            ImGui::Text(names[i]); ImGui::NextColumn();
7254
            ImGui::Text(paths[i]); ImGui::NextColumn();
7255
            ImGui::Text("%d", hovered); ImGui::NextColumn();
7256
        }
7257
        ImGui::Columns(1);
7258
        ImGui::Separator();
7259
        ImGui::TreePop();
7260
    }
7261
7262
    IMGUI_DEMO_MARKER("Columns (legacy API)/Borders");
7263
    if (ImGui::TreeNode("Borders"))
7264
    {
7265
        // NB: Future columns API should allow automatic horizontal borders.
7266
        static bool h_borders = true;
7267
        static bool v_borders = true;
7268
        static int columns_count = 4;
7269
        const int lines_count = 3;
7270
        ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
7271
        ImGui::DragInt("##columns_count", &columns_count, 0.1f, 2, 10, "%d columns");
7272
        if (columns_count < 2)
7273
            columns_count = 2;
7274
        ImGui::SameLine();
7275
        ImGui::Checkbox("horizontal", &h_borders);
7276
        ImGui::SameLine();
7277
        ImGui::Checkbox("vertical", &v_borders);
7278
        ImGui::Columns(columns_count, NULL, v_borders);
7279
        for (int i = 0; i < columns_count * lines_count; i++)
7280
        {
7281
            if (h_borders && ImGui::GetColumnIndex() == 0)
7282
                ImGui::Separator();
7283
            ImGui::PushID(i);
7284
            ImGui::Text("%c%c%c", 'a' + i, 'a' + i, 'a' + i);
7285
            ImGui::Text("Width %.2f", ImGui::GetColumnWidth());
7286
            ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x);
7287
            ImGui::Text("Offset %.2f", ImGui::GetColumnOffset());
7288
            ImGui::Text("Long text that is likely to clip");
7289
            ImGui::Button("Button", ImVec2(-FLT_MIN, 0.0f));
7290
            ImGui::PopID();
7291
            ImGui::NextColumn();
7292
        }
7293
        ImGui::Columns(1);
7294
        if (h_borders)
7295
            ImGui::Separator();
7296
        ImGui::TreePop();
7297
    }
7298
7299
    // Create multiple items in a same cell before switching to next column
7300
    IMGUI_DEMO_MARKER("Columns (legacy API)/Mixed items");
7301
    if (ImGui::TreeNode("Mixed items"))
7302
    {
7303
        ImGui::Columns(3, "mixed");
7304
        ImGui::Separator();
7305
7306
        ImGui::Text("Hello");
7307
        ImGui::Button("Banana");
7308
        ImGui::NextColumn();
7309
7310
        ImGui::Text("ImGui");
7311
        ImGui::Button("Apple");
7312
        static float foo = 1.0f;
7313
        ImGui::InputFloat("red", &foo, 0.05f, 0, "%.3f");
7314
        ImGui::Text("An extra line here.");
7315
        ImGui::NextColumn();
7316
7317
        ImGui::Text("Sailor");
7318
        ImGui::Button("Corniflower");
7319
        static float bar = 1.0f;
7320
        ImGui::InputFloat("blue", &bar, 0.05f, 0, "%.3f");
7321
        ImGui::NextColumn();
7322
7323
        if (ImGui::CollapsingHeader("Category A")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
7324
        if (ImGui::CollapsingHeader("Category B")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
7325
        if (ImGui::CollapsingHeader("Category C")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
7326
        ImGui::Columns(1);
7327
        ImGui::Separator();
7328
        ImGui::TreePop();
7329
    }
7330
7331
    // Word wrapping
7332
    IMGUI_DEMO_MARKER("Columns (legacy API)/Word-wrapping");
7333
    if (ImGui::TreeNode("Word-wrapping"))
7334
    {
7335
        ImGui::Columns(2, "word-wrapping");
7336
        ImGui::Separator();
7337
        ImGui::TextWrapped("The quick brown fox jumps over the lazy dog.");
7338
        ImGui::TextWrapped("Hello Left");
7339
        ImGui::NextColumn();
7340
        ImGui::TextWrapped("The quick brown fox jumps over the lazy dog.");
7341
        ImGui::TextWrapped("Hello Right");
7342
        ImGui::Columns(1);
7343
        ImGui::Separator();
7344
        ImGui::TreePop();
7345
    }
7346
7347
    IMGUI_DEMO_MARKER("Columns (legacy API)/Horizontal Scrolling");
7348
    if (ImGui::TreeNode("Horizontal Scrolling"))
7349
    {
7350
        ImGui::SetNextWindowContentSize(ImVec2(1500.0f, 0.0f));
7351
        ImVec2 child_size = ImVec2(0, ImGui::GetFontSize() * 20.0f);
7352
        ImGui::BeginChild("##ScrollingRegion", child_size, ImGuiChildFlags_None, ImGuiWindowFlags_HorizontalScrollbar);
7353
        ImGui::Columns(10);
7354
7355
        // Also demonstrate using clipper for large vertical lists
7356
        int ITEMS_COUNT = 2000;
7357
        ImGuiListClipper clipper;
7358
        clipper.Begin(ITEMS_COUNT);
7359
        while (clipper.Step())
7360
        {
7361
            for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
7362
                for (int j = 0; j < 10; j++)
7363
                {
7364
                    ImGui::Text("Line %d Column %d...", i, j);
7365
                    ImGui::NextColumn();
7366
                }
7367
        }
7368
        ImGui::Columns(1);
7369
        ImGui::EndChild();
7370
        ImGui::TreePop();
7371
    }
7372
7373
    IMGUI_DEMO_MARKER("Columns (legacy API)/Tree");
7374
    if (ImGui::TreeNode("Tree"))
7375
    {
7376
        ImGui::Columns(2, "tree", true);
7377
        for (int x = 0; x < 3; x++)
7378
        {
7379
            bool open1 = ImGui::TreeNode((void*)(intptr_t)x, "Node%d", x);
7380
            ImGui::NextColumn();
7381
            ImGui::Text("Node contents");
7382
            ImGui::NextColumn();
7383
            if (open1)
7384
            {
7385
                for (int y = 0; y < 3; y++)
7386
                {
7387
                    bool open2 = ImGui::TreeNode((void*)(intptr_t)y, "Node%d.%d", x, y);
7388
                    ImGui::NextColumn();
7389
                    ImGui::Text("Node contents");
7390
                    if (open2)
7391
                    {
7392
                        ImGui::Text("Even more contents");
7393
                        if (ImGui::TreeNode("Tree in column"))
7394
                        {
7395
                            ImGui::Text("The quick brown fox jumps over the lazy dog");
7396
                            ImGui::TreePop();
7397
                        }
7398
                    }
7399
                    ImGui::NextColumn();
7400
                    if (open2)
7401
                        ImGui::TreePop();
7402
                }
7403
                ImGui::TreePop();
7404
            }
7405
        }
7406
        ImGui::Columns(1);
7407
        ImGui::TreePop();
7408
    }
7409
7410
    ImGui::TreePop();
7411
}
7412
7413
//-----------------------------------------------------------------------------
7414
// [SECTION] ShowDemoWindowInputs()
7415
//-----------------------------------------------------------------------------
7416
7417
static void ShowDemoWindowInputs()
7418
{
7419
    IMGUI_DEMO_MARKER("Inputs & Focus");
7420
    if (ImGui::CollapsingHeader("Inputs & Focus"))
7421
    {
7422
        ImGuiIO& io = ImGui::GetIO();
7423
7424
        // Display inputs submitted to ImGuiIO
7425
        IMGUI_DEMO_MARKER("Inputs & Focus/Inputs");
7426
        ImGui::SetNextItemOpen(true, ImGuiCond_Once);
7427
        bool inputs_opened = ImGui::TreeNode("Inputs");
7428
        ImGui::SameLine();
7429
        HelpMarker(
7430
            "This is a simplified view. See more detailed input state:\n"
7431
            "- in 'Tools->Metrics/Debugger->Inputs'.\n"
7432
            "- in 'Tools->Debug Log->IO'.");
7433
        if (inputs_opened)
7434
        {
7435
            if (ImGui::IsMousePosValid())
7436
                ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y);
7437
            else
7438
                ImGui::Text("Mouse pos: <INVALID>");
7439
            ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y);
7440
            ImGui::Text("Mouse down:");
7441
            for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDown(i)) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); }
7442
            ImGui::Text("Mouse wheel: %.1f", io.MouseWheel);
7443
7444
            // We iterate both legacy native range and named ImGuiKey ranges. This is a little unusual/odd but this allows
7445
            // displaying the data for old/new backends.
7446
            // User code should never have to go through such hoops!
7447
            // You can generally iterate between ImGuiKey_NamedKey_BEGIN and ImGuiKey_NamedKey_END.
7448
            struct funcs { static bool IsLegacyNativeDupe(ImGuiKey) { return false; } };
7449
            ImGuiKey start_key = ImGuiKey_NamedKey_BEGIN;
7450
            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); }
7451
            ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : "");
7452
            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.
7453
7454
            ImGui::TreePop();
7455
        }
7456
7457
        // Display ImGuiIO output flags
7458
        IMGUI_DEMO_MARKER("Inputs & Focus/Outputs");
7459
        ImGui::SetNextItemOpen(true, ImGuiCond_Once);
7460
        bool outputs_opened = ImGui::TreeNode("Outputs");
7461
        ImGui::SameLine();
7462
        HelpMarker(
7463
            "The value of io.WantCaptureMouse and io.WantCaptureKeyboard are normally set by Dear ImGui "
7464
            "to instruct your application of how to route inputs. Typically, when a value is true, it means "
7465
            "Dear ImGui wants the corresponding inputs and we expect the underlying application to ignore them.\n\n"
7466
            "The most typical case is: when hovering a window, Dear ImGui set io.WantCaptureMouse to true, "
7467
            "and underlying application should ignore mouse inputs (in practice there are many and more subtle "
7468
            "rules leading to how those flags are set).");
7469
        if (outputs_opened)
7470
        {
7471
            ImGui::Text("io.WantCaptureMouse: %d", io.WantCaptureMouse);
7472
            ImGui::Text("io.WantCaptureMouseUnlessPopupClose: %d", io.WantCaptureMouseUnlessPopupClose);
7473
            ImGui::Text("io.WantCaptureKeyboard: %d", io.WantCaptureKeyboard);
7474
            ImGui::Text("io.WantTextInput: %d", io.WantTextInput);
7475
            ImGui::Text("io.WantSetMousePos: %d", io.WantSetMousePos);
7476
            ImGui::Text("io.NavActive: %d, io.NavVisible: %d", io.NavActive, io.NavVisible);
7477
7478
            IMGUI_DEMO_MARKER("Inputs & Focus/Outputs/WantCapture override");
7479
            if (ImGui::TreeNode("WantCapture override"))
7480
            {
7481
                HelpMarker(
7482
                    "Hovering the colored canvas will override io.WantCaptureXXX fields.\n"
7483
                    "Notice how normally (when set to none), the value of io.WantCaptureKeyboard would be false when hovering "
7484
                    "and true when clicking.");
7485
                static int capture_override_mouse = -1;
7486
                static int capture_override_keyboard = -1;
7487
                const char* capture_override_desc[] = { "None", "Set to false", "Set to true" };
7488
                ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15);
7489
                ImGui::SliderInt("SetNextFrameWantCaptureMouse() on hover", &capture_override_mouse, -1, +1, capture_override_desc[capture_override_mouse + 1], ImGuiSliderFlags_AlwaysClamp);
7490
                ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15);
7491
                ImGui::SliderInt("SetNextFrameWantCaptureKeyboard() on hover", &capture_override_keyboard, -1, +1, capture_override_desc[capture_override_keyboard + 1], ImGuiSliderFlags_AlwaysClamp);
7492
7493
                ImGui::ColorButton("##panel", ImVec4(0.7f, 0.1f, 0.7f, 1.0f), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop, ImVec2(128.0f, 96.0f)); // Dummy item
7494
                if (ImGui::IsItemHovered() && capture_override_mouse != -1)
7495
                    ImGui::SetNextFrameWantCaptureMouse(capture_override_mouse == 1);
7496
                if (ImGui::IsItemHovered() && capture_override_keyboard != -1)
7497
                    ImGui::SetNextFrameWantCaptureKeyboard(capture_override_keyboard == 1);
7498
7499
                ImGui::TreePop();
7500
            }
7501
            ImGui::TreePop();
7502
        }
7503
7504
        // Demonstrate using Shortcut() and Routing Policies.
7505
        // The general flow is:
7506
        // - Code interested in a chord (e.g. "Ctrl+A") declares their intent.
7507
        // - Multiple locations may be interested in same chord! Routing helps find a winner.
7508
        // - Every frame, we resolve all claims and assign one owner if the modifiers are matching.
7509
        // - The lower-level function is 'bool SetShortcutRouting()', returns true when caller got the route.
7510
        // - Most of the times, SetShortcutRouting() is not called directly. User mostly calls Shortcut() with routing flags.
7511
        // - If you call Shortcut() WITHOUT any routing option, it uses ImGuiInputFlags_RouteFocused.
7512
        // TL;DR: Most uses will simply be:
7513
        // - Shortcut(ImGuiMod_Ctrl | ImGuiKey_A); // Use ImGuiInputFlags_RouteFocused policy.
7514
        IMGUI_DEMO_MARKER("Inputs & Focus/Shortcuts");
7515
        if (ImGui::TreeNode("Shortcuts"))
7516
        {
7517
            static ImGuiInputFlags route_options = ImGuiInputFlags_Repeat;
7518
            static ImGuiInputFlags route_type = ImGuiInputFlags_RouteFocused;
7519
            ImGui::CheckboxFlags("ImGuiInputFlags_Repeat", &route_options, ImGuiInputFlags_Repeat);
7520
            ImGui::RadioButton("ImGuiInputFlags_RouteActive", &route_type, ImGuiInputFlags_RouteActive);
7521
            ImGui::RadioButton("ImGuiInputFlags_RouteFocused (default)", &route_type, ImGuiInputFlags_RouteFocused);
7522
            ImGui::RadioButton("ImGuiInputFlags_RouteGlobal", &route_type, ImGuiInputFlags_RouteGlobal);
7523
            ImGui::Indent();
7524
            ImGui::BeginDisabled(route_type != ImGuiInputFlags_RouteGlobal);
7525
            ImGui::CheckboxFlags("ImGuiInputFlags_RouteOverFocused", &route_options, ImGuiInputFlags_RouteOverFocused);
7526
            ImGui::CheckboxFlags("ImGuiInputFlags_RouteOverActive", &route_options, ImGuiInputFlags_RouteOverActive);
7527
            ImGui::CheckboxFlags("ImGuiInputFlags_RouteUnlessBgFocused", &route_options, ImGuiInputFlags_RouteUnlessBgFocused);
7528
            ImGui::EndDisabled();
7529
            ImGui::Unindent();
7530
            ImGui::RadioButton("ImGuiInputFlags_RouteAlways", &route_type, ImGuiInputFlags_RouteAlways);
7531
            ImGuiInputFlags flags = route_type | route_options; // Merged flags
7532
            if (route_type != ImGuiInputFlags_RouteGlobal)
7533
                flags &= ~(ImGuiInputFlags_RouteOverFocused | ImGuiInputFlags_RouteOverActive | ImGuiInputFlags_RouteUnlessBgFocused);
7534
7535
            ImGui::SeparatorText("Using SetNextItemShortcut()");
7536
            ImGui::Text("Ctrl+S");
7537
            ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_S, flags | ImGuiInputFlags_Tooltip);
7538
            ImGui::Button("Save");
7539
            ImGui::Text("Alt+F");
7540
            ImGui::SetNextItemShortcut(ImGuiMod_Alt | ImGuiKey_F, flags | ImGuiInputFlags_Tooltip);
7541
            static float f = 0.5f;
7542
            ImGui::SliderFloat("Factor", &f, 0.0f, 1.0f);
7543
7544
            ImGui::SeparatorText("Using Shortcut()");
7545
            const float line_height = ImGui::GetTextLineHeightWithSpacing();
7546
            const ImGuiKeyChord key_chord = ImGuiMod_Ctrl | ImGuiKey_A;
7547
7548
            ImGui::Text("Ctrl+A");
7549
            ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "...");
7550
7551
            ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 0.0f, 1.0f, 0.1f));
7552
7553
            ImGui::BeginChild("WindowA", ImVec2(-FLT_MIN, line_height * 14), true);
7554
            ImGui::Text("Press CTRL+A and see who receives it!");
7555
            ImGui::Separator();
7556
7557
            // 1: Window polling for CTRL+A
7558
            ImGui::Text("(in WindowA)");
7559
            ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "...");
7560
7561
            // 2: InputText also polling for CTRL+A: it always uses _RouteFocused internally (gets priority when active)
7562
            // (Commmented because the owner-aware version of Shortcut() is still in imgui_internal.h)
7563
            //char str[16] = "Press CTRL+A";
7564
            //ImGui::Spacing();
7565
            //ImGui::InputText("InputTextB", str, IM_ARRAYSIZE(str), ImGuiInputTextFlags_ReadOnly);
7566
            //ImGuiID item_id = ImGui::GetItemID();
7567
            //ImGui::SameLine(); HelpMarker("Internal widgets always use _RouteFocused");
7568
            //ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags, item_id) ? "PRESSED" : "...");
7569
7570
            // 3: Dummy child is not claiming the route: focusing them shouldn't steal route away from WindowA
7571
            ImGui::BeginChild("ChildD", ImVec2(-FLT_MIN, line_height * 4), true);
7572
            ImGui::Text("(in ChildD: not using same Shortcut)");
7573
            ImGui::Text("IsWindowFocused: %d", ImGui::IsWindowFocused());
7574
            ImGui::EndChild();
7575
7576
            // 4: Child window polling for CTRL+A. It is deeper than WindowA and gets priority when focused.
7577
            ImGui::BeginChild("ChildE", ImVec2(-FLT_MIN, line_height * 4), true);
7578
            ImGui::Text("(in ChildE: using same Shortcut)");
7579
            ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "...");
7580
            ImGui::EndChild();
7581
7582
            // 5: In a popup
7583
            if (ImGui::Button("Open Popup"))
7584
                ImGui::OpenPopup("PopupF");
7585
            if (ImGui::BeginPopup("PopupF"))
7586
            {
7587
                ImGui::Text("(in PopupF)");
7588
                ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "...");
7589
                // (Commmented because the owner-aware version of Shortcut() is still in imgui_internal.h)
7590
                //ImGui::InputText("InputTextG", str, IM_ARRAYSIZE(str), ImGuiInputTextFlags_ReadOnly);
7591
                //ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags, ImGui::GetItemID()) ? "PRESSED" : "...");
7592
                ImGui::EndPopup();
7593
            }
7594
            ImGui::EndChild();
7595
            ImGui::PopStyleColor();
7596
7597
            ImGui::TreePop();
7598
        }
7599
7600
        // Display mouse cursors
7601
        IMGUI_DEMO_MARKER("Inputs & Focus/Mouse Cursors");
7602
        if (ImGui::TreeNode("Mouse Cursors"))
7603
        {
7604
            const char* mouse_cursors_names[] = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "NotAllowed" };
7605
            IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT);
7606
7607
            ImGuiMouseCursor current = ImGui::GetMouseCursor();
7608
            const char* cursor_name = (current >= ImGuiMouseCursor_Arrow) && (current < ImGuiMouseCursor_COUNT) ? mouse_cursors_names[current] : "N/A";
7609
            ImGui::Text("Current mouse cursor = %d: %s", current, cursor_name);
7610
            ImGui::BeginDisabled(true);
7611
            ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors);
7612
            ImGui::EndDisabled();
7613
7614
            ImGui::Text("Hover to see mouse cursors:");
7615
            ImGui::SameLine(); HelpMarker(
7616
                "Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. "
7617
                "If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, "
7618
                "otherwise your backend needs to handle it.");
7619
            for (int i = 0; i < ImGuiMouseCursor_COUNT; i++)
7620
            {
7621
                char label[32];
7622
                sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]);
7623
                ImGui::Bullet(); ImGui::Selectable(label, false);
7624
                if (ImGui::IsItemHovered())
7625
                    ImGui::SetMouseCursor(i);
7626
            }
7627
            ImGui::TreePop();
7628
        }
7629
7630
        IMGUI_DEMO_MARKER("Inputs & Focus/Tabbing");
7631
        if (ImGui::TreeNode("Tabbing"))
7632
        {
7633
            ImGui::Text("Use TAB/SHIFT+TAB to cycle through keyboard editable fields.");
7634
            static char buf[32] = "hello";
7635
            ImGui::InputText("1", buf, IM_ARRAYSIZE(buf));
7636
            ImGui::InputText("2", buf, IM_ARRAYSIZE(buf));
7637
            ImGui::InputText("3", buf, IM_ARRAYSIZE(buf));
7638
            ImGui::PushItemFlag(ImGuiItemFlags_NoTabStop, true);
7639
            ImGui::InputText("4 (tab skip)", buf, IM_ARRAYSIZE(buf));
7640
            ImGui::SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab.");
7641
            ImGui::PopItemFlag();
7642
            ImGui::InputText("5", buf, IM_ARRAYSIZE(buf));
7643
            ImGui::TreePop();
7644
        }
7645
7646
        IMGUI_DEMO_MARKER("Inputs & Focus/Focus from code");
7647
        if (ImGui::TreeNode("Focus from code"))
7648
        {
7649
            bool focus_1 = ImGui::Button("Focus on 1"); ImGui::SameLine();
7650
            bool focus_2 = ImGui::Button("Focus on 2"); ImGui::SameLine();
7651
            bool focus_3 = ImGui::Button("Focus on 3");
7652
            int has_focus = 0;
7653
            static char buf[128] = "click on a button to set focus";
7654
7655
            if (focus_1) ImGui::SetKeyboardFocusHere();
7656
            ImGui::InputText("1", buf, IM_ARRAYSIZE(buf));
7657
            if (ImGui::IsItemActive()) has_focus = 1;
7658
7659
            if (focus_2) ImGui::SetKeyboardFocusHere();
7660
            ImGui::InputText("2", buf, IM_ARRAYSIZE(buf));
7661
            if (ImGui::IsItemActive()) has_focus = 2;
7662
7663
            ImGui::PushItemFlag(ImGuiItemFlags_NoTabStop, true);
7664
            if (focus_3) ImGui::SetKeyboardFocusHere();
7665
            ImGui::InputText("3 (tab skip)", buf, IM_ARRAYSIZE(buf));
7666
            if (ImGui::IsItemActive()) has_focus = 3;
7667
            ImGui::SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab.");
7668
            ImGui::PopItemFlag();
7669
7670
            if (has_focus)
7671
                ImGui::Text("Item with focus: %d", has_focus);
7672
            else
7673
                ImGui::Text("Item with focus: <none>");
7674
7675
            // Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item
7676
            static float f3[3] = { 0.0f, 0.0f, 0.0f };
7677
            int focus_ahead = -1;
7678
            if (ImGui::Button("Focus on X")) { focus_ahead = 0; } ImGui::SameLine();
7679
            if (ImGui::Button("Focus on Y")) { focus_ahead = 1; } ImGui::SameLine();
7680
            if (ImGui::Button("Focus on Z")) { focus_ahead = 2; }
7681
            if (focus_ahead != -1) ImGui::SetKeyboardFocusHere(focus_ahead);
7682
            ImGui::SliderFloat3("Float3", &f3[0], 0.0f, 1.0f);
7683
7684
            ImGui::TextWrapped("NB: Cursor & selection are preserved when refocusing last used item in code.");
7685
            ImGui::TreePop();
7686
        }
7687
7688
        IMGUI_DEMO_MARKER("Inputs & Focus/Dragging");
7689
        if (ImGui::TreeNode("Dragging"))
7690
        {
7691
            ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget.");
7692
            for (int button = 0; button < 3; button++)
7693
            {
7694
                ImGui::Text("IsMouseDragging(%d):", button);
7695
                ImGui::Text("  w/ default threshold: %d,", ImGui::IsMouseDragging(button));
7696
                ImGui::Text("  w/ zero threshold: %d,", ImGui::IsMouseDragging(button, 0.0f));
7697
                ImGui::Text("  w/ large threshold: %d,", ImGui::IsMouseDragging(button, 20.0f));
7698
            }
7699
7700
            ImGui::Button("Drag Me");
7701
            if (ImGui::IsItemActive())
7702
                ImGui::GetForegroundDrawList()->AddLine(io.MouseClickedPos[0], io.MousePos, ImGui::GetColorU32(ImGuiCol_Button), 4.0f); // Draw a line between the button and the mouse cursor
7703
7704
            // Drag operations gets "unlocked" when the mouse has moved past a certain threshold
7705
            // (the default threshold is stored in io.MouseDragThreshold). You can request a lower or higher
7706
            // threshold using the second parameter of IsMouseDragging() and GetMouseDragDelta().
7707
            ImVec2 value_raw = ImGui::GetMouseDragDelta(0, 0.0f);
7708
            ImVec2 value_with_lock_threshold = ImGui::GetMouseDragDelta(0);
7709
            ImVec2 mouse_delta = io.MouseDelta;
7710
            ImGui::Text("GetMouseDragDelta(0):");
7711
            ImGui::Text("  w/ default threshold: (%.1f, %.1f)", value_with_lock_threshold.x, value_with_lock_threshold.y);
7712
            ImGui::Text("  w/ zero threshold: (%.1f, %.1f)", value_raw.x, value_raw.y);
7713
            ImGui::Text("io.MouseDelta: (%.1f, %.1f)", mouse_delta.x, mouse_delta.y);
7714
            ImGui::TreePop();
7715
        }
7716
    }
7717
}
7718
7719
//-----------------------------------------------------------------------------
7720
// [SECTION] About Window / ShowAboutWindow()
7721
// Access from Dear ImGui Demo -> Tools -> About
7722
//-----------------------------------------------------------------------------
7723
7724
void ImGui::ShowAboutWindow(bool* p_open)
7725
{
7726
    if (!ImGui::Begin("About Dear ImGui", p_open, ImGuiWindowFlags_AlwaysAutoResize))
7727
    {
7728
        ImGui::End();
7729
        return;
7730
    }
7731
    IMGUI_DEMO_MARKER("Tools/About Dear ImGui");
7732
    ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
7733
7734
    ImGui::TextLinkOpenURL("Homepage", "https://github.com/ocornut/imgui");
7735
    ImGui::SameLine();
7736
    ImGui::TextLinkOpenURL("FAQ", "https://github.com/ocornut/imgui/blob/master/docs/FAQ.md");
7737
    ImGui::SameLine();
7738
    ImGui::TextLinkOpenURL("Wiki", "https://github.com/ocornut/imgui/wiki");
7739
    ImGui::SameLine();
7740
    ImGui::TextLinkOpenURL("Releases", "https://github.com/ocornut/imgui/releases");
7741
    ImGui::SameLine();
7742
    ImGui::TextLinkOpenURL("Funding", "https://github.com/ocornut/imgui/wiki/Funding");
7743
7744
    ImGui::Separator();
7745
    ImGui::Text("By Omar Cornut and all Dear ImGui contributors.");
7746
    ImGui::Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information.");
7747
    ImGui::Text("If your company uses this, please consider funding the project.");
7748
7749
    static bool show_config_info = false;
7750
    ImGui::Checkbox("Config/Build Information", &show_config_info);
7751
    if (show_config_info)
7752
    {
7753
        ImGuiIO& io = ImGui::GetIO();
7754
        ImGuiStyle& style = ImGui::GetStyle();
7755
7756
        bool copy_to_clipboard = ImGui::Button("Copy to clipboard");
7757
        ImVec2 child_size = ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 18);
7758
        ImGui::BeginChild(ImGui::GetID("cfg_infos"), child_size, ImGuiChildFlags_FrameStyle);
7759
        if (copy_to_clipboard)
7760
        {
7761
            ImGui::LogToClipboard();
7762
            ImGui::LogText("```\n"); // Back quotes will make text appears without formatting when pasting on GitHub
7763
        }
7764
7765
        ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
7766
        ImGui::Separator();
7767
        ImGui::Text("sizeof(size_t): %d, sizeof(ImDrawIdx): %d, sizeof(ImDrawVert): %d", (int)sizeof(size_t), (int)sizeof(ImDrawIdx), (int)sizeof(ImDrawVert));
7768
        ImGui::Text("define: __cplusplus=%d", (int)__cplusplus);
7769
#ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
7770
        ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_FUNCTIONS");
7771
#endif
7772
#ifdef IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS
7773
        ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS");
7774
#endif
7775
#ifdef IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
7776
        ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS");
7777
#endif
7778
#ifdef IMGUI_DISABLE_WIN32_FUNCTIONS
7779
        ImGui::Text("define: IMGUI_DISABLE_WIN32_FUNCTIONS");
7780
#endif
7781
#ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
7782
        ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS");
7783
#endif
7784
#ifdef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS
7785
        ImGui::Text("define: IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS");
7786
#endif
7787
#ifdef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
7788
        ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS");
7789
#endif
7790
#ifdef IMGUI_DISABLE_FILE_FUNCTIONS
7791
        ImGui::Text("define: IMGUI_DISABLE_FILE_FUNCTIONS");
7792
#endif
7793
#ifdef IMGUI_DISABLE_DEFAULT_ALLOCATORS
7794
        ImGui::Text("define: IMGUI_DISABLE_DEFAULT_ALLOCATORS");
7795
#endif
7796
#ifdef IMGUI_USE_BGRA_PACKED_COLOR
7797
        ImGui::Text("define: IMGUI_USE_BGRA_PACKED_COLOR");
7798
#endif
7799
#ifdef _WIN32
7800
        ImGui::Text("define: _WIN32");
7801
#endif
7802
#ifdef _WIN64
7803
        ImGui::Text("define: _WIN64");
7804
#endif
7805
#ifdef __linux__
7806
        ImGui::Text("define: __linux__");
7807
#endif
7808
#ifdef __APPLE__
7809
        ImGui::Text("define: __APPLE__");
7810
#endif
7811
#ifdef _MSC_VER
7812
        ImGui::Text("define: _MSC_VER=%d", _MSC_VER);
7813
#endif
7814
#ifdef _MSVC_LANG
7815
        ImGui::Text("define: _MSVC_LANG=%d", (int)_MSVC_LANG);
7816
#endif
7817
#ifdef __MINGW32__
7818
        ImGui::Text("define: __MINGW32__");
7819
#endif
7820
#ifdef __MINGW64__
7821
        ImGui::Text("define: __MINGW64__");
7822
#endif
7823
#ifdef __GNUC__
7824
        ImGui::Text("define: __GNUC__=%d", (int)__GNUC__);
7825
#endif
7826
#ifdef __clang_version__
7827
        ImGui::Text("define: __clang_version__=%s", __clang_version__);
7828
#endif
7829
#ifdef __EMSCRIPTEN__
7830
        ImGui::Text("define: __EMSCRIPTEN__");
7831
        ImGui::Text("Emscripten: %d.%d.%d", __EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__);
7832
#endif
7833
#ifdef IMGUI_HAS_VIEWPORT
7834
        ImGui::Text("define: IMGUI_HAS_VIEWPORT");
7835
#endif
7836
#ifdef IMGUI_HAS_DOCK
7837
        ImGui::Text("define: IMGUI_HAS_DOCK");
7838
#endif
7839
        ImGui::Separator();
7840
        ImGui::Text("io.BackendPlatformName: %s", io.BackendPlatformName ? io.BackendPlatformName : "NULL");
7841
        ImGui::Text("io.BackendRendererName: %s", io.BackendRendererName ? io.BackendRendererName : "NULL");
7842
        ImGui::Text("io.ConfigFlags: 0x%08X", io.ConfigFlags);
7843
        if (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard)        ImGui::Text(" NavEnableKeyboard");
7844
        if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad)         ImGui::Text(" NavEnableGamepad");
7845
        if (io.ConfigFlags & ImGuiConfigFlags_NoMouse)                  ImGui::Text(" NoMouse");
7846
        if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)      ImGui::Text(" NoMouseCursorChange");
7847
        if (io.ConfigFlags & ImGuiConfigFlags_NoKeyboard)               ImGui::Text(" NoKeyboard");
7848
        if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)            ImGui::Text(" DockingEnable");
7849
        if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)          ImGui::Text(" ViewportsEnable");
7850
        if (io.ConfigFlags & ImGuiConfigFlags_DpiEnableScaleViewports)  ImGui::Text(" DpiEnableScaleViewports");
7851
        if (io.ConfigFlags & ImGuiConfigFlags_DpiEnableScaleFonts)      ImGui::Text(" DpiEnableScaleFonts");
7852
        if (io.MouseDrawCursor)                                         ImGui::Text("io.MouseDrawCursor");
7853
        if (io.ConfigViewportsNoAutoMerge)                              ImGui::Text("io.ConfigViewportsNoAutoMerge");
7854
        if (io.ConfigViewportsNoTaskBarIcon)                            ImGui::Text("io.ConfigViewportsNoTaskBarIcon");
7855
        if (io.ConfigViewportsNoDecoration)                             ImGui::Text("io.ConfigViewportsNoDecoration");
7856
        if (io.ConfigViewportsNoDefaultParent)                          ImGui::Text("io.ConfigViewportsNoDefaultParent");
7857
        if (io.ConfigDockingNoSplit)                                    ImGui::Text("io.ConfigDockingNoSplit");
7858
        if (io.ConfigDockingWithShift)                                  ImGui::Text("io.ConfigDockingWithShift");
7859
        if (io.ConfigDockingAlwaysTabBar)                               ImGui::Text("io.ConfigDockingAlwaysTabBar");
7860
        if (io.ConfigDockingTransparentPayload)                         ImGui::Text("io.ConfigDockingTransparentPayload");
7861
        if (io.ConfigMacOSXBehaviors)                                   ImGui::Text("io.ConfigMacOSXBehaviors");
7862
        if (io.ConfigNavMoveSetMousePos)                                ImGui::Text("io.ConfigNavMoveSetMousePos");
7863
        if (io.ConfigNavCaptureKeyboard)                                ImGui::Text("io.ConfigNavCaptureKeyboard");
7864
        if (io.ConfigInputTextCursorBlink)                              ImGui::Text("io.ConfigInputTextCursorBlink");
7865
        if (io.ConfigWindowsResizeFromEdges)                            ImGui::Text("io.ConfigWindowsResizeFromEdges");
7866
        if (io.ConfigWindowsMoveFromTitleBarOnly)                       ImGui::Text("io.ConfigWindowsMoveFromTitleBarOnly");
7867
        if (io.ConfigMemoryCompactTimer >= 0.0f)                        ImGui::Text("io.ConfigMemoryCompactTimer = %.1f", io.ConfigMemoryCompactTimer);
7868
        ImGui::Text("io.BackendFlags: 0x%08X", io.BackendFlags);
7869
        if (io.BackendFlags & ImGuiBackendFlags_HasGamepad)             ImGui::Text(" HasGamepad");
7870
        if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors)        ImGui::Text(" HasMouseCursors");
7871
        if (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos)         ImGui::Text(" HasSetMousePos");
7872
        if (io.BackendFlags & ImGuiBackendFlags_PlatformHasViewports)   ImGui::Text(" PlatformHasViewports");
7873
        if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport)ImGui::Text(" HasMouseHoveredViewport");
7874
        if (io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset)   ImGui::Text(" RendererHasVtxOffset");
7875
        if (io.BackendFlags & ImGuiBackendFlags_RendererHasViewports)   ImGui::Text(" RendererHasViewports");
7876
        ImGui::Separator();
7877
        ImGui::Text("io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", io.Fonts->Fonts.Size, io.Fonts->Flags, io.Fonts->TexWidth, io.Fonts->TexHeight);
7878
        ImGui::Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y);
7879
        ImGui::Text("io.DisplayFramebufferScale: %.2f,%.2f", io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y);
7880
        ImGui::Separator();
7881
        ImGui::Text("style.WindowPadding: %.2f,%.2f", style.WindowPadding.x, style.WindowPadding.y);
7882
        ImGui::Text("style.WindowBorderSize: %.2f", style.WindowBorderSize);
7883
        ImGui::Text("style.FramePadding: %.2f,%.2f", style.FramePadding.x, style.FramePadding.y);
7884
        ImGui::Text("style.FrameRounding: %.2f", style.FrameRounding);
7885
        ImGui::Text("style.FrameBorderSize: %.2f", style.FrameBorderSize);
7886
        ImGui::Text("style.ItemSpacing: %.2f,%.2f", style.ItemSpacing.x, style.ItemSpacing.y);
7887
        ImGui::Text("style.ItemInnerSpacing: %.2f,%.2f", style.ItemInnerSpacing.x, style.ItemInnerSpacing.y);
7888
7889
        if (copy_to_clipboard)
7890
        {
7891
            ImGui::LogText("\n```\n");
7892
            ImGui::LogFinish();
7893
        }
7894
        ImGui::EndChild();
7895
    }
7896
    ImGui::End();
7897
}
7898
7899
//-----------------------------------------------------------------------------
7900
// [SECTION] Style Editor / ShowStyleEditor()
7901
//-----------------------------------------------------------------------------
7902
// - ShowFontSelector()
7903
// - ShowStyleSelector()
7904
// - ShowStyleEditor()
7905
//-----------------------------------------------------------------------------
7906
7907
// Forward declare ShowFontAtlas() which isn't worth putting in public API yet
7908
namespace ImGui { IMGUI_API void ShowFontAtlas(ImFontAtlas* atlas); }
7909
7910
// Demo helper function to select among loaded fonts.
7911
// Here we use the regular BeginCombo()/EndCombo() api which is the more flexible one.
7912
void ImGui::ShowFontSelector(const char* label)
7913
{
7914
    ImGuiIO& io = ImGui::GetIO();
7915
    ImFont* font_current = ImGui::GetFont();
7916
    if (ImGui::BeginCombo(label, font_current->GetDebugName()))
7917
    {
7918
        for (ImFont* font : io.Fonts->Fonts)
7919
        {
7920
            ImGui::PushID((void*)font);
7921
            if (ImGui::Selectable(font->GetDebugName(), font == font_current))
7922
                io.FontDefault = font;
7923
            ImGui::PopID();
7924
        }
7925
        ImGui::EndCombo();
7926
    }
7927
    ImGui::SameLine();
7928
    HelpMarker(
7929
        "- Load additional fonts with io.Fonts->AddFontFromFileTTF().\n"
7930
        "- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n"
7931
        "- Read FAQ and docs/FONTS.md for more details.\n"
7932
        "- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame().");
7933
}
7934
7935
// Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options.
7936
// Here we use the simplified Combo() api that packs items into a single literal string.
7937
// Useful for quick combo boxes where the choices are known locally.
7938
bool ImGui::ShowStyleSelector(const char* label)
7939
{
7940
    static int style_idx = -1;
7941
    if (ImGui::Combo(label, &style_idx, "Dark\0Light\0Classic\0"))
7942
    {
7943
        switch (style_idx)
7944
        {
7945
        case 0: ImGui::StyleColorsDark(); break;
7946
        case 1: ImGui::StyleColorsLight(); break;
7947
        case 2: ImGui::StyleColorsClassic(); break;
7948
        }
7949
        return true;
7950
    }
7951
    return false;
7952
}
7953
7954
void ImGui::ShowStyleEditor(ImGuiStyle* ref)
7955
{
7956
    IMGUI_DEMO_MARKER("Tools/Style Editor");
7957
    // You can pass in a reference ImGuiStyle structure to compare to, revert to and save to
7958
    // (without a reference style pointer, we will use one compared locally as a reference)
7959
    ImGuiStyle& style = ImGui::GetStyle();
7960
    static ImGuiStyle ref_saved_style;
7961
7962
    // Default to using internal storage as reference
7963
    static bool init = true;
7964
    if (init && ref == NULL)
7965
        ref_saved_style = style;
7966
    init = false;
7967
    if (ref == NULL)
7968
        ref = &ref_saved_style;
7969
7970
    ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.50f);
7971
7972
    if (ImGui::ShowStyleSelector("Colors##Selector"))
7973
        ref_saved_style = style;
7974
    ImGui::ShowFontSelector("Fonts##Selector");
7975
7976
    // Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f)
7977
    if (ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"))
7978
        style.GrabRounding = style.FrameRounding; // Make GrabRounding always the same value as FrameRounding
7979
    { bool border = (style.WindowBorderSize > 0.0f); if (ImGui::Checkbox("WindowBorder", &border)) { style.WindowBorderSize = border ? 1.0f : 0.0f; } }
7980
    ImGui::SameLine();
7981
    { bool border = (style.FrameBorderSize > 0.0f);  if (ImGui::Checkbox("FrameBorder",  &border)) { style.FrameBorderSize  = border ? 1.0f : 0.0f; } }
7982
    ImGui::SameLine();
7983
    { bool border = (style.PopupBorderSize > 0.0f);  if (ImGui::Checkbox("PopupBorder",  &border)) { style.PopupBorderSize  = border ? 1.0f : 0.0f; } }
7984
7985
    // Save/Revert button
7986
    if (ImGui::Button("Save Ref"))
7987
        *ref = ref_saved_style = style;
7988
    ImGui::SameLine();
7989
    if (ImGui::Button("Revert Ref"))
7990
        style = *ref;
7991
    ImGui::SameLine();
7992
    HelpMarker(
7993
        "Save/Revert in local non-persistent storage. Default Colors definition are not affected. "
7994
        "Use \"Export\" below to save them somewhere.");
7995
7996
    ImGui::Separator();
7997
7998
    if (ImGui::BeginTabBar("##tabs", ImGuiTabBarFlags_None))
7999
    {
8000
        if (ImGui::BeginTabItem("Sizes"))
8001
        {
8002
            ImGui::SeparatorText("Main");
8003
            ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f");
8004
            ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f");
8005
            ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f");
8006
            ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f");
8007
            ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f");
8008
            ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f");
8009
            ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f");
8010
            ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f");
8011
8012
            ImGui::SeparatorText("Borders");
8013
            ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f");
8014
            ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f");
8015
            ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f");
8016
            ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f");
8017
            ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f");
8018
            ImGui::SliderFloat("TabBarBorderSize", &style.TabBarBorderSize, 0.0f, 2.0f, "%.0f");
8019
            ImGui::SliderFloat("TabBarOverlineSize", &style.TabBarOverlineSize, 0.0f, 2.0f, "%.0f");
8020
            ImGui::SameLine(); HelpMarker("Overline is only drawn over the selected tab when ImGuiTabBarFlags_DrawSelectedOverline is set.");
8021
8022
            ImGui::SeparatorText("Rounding");
8023
            ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f");
8024
            ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f");
8025
            ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f");
8026
            ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f, "%.0f");
8027
            ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f");
8028
            ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f");
8029
            ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f");
8030
8031
            ImGui::SeparatorText("Tables");
8032
            ImGui::SliderFloat2("CellPadding", (float*)&style.CellPadding, 0.0f, 20.0f, "%.0f");
8033
            ImGui::SliderAngle("TableAngledHeadersAngle", &style.TableAngledHeadersAngle, -50.0f, +50.0f);
8034
            ImGui::SliderFloat2("TableAngledHeadersTextAlign", (float*)&style.TableAngledHeadersTextAlign, 0.0f, 1.0f, "%.2f");
8035
8036
            ImGui::SeparatorText("Widgets");
8037
            ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f");
8038
            int window_menu_button_position = style.WindowMenuButtonPosition + 1;
8039
            if (ImGui::Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0"))
8040
                style.WindowMenuButtonPosition = (ImGuiDir)(window_menu_button_position - 1);
8041
            ImGui::Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, "Left\0Right\0");
8042
            ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f");
8043
            ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content.");
8044
            ImGui::SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f");
8045
            ImGui::SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content.");
8046
            ImGui::SliderFloat("SeparatorTextBorderSize", &style.SeparatorTextBorderSize, 0.0f, 10.0f, "%.0f");
8047
            ImGui::SliderFloat2("SeparatorTextAlign", (float*)&style.SeparatorTextAlign, 0.0f, 1.0f, "%.2f");
8048
            ImGui::SliderFloat2("SeparatorTextPadding", (float*)&style.SeparatorTextPadding, 0.0f, 40.0f, "%.0f");
8049
            ImGui::SliderFloat("LogSliderDeadzone", &style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f");
8050
8051
            ImGui::SeparatorText("Docking");
8052
            ImGui::SliderFloat("DockingSplitterSize", &style.DockingSeparatorSize, 0.0f, 12.0f, "%.0f");
8053
8054
            ImGui::SeparatorText("Tooltips");
8055
            for (int n = 0; n < 2; n++)
8056
                if (ImGui::TreeNodeEx(n == 0 ? "HoverFlagsForTooltipMouse" : "HoverFlagsForTooltipNav"))
8057
                {
8058
                    ImGuiHoveredFlags* p = (n == 0) ? &style.HoverFlagsForTooltipMouse : &style.HoverFlagsForTooltipNav;
8059
                    ImGui::CheckboxFlags("ImGuiHoveredFlags_DelayNone", p, ImGuiHoveredFlags_DelayNone);
8060
                    ImGui::CheckboxFlags("ImGuiHoveredFlags_DelayShort", p, ImGuiHoveredFlags_DelayShort);
8061
                    ImGui::CheckboxFlags("ImGuiHoveredFlags_DelayNormal", p, ImGuiHoveredFlags_DelayNormal);
8062
                    ImGui::CheckboxFlags("ImGuiHoveredFlags_Stationary", p, ImGuiHoveredFlags_Stationary);
8063
                    ImGui::CheckboxFlags("ImGuiHoveredFlags_NoSharedDelay", p, ImGuiHoveredFlags_NoSharedDelay);
8064
                    ImGui::TreePop();
8065
                }
8066
8067
            ImGui::SeparatorText("Misc");
8068
            ImGui::SliderFloat2("DisplayWindowPadding", (float*)&style.DisplayWindowPadding, 0.0f, 30.0f, "%.0f"); ImGui::SameLine(); HelpMarker("Apply to regular windows: amount which we enforce to keep visible when moving near edges of your screen.");
8069
            ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); ImGui::SameLine(); HelpMarker("Apply to every windows, menus, popups, tooltips: amount where we avoid displaying contents. Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).");
8070
8071
            ImGui::EndTabItem();
8072
        }
8073
8074
        if (ImGui::BeginTabItem("Colors"))
8075
        {
8076
            static int output_dest = 0;
8077
            static bool output_only_modified = true;
8078
            if (ImGui::Button("Export"))
8079
            {
8080
                if (output_dest == 0)
8081
                    ImGui::LogToClipboard();
8082
                else
8083
                    ImGui::LogToTTY();
8084
                ImGui::LogText("ImVec4* colors = ImGui::GetStyle().Colors;" IM_NEWLINE);
8085
                for (int i = 0; i < ImGuiCol_COUNT; i++)
8086
                {
8087
                    const ImVec4& col = style.Colors[i];
8088
                    const char* name = ImGui::GetStyleColorName(i);
8089
                    if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0)
8090
                        ImGui::LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE,
8091
                            name, 23 - (int)strlen(name), "", col.x, col.y, col.z, col.w);
8092
                }
8093
                ImGui::LogFinish();
8094
            }
8095
            ImGui::SameLine(); ImGui::SetNextItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0");
8096
            ImGui::SameLine(); ImGui::Checkbox("Only Modified Colors", &output_only_modified);
8097
8098
            static ImGuiTextFilter filter;
8099
            filter.Draw("Filter colors", ImGui::GetFontSize() * 16);
8100
8101
            static ImGuiColorEditFlags alpha_flags = 0;
8102
            if (ImGui::RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_None))             { alpha_flags = ImGuiColorEditFlags_None; } ImGui::SameLine();
8103
            if (ImGui::RadioButton("Alpha",  alpha_flags == ImGuiColorEditFlags_AlphaPreview))     { alpha_flags = ImGuiColorEditFlags_AlphaPreview; } ImGui::SameLine();
8104
            if (ImGui::RadioButton("Both",   alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } ImGui::SameLine();
8105
            HelpMarker(
8106
                "In the color list:\n"
8107
                "Left-click on color square to open color picker,\n"
8108
                "Right-click to open edit options menu.");
8109
8110
            ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 10), ImVec2(FLT_MAX, FLT_MAX));
8111
            ImGui::BeginChild("##colors", ImVec2(0, 0), ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar);
8112
            ImGui::PushItemWidth(ImGui::GetFontSize() * -12);
8113
            for (int i = 0; i < ImGuiCol_COUNT; i++)
8114
            {
8115
                const char* name = ImGui::GetStyleColorName(i);
8116
                if (!filter.PassFilter(name))
8117
                    continue;
8118
                ImGui::PushID(i);
8119
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
8120
                if (ImGui::Button("?"))
8121
                    ImGui::DebugFlashStyleColor((ImGuiCol)i);
8122
                ImGui::SetItemTooltip("Flash given color to identify places where it is used.");
8123
                ImGui::SameLine();
8124
#endif
8125
                ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags);
8126
                if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0)
8127
                {
8128
                    // Tips: in a real user application, you may want to merge and use an icon font into the main font,
8129
                    // so instead of "Save"/"Revert" you'd use icons!
8130
                    // Read the FAQ and docs/FONTS.md about using icon fonts. It's really easy and super convenient!
8131
                    ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) { ref->Colors[i] = style.Colors[i]; }
8132
                    ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) { style.Colors[i] = ref->Colors[i]; }
8133
                }
8134
                ImGui::SameLine(0.0f, style.ItemInnerSpacing.x);
8135
                ImGui::TextUnformatted(name);
8136
                ImGui::PopID();
8137
            }
8138
            ImGui::PopItemWidth();
8139
            ImGui::EndChild();
8140
8141
            ImGui::EndTabItem();
8142
        }
8143
8144
        if (ImGui::BeginTabItem("Fonts"))
8145
        {
8146
            ImGuiIO& io = ImGui::GetIO();
8147
            ImFontAtlas* atlas = io.Fonts;
8148
            HelpMarker("Read FAQ and docs/FONTS.md for details on font loading.");
8149
            ImGui::ShowFontAtlas(atlas);
8150
8151
            // Post-baking font scaling. Note that this is NOT the nice way of scaling fonts, read below.
8152
            // (we enforce hard clamping manually as by default DragFloat/SliderFloat allows CTRL+Click text to get out of bounds).
8153
            const float MIN_SCALE = 0.3f;
8154
            const float MAX_SCALE = 2.0f;
8155
            HelpMarker(
8156
                "Those are old settings provided for convenience.\n"
8157
                "However, the _correct_ way of scaling your UI is currently to reload your font at the designed size, "
8158
                "rebuild the font atlas, and call style.ScaleAllSizes() on a reference ImGuiStyle structure.\n"
8159
                "Using those settings here will give you poor quality results.");
8160
            static float window_scale = 1.0f;
8161
            ImGui::PushItemWidth(ImGui::GetFontSize() * 8);
8162
            if (ImGui::DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp)) // Scale only this window
8163
                ImGui::SetWindowFontScale(window_scale);
8164
            ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp); // Scale everything
8165
            ImGui::PopItemWidth();
8166
8167
            ImGui::EndTabItem();
8168
        }
8169
8170
        if (ImGui::BeginTabItem("Rendering"))
8171
        {
8172
            ImGui::Checkbox("Anti-aliased lines", &style.AntiAliasedLines);
8173
            ImGui::SameLine();
8174
            HelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well.");
8175
8176
            ImGui::Checkbox("Anti-aliased lines use texture", &style.AntiAliasedLinesUseTex);
8177
            ImGui::SameLine();
8178
            HelpMarker("Faster lines using texture data. Require backend to render with bilinear filtering (not point/nearest filtering).");
8179
8180
            ImGui::Checkbox("Anti-aliased fill", &style.AntiAliasedFill);
8181
            ImGui::PushItemWidth(ImGui::GetFontSize() * 8);
8182
            ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, 10.0f, "%.2f");
8183
            if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f;
8184
8185
            // When editing the "Circle Segment Max Error" value, draw a preview of its effect on auto-tessellated circles.
8186
            ImGui::DragFloat("Circle Tessellation Max Error", &style.CircleTessellationMaxError , 0.005f, 0.10f, 5.0f, "%.2f", ImGuiSliderFlags_AlwaysClamp);
8187
            const bool show_samples = ImGui::IsItemActive();
8188
            if (show_samples)
8189
                ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos());
8190
            if (show_samples && ImGui::BeginTooltip())
8191
            {
8192
                ImGui::TextUnformatted("(R = radius, N = approx number of segments)");
8193
                ImGui::Spacing();
8194
                ImDrawList* draw_list = ImGui::GetWindowDrawList();
8195
                const float min_widget_width = ImGui::CalcTextSize("R: MMM\nN: MMM").x;
8196
                for (int n = 0; n < 8; n++)
8197
                {
8198
                    const float RAD_MIN = 5.0f;
8199
                    const float RAD_MAX = 70.0f;
8200
                    const float rad = RAD_MIN + (RAD_MAX - RAD_MIN) * (float)n / (8.0f - 1.0f);
8201
8202
                    ImGui::BeginGroup();
8203
8204
                    // N is not always exact here due to how PathArcTo() function work internally
8205
                    ImGui::Text("R: %.f\nN: %d", rad, draw_list->_CalcCircleAutoSegmentCount(rad));
8206
8207
                    const float canvas_width = IM_MAX(min_widget_width, rad * 2.0f);
8208
                    const float offset_x     = floorf(canvas_width * 0.5f);
8209
                    const float offset_y     = floorf(RAD_MAX);
8210
8211
                    const ImVec2 p1 = ImGui::GetCursorScreenPos();
8212
                    draw_list->AddCircle(ImVec2(p1.x + offset_x, p1.y + offset_y), rad, ImGui::GetColorU32(ImGuiCol_Text));
8213
                    ImGui::Dummy(ImVec2(canvas_width, RAD_MAX * 2));
8214
8215
                    /*
8216
                    const ImVec2 p2 = ImGui::GetCursorScreenPos();
8217
                    draw_list->AddCircleFilled(ImVec2(p2.x + offset_x, p2.y + offset_y), rad, ImGui::GetColorU32(ImGuiCol_Text));
8218
                    ImGui::Dummy(ImVec2(canvas_width, RAD_MAX * 2));
8219
                    */
8220
8221
                    ImGui::EndGroup();
8222
                    ImGui::SameLine();
8223
                }
8224
                ImGui::EndTooltip();
8225
            }
8226
            ImGui::SameLine();
8227
            HelpMarker("When drawing circle primitives with \"num_segments == 0\" tesselation will be calculated automatically.");
8228
8229
            ImGui::DragFloat("Global Alpha", &style.Alpha, 0.005f, 0.20f, 1.0f, "%.2f"); // Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero.
8230
            ImGui::DragFloat("Disabled Alpha", &style.DisabledAlpha, 0.005f, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); HelpMarker("Additional alpha multiplier for disabled items (multiply over current value of Alpha).");
8231
            ImGui::PopItemWidth();
8232
8233
            ImGui::EndTabItem();
8234
        }
8235
8236
        ImGui::EndTabBar();
8237
    }
8238
8239
    ImGui::PopItemWidth();
8240
}
8241
8242
//-----------------------------------------------------------------------------
8243
// [SECTION] User Guide / ShowUserGuide()
8244
//-----------------------------------------------------------------------------
8245
8246
void ImGui::ShowUserGuide()
8247
{
8248
    ImGuiIO& io = ImGui::GetIO();
8249
    ImGui::BulletText("Double-click on title bar to collapse window.");
8250
    ImGui::BulletText(
8251
        "Click and drag on lower corner to resize window\n"
8252
        "(double-click to auto fit window to its contents).");
8253
    ImGui::BulletText("CTRL+Click on a slider or drag box to input value as text.");
8254
    ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields.");
8255
    ImGui::BulletText("CTRL+Tab to select a window.");
8256
    if (io.FontAllowUserScaling)
8257
        ImGui::BulletText("CTRL+Mouse Wheel to zoom window contents.");
8258
    ImGui::BulletText("While inputing text:\n");
8259
    ImGui::Indent();
8260
    ImGui::BulletText("CTRL+Left/Right to word jump.");
8261
    ImGui::BulletText("CTRL+A or double-click to select all.");
8262
    ImGui::BulletText("CTRL+X/C/V to use clipboard cut/copy/paste.");
8263
    ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo.");
8264
    ImGui::BulletText("ESCAPE to revert.");
8265
    ImGui::Unindent();
8266
    ImGui::BulletText("With keyboard navigation enabled:");
8267
    ImGui::Indent();
8268
    ImGui::BulletText("Arrow keys to navigate.");
8269
    ImGui::BulletText("Space to activate a widget.");
8270
    ImGui::BulletText("Return to input text into a widget.");
8271
    ImGui::BulletText("Escape to deactivate a widget, close popup, exit child window.");
8272
    ImGui::BulletText("Alt to jump to the menu layer of a window.");
8273
    ImGui::Unindent();
8274
}
8275
8276
//-----------------------------------------------------------------------------
8277
// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar()
8278
//-----------------------------------------------------------------------------
8279
// - ShowExampleAppMainMenuBar()
8280
// - ShowExampleMenuFile()
8281
//-----------------------------------------------------------------------------
8282
8283
// Demonstrate creating a "main" fullscreen menu bar and populating it.
8284
// Note the difference between BeginMainMenuBar() and BeginMenuBar():
8285
// - BeginMenuBar() = menu-bar inside current window (which needs the ImGuiWindowFlags_MenuBar flag!)
8286
// - BeginMainMenuBar() = helper to create menu-bar-sized window at the top of the main viewport + call BeginMenuBar() into it.
8287
static void ShowExampleAppMainMenuBar()
8288
{
8289
    if (ImGui::BeginMainMenuBar())
8290
    {
8291
        if (ImGui::BeginMenu("File"))
8292
        {
8293
            ShowExampleMenuFile();
8294
            ImGui::EndMenu();
8295
        }
8296
        if (ImGui::BeginMenu("Edit"))
8297
        {
8298
            if (ImGui::MenuItem("Undo", "CTRL+Z")) {}
8299
            if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) {}  // Disabled item
8300
            ImGui::Separator();
8301
            if (ImGui::MenuItem("Cut", "CTRL+X")) {}
8302
            if (ImGui::MenuItem("Copy", "CTRL+C")) {}
8303
            if (ImGui::MenuItem("Paste", "CTRL+V")) {}
8304
            ImGui::EndMenu();
8305
        }
8306
        ImGui::EndMainMenuBar();
8307
    }
8308
}
8309
8310
// Note that shortcuts are currently provided for display only
8311
// (future version will add explicit flags to BeginMenu() to request processing shortcuts)
8312
static void ShowExampleMenuFile()
8313
{
8314
    IMGUI_DEMO_MARKER("Examples/Menu");
8315
    ImGui::MenuItem("(demo menu)", NULL, false, false);
8316
    if (ImGui::MenuItem("New")) {}
8317
    if (ImGui::MenuItem("Open", "Ctrl+O")) {}
8318
    if (ImGui::BeginMenu("Open Recent"))
8319
    {
8320
        ImGui::MenuItem("fish_hat.c");
8321
        ImGui::MenuItem("fish_hat.inl");
8322
        ImGui::MenuItem("fish_hat.h");
8323
        if (ImGui::BeginMenu("More.."))
8324
        {
8325
            ImGui::MenuItem("Hello");
8326
            ImGui::MenuItem("Sailor");
8327
            if (ImGui::BeginMenu("Recurse.."))
8328
            {
8329
                ShowExampleMenuFile();
8330
                ImGui::EndMenu();
8331
            }
8332
            ImGui::EndMenu();
8333
        }
8334
        ImGui::EndMenu();
8335
    }
8336
    if (ImGui::MenuItem("Save", "Ctrl+S")) {}
8337
    if (ImGui::MenuItem("Save As..")) {}
8338
8339
    ImGui::Separator();
8340
    IMGUI_DEMO_MARKER("Examples/Menu/Options");
8341
    if (ImGui::BeginMenu("Options"))
8342
    {
8343
        static bool enabled = true;
8344
        ImGui::MenuItem("Enabled", "", &enabled);
8345
        ImGui::BeginChild("child", ImVec2(0, 60), ImGuiChildFlags_Borders);
8346
        for (int i = 0; i < 10; i++)
8347
            ImGui::Text("Scrolling Text %d", i);
8348
        ImGui::EndChild();
8349
        static float f = 0.5f;
8350
        static int n = 0;
8351
        ImGui::SliderFloat("Value", &f, 0.0f, 1.0f);
8352
        ImGui::InputFloat("Input", &f, 0.1f);
8353
        ImGui::Combo("Combo", &n, "Yes\0No\0Maybe\0\0");
8354
        ImGui::EndMenu();
8355
    }
8356
8357
    IMGUI_DEMO_MARKER("Examples/Menu/Colors");
8358
    if (ImGui::BeginMenu("Colors"))
8359
    {
8360
        float sz = ImGui::GetTextLineHeight();
8361
        for (int i = 0; i < ImGuiCol_COUNT; i++)
8362
        {
8363
            const char* name = ImGui::GetStyleColorName((ImGuiCol)i);
8364
            ImVec2 p = ImGui::GetCursorScreenPos();
8365
            ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + sz, p.y + sz), ImGui::GetColorU32((ImGuiCol)i));
8366
            ImGui::Dummy(ImVec2(sz, sz));
8367
            ImGui::SameLine();
8368
            ImGui::MenuItem(name);
8369
        }
8370
        ImGui::EndMenu();
8371
    }
8372
8373
    // Here we demonstrate appending again to the "Options" menu (which we already created above)
8374
    // Of course in this demo it is a little bit silly that this function calls BeginMenu("Options") twice.
8375
    // In a real code-base using it would make senses to use this feature from very different code locations.
8376
    if (ImGui::BeginMenu("Options")) // <-- Append!
8377
    {
8378
        IMGUI_DEMO_MARKER("Examples/Menu/Append to an existing menu");
8379
        static bool b = true;
8380
        ImGui::Checkbox("SomeOption", &b);
8381
        ImGui::EndMenu();
8382
    }
8383
8384
    if (ImGui::BeginMenu("Disabled", false)) // Disabled
8385
    {
8386
        IM_ASSERT(0);
8387
    }
8388
    if (ImGui::MenuItem("Checked", NULL, true)) {}
8389
    ImGui::Separator();
8390
    if (ImGui::MenuItem("Quit", "Alt+F4")) {}
8391
}
8392
8393
//-----------------------------------------------------------------------------
8394
// [SECTION] Example App: Debug Console / ShowExampleAppConsole()
8395
//-----------------------------------------------------------------------------
8396
8397
// Demonstrate creating a simple console window, with scrolling, filtering, completion and history.
8398
// For the console example, we are using a more C++ like approach of declaring a class to hold both data and functions.
8399
struct ExampleAppConsole
8400
{
8401
    char                  InputBuf[256];
8402
    ImVector<char*>       Items;
8403
    ImVector<const char*> Commands;
8404
    ImVector<char*>       History;
8405
    int                   HistoryPos;    // -1: new line, 0..History.Size-1 browsing history.
8406
    ImGuiTextFilter       Filter;
8407
    bool                  AutoScroll;
8408
    bool                  ScrollToBottom;
8409
8410
    ExampleAppConsole()
8411
    {
8412
        IMGUI_DEMO_MARKER("Examples/Console");
8413
        ClearLog();
8414
        memset(InputBuf, 0, sizeof(InputBuf));
8415
        HistoryPos = -1;
8416
8417
        // "CLASSIFY" is here to provide the test case where "C"+[tab] completes to "CL" and display multiple matches.
8418
        Commands.push_back("HELP");
8419
        Commands.push_back("HISTORY");
8420
        Commands.push_back("CLEAR");
8421
        Commands.push_back("CLASSIFY");
8422
        AutoScroll = true;
8423
        ScrollToBottom = false;
8424
        AddLog("Welcome to Dear ImGui!");
8425
    }
8426
    ~ExampleAppConsole()
8427
    {
8428
        ClearLog();
8429
        for (int i = 0; i < History.Size; i++)
8430
            ImGui::MemFree(History[i]);
8431
    }
8432
8433
    // Portable helpers
8434
    static int   Stricmp(const char* s1, const char* s2)         { int d; while ((d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; } return d; }
8435
    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; }
8436
    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); }
8437
    static void  Strtrim(char* s)                                { char* str_end = s + strlen(s); while (str_end > s && str_end[-1] == ' ') str_end--; *str_end = 0; }
8438
8439
    void    ClearLog()
8440
    {
8441
        for (int i = 0; i < Items.Size; i++)
8442
            ImGui::MemFree(Items[i]);
8443
        Items.clear();
8444
    }
8445
8446
    void    AddLog(const char* fmt, ...) IM_FMTARGS(2)
8447
    {
8448
        // FIXME-OPT
8449
        char buf[1024];
8450
        va_list args;
8451
        va_start(args, fmt);
8452
        vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args);
8453
        buf[IM_ARRAYSIZE(buf)-1] = 0;
8454
        va_end(args);
8455
        Items.push_back(Strdup(buf));
8456
    }
8457
8458
    void    Draw(const char* title, bool* p_open)
8459
    {
8460
        ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
8461
        if (!ImGui::Begin(title, p_open))
8462
        {
8463
            ImGui::End();
8464
            return;
8465
        }
8466
8467
        // As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar.
8468
        // So e.g. IsItemHovered() will return true when hovering the title bar.
8469
        // Here we create a context menu only available from the title bar.
8470
        if (ImGui::BeginPopupContextItem())
8471
        {
8472
            if (ImGui::MenuItem("Close Console"))
8473
                *p_open = false;
8474
            ImGui::EndPopup();
8475
        }
8476
8477
        ImGui::TextWrapped(
8478
            "This example implements a console with basic coloring, completion (TAB key) and history (Up/Down keys). A more elaborate "
8479
            "implementation may want to store entries along with extra data such as timestamp, emitter, etc.");
8480
        ImGui::TextWrapped("Enter 'HELP' for help.");
8481
8482
        // TODO: display items starting from the bottom
8483
8484
        if (ImGui::SmallButton("Add Debug Text"))  { AddLog("%d some text", Items.Size); AddLog("some more text"); AddLog("display very important message here!"); }
8485
        ImGui::SameLine();
8486
        if (ImGui::SmallButton("Add Debug Error")) { AddLog("[error] something went wrong"); }
8487
        ImGui::SameLine();
8488
        if (ImGui::SmallButton("Clear"))           { ClearLog(); }
8489
        ImGui::SameLine();
8490
        bool copy_to_clipboard = ImGui::SmallButton("Copy");
8491
        //static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); }
8492
8493
        ImGui::Separator();
8494
8495
        // Options menu
8496
        if (ImGui::BeginPopup("Options"))
8497
        {
8498
            ImGui::Checkbox("Auto-scroll", &AutoScroll);
8499
            ImGui::EndPopup();
8500
        }
8501
8502
        // Options, Filter
8503
        ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_O, ImGuiInputFlags_Tooltip);
8504
        if (ImGui::Button("Options"))
8505
            ImGui::OpenPopup("Options");
8506
        ImGui::SameLine();
8507
        Filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180);
8508
        ImGui::Separator();
8509
8510
        // Reserve enough left-over height for 1 separator + 1 input text
8511
        const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
8512
        if (ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_HorizontalScrollbar))
8513
        {
8514
            if (ImGui::BeginPopupContextWindow())
8515
            {
8516
                if (ImGui::Selectable("Clear")) ClearLog();
8517
                ImGui::EndPopup();
8518
            }
8519
8520
            // Display every line as a separate entry so we can change their color or add custom widgets.
8521
            // If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end());
8522
            // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping
8523
            // to only process visible items. The clipper will automatically measure the height of your first item and then
8524
            // "seek" to display only items in the visible area.
8525
            // To use the clipper we can replace your standard loop:
8526
            //      for (int i = 0; i < Items.Size; i++)
8527
            //   With:
8528
            //      ImGuiListClipper clipper;
8529
            //      clipper.Begin(Items.Size);
8530
            //      while (clipper.Step())
8531
            //         for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
8532
            // - That your items are evenly spaced (same height)
8533
            // - That you have cheap random access to your elements (you can access them given their index,
8534
            //   without processing all the ones before)
8535
            // You cannot this code as-is if a filter is active because it breaks the 'cheap random-access' property.
8536
            // We would need random-access on the post-filtered list.
8537
            // A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices
8538
            // or offsets of items that passed the filtering test, recomputing this array when user changes the filter,
8539
            // and appending newly elements as they are inserted. This is left as a task to the user until we can manage
8540
            // to improve this example code!
8541
            // If your items are of variable height:
8542
            // - Split them into same height items would be simpler and facilitate random-seeking into your list.
8543
            // - Consider using manual call to IsRectVisible() and skipping extraneous decoration from your items.
8544
            ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing
8545
            if (copy_to_clipboard)
8546
                ImGui::LogToClipboard();
8547
            for (const char* item : Items)
8548
            {
8549
                if (!Filter.PassFilter(item))
8550
                    continue;
8551
8552
                // Normally you would store more information in your item than just a string.
8553
                // (e.g. make Items[] an array of structure, store color/type etc.)
8554
                ImVec4 color;
8555
                bool has_color = false;
8556
                if (strstr(item, "[error]")) { color = ImVec4(1.0f, 0.4f, 0.4f, 1.0f); has_color = true; }
8557
                else if (strncmp(item, "# ", 2) == 0) { color = ImVec4(1.0f, 0.8f, 0.6f, 1.0f); has_color = true; }
8558
                if (has_color)
8559
                    ImGui::PushStyleColor(ImGuiCol_Text, color);
8560
                ImGui::TextUnformatted(item);
8561
                if (has_color)
8562
                    ImGui::PopStyleColor();
8563
            }
8564
            if (copy_to_clipboard)
8565
                ImGui::LogFinish();
8566
8567
            // Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame.
8568
            // Using a scrollbar or mouse-wheel will take away from the bottom edge.
8569
            if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()))
8570
                ImGui::SetScrollHereY(1.0f);
8571
            ScrollToBottom = false;
8572
8573
            ImGui::PopStyleVar();
8574
        }
8575
        ImGui::EndChild();
8576
        ImGui::Separator();
8577
8578
        // Command-line
8579
        bool reclaim_focus = false;
8580
        ImGuiInputTextFlags input_text_flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_EscapeClearsAll | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory;
8581
        if (ImGui::InputText("Input", InputBuf, IM_ARRAYSIZE(InputBuf), input_text_flags, &TextEditCallbackStub, (void*)this))
8582
        {
8583
            char* s = InputBuf;
8584
            Strtrim(s);
8585
            if (s[0])
8586
                ExecCommand(s);
8587
            strcpy(s, "");
8588
            reclaim_focus = true;
8589
        }
8590
8591
        // Auto-focus on window apparition
8592
        ImGui::SetItemDefaultFocus();
8593
        if (reclaim_focus)
8594
            ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget
8595
8596
        ImGui::End();
8597
    }
8598
8599
    void    ExecCommand(const char* command_line)
8600
    {
8601
        AddLog("# %s\n", command_line);
8602
8603
        // Insert into history. First find match and delete it so it can be pushed to the back.
8604
        // This isn't trying to be smart or optimal.
8605
        HistoryPos = -1;
8606
        for (int i = History.Size - 1; i >= 0; i--)
8607
            if (Stricmp(History[i], command_line) == 0)
8608
            {
8609
                ImGui::MemFree(History[i]);
8610
                History.erase(History.begin() + i);
8611
                break;
8612
            }
8613
        History.push_back(Strdup(command_line));
8614
8615
        // Process command
8616
        if (Stricmp(command_line, "CLEAR") == 0)
8617
        {
8618
            ClearLog();
8619
        }
8620
        else if (Stricmp(command_line, "HELP") == 0)
8621
        {
8622
            AddLog("Commands:");
8623
            for (int i = 0; i < Commands.Size; i++)
8624
                AddLog("- %s", Commands[i]);
8625
        }
8626
        else if (Stricmp(command_line, "HISTORY") == 0)
8627
        {
8628
            int first = History.Size - 10;
8629
            for (int i = first > 0 ? first : 0; i < History.Size; i++)
8630
                AddLog("%3d: %s\n", i, History[i]);
8631
        }
8632
        else
8633
        {
8634
            AddLog("Unknown command: '%s'\n", command_line);
8635
        }
8636
8637
        // On command input, we scroll to bottom even if AutoScroll==false
8638
        ScrollToBottom = true;
8639
    }
8640
8641
    // In C++11 you'd be better off using lambdas for this sort of forwarding callbacks
8642
    static int TextEditCallbackStub(ImGuiInputTextCallbackData* data)
8643
    {
8644
        ExampleAppConsole* console = (ExampleAppConsole*)data->UserData;
8645
        return console->TextEditCallback(data);
8646
    }
8647
8648
    int     TextEditCallback(ImGuiInputTextCallbackData* data)
8649
    {
8650
        //AddLog("cursor: %d, selection: %d-%d", data->CursorPos, data->SelectionStart, data->SelectionEnd);
8651
        switch (data->EventFlag)
8652
        {
8653
        case ImGuiInputTextFlags_CallbackCompletion:
8654
            {
8655
                // Example of TEXT COMPLETION
8656
8657
                // Locate beginning of current word
8658
                const char* word_end = data->Buf + data->CursorPos;
8659
                const char* word_start = word_end;
8660
                while (word_start > data->Buf)
8661
                {
8662
                    const char c = word_start[-1];
8663
                    if (c == ' ' || c == '\t' || c == ',' || c == ';')
8664
                        break;
8665
                    word_start--;
8666
                }
8667
8668
                // Build a list of candidates
8669
                ImVector<const char*> candidates;
8670
                for (int i = 0; i < Commands.Size; i++)
8671
                    if (Strnicmp(Commands[i], word_start, (int)(word_end - word_start)) == 0)
8672
                        candidates.push_back(Commands[i]);
8673
8674
                if (candidates.Size == 0)
8675
                {
8676
                    // No match
8677
                    AddLog("No match for \"%.*s\"!\n", (int)(word_end - word_start), word_start);
8678
                }
8679
                else if (candidates.Size == 1)
8680
                {
8681
                    // Single match. Delete the beginning of the word and replace it entirely so we've got nice casing.
8682
                    data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start));
8683
                    data->InsertChars(data->CursorPos, candidates[0]);
8684
                    data->InsertChars(data->CursorPos, " ");
8685
                }
8686
                else
8687
                {
8688
                    // Multiple matches. Complete as much as we can..
8689
                    // So inputing "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches.
8690
                    int match_len = (int)(word_end - word_start);
8691
                    for (;;)
8692
                    {
8693
                        int c = 0;
8694
                        bool all_candidates_matches = true;
8695
                        for (int i = 0; i < candidates.Size && all_candidates_matches; i++)
8696
                            if (i == 0)
8697
                                c = toupper(candidates[i][match_len]);
8698
                            else if (c == 0 || c != toupper(candidates[i][match_len]))
8699
                                all_candidates_matches = false;
8700
                        if (!all_candidates_matches)
8701
                            break;
8702
                        match_len++;
8703
                    }
8704
8705
                    if (match_len > 0)
8706
                    {
8707
                        data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start));
8708
                        data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len);
8709
                    }
8710
8711
                    // List matches
8712
                    AddLog("Possible matches:\n");
8713
                    for (int i = 0; i < candidates.Size; i++)
8714
                        AddLog("- %s\n", candidates[i]);
8715
                }
8716
8717
                break;
8718
            }
8719
        case ImGuiInputTextFlags_CallbackHistory:
8720
            {
8721
                // Example of HISTORY
8722
                const int prev_history_pos = HistoryPos;
8723
                if (data->EventKey == ImGuiKey_UpArrow)
8724
                {
8725
                    if (HistoryPos == -1)
8726
                        HistoryPos = History.Size - 1;
8727
                    else if (HistoryPos > 0)
8728
                        HistoryPos--;
8729
                }
8730
                else if (data->EventKey == ImGuiKey_DownArrow)
8731
                {
8732
                    if (HistoryPos != -1)
8733
                        if (++HistoryPos >= History.Size)
8734
                            HistoryPos = -1;
8735
                }
8736
8737
                // A better implementation would preserve the data on the current input line along with cursor position.
8738
                if (prev_history_pos != HistoryPos)
8739
                {
8740
                    const char* history_str = (HistoryPos >= 0) ? History[HistoryPos] : "";
8741
                    data->DeleteChars(0, data->BufTextLen);
8742
                    data->InsertChars(0, history_str);
8743
                }
8744
            }
8745
        }
8746
        return 0;
8747
    }
8748
};
8749
8750
static void ShowExampleAppConsole(bool* p_open)
8751
{
8752
    static ExampleAppConsole console;
8753
    console.Draw("Example: Console", p_open);
8754
}
8755
8756
//-----------------------------------------------------------------------------
8757
// [SECTION] Example App: Debug Log / ShowExampleAppLog()
8758
//-----------------------------------------------------------------------------
8759
8760
// Usage:
8761
//  static ExampleAppLog my_log;
8762
//  my_log.AddLog("Hello %d world\n", 123);
8763
//  my_log.Draw("title");
8764
struct ExampleAppLog
8765
{
8766
    ImGuiTextBuffer     Buf;
8767
    ImGuiTextFilter     Filter;
8768
    ImVector<int>       LineOffsets; // Index to lines offset. We maintain this with AddLog() calls.
8769
    bool                AutoScroll;  // Keep scrolling if already at the bottom.
8770
8771
    ExampleAppLog()
8772
    {
8773
        AutoScroll = true;
8774
        Clear();
8775
    }
8776
8777
    void    Clear()
8778
    {
8779
        Buf.clear();
8780
        LineOffsets.clear();
8781
        LineOffsets.push_back(0);
8782
    }
8783
8784
    void    AddLog(const char* fmt, ...) IM_FMTARGS(2)
8785
    {
8786
        int old_size = Buf.size();
8787
        va_list args;
8788
        va_start(args, fmt);
8789
        Buf.appendfv(fmt, args);
8790
        va_end(args);
8791
        for (int new_size = Buf.size(); old_size < new_size; old_size++)
8792
            if (Buf[old_size] == '\n')
8793
                LineOffsets.push_back(old_size + 1);
8794
    }
8795
8796
    void    Draw(const char* title, bool* p_open = NULL)
8797
    {
8798
        if (!ImGui::Begin(title, p_open))
8799
        {
8800
            ImGui::End();
8801
            return;
8802
        }
8803
8804
        // Options menu
8805
        if (ImGui::BeginPopup("Options"))
8806
        {
8807
            ImGui::Checkbox("Auto-scroll", &AutoScroll);
8808
            ImGui::EndPopup();
8809
        }
8810
8811
        // Main window
8812
        if (ImGui::Button("Options"))
8813
            ImGui::OpenPopup("Options");
8814
        ImGui::SameLine();
8815
        bool clear = ImGui::Button("Clear");
8816
        ImGui::SameLine();
8817
        bool copy = ImGui::Button("Copy");
8818
        ImGui::SameLine();
8819
        Filter.Draw("Filter", -100.0f);
8820
8821
        ImGui::Separator();
8822
8823
        if (ImGui::BeginChild("scrolling", ImVec2(0, 0), ImGuiChildFlags_None, ImGuiWindowFlags_HorizontalScrollbar))
8824
        {
8825
            if (clear)
8826
                Clear();
8827
            if (copy)
8828
                ImGui::LogToClipboard();
8829
8830
            ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
8831
            const char* buf = Buf.begin();
8832
            const char* buf_end = Buf.end();
8833
            if (Filter.IsActive())
8834
            {
8835
                // In this example we don't use the clipper when Filter is enabled.
8836
                // This is because we don't have random access to the result of our filter.
8837
                // A real application processing logs with ten of thousands of entries may want to store the result of
8838
                // search/filter.. especially if the filtering function is not trivial (e.g. reg-exp).
8839
                for (int line_no = 0; line_no < LineOffsets.Size; line_no++)
8840
                {
8841
                    const char* line_start = buf + LineOffsets[line_no];
8842
                    const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
8843
                    if (Filter.PassFilter(line_start, line_end))
8844
                        ImGui::TextUnformatted(line_start, line_end);
8845
                }
8846
            }
8847
            else
8848
            {
8849
                // The simplest and easy way to display the entire buffer:
8850
                //   ImGui::TextUnformatted(buf_begin, buf_end);
8851
                // And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward
8852
                // to skip non-visible lines. Here we instead demonstrate using the clipper to only process lines that are
8853
                // within the visible area.
8854
                // If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them
8855
                // on your side is recommended. Using ImGuiListClipper requires
8856
                // - A) random access into your data
8857
                // - B) items all being the  same height,
8858
                // both of which we can handle since we have an array pointing to the beginning of each line of text.
8859
                // When using the filter (in the block of code above) we don't have random access into the data to display
8860
                // anymore, which is why we don't use the clipper. Storing or skimming through the search result would make
8861
                // it possible (and would be recommended if you want to search through tens of thousands of entries).
8862
                ImGuiListClipper clipper;
8863
                clipper.Begin(LineOffsets.Size);
8864
                while (clipper.Step())
8865
                {
8866
                    for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++)
8867
                    {
8868
                        const char* line_start = buf + LineOffsets[line_no];
8869
                        const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
8870
                        ImGui::TextUnformatted(line_start, line_end);
8871
                    }
8872
                }
8873
                clipper.End();
8874
            }
8875
            ImGui::PopStyleVar();
8876
8877
            // Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame.
8878
            // Using a scrollbar or mouse-wheel will take away from the bottom edge.
8879
            if (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())
8880
                ImGui::SetScrollHereY(1.0f);
8881
        }
8882
        ImGui::EndChild();
8883
        ImGui::End();
8884
    }
8885
};
8886
8887
// Demonstrate creating a simple log window with basic filtering.
8888
static void ShowExampleAppLog(bool* p_open)
8889
{
8890
    static ExampleAppLog log;
8891
8892
    // For the demo: add a debug button _BEFORE_ the normal log window contents
8893
    // We take advantage of a rarely used feature: multiple calls to Begin()/End() are appending to the _same_ window.
8894
    // Most of the contents of the window will be added by the log.Draw() call.
8895
    ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver);
8896
    ImGui::Begin("Example: Log", p_open);
8897
    IMGUI_DEMO_MARKER("Examples/Log");
8898
    if (ImGui::SmallButton("[Debug] Add 5 entries"))
8899
    {
8900
        static int counter = 0;
8901
        const char* categories[3] = { "info", "warn", "error" };
8902
        const char* words[] = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" };
8903
        for (int n = 0; n < 5; n++)
8904
        {
8905
            const char* category = categories[counter % IM_ARRAYSIZE(categories)];
8906
            const char* word = words[counter % IM_ARRAYSIZE(words)];
8907
            log.AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n",
8908
                ImGui::GetFrameCount(), category, ImGui::GetTime(), word);
8909
            counter++;
8910
        }
8911
    }
8912
    ImGui::End();
8913
8914
    // Actually call in the regular Log helper (which will Begin() into the same window as we just did)
8915
    log.Draw("Example: Log", p_open);
8916
}
8917
8918
//-----------------------------------------------------------------------------
8919
// [SECTION] Example App: Simple Layout / ShowExampleAppLayout()
8920
//-----------------------------------------------------------------------------
8921
8922
// Demonstrate create a window with multiple child windows.
8923
static void ShowExampleAppLayout(bool* p_open)
8924
{
8925
    ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiCond_FirstUseEver);
8926
    if (ImGui::Begin("Example: Simple layout", p_open, ImGuiWindowFlags_MenuBar))
8927
    {
8928
        IMGUI_DEMO_MARKER("Examples/Simple layout");
8929
        if (ImGui::BeginMenuBar())
8930
        {
8931
            if (ImGui::BeginMenu("File"))
8932
            {
8933
                if (ImGui::MenuItem("Close", "Ctrl+W")) { *p_open = false; }
8934
                ImGui::EndMenu();
8935
            }
8936
            ImGui::EndMenuBar();
8937
        }
8938
8939
        // Left
8940
        static int selected = 0;
8941
        {
8942
            ImGui::BeginChild("left pane", ImVec2(150, 0), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeX);
8943
            for (int i = 0; i < 100; i++)
8944
            {
8945
                // FIXME: Good candidate to use ImGuiSelectableFlags_SelectOnNav
8946
                char label[128];
8947
                sprintf(label, "MyObject %d", i);
8948
                if (ImGui::Selectable(label, selected == i))
8949
                    selected = i;
8950
            }
8951
            ImGui::EndChild();
8952
        }
8953
        ImGui::SameLine();
8954
8955
        // Right
8956
        {
8957
            ImGui::BeginGroup();
8958
            ImGui::BeginChild("item view", ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us
8959
            ImGui::Text("MyObject: %d", selected);
8960
            ImGui::Separator();
8961
            if (ImGui::BeginTabBar("##Tabs", ImGuiTabBarFlags_None))
8962
            {
8963
                if (ImGui::BeginTabItem("Description"))
8964
                {
8965
                    ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ");
8966
                    ImGui::EndTabItem();
8967
                }
8968
                if (ImGui::BeginTabItem("Details"))
8969
                {
8970
                    ImGui::Text("ID: 0123456789");
8971
                    ImGui::EndTabItem();
8972
                }
8973
                ImGui::EndTabBar();
8974
            }
8975
            ImGui::EndChild();
8976
            if (ImGui::Button("Revert")) {}
8977
            ImGui::SameLine();
8978
            if (ImGui::Button("Save")) {}
8979
            ImGui::EndGroup();
8980
        }
8981
    }
8982
    ImGui::End();
8983
}
8984
8985
//-----------------------------------------------------------------------------
8986
// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor()
8987
//-----------------------------------------------------------------------------
8988
// Some of the interactions are a bit lack-luster:
8989
// - We would want pressing validating or leaving the filter to somehow restore focus.
8990
// - We may want more advanced filtering (child nodes) and clipper support: both will need extra work.
8991
// - We would want to customize some keyboard interactions to easily keyboard navigate between the tree and the properties.
8992
//-----------------------------------------------------------------------------
8993
8994
struct ExampleAppPropertyEditor
8995
{
8996
    ImGuiTextFilter     Filter;
8997
    ExampleTreeNode*    VisibleNode = NULL;
8998
8999
    void Draw(ExampleTreeNode* root_node)
9000
    {
9001
        // Left side: draw tree
9002
        // - Currently using a table to benefit from RowBg feature
9003
        if (ImGui::BeginChild("##tree", ImVec2(300, 0), ImGuiChildFlags_ResizeX | ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened))
9004
        {
9005
            ImGui::SetNextItemWidth(-FLT_MIN);
9006
            ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F, ImGuiInputFlags_Tooltip);
9007
            ImGui::PushItemFlag(ImGuiItemFlags_NoNavDefaultFocus, true);
9008
            if (ImGui::InputTextWithHint("##Filter", "incl,-excl", Filter.InputBuf, IM_ARRAYSIZE(Filter.InputBuf), ImGuiInputTextFlags_EscapeClearsAll))
9009
                Filter.Build();
9010
            ImGui::PopItemFlag();
9011
9012
            if (ImGui::BeginTable("##bg", 1, ImGuiTableFlags_RowBg))
9013
            {
9014
                for (ExampleTreeNode* node : root_node->Childs)
9015
                    if (Filter.PassFilter(node->Name)) // Filter root node
9016
                        DrawTreeNode(node);
9017
                ImGui::EndTable();
9018
            }
9019
        }
9020
        ImGui::EndChild();
9021
9022
        // Right side: draw properties
9023
        ImGui::SameLine();
9024
9025
        ImGui::BeginGroup(); // Lock X position
9026
        if (ExampleTreeNode* node = VisibleNode)
9027
        {
9028
            ImGui::Text("%s", node->Name);
9029
            ImGui::TextDisabled("UID: 0x%08X", node->UID);
9030
            ImGui::Separator();
9031
            if (ImGui::BeginTable("##properties", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY))
9032
            {
9033
                ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed);
9034
                ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 2.0f); // Default twice larger
9035
                if (node->HasData)
9036
                {
9037
                    // In a typical application, the structure description would be derived from a data-driven system.
9038
                    // - We try to mimic this with our ExampleMemberInfo structure and the ExampleTreeNodeMemberInfos[] array.
9039
                    // - Limits and some details are hard-coded to simplify the demo.
9040
                    for (const ExampleMemberInfo& field_desc : ExampleTreeNodeMemberInfos)
9041
                    {
9042
                        ImGui::TableNextRow();
9043
                        ImGui::PushID(field_desc.Name);
9044
                        ImGui::TableNextColumn();
9045
                        ImGui::AlignTextToFramePadding();
9046
                        ImGui::TextUnformatted(field_desc.Name);
9047
                        ImGui::TableNextColumn();
9048
                        void* field_ptr = (void*)(((unsigned char*)node) + field_desc.Offset);
9049
                        switch (field_desc.DataType)
9050
                        {
9051
                        case ImGuiDataType_Bool:
9052
                        {
9053
                            IM_ASSERT(field_desc.DataCount == 1);
9054
                            ImGui::Checkbox("##Editor", (bool*)field_ptr);
9055
                            break;
9056
                        }
9057
                        case ImGuiDataType_S32:
9058
                        {
9059
                            int v_min = INT_MIN, v_max = INT_MAX;
9060
                            ImGui::SetNextItemWidth(-FLT_MIN);
9061
                            ImGui::DragScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, 1.0f, &v_min, &v_max);
9062
                            break;
9063
                        }
9064
                        case ImGuiDataType_Float:
9065
                        {
9066
                            float v_min = 0.0f, v_max = 1.0f;
9067
                            ImGui::SetNextItemWidth(-FLT_MIN);
9068
                            ImGui::SliderScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, &v_min, &v_max);
9069
                            break;
9070
                        }
9071
                        }
9072
                        ImGui::PopID();
9073
                    }
9074
                }
9075
                ImGui::EndTable();
9076
            }
9077
        }
9078
        ImGui::EndGroup();
9079
    }
9080
9081
    void DrawTreeNode(ExampleTreeNode* node)
9082
    {
9083
        ImGui::TableNextRow();
9084
        ImGui::TableNextColumn();
9085
        ImGui::PushID(node->UID);
9086
        ImGuiTreeNodeFlags tree_flags = ImGuiTreeNodeFlags_None;
9087
        tree_flags |= ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;    // Standard opening mode as we are likely to want to add selection afterwards
9088
        tree_flags |= ImGuiTreeNodeFlags_NavLeftJumpsBackHere;                                  // Left arrow support
9089
        if (node == VisibleNode)
9090
            tree_flags |= ImGuiTreeNodeFlags_Selected;
9091
        if (node->Childs.Size == 0)
9092
            tree_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet;
9093
        if (node->DataMyBool == false)
9094
            ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]);
9095
        bool node_open = ImGui::TreeNodeEx("", tree_flags, "%s", node->Name);
9096
        if (node->DataMyBool == false)
9097
            ImGui::PopStyleColor();
9098
        if (ImGui::IsItemFocused())
9099
            VisibleNode = node;
9100
        if (node_open)
9101
        {
9102
            for (ExampleTreeNode* child : node->Childs)
9103
                DrawTreeNode(child);
9104
            ImGui::TreePop();
9105
        }
9106
        ImGui::PopID();
9107
    }
9108
};
9109
9110
// Demonstrate creating a simple property editor.
9111
static void ShowExampleAppPropertyEditor(bool* p_open, ImGuiDemoWindowData* demo_data)
9112
{
9113
    ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver);
9114
    if (!ImGui::Begin("Example: Property editor", p_open))
9115
    {
9116
        ImGui::End();
9117
        return;
9118
    }
9119
9120
    IMGUI_DEMO_MARKER("Examples/Property Editor");
9121
    static ExampleAppPropertyEditor property_editor;
9122
    if (demo_data->DemoTree == NULL)
9123
        demo_data->DemoTree = ExampleTree_CreateDemoTree();
9124
    property_editor.Draw(demo_data->DemoTree);
9125
9126
    ImGui::End();
9127
}
9128
9129
//-----------------------------------------------------------------------------
9130
// [SECTION] Example App: Long Text / ShowExampleAppLongText()
9131
//-----------------------------------------------------------------------------
9132
9133
// Demonstrate/test rendering huge amount of text, and the incidence of clipping.
9134
static void ShowExampleAppLongText(bool* p_open)
9135
{
9136
    ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
9137
    if (!ImGui::Begin("Example: Long text display", p_open))
9138
    {
9139
        ImGui::End();
9140
        return;
9141
    }
9142
    IMGUI_DEMO_MARKER("Examples/Long text display");
9143
9144
    static int test_type = 0;
9145
    static ImGuiTextBuffer log;
9146
    static int lines = 0;
9147
    ImGui::Text("Printing unusually long amount of text.");
9148
    ImGui::Combo("Test type", &test_type,
9149
        "Single call to TextUnformatted()\0"
9150
        "Multiple calls to Text(), clipped\0"
9151
        "Multiple calls to Text(), not clipped (slow)\0");
9152
    ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size());
9153
    if (ImGui::Button("Clear")) { log.clear(); lines = 0; }
9154
    ImGui::SameLine();
9155
    if (ImGui::Button("Add 1000 lines"))
9156
    {
9157
        for (int i = 0; i < 1000; i++)
9158
            log.appendf("%i The quick brown fox jumps over the lazy dog\n", lines + i);
9159
        lines += 1000;
9160
    }
9161
    ImGui::BeginChild("Log");
9162
    switch (test_type)
9163
    {
9164
    case 0:
9165
        // Single call to TextUnformatted() with a big buffer
9166
        ImGui::TextUnformatted(log.begin(), log.end());
9167
        break;
9168
    case 1:
9169
        {
9170
            // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper.
9171
            ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
9172
            ImGuiListClipper clipper;
9173
            clipper.Begin(lines);
9174
            while (clipper.Step())
9175
                for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
9176
                    ImGui::Text("%i The quick brown fox jumps over the lazy dog", i);
9177
            ImGui::PopStyleVar();
9178
            break;
9179
        }
9180
    case 2:
9181
        // Multiple calls to Text(), not clipped (slow)
9182
        ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
9183
        for (int i = 0; i < lines; i++)
9184
            ImGui::Text("%i The quick brown fox jumps over the lazy dog", i);
9185
        ImGui::PopStyleVar();
9186
        break;
9187
    }
9188
    ImGui::EndChild();
9189
    ImGui::End();
9190
}
9191
9192
//-----------------------------------------------------------------------------
9193
// [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize()
9194
//-----------------------------------------------------------------------------
9195
9196
// Demonstrate creating a window which gets auto-resized according to its content.
9197
static void ShowExampleAppAutoResize(bool* p_open)
9198
{
9199
    if (!ImGui::Begin("Example: Auto-resizing window", p_open, ImGuiWindowFlags_AlwaysAutoResize))
9200
    {
9201
        ImGui::End();
9202
        return;
9203
    }
9204
    IMGUI_DEMO_MARKER("Examples/Auto-resizing window");
9205
9206
    static int lines = 10;
9207
    ImGui::TextUnformatted(
9208
        "Window will resize every-frame to the size of its content.\n"
9209
        "Note that you probably don't want to query the window size to\n"
9210
        "output your content because that would create a feedback loop.");
9211
    ImGui::SliderInt("Number of lines", &lines, 1, 20);
9212
    for (int i = 0; i < lines; i++)
9213
        ImGui::Text("%*sThis is line %d", i * 4, "", i); // Pad with space to extend size horizontally
9214
    ImGui::End();
9215
}
9216
9217
//-----------------------------------------------------------------------------
9218
// [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize()
9219
//-----------------------------------------------------------------------------
9220
9221
// Demonstrate creating a window with custom resize constraints.
9222
// Note that size constraints currently don't work on a docked window (when in 'docking' branch)
9223
static void ShowExampleAppConstrainedResize(bool* p_open)
9224
{
9225
    struct CustomConstraints
9226
    {
9227
        // Helper functions to demonstrate programmatic constraints
9228
        // FIXME: This doesn't take account of decoration size (e.g. title bar), library should make this easier.
9229
        // FIXME: None of the three demos works consistently when resizing from borders.
9230
        static void AspectRatio(ImGuiSizeCallbackData* data)
9231
        {
9232
            float aspect_ratio = *(float*)data->UserData;
9233
            data->DesiredSize.y = (float)(int)(data->DesiredSize.x / aspect_ratio);
9234
        }
9235
        static void Square(ImGuiSizeCallbackData* data)
9236
        {
9237
            data->DesiredSize.x = data->DesiredSize.y = IM_MAX(data->DesiredSize.x, data->DesiredSize.y);
9238
        }
9239
        static void Step(ImGuiSizeCallbackData* data)
9240
        {
9241
            float step = *(float*)data->UserData;
9242
            data->DesiredSize = ImVec2((int)(data->DesiredSize.x / step + 0.5f) * step, (int)(data->DesiredSize.y / step + 0.5f) * step);
9243
        }
9244
    };
9245
9246
    const char* test_desc[] =
9247
    {
9248
        "Between 100x100 and 500x500",
9249
        "At least 100x100",
9250
        "Resize vertical + lock current width",
9251
        "Resize horizontal + lock current height",
9252
        "Width Between 400 and 500",
9253
        "Height at least 400",
9254
        "Custom: Aspect Ratio 16:9",
9255
        "Custom: Always Square",
9256
        "Custom: Fixed Steps (100)",
9257
    };
9258
9259
    // Options
9260
    static bool auto_resize = false;
9261
    static bool window_padding = true;
9262
    static int type = 6; // Aspect Ratio
9263
    static int display_lines = 10;
9264
9265
    // Submit constraint
9266
    float aspect_ratio = 16.0f / 9.0f;
9267
    float fixed_step = 100.0f;
9268
    if (type == 0) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(500, 500));         // Between 100x100 and 500x500
9269
    if (type == 1) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100
9270
    if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 0),    ImVec2(-1, FLT_MAX));      // Resize vertical + lock current width
9271
    if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1),    ImVec2(FLT_MAX, -1));      // Resize horizontal + lock current height
9272
    if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1),  ImVec2(500, -1));          // Width Between and 400 and 500
9273
    if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400),  ImVec2(-1, FLT_MAX));      // Height at least 400
9274
    if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0),     ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::AspectRatio, (void*)&aspect_ratio);   // Aspect ratio
9275
    if (type == 7) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0),     ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square);                              // Always Square
9276
    if (type == 8) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0),     ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)&fixed_step);            // Fixed Step
9277
9278
    // Submit window
9279
    if (!window_padding)
9280
        ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
9281
    const ImGuiWindowFlags window_flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0;
9282
    const bool window_open = ImGui::Begin("Example: Constrained Resize", p_open, window_flags);
9283
    if (!window_padding)
9284
        ImGui::PopStyleVar();
9285
    if (window_open)
9286
    {
9287
        IMGUI_DEMO_MARKER("Examples/Constrained Resizing window");
9288
        if (ImGui::GetIO().KeyShift)
9289
        {
9290
            // Display a dummy viewport (in your real app you would likely use ImageButton() to display a texture.
9291
            ImVec2 avail_size = ImGui::GetContentRegionAvail();
9292
            ImVec2 pos = ImGui::GetCursorScreenPos();
9293
            ImGui::ColorButton("viewport", ImVec4(0.5f, 0.2f, 0.5f, 1.0f), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop, avail_size);
9294
            ImGui::SetCursorScreenPos(ImVec2(pos.x + 10, pos.y + 10));
9295
            ImGui::Text("%.2f x %.2f", avail_size.x, avail_size.y);
9296
        }
9297
        else
9298
        {
9299
            ImGui::Text("(Hold SHIFT to display a dummy viewport)");
9300
            if (ImGui::IsWindowDocked())
9301
                ImGui::Text("Warning: Sizing Constraints won't work if the window is docked!");
9302
            if (ImGui::Button("Set 200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine();
9303
            if (ImGui::Button("Set 500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine();
9304
            if (ImGui::Button("Set 800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); }
9305
            ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20);
9306
            ImGui::Combo("Constraint", &type, test_desc, IM_ARRAYSIZE(test_desc));
9307
            ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20);
9308
            ImGui::DragInt("Lines", &display_lines, 0.2f, 1, 100);
9309
            ImGui::Checkbox("Auto-resize", &auto_resize);
9310
            ImGui::Checkbox("Window padding", &window_padding);
9311
            for (int i = 0; i < display_lines; i++)
9312
                ImGui::Text("%*sHello, sailor! Making this line long enough for the example.", i * 4, "");
9313
        }
9314
    }
9315
    ImGui::End();
9316
}
9317
9318
//-----------------------------------------------------------------------------
9319
// [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay()
9320
//-----------------------------------------------------------------------------
9321
9322
// Demonstrate creating a simple static window with no decoration
9323
// + a context-menu to choose which corner of the screen to use.
9324
static void ShowExampleAppSimpleOverlay(bool* p_open)
9325
{
9326
    static int location = 0;
9327
    ImGuiIO& io = ImGui::GetIO();
9328
    ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav;
9329
    if (location >= 0)
9330
    {
9331
        const float PAD = 10.0f;
9332
        const ImGuiViewport* viewport = ImGui::GetMainViewport();
9333
        ImVec2 work_pos = viewport->WorkPos; // Use work area to avoid menu-bar/task-bar, if any!
9334
        ImVec2 work_size = viewport->WorkSize;
9335
        ImVec2 window_pos, window_pos_pivot;
9336
        window_pos.x = (location & 1) ? (work_pos.x + work_size.x - PAD) : (work_pos.x + PAD);
9337
        window_pos.y = (location & 2) ? (work_pos.y + work_size.y - PAD) : (work_pos.y + PAD);
9338
        window_pos_pivot.x = (location & 1) ? 1.0f : 0.0f;
9339
        window_pos_pivot.y = (location & 2) ? 1.0f : 0.0f;
9340
        ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot);
9341
        ImGui::SetNextWindowViewport(viewport->ID);
9342
        window_flags |= ImGuiWindowFlags_NoMove;
9343
    }
9344
    else if (location == -2)
9345
    {
9346
        // Center window
9347
        ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Always, ImVec2(0.5f, 0.5f));
9348
        window_flags |= ImGuiWindowFlags_NoMove;
9349
    }
9350
    ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background
9351
    if (ImGui::Begin("Example: Simple overlay", p_open, window_flags))
9352
    {
9353
        IMGUI_DEMO_MARKER("Examples/Simple Overlay");
9354
        ImGui::Text("Simple overlay\n" "(right-click to change position)");
9355
        ImGui::Separator();
9356
        if (ImGui::IsMousePosValid())
9357
            ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y);
9358
        else
9359
            ImGui::Text("Mouse Position: <invalid>");
9360
        if (ImGui::BeginPopupContextWindow())
9361
        {
9362
            if (ImGui::MenuItem("Custom",       NULL, location == -1)) location = -1;
9363
            if (ImGui::MenuItem("Center",       NULL, location == -2)) location = -2;
9364
            if (ImGui::MenuItem("Top-left",     NULL, location == 0)) location = 0;
9365
            if (ImGui::MenuItem("Top-right",    NULL, location == 1)) location = 1;
9366
            if (ImGui::MenuItem("Bottom-left",  NULL, location == 2)) location = 2;
9367
            if (ImGui::MenuItem("Bottom-right", NULL, location == 3)) location = 3;
9368
            if (p_open && ImGui::MenuItem("Close")) *p_open = false;
9369
            ImGui::EndPopup();
9370
        }
9371
    }
9372
    ImGui::End();
9373
}
9374
9375
//-----------------------------------------------------------------------------
9376
// [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen()
9377
//-----------------------------------------------------------------------------
9378
9379
// Demonstrate creating a window covering the entire screen/viewport
9380
static void ShowExampleAppFullscreen(bool* p_open)
9381
{
9382
    static bool use_work_area = true;
9383
    static ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings;
9384
9385
    // We demonstrate using the full viewport area or the work area (without menu-bars, task-bars etc.)
9386
    // Based on your use case you may want one or the other.
9387
    const ImGuiViewport* viewport = ImGui::GetMainViewport();
9388
    ImGui::SetNextWindowPos(use_work_area ? viewport->WorkPos : viewport->Pos);
9389
    ImGui::SetNextWindowSize(use_work_area ? viewport->WorkSize : viewport->Size);
9390
9391
    if (ImGui::Begin("Example: Fullscreen window", p_open, flags))
9392
    {
9393
        ImGui::Checkbox("Use work area instead of main area", &use_work_area);
9394
        ImGui::SameLine();
9395
        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.");
9396
9397
        ImGui::CheckboxFlags("ImGuiWindowFlags_NoBackground", &flags, ImGuiWindowFlags_NoBackground);
9398
        ImGui::CheckboxFlags("ImGuiWindowFlags_NoDecoration", &flags, ImGuiWindowFlags_NoDecoration);
9399
        ImGui::Indent();
9400
        ImGui::CheckboxFlags("ImGuiWindowFlags_NoTitleBar", &flags, ImGuiWindowFlags_NoTitleBar);
9401
        ImGui::CheckboxFlags("ImGuiWindowFlags_NoCollapse", &flags, ImGuiWindowFlags_NoCollapse);
9402
        ImGui::CheckboxFlags("ImGuiWindowFlags_NoScrollbar", &flags, ImGuiWindowFlags_NoScrollbar);
9403
        ImGui::Unindent();
9404
9405
        if (p_open && ImGui::Button("Close this window"))
9406
            *p_open = false;
9407
    }
9408
    ImGui::End();
9409
}
9410
9411
//-----------------------------------------------------------------------------
9412
// [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles()
9413
//-----------------------------------------------------------------------------
9414
9415
// Demonstrate the use of "##" and "###" in identifiers to manipulate ID generation.
9416
// This applies to all regular items as well.
9417
// Read FAQ section "How can I have multiple widgets with the same label?" for details.
9418
static void ShowExampleAppWindowTitles(bool*)
9419
{
9420
    const ImGuiViewport* viewport = ImGui::GetMainViewport();
9421
    const ImVec2 base_pos = viewport->Pos;
9422
9423
    // By default, Windows are uniquely identified by their title.
9424
    // You can use the "##" and "###" markers to manipulate the display/ID.
9425
9426
    // Using "##" to display same title but have unique identifier.
9427
    ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 100), ImGuiCond_FirstUseEver);
9428
    ImGui::Begin("Same title as another window##1");
9429
    IMGUI_DEMO_MARKER("Examples/Manipulating window titles");
9430
    ImGui::Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique.");
9431
    ImGui::End();
9432
9433
    ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 200), ImGuiCond_FirstUseEver);
9434
    ImGui::Begin("Same title as another window##2");
9435
    ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique.");
9436
    ImGui::End();
9437
9438
    // Using "###" to display a changing title but keep a static identifier "AnimatedTitle"
9439
    char buf[128];
9440
    sprintf(buf, "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime() / 0.25f) & 3], ImGui::GetFrameCount());
9441
    ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 300), ImGuiCond_FirstUseEver);
9442
    ImGui::Begin(buf);
9443
    ImGui::Text("This window has a changing title.");
9444
    ImGui::End();
9445
}
9446
9447
//-----------------------------------------------------------------------------
9448
// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering()
9449
//-----------------------------------------------------------------------------
9450
9451
// Add a |_| looking shape
9452
static void PathConcaveShape(ImDrawList* draw_list, float x, float y, float sz)
9453
{
9454
    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 } };
9455
    for (const ImVec2& p : pos_norms)
9456
        draw_list->PathLineTo(ImVec2(x + 0.5f + (int)(sz * p.x), y + 0.5f + (int)(sz * p.y)));
9457
}
9458
9459
// Demonstrate using the low-level ImDrawList to draw custom shapes.
9460
static void ShowExampleAppCustomRendering(bool* p_open)
9461
{
9462
    if (!ImGui::Begin("Example: Custom rendering", p_open))
9463
    {
9464
        ImGui::End();
9465
        return;
9466
    }
9467
    IMGUI_DEMO_MARKER("Examples/Custom Rendering");
9468
9469
    // Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of
9470
    // overloaded operators, etc. Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your
9471
    // types and ImVec2/ImVec4. Dear ImGui defines overloaded operators but they are internal to imgui.cpp and not
9472
    // exposed outside (to avoid messing with your types) In this example we are not using the maths operators!
9473
9474
    if (ImGui::BeginTabBar("##TabBar"))
9475
    {
9476
        if (ImGui::BeginTabItem("Primitives"))
9477
        {
9478
            ImGui::PushItemWidth(-ImGui::GetFontSize() * 15);
9479
            ImDrawList* draw_list = ImGui::GetWindowDrawList();
9480
9481
            // Draw gradients
9482
            // (note that those are currently exacerbating our sRGB/Linear issues)
9483
            // Calling ImGui::GetColorU32() multiplies the given colors by the current Style Alpha, but you may pass the IM_COL32() directly as well..
9484
            ImGui::Text("Gradients");
9485
            ImVec2 gradient_size = ImVec2(ImGui::CalcItemWidth(), ImGui::GetFrameHeight());
9486
            {
9487
                ImVec2 p0 = ImGui::GetCursorScreenPos();
9488
                ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y);
9489
                ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 0, 0, 255));
9490
                ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 255, 255, 255));
9491
                draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a);
9492
                ImGui::InvisibleButton("##gradient1", gradient_size);
9493
            }
9494
            {
9495
                ImVec2 p0 = ImGui::GetCursorScreenPos();
9496
                ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y);
9497
                ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 255, 0, 255));
9498
                ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 0, 0, 255));
9499
                draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a);
9500
                ImGui::InvisibleButton("##gradient2", gradient_size);
9501
            }
9502
9503
            // Draw a bunch of primitives
9504
            ImGui::Text("All primitives");
9505
            static float sz = 36.0f;
9506
            static float thickness = 3.0f;
9507
            static int ngon_sides = 6;
9508
            static bool circle_segments_override = false;
9509
            static int circle_segments_override_v = 12;
9510
            static bool curve_segments_override = false;
9511
            static int curve_segments_override_v = 8;
9512
            static ImVec4 colf = ImVec4(1.0f, 1.0f, 0.4f, 1.0f);
9513
            ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 100.0f, "%.0f");
9514
            ImGui::DragFloat("Thickness", &thickness, 0.05f, 1.0f, 8.0f, "%.02f");
9515
            ImGui::SliderInt("N-gon sides", &ngon_sides, 3, 12);
9516
            ImGui::Checkbox("##circlesegmentoverride", &circle_segments_override);
9517
            ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
9518
            circle_segments_override |= ImGui::SliderInt("Circle segments override", &circle_segments_override_v, 3, 40);
9519
            ImGui::Checkbox("##curvessegmentoverride", &curve_segments_override);
9520
            ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
9521
            curve_segments_override |= ImGui::SliderInt("Curves segments override", &curve_segments_override_v, 3, 40);
9522
            ImGui::ColorEdit4("Color", &colf.x);
9523
9524
            const ImVec2 p = ImGui::GetCursorScreenPos();
9525
            const ImU32 col = ImColor(colf);
9526
            const float spacing = 10.0f;
9527
            const ImDrawFlags corners_tl_br = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersBottomRight;
9528
            const float rounding = sz / 5.0f;
9529
            const int circle_segments = circle_segments_override ? circle_segments_override_v : 0;
9530
            const int curve_segments = curve_segments_override ? curve_segments_override_v : 0;
9531
            const ImVec2 cp3[3] = { ImVec2(0.0f, sz * 0.6f), ImVec2(sz * 0.5f, -sz * 0.4f), ImVec2(sz, sz) }; // Control points for curves
9532
            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) };
9533
9534
            float x = p.x + 4.0f;
9535
            float y = p.y + 4.0f;
9536
            for (int n = 0; n < 2; n++)
9537
            {
9538
                // First line uses a thickness of 1.0f, second line uses the configurable thickness
9539
                float th = (n == 0) ? 1.0f : thickness;
9540
                draw_list->AddNgon(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, ngon_sides, th);                 x += sz + spacing;  // N-gon
9541
                draw_list->AddCircle(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments, th);          x += sz + spacing;  // Circle
9542
                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
9543
                draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0f, ImDrawFlags_None, th);          x += sz + spacing;  // Square
9544
                draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, ImDrawFlags_None, th);      x += sz + spacing;  // Square with all rounded corners
9545
                draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, corners_tl_br, th);         x += sz + spacing;  // Square with two rounded corners
9546
                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
9547
                //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
9548
                PathConcaveShape(draw_list, x, y, sz); draw_list->PathStroke(col, ImDrawFlags_Closed, th);          x += sz + spacing;  // Concave Shape
9549
                //draw_list->AddPolyline(concave_shape, IM_ARRAYSIZE(concave_shape), col, ImDrawFlags_Closed, th);
9550
                draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y), col, th);                                       x += sz + spacing;  // Horizontal line (note: drawing a filled rectangle will be faster!)
9551
                draw_list->AddLine(ImVec2(x, y), ImVec2(x, y + sz), col, th);                                       x += spacing;       // Vertical line (note: drawing a filled rectangle will be faster!)
9552
                draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y + sz), col, th);                                  x += sz + spacing;  // Diagonal line
9553
9554
                // Path
9555
                draw_list->PathArcTo(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, 3.141592f, 3.141592f * -0.5f);
9556
                draw_list->PathStroke(col, ImDrawFlags_None, th);
9557
                x += sz + spacing;
9558
9559
                // Quadratic Bezier Curve (3 control points)
9560
                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);
9561
                x += sz + spacing;
9562
9563
                // Cubic Bezier Curve (4 control points)
9564
                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);
9565
9566
                x = p.x + 4;
9567
                y += sz + spacing;
9568
            }
9569
9570
            // Filled shapes
9571
            draw_list->AddNgonFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, col, ngon_sides);             x += sz + spacing;  // N-gon
9572
            draw_list->AddCircleFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, col, circle_segments);      x += sz + spacing;  // Circle
9573
            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
9574
            draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col);                                    x += sz + spacing;  // Square
9575
            draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f);                             x += sz + spacing;  // Square with all rounded corners
9576
            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
9577
            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
9578
            //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
9579
            PathConcaveShape(draw_list, x, y, sz); draw_list->PathFillConcave(col);                                 x += sz + spacing;  // Concave shape
9580
            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)
9581
            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)
9582
            draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + 1, y + 1), col);                                      x += sz;            // Pixel (faster than AddLine)
9583
9584
            // Path
9585
            draw_list->PathArcTo(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, 3.141592f * -0.5f, 3.141592f);
9586
            draw_list->PathFillConvex(col);
9587
            x += sz + spacing;
9588
9589
            // Quadratic Bezier Curve (3 control points)
9590
            draw_list->PathLineTo(ImVec2(x + cp3[0].x, y + cp3[0].y));
9591
            draw_list->PathBezierQuadraticCurveTo(ImVec2(x + cp3[1].x, y + cp3[1].y), ImVec2(x + cp3[2].x, y + cp3[2].y), curve_segments);
9592
            draw_list->PathFillConvex(col);
9593
            x += sz + spacing;
9594
9595
            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));
9596
            x += sz + spacing;
9597
9598
            ImGui::Dummy(ImVec2((sz + spacing) * 13.2f, (sz + spacing) * 3.0f));
9599
            ImGui::PopItemWidth();
9600
            ImGui::EndTabItem();
9601
        }
9602
9603
        if (ImGui::BeginTabItem("Canvas"))
9604
        {
9605
            static ImVector<ImVec2> points;
9606
            static ImVec2 scrolling(0.0f, 0.0f);
9607
            static bool opt_enable_grid = true;
9608
            static bool opt_enable_context_menu = true;
9609
            static bool adding_line = false;
9610
9611
            ImGui::Checkbox("Enable grid", &opt_enable_grid);
9612
            ImGui::Checkbox("Enable context menu", &opt_enable_context_menu);
9613
            ImGui::Text("Mouse Left: drag to add lines,\nMouse Right: drag to scroll, click for context menu.");
9614
9615
            // Typically you would use a BeginChild()/EndChild() pair to benefit from a clipping region + own scrolling.
9616
            // Here we demonstrate that this can be replaced by simple offsetting + custom drawing + PushClipRect/PopClipRect() calls.
9617
            // To use a child window instead we could use, e.g:
9618
            //      ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));      // Disable padding
9619
            //      ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(50, 50, 50, 255));  // Set a background color
9620
            //      ImGui::BeginChild("canvas", ImVec2(0.0f, 0.0f), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove);
9621
            //      ImGui::PopStyleColor();
9622
            //      ImGui::PopStyleVar();
9623
            //      [...]
9624
            //      ImGui::EndChild();
9625
9626
            // Using InvisibleButton() as a convenience 1) it will advance the layout cursor and 2) allows us to use IsItemHovered()/IsItemActive()
9627
            ImVec2 canvas_p0 = ImGui::GetCursorScreenPos();      // ImDrawList API uses screen coordinates!
9628
            ImVec2 canvas_sz = ImGui::GetContentRegionAvail();   // Resize canvas to what's available
9629
            if (canvas_sz.x < 50.0f) canvas_sz.x = 50.0f;
9630
            if (canvas_sz.y < 50.0f) canvas_sz.y = 50.0f;
9631
            ImVec2 canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y);
9632
9633
            // Draw border and background color
9634
            ImGuiIO& io = ImGui::GetIO();
9635
            ImDrawList* draw_list = ImGui::GetWindowDrawList();
9636
            draw_list->AddRectFilled(canvas_p0, canvas_p1, IM_COL32(50, 50, 50, 255));
9637
            draw_list->AddRect(canvas_p0, canvas_p1, IM_COL32(255, 255, 255, 255));
9638
9639
            // This will catch our interactions
9640
            ImGui::InvisibleButton("canvas", canvas_sz, ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight);
9641
            const bool is_hovered = ImGui::IsItemHovered(); // Hovered
9642
            const bool is_active = ImGui::IsItemActive();   // Held
9643
            const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y); // Lock scrolled origin
9644
            const ImVec2 mouse_pos_in_canvas(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
9645
9646
            // Add first and second point
9647
            if (is_hovered && !adding_line && ImGui::IsMouseClicked(ImGuiMouseButton_Left))
9648
            {
9649
                points.push_back(mouse_pos_in_canvas);
9650
                points.push_back(mouse_pos_in_canvas);
9651
                adding_line = true;
9652
            }
9653
            if (adding_line)
9654
            {
9655
                points.back() = mouse_pos_in_canvas;
9656
                if (!ImGui::IsMouseDown(ImGuiMouseButton_Left))
9657
                    adding_line = false;
9658
            }
9659
9660
            // Pan (we use a zero mouse threshold when there's no context menu)
9661
            // You may decide to make that threshold dynamic based on whether the mouse is hovering something etc.
9662
            const float mouse_threshold_for_pan = opt_enable_context_menu ? -1.0f : 0.0f;
9663
            if (is_active && ImGui::IsMouseDragging(ImGuiMouseButton_Right, mouse_threshold_for_pan))
9664
            {
9665
                scrolling.x += io.MouseDelta.x;
9666
                scrolling.y += io.MouseDelta.y;
9667
            }
9668
9669
            // Context menu (under default mouse threshold)
9670
            ImVec2 drag_delta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Right);
9671
            if (opt_enable_context_menu && drag_delta.x == 0.0f && drag_delta.y == 0.0f)
9672
                ImGui::OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight);
9673
            if (ImGui::BeginPopup("context"))
9674
            {
9675
                if (adding_line)
9676
                    points.resize(points.size() - 2);
9677
                adding_line = false;
9678
                if (ImGui::MenuItem("Remove one", NULL, false, points.Size > 0)) { points.resize(points.size() - 2); }
9679
                if (ImGui::MenuItem("Remove all", NULL, false, points.Size > 0)) { points.clear(); }
9680
                ImGui::EndPopup();
9681
            }
9682
9683
            // Draw grid + all lines in the canvas
9684
            draw_list->PushClipRect(canvas_p0, canvas_p1, true);
9685
            if (opt_enable_grid)
9686
            {
9687
                const float GRID_STEP = 64.0f;
9688
                for (float x = fmodf(scrolling.x, GRID_STEP); x < canvas_sz.x; x += GRID_STEP)
9689
                    draw_list->AddLine(ImVec2(canvas_p0.x + x, canvas_p0.y), ImVec2(canvas_p0.x + x, canvas_p1.y), IM_COL32(200, 200, 200, 40));
9690
                for (float y = fmodf(scrolling.y, GRID_STEP); y < canvas_sz.y; y += GRID_STEP)
9691
                    draw_list->AddLine(ImVec2(canvas_p0.x, canvas_p0.y + y), ImVec2(canvas_p1.x, canvas_p0.y + y), IM_COL32(200, 200, 200, 40));
9692
            }
9693
            for (int n = 0; n < points.Size; n += 2)
9694
                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);
9695
            draw_list->PopClipRect();
9696
9697
            ImGui::EndTabItem();
9698
        }
9699
9700
        if (ImGui::BeginTabItem("BG/FG draw lists"))
9701
        {
9702
            static bool draw_bg = true;
9703
            static bool draw_fg = true;
9704
            ImGui::Checkbox("Draw in Background draw list", &draw_bg);
9705
            ImGui::SameLine(); HelpMarker("The Background draw list will be rendered below every Dear ImGui windows.");
9706
            ImGui::Checkbox("Draw in Foreground draw list", &draw_fg);
9707
            ImGui::SameLine(); HelpMarker("The Foreground draw list will be rendered over every Dear ImGui windows.");
9708
            ImVec2 window_pos = ImGui::GetWindowPos();
9709
            ImVec2 window_size = ImGui::GetWindowSize();
9710
            ImVec2 window_center = ImVec2(window_pos.x + window_size.x * 0.5f, window_pos.y + window_size.y * 0.5f);
9711
            if (draw_bg)
9712
                ImGui::GetBackgroundDrawList()->AddCircle(window_center, window_size.x * 0.6f, IM_COL32(255, 0, 0, 200), 0, 10 + 4);
9713
            if (draw_fg)
9714
                ImGui::GetForegroundDrawList()->AddCircle(window_center, window_size.y * 0.6f, IM_COL32(0, 255, 0, 200), 0, 10);
9715
            ImGui::EndTabItem();
9716
        }
9717
9718
        // Demonstrate out-of-order rendering via channels splitting
9719
        // We use functions in ImDrawList as each draw list contains a convenience splitter,
9720
        // but you can also instantiate your own ImDrawListSplitter if you need to nest them.
9721
        if (ImGui::BeginTabItem("Draw Channels"))
9722
        {
9723
            ImDrawList* draw_list = ImGui::GetWindowDrawList();
9724
            {
9725
                ImGui::Text("Blue shape is drawn first: appears in back");
9726
                ImGui::Text("Red shape is drawn after: appears in front");
9727
                ImVec2 p0 = ImGui::GetCursorScreenPos();
9728
                draw_list->AddRectFilled(ImVec2(p0.x, p0.y), ImVec2(p0.x + 50, p0.y + 50), IM_COL32(0, 0, 255, 255)); // Blue
9729
                draw_list->AddRectFilled(ImVec2(p0.x + 25, p0.y + 25), ImVec2(p0.x + 75, p0.y + 75), IM_COL32(255, 0, 0, 255)); // Red
9730
                ImGui::Dummy(ImVec2(75, 75));
9731
            }
9732
            ImGui::Separator();
9733
            {
9734
                ImGui::Text("Blue shape is drawn first, into channel 1: appears in front");
9735
                ImGui::Text("Red shape is drawn after, into channel 0: appears in back");
9736
                ImVec2 p1 = ImGui::GetCursorScreenPos();
9737
9738
                // Create 2 channels and draw a Blue shape THEN a Red shape.
9739
                // You can create any number of channels. Tables API use 1 channel per column in order to better batch draw calls.
9740
                draw_list->ChannelsSplit(2);
9741
                draw_list->ChannelsSetCurrent(1);
9742
                draw_list->AddRectFilled(ImVec2(p1.x, p1.y), ImVec2(p1.x + 50, p1.y + 50), IM_COL32(0, 0, 255, 255)); // Blue
9743
                draw_list->ChannelsSetCurrent(0);
9744
                draw_list->AddRectFilled(ImVec2(p1.x + 25, p1.y + 25), ImVec2(p1.x + 75, p1.y + 75), IM_COL32(255, 0, 0, 255)); // Red
9745
9746
                // Flatten/reorder channels. Red shape is in channel 0 and it appears below the Blue shape in channel 1.
9747
                // This works by copying draw indices only (vertices are not copied).
9748
                draw_list->ChannelsMerge();
9749
                ImGui::Dummy(ImVec2(75, 75));
9750
                ImGui::Text("After reordering, contents of channel 0 appears below channel 1.");
9751
            }
9752
            ImGui::EndTabItem();
9753
        }
9754
9755
        ImGui::EndTabBar();
9756
    }
9757
9758
    ImGui::End();
9759
}
9760
9761
//-----------------------------------------------------------------------------
9762
// [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace()
9763
//-----------------------------------------------------------------------------
9764
9765
// Demonstrate using DockSpace() to create an explicit docking node within an existing window.
9766
// Note: You can use most Docking facilities without calling any API. You DO NOT need to call DockSpace() to use Docking!
9767
// - Drag from window title bar or their tab to dock/undock. Hold SHIFT to disable docking.
9768
// - Drag from window menu button (upper-left button) to undock an entire node (all windows).
9769
// - When io.ConfigDockingWithShift == true, you instead need to hold SHIFT to enable docking.
9770
// About dockspaces:
9771
// - Use DockSpace() to create an explicit dock node _within_ an existing window.
9772
// - Use DockSpaceOverViewport() to create an explicit dock node covering the screen or a specific viewport.
9773
//   This is often used with ImGuiDockNodeFlags_PassthruCentralNode.
9774
// - Important: Dockspaces need to be submitted _before_ any window they can host. Submit it early in your frame! (*)
9775
// - Important: Dockspaces need to be kept alive if hidden, otherwise windows docked into it will be undocked.
9776
//   e.g. if you have multiple tabs with a dockspace inside each tab: submit the non-visible dockspaces with ImGuiDockNodeFlags_KeepAliveOnly.
9777
// (*) because of this constraint, the implicit \"Debug\" window can not be docked into an explicit DockSpace() node,
9778
// because that window is submitted as part of the part of the NewFrame() call. An easy workaround is that you can create
9779
// your own implicit "Debug##2" window after calling DockSpace() and leave it in the window stack for anyone to use.
9780
void ShowExampleAppDockSpace(bool* p_open)
9781
{
9782
    // READ THIS !!!
9783
    // TL;DR; this demo is more complicated than what most users you would normally use.
9784
    // If we remove all options we are showcasing, this demo would become:
9785
    //     void ShowExampleAppDockSpace()
9786
    //     {
9787
    //         ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport());
9788
    //     }
9789
    // In most cases you should be able to just call DockSpaceOverViewport() and ignore all the code below!
9790
    // In this specific demo, we are not using DockSpaceOverViewport() because:
9791
    // - (1) we allow the host window to be floating/moveable instead of filling the viewport (when opt_fullscreen == false)
9792
    // - (2) we allow the host window to have padding (when opt_padding == true)
9793
    // - (3) we expose many flags and need a way to have them visible.
9794
    // - (4) we have a local menu bar in the host window (vs. you could use BeginMainMenuBar() + DockSpaceOverViewport()
9795
    //      in your code, but we don't here because we allow the window to be floating)
9796
9797
    static bool opt_fullscreen = true;
9798
    static bool opt_padding = false;
9799
    static ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_None;
9800
9801
    // We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into,
9802
    // because it would be confusing to have two docking targets within each others.
9803
    ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking;
9804
    if (opt_fullscreen)
9805
    {
9806
        const ImGuiViewport* viewport = ImGui::GetMainViewport();
9807
        ImGui::SetNextWindowPos(viewport->WorkPos);
9808
        ImGui::SetNextWindowSize(viewport->WorkSize);
9809
        ImGui::SetNextWindowViewport(viewport->ID);
9810
        ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
9811
        ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
9812
        window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
9813
        window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
9814
    }
9815
    else
9816
    {
9817
        dockspace_flags &= ~ImGuiDockNodeFlags_PassthruCentralNode;
9818
    }
9819
9820
    // When using ImGuiDockNodeFlags_PassthruCentralNode, DockSpace() will render our background
9821
    // and handle the pass-thru hole, so we ask Begin() to not render a background.
9822
    if (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode)
9823
        window_flags |= ImGuiWindowFlags_NoBackground;
9824
9825
    // Important: note that we proceed even if Begin() returns false (aka window is collapsed).
9826
    // This is because we want to keep our DockSpace() active. If a DockSpace() is inactive,
9827
    // all active windows docked into it will lose their parent and become undocked.
9828
    // We cannot preserve the docking relationship between an active window and an inactive docking, otherwise
9829
    // any change of dockspace/settings would lead to windows being stuck in limbo and never being visible.
9830
    if (!opt_padding)
9831
        ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
9832
    ImGui::Begin("DockSpace Demo", p_open, window_flags);
9833
    if (!opt_padding)
9834
        ImGui::PopStyleVar();
9835
9836
    if (opt_fullscreen)
9837
        ImGui::PopStyleVar(2);
9838
9839
    // Submit the DockSpace
9840
    ImGuiIO& io = ImGui::GetIO();
9841
    if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
9842
    {
9843
        ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
9844
        ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
9845
    }
9846
    else
9847
    {
9848
        ShowDockingDisabledMessage();
9849
    }
9850
9851
    if (ImGui::BeginMenuBar())
9852
    {
9853
        if (ImGui::BeginMenu("Options"))
9854
        {
9855
            // Disabling fullscreen would allow the window to be moved to the front of other windows,
9856
            // which we can't undo at the moment without finer window depth/z control.
9857
            ImGui::MenuItem("Fullscreen", NULL, &opt_fullscreen);
9858
            ImGui::MenuItem("Padding", NULL, &opt_padding);
9859
            ImGui::Separator();
9860
9861
            if (ImGui::MenuItem("Flag: NoDockingOverCentralNode", "", (dockspace_flags & ImGuiDockNodeFlags_NoDockingOverCentralNode) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoDockingOverCentralNode; }
9862
            if (ImGui::MenuItem("Flag: NoDockingSplit",         "", (dockspace_flags & ImGuiDockNodeFlags_NoDockingSplit) != 0))             { dockspace_flags ^= ImGuiDockNodeFlags_NoDockingSplit; }
9863
            if (ImGui::MenuItem("Flag: NoUndocking",            "", (dockspace_flags & ImGuiDockNodeFlags_NoUndocking) != 0))                { dockspace_flags ^= ImGuiDockNodeFlags_NoUndocking; }
9864
            if (ImGui::MenuItem("Flag: NoResize",               "", (dockspace_flags & ImGuiDockNodeFlags_NoResize) != 0))                   { dockspace_flags ^= ImGuiDockNodeFlags_NoResize; }
9865
            if (ImGui::MenuItem("Flag: AutoHideTabBar",         "", (dockspace_flags & ImGuiDockNodeFlags_AutoHideTabBar) != 0))             { dockspace_flags ^= ImGuiDockNodeFlags_AutoHideTabBar; }
9866
            if (ImGui::MenuItem("Flag: PassthruCentralNode",    "", (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode) != 0, opt_fullscreen)) { dockspace_flags ^= ImGuiDockNodeFlags_PassthruCentralNode; }
9867
            ImGui::Separator();
9868
9869
            if (ImGui::MenuItem("Close", NULL, false, p_open != NULL))
9870
                *p_open = false;
9871
            ImGui::EndMenu();
9872
        }
9873
        HelpMarker(
9874
            "When docking is enabled, you can ALWAYS dock MOST window into another! Try it now!" "\n"
9875
            "- Drag from window title bar or their tab to dock/undock." "\n"
9876
            "- Drag from window menu button (upper-left button) to undock an entire node (all windows)." "\n"
9877
            "- Hold SHIFT to disable docking (if io.ConfigDockingWithShift == false, default)" "\n"
9878
            "- Hold SHIFT to enable docking (if io.ConfigDockingWithShift == true)" "\n"
9879
            "This demo app has nothing to do with enabling docking!" "\n\n"
9880
            "This demo app only demonstrate the use of ImGui::DockSpace() which allows you to manually create a docking node _within_ another window." "\n\n"
9881
            "Read comments in ShowExampleAppDockSpace() for more details.");
9882
9883
        ImGui::EndMenuBar();
9884
    }
9885
9886
    ImGui::End();
9887
}
9888
9889
//-----------------------------------------------------------------------------
9890
// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
9891
//-----------------------------------------------------------------------------
9892
9893
// Simplified structure to mimic a Document model
9894
struct MyDocument
9895
{
9896
    char        Name[32];   // Document title
9897
    int         UID;        // Unique ID (necessary as we can change title)
9898
    bool        Open;       // Set when open (we keep an array of all available documents to simplify demo code!)
9899
    bool        OpenPrev;   // Copy of Open from last update.
9900
    bool        Dirty;      // Set when the document has been modified
9901
    ImVec4      Color;      // An arbitrary variable associated to the document
9902
9903
    MyDocument(int uid, const char* name, bool open = true, const ImVec4& color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f))
9904
    {
9905
        UID = uid;
9906
        snprintf(Name, sizeof(Name), "%s", name);
9907
        Open = OpenPrev = open;
9908
        Dirty = false;
9909
        Color = color;
9910
    }
9911
    void DoOpen()       { Open = true; }
9912
    void DoForceClose() { Open = false; Dirty = false; }
9913
    void DoSave()       { Dirty = false; }
9914
};
9915
9916
struct ExampleAppDocuments
9917
{
9918
    ImVector<MyDocument>    Documents;
9919
    ImVector<MyDocument*>   CloseQueue;
9920
    MyDocument*             RenamingDoc = NULL;
9921
    bool                    RenamingStarted = false;
9922
9923
    ExampleAppDocuments()
9924
    {
9925
        Documents.push_back(MyDocument(0, "Lettuce",             true,  ImVec4(0.4f, 0.8f, 0.4f, 1.0f)));
9926
        Documents.push_back(MyDocument(1, "Eggplant",            true,  ImVec4(0.8f, 0.5f, 1.0f, 1.0f)));
9927
        Documents.push_back(MyDocument(2, "Carrot",              true,  ImVec4(1.0f, 0.8f, 0.5f, 1.0f)));
9928
        Documents.push_back(MyDocument(3, "Tomato",              false, ImVec4(1.0f, 0.3f, 0.4f, 1.0f)));
9929
        Documents.push_back(MyDocument(4, "A Rather Long Title", false, ImVec4(0.4f, 0.8f, 0.8f, 1.0f)));
9930
        Documents.push_back(MyDocument(5, "Some Document",       false, ImVec4(0.8f, 0.8f, 1.0f, 1.0f)));
9931
    }
9932
9933
    // As we allow to change document name, we append a never-changing document ID so tabs are stable
9934
    void GetTabName(MyDocument* doc, char* out_buf, size_t out_buf_size)
9935
    {
9936
        snprintf(out_buf, out_buf_size, "%s###doc%d", doc->Name, doc->UID);
9937
    }
9938
9939
    // Display placeholder contents for the Document
9940
    void DisplayDocContents(MyDocument* doc)
9941
    {
9942
        ImGui::PushID(doc);
9943
        ImGui::Text("Document \"%s\"", doc->Name);
9944
        ImGui::PushStyleColor(ImGuiCol_Text, doc->Color);
9945
        ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.");
9946
        ImGui::PopStyleColor();
9947
9948
        ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_R, ImGuiInputFlags_Tooltip);
9949
        if (ImGui::Button("Rename.."))
9950
        {
9951
            RenamingDoc = doc;
9952
            RenamingStarted = true;
9953
        }
9954
        ImGui::SameLine();
9955
9956
        ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_M, ImGuiInputFlags_Tooltip);
9957
        if (ImGui::Button("Modify"))
9958
            doc->Dirty = true;
9959
9960
        ImGui::SameLine();
9961
        ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_S, ImGuiInputFlags_Tooltip);
9962
        if (ImGui::Button("Save"))
9963
            doc->DoSave();
9964
9965
        ImGui::SameLine();
9966
        ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_W, ImGuiInputFlags_Tooltip);
9967
        if (ImGui::Button("Close"))
9968
            CloseQueue.push_back(doc);
9969
        ImGui::ColorEdit3("color", &doc->Color.x);  // Useful to test drag and drop and hold-dragged-to-open-tab behavior.
9970
        ImGui::PopID();
9971
    }
9972
9973
    // Display context menu for the Document
9974
    void DisplayDocContextMenu(MyDocument* doc)
9975
    {
9976
        if (!ImGui::BeginPopupContextItem())
9977
            return;
9978
9979
        char buf[256];
9980
        sprintf(buf, "Save %s", doc->Name);
9981
        if (ImGui::MenuItem(buf, "Ctrl+S", false, doc->Open))
9982
            doc->DoSave();
9983
        if (ImGui::MenuItem("Rename...", "Ctrl+R", false, doc->Open))
9984
            RenamingDoc = doc;
9985
        if (ImGui::MenuItem("Close", "Ctrl+W", false, doc->Open))
9986
            CloseQueue.push_back(doc);
9987
        ImGui::EndPopup();
9988
    }
9989
9990
    // [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface.
9991
    // If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo,
9992
    // as opposed to clicking on the regular tab closing button) and stops being submitted, it will take a frame for
9993
    // 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
9994
    // disappeared was the selected one, the tab bar will report no selected tab during the frame. This will effectively
9995
    // give the impression of a flicker for one frame.
9996
    // We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch.
9997
    // Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag.
9998
    void NotifyOfDocumentsClosedElsewhere()
9999
    {
10000
        for (MyDocument& doc : Documents)
10001
        {
10002
            if (!doc.Open && doc.OpenPrev)
10003
                ImGui::SetTabItemClosed(doc.Name);
10004
            doc.OpenPrev = doc.Open;
10005
        }
10006
    }
10007
};
10008
10009
void ShowExampleAppDocuments(bool* p_open)
10010
{
10011
    static ExampleAppDocuments app;
10012
10013
    // Options
10014
    enum Target
10015
    {
10016
        Target_None,
10017
        Target_Tab,                 // Create documents as local tab into a local tab bar
10018
        Target_DockSpaceAndWindow   // Create documents as regular windows, and create an embedded dockspace
10019
    };
10020
    static Target opt_target = Target_Tab;
10021
    static bool opt_reorderable = true;
10022
    static ImGuiTabBarFlags opt_fitting_flags = ImGuiTabBarFlags_FittingPolicyDefault_;
10023
10024
    // When (opt_target == Target_DockSpaceAndWindow) there is the possibily that one of our child Document window (e.g. "Eggplant")
10025
    // that we emit gets docked into the same spot as the parent window ("Example: Documents").
10026
    // This would create a problematic feedback loop because selecting the "Eggplant" tab would make the "Example: Documents" tab
10027
    // not visible, which in turn would stop submitting the "Eggplant" window.
10028
    // We avoid this problem by submitting our documents window even if our parent window is not currently visible.
10029
    // Another solution may be to make the "Example: Documents" window use the ImGuiWindowFlags_NoDocking.
10030
10031
    bool window_contents_visible = ImGui::Begin("Example: Documents", p_open, ImGuiWindowFlags_MenuBar);
10032
    if (!window_contents_visible && opt_target != Target_DockSpaceAndWindow)
10033
    {
10034
        ImGui::End();
10035
        return;
10036
    }
10037
10038
    // Menu
10039
    if (ImGui::BeginMenuBar())
10040
    {
10041
        if (ImGui::BeginMenu("File"))
10042
        {
10043
            int open_count = 0;
10044
            for (MyDocument& doc : app.Documents)
10045
                open_count += doc.Open ? 1 : 0;
10046
10047
            if (ImGui::BeginMenu("Open", open_count < app.Documents.Size))
10048
            {
10049
                for (MyDocument& doc : app.Documents)
10050
                    if (!doc.Open && ImGui::MenuItem(doc.Name))
10051
                        doc.DoOpen();
10052
                ImGui::EndMenu();
10053
            }
10054
            if (ImGui::MenuItem("Close All Documents", NULL, false, open_count > 0))
10055
                for (MyDocument& doc : app.Documents)
10056
                    app.CloseQueue.push_back(&doc);
10057
            if (ImGui::MenuItem("Exit") && p_open)
10058
                *p_open = false;
10059
            ImGui::EndMenu();
10060
        }
10061
        ImGui::EndMenuBar();
10062
    }
10063
10064
    // [Debug] List documents with one checkbox for each
10065
    for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
10066
    {
10067
        MyDocument& doc = app.Documents[doc_n];
10068
        if (doc_n > 0)
10069
            ImGui::SameLine();
10070
        ImGui::PushID(&doc);
10071
        if (ImGui::Checkbox(doc.Name, &doc.Open))
10072
            if (!doc.Open)
10073
                doc.DoForceClose();
10074
        ImGui::PopID();
10075
    }
10076
    ImGui::PushItemWidth(ImGui::GetFontSize() * 12);
10077
    ImGui::Combo("Output", (int*)&opt_target, "None\0TabBar+Tabs\0DockSpace+Window\0");
10078
    ImGui::PopItemWidth();
10079
    bool redock_all = false;
10080
    if (opt_target == Target_Tab)                { ImGui::SameLine(); ImGui::Checkbox("Reorderable Tabs", &opt_reorderable); }
10081
    if (opt_target == Target_DockSpaceAndWindow) { ImGui::SameLine(); redock_all = ImGui::Button("Redock all"); }
10082
10083
    ImGui::Separator();
10084
10085
    // About the ImGuiWindowFlags_UnsavedDocument / ImGuiTabItemFlags_UnsavedDocument flags.
10086
    // They have multiple effects:
10087
    // - Display a dot next to the title.
10088
    // - Tab is selected when clicking the X close button.
10089
    // - Closure is not assumed (will wait for user to stop submitting the tab).
10090
    //   Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar.
10091
    //   We need to assume closure by default otherwise waiting for "lack of submission" on the next frame would leave an empty
10092
    //   hole for one-frame, both in the tab-bar and in tab-contents when closing a tab/window.
10093
    //   The rarely used SetTabItemClosed() function is a way to notify of programmatic closure to avoid the one-frame hole.
10094
10095
    // Tabs
10096
    if (opt_target == Target_Tab)
10097
    {
10098
        ImGuiTabBarFlags tab_bar_flags = (opt_fitting_flags) | (opt_reorderable ? ImGuiTabBarFlags_Reorderable : 0);
10099
        tab_bar_flags |= ImGuiTabBarFlags_DrawSelectedOverline;
10100
        if (ImGui::BeginTabBar("##tabs", tab_bar_flags))
10101
        {
10102
            if (opt_reorderable)
10103
                app.NotifyOfDocumentsClosedElsewhere();
10104
10105
            // [DEBUG] Stress tests
10106
            //if ((ImGui::GetFrameCount() % 30) == 0) docs[1].Open ^= 1;            // [DEBUG] Automatically show/hide a tab. Test various interactions e.g. dragging with this on.
10107
            //if (ImGui::GetIO().KeyCtrl) ImGui::SetTabItemSelected(docs[1].Name);  // [DEBUG] Test SetTabItemSelected(), probably not very useful as-is anyway..
10108
10109
            // Submit Tabs
10110
            for (MyDocument& doc : app.Documents)
10111
            {
10112
                if (!doc.Open)
10113
                    continue;
10114
10115
                // As we allow to change document name, we append a never-changing document id so tabs are stable
10116
                char doc_name_buf[64];
10117
                app.GetTabName(&doc, doc_name_buf, sizeof(doc_name_buf));
10118
                ImGuiTabItemFlags tab_flags = (doc.Dirty ? ImGuiTabItemFlags_UnsavedDocument : 0);
10119
                bool visible = ImGui::BeginTabItem(doc_name_buf, &doc.Open, tab_flags);
10120
10121
                // Cancel attempt to close when unsaved add to save queue so we can display a popup.
10122
                if (!doc.Open && doc.Dirty)
10123
                {
10124
                    doc.Open = true;
10125
                    app.CloseQueue.push_back(&doc);
10126
                }
10127
10128
                app.DisplayDocContextMenu(&doc);
10129
                if (visible)
10130
                {
10131
                    app.DisplayDocContents(&doc);
10132
                    ImGui::EndTabItem();
10133
                }
10134
            }
10135
10136
            ImGui::EndTabBar();
10137
        }
10138
    }
10139
    else if (opt_target == Target_DockSpaceAndWindow)
10140
    {
10141
        if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_DockingEnable)
10142
        {
10143
            app.NotifyOfDocumentsClosedElsewhere();
10144
10145
            // Create a DockSpace node where any window can be docked
10146
            ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
10147
            ImGui::DockSpace(dockspace_id);
10148
10149
            // Create Windows
10150
            for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
10151
            {
10152
                MyDocument* doc = &app.Documents[doc_n];
10153
                if (!doc->Open)
10154
                    continue;
10155
10156
                ImGui::SetNextWindowDockID(dockspace_id, redock_all ? ImGuiCond_Always : ImGuiCond_FirstUseEver);
10157
                ImGuiWindowFlags window_flags = (doc->Dirty ? ImGuiWindowFlags_UnsavedDocument : 0);
10158
                bool visible = ImGui::Begin(doc->Name, &doc->Open, window_flags);
10159
10160
                // Cancel attempt to close when unsaved add to save queue so we can display a popup.
10161
                if (!doc->Open && doc->Dirty)
10162
                {
10163
                    doc->Open = true;
10164
                    app.CloseQueue.push_back(doc);
10165
                }
10166
10167
                app.DisplayDocContextMenu(doc);
10168
                if (visible)
10169
                    app.DisplayDocContents(doc);
10170
10171
                ImGui::End();
10172
            }
10173
        }
10174
        else
10175
        {
10176
            ShowDockingDisabledMessage();
10177
        }
10178
    }
10179
10180
    // Early out other contents
10181
    if (!window_contents_visible)
10182
    {
10183
        ImGui::End();
10184
        return;
10185
    }
10186
10187
    // Display renaming UI
10188
    if (app.RenamingDoc != NULL)
10189
    {
10190
        if (app.RenamingStarted)
10191
            ImGui::OpenPopup("Rename");
10192
        if (ImGui::BeginPopup("Rename"))
10193
        {
10194
            ImGui::SetNextItemWidth(ImGui::GetFontSize() * 30);
10195
            if (ImGui::InputText("###Name", app.RenamingDoc->Name, IM_ARRAYSIZE(app.RenamingDoc->Name), ImGuiInputTextFlags_EnterReturnsTrue))
10196
            {
10197
                ImGui::CloseCurrentPopup();
10198
                app.RenamingDoc = NULL;
10199
            }
10200
            if (app.RenamingStarted)
10201
                ImGui::SetKeyboardFocusHere(-1);
10202
            ImGui::EndPopup();
10203
        }
10204
        else
10205
        {
10206
            app.RenamingDoc = NULL;
10207
        }
10208
        app.RenamingStarted = false;
10209
    }
10210
10211
    // Display closing confirmation UI
10212
    if (!app.CloseQueue.empty())
10213
    {
10214
        int close_queue_unsaved_documents = 0;
10215
        for (int n = 0; n < app.CloseQueue.Size; n++)
10216
            if (app.CloseQueue[n]->Dirty)
10217
                close_queue_unsaved_documents++;
10218
10219
        if (close_queue_unsaved_documents == 0)
10220
        {
10221
            // Close documents when all are unsaved
10222
            for (int n = 0; n < app.CloseQueue.Size; n++)
10223
                app.CloseQueue[n]->DoForceClose();
10224
            app.CloseQueue.clear();
10225
        }
10226
        else
10227
        {
10228
            if (!ImGui::IsPopupOpen("Save?"))
10229
                ImGui::OpenPopup("Save?");
10230
            if (ImGui::BeginPopupModal("Save?", NULL, ImGuiWindowFlags_AlwaysAutoResize))
10231
            {
10232
                ImGui::Text("Save change to the following items?");
10233
                float item_height = ImGui::GetTextLineHeightWithSpacing();
10234
                if (ImGui::BeginChild(ImGui::GetID("frame"), ImVec2(-FLT_MIN, 6.25f * item_height), ImGuiChildFlags_FrameStyle))
10235
                    for (MyDocument* doc : app.CloseQueue)
10236
                        if (doc->Dirty)
10237
                            ImGui::Text("%s", doc->Name);
10238
                ImGui::EndChild();
10239
10240
                ImVec2 button_size(ImGui::GetFontSize() * 7.0f, 0.0f);
10241
                if (ImGui::Button("Yes", button_size))
10242
                {
10243
                    for (MyDocument* doc : app.CloseQueue)
10244
                    {
10245
                        if (doc->Dirty)
10246
                            doc->DoSave();
10247
                        doc->DoForceClose();
10248
                    }
10249
                    app.CloseQueue.clear();
10250
                    ImGui::CloseCurrentPopup();
10251
                }
10252
                ImGui::SameLine();
10253
                if (ImGui::Button("No", button_size))
10254
                {
10255
                    for (MyDocument* doc : app.CloseQueue)
10256
                        doc->DoForceClose();
10257
                    app.CloseQueue.clear();
10258
                    ImGui::CloseCurrentPopup();
10259
                }
10260
                ImGui::SameLine();
10261
                if (ImGui::Button("Cancel", button_size))
10262
                {
10263
                    app.CloseQueue.clear();
10264
                    ImGui::CloseCurrentPopup();
10265
                }
10266
                ImGui::EndPopup();
10267
            }
10268
        }
10269
    }
10270
10271
    ImGui::End();
10272
}
10273
10274
//-----------------------------------------------------------------------------
10275
// [SECTION] Example App: Assets Browser / ShowExampleAppAssetsBrowser()
10276
//-----------------------------------------------------------------------------
10277
10278
//#include "imgui_internal.h" // NavMoveRequestTryWrapping()
10279
10280
struct ExampleAsset
10281
{
10282
    ImGuiID ID;
10283
    int     Type;
10284
10285
    ExampleAsset(ImGuiID id, int type) { ID = id; Type = type; }
10286
10287
    static const ImGuiTableSortSpecs* s_current_sort_specs;
10288
10289
    static void SortWithSortSpecs(ImGuiTableSortSpecs* sort_specs, ExampleAsset* items, int items_count)
10290
    {
10291
        s_current_sort_specs = sort_specs; // Store in variable accessible by the sort function.
10292
        if (items_count > 1)
10293
            qsort(items, (size_t)items_count, sizeof(items[0]), ExampleAsset::CompareWithSortSpecs);
10294
        s_current_sort_specs = NULL;
10295
    }
10296
10297
    // Compare function to be used by qsort()
10298
    static int IMGUI_CDECL CompareWithSortSpecs(const void* lhs, const void* rhs)
10299
    {
10300
        const ExampleAsset* a = (const ExampleAsset*)lhs;
10301
        const ExampleAsset* b = (const ExampleAsset*)rhs;
10302
        for (int n = 0; n < s_current_sort_specs->SpecsCount; n++)
10303
        {
10304
            const ImGuiTableColumnSortSpecs* sort_spec = &s_current_sort_specs->Specs[n];
10305
            int delta = 0;
10306
            if (sort_spec->ColumnIndex == 0)
10307
                delta = ((int)a->ID - (int)b->ID);
10308
            else if (sort_spec->ColumnIndex == 1)
10309
                delta = (a->Type - b->Type);
10310
            if (delta > 0)
10311
                return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? +1 : -1;
10312
            if (delta < 0)
10313
                return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? -1 : +1;
10314
        }
10315
        return ((int)a->ID - (int)b->ID);
10316
    }
10317
};
10318
const ImGuiTableSortSpecs* ExampleAsset::s_current_sort_specs = NULL;
10319
10320
struct ExampleAssetsBrowser
10321
{
10322
    // Options
10323
    bool            ShowTypeOverlay = true;
10324
    bool            AllowSorting = true;
10325
    bool            AllowDragUnselected = false;
10326
    bool            AllowBoxSelect = true;
10327
    float           IconSize = 32.0f;
10328
    int             IconSpacing = 10;
10329
    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.
10330
    bool            StretchSpacing = true;
10331
10332
    // State
10333
    ImVector<ExampleAsset> Items;               // Our items
10334
    ExampleSelectionWithDeletion Selection;     // Our selection (ImGuiSelectionBasicStorage + helper funcs to handle deletion)
10335
    ImGuiID         NextItemId = 0;             // Unique identifier when creating new items
10336
    bool            RequestDelete = false;      // Deferred deletion request
10337
    bool            RequestSort = false;        // Deferred sort request
10338
    float           ZoomWheelAccum = 0.0f;      // Mouse wheel accumulator to handle smooth wheels better
10339
10340
    // Calculated sizes for layout, output of UpdateLayoutSizes(). Could be locals but our code is simpler this way.
10341
    ImVec2          LayoutItemSize;
10342
    ImVec2          LayoutItemStep;             // == LayoutItemSize + LayoutItemSpacing
10343
    float           LayoutItemSpacing = 0.0f;
10344
    float           LayoutSelectableSpacing = 0.0f;
10345
    float           LayoutOuterPadding = 0.0f;
10346
    int             LayoutColumnCount = 0;
10347
    int             LayoutLineCount = 0;
10348
10349
    // Functions
10350
    ExampleAssetsBrowser()
10351
    {
10352
        AddItems(10000);
10353
    }
10354
    void AddItems(int count)
10355
    {
10356
        if (Items.Size == 0)
10357
            NextItemId = 0;
10358
        Items.reserve(Items.Size + count);
10359
        for (int n = 0; n < count; n++, NextItemId++)
10360
            Items.push_back(ExampleAsset(NextItemId, (NextItemId % 20) < 15 ? 0 : (NextItemId % 20) < 18 ? 1 : 2));
10361
        RequestSort = true;
10362
    }
10363
    void ClearItems()
10364
    {
10365
        Items.clear();
10366
        Selection.Clear();
10367
    }
10368
10369
    // Logic would be written in the main code BeginChild() and outputing to local variables.
10370
    // We extracted it into a function so we can call it easily from multiple places.
10371
    void UpdateLayoutSizes(float avail_width)
10372
    {
10373
        // Layout: when not stretching: allow extending into right-most spacing.
10374
        LayoutItemSpacing = (float)IconSpacing;
10375
        if (StretchSpacing == false)
10376
            avail_width += floorf(LayoutItemSpacing * 0.5f);
10377
10378
        // Layout: calculate number of icon per line and number of lines
10379
        LayoutItemSize = ImVec2(floorf(IconSize), floorf(IconSize));
10380
        LayoutColumnCount = IM_MAX((int)(avail_width / (LayoutItemSize.x + LayoutItemSpacing)), 1);
10381
        LayoutLineCount = (Items.Size + LayoutColumnCount - 1) / LayoutColumnCount;
10382
10383
        // Layout: when stretching: allocate remaining space to more spacing. Round before division, so item_spacing may be non-integer.
10384
        if (StretchSpacing && LayoutColumnCount > 1)
10385
            LayoutItemSpacing = floorf(avail_width - LayoutItemSize.x * LayoutColumnCount) / LayoutColumnCount;
10386
10387
        LayoutItemStep = ImVec2(LayoutItemSize.x + LayoutItemSpacing, LayoutItemSize.y + LayoutItemSpacing);
10388
        LayoutSelectableSpacing = IM_MAX(floorf(LayoutItemSpacing) - IconHitSpacing, 0.0f);
10389
        LayoutOuterPadding = floorf(LayoutItemSpacing * 0.5f);
10390
    }
10391
10392
    void Draw(const char* title, bool* p_open)
10393
    {
10394
        ImGui::SetNextWindowSize(ImVec2(IconSize * 25, IconSize * 15), ImGuiCond_FirstUseEver);
10395
        if (!ImGui::Begin(title, p_open, ImGuiWindowFlags_MenuBar))
10396
        {
10397
            ImGui::End();
10398
            return;
10399
        }
10400
10401
        // Menu bar
10402
        if (ImGui::BeginMenuBar())
10403
        {
10404
            if (ImGui::BeginMenu("File"))
10405
            {
10406
                if (ImGui::MenuItem("Add 10000 items"))
10407
                    AddItems(10000);
10408
                if (ImGui::MenuItem("Clear items"))
10409
                    ClearItems();
10410
                ImGui::Separator();
10411
                if (ImGui::MenuItem("Close", NULL, false, p_open != NULL))
10412
                    *p_open = false;
10413
                ImGui::EndMenu();
10414
            }
10415
            if (ImGui::BeginMenu("Edit"))
10416
            {
10417
                if (ImGui::MenuItem("Delete", "Del", false, Selection.Size > 0))
10418
                    RequestDelete = true;
10419
                ImGui::EndMenu();
10420
            }
10421
            if (ImGui::BeginMenu("Options"))
10422
            {
10423
                ImGui::PushItemWidth(ImGui::GetFontSize() * 10);
10424
10425
                ImGui::SeparatorText("Contents");
10426
                ImGui::Checkbox("Show Type Overlay", &ShowTypeOverlay);
10427
                ImGui::Checkbox("Allow Sorting", &AllowSorting);
10428
10429
                ImGui::SeparatorText("Selection Behavior");
10430
                ImGui::Checkbox("Allow dragging unselected item", &AllowDragUnselected);
10431
                ImGui::Checkbox("Allow box-selection", &AllowBoxSelect);
10432
10433
                ImGui::SeparatorText("Layout");
10434
                ImGui::SliderFloat("Icon Size", &IconSize, 16.0f, 128.0f, "%.0f");
10435
                ImGui::SameLine(); HelpMarker("Use CTRL+Wheel to zoom");
10436
                ImGui::SliderInt("Icon Spacing", &IconSpacing, 0, 32);
10437
                ImGui::SliderInt("Icon Hit Spacing", &IconHitSpacing, 0, 32);
10438
                ImGui::Checkbox("Stretch Spacing", &StretchSpacing);
10439
                ImGui::PopItemWidth();
10440
                ImGui::EndMenu();
10441
            }
10442
            ImGui::EndMenuBar();
10443
        }
10444
10445
        // Show a table with ONLY one header row to showcase the idea/possibility of using this to provide a sorting UI
10446
        if (AllowSorting)
10447
        {
10448
            ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
10449
            ImGuiTableFlags table_flags_for_sort_specs = ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Borders;
10450
            if (ImGui::BeginTable("for_sort_specs_only", 2, table_flags_for_sort_specs, ImVec2(0.0f, ImGui::GetFrameHeight())))
10451
            {
10452
                ImGui::TableSetupColumn("Index");
10453
                ImGui::TableSetupColumn("Type");
10454
                ImGui::TableHeadersRow();
10455
                if (ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs())
10456
                    if (sort_specs->SpecsDirty || RequestSort)
10457
                    {
10458
                        ExampleAsset::SortWithSortSpecs(sort_specs, Items.Data, Items.Size);
10459
                        sort_specs->SpecsDirty = RequestSort = false;
10460
                    }
10461
                ImGui::EndTable();
10462
            }
10463
            ImGui::PopStyleVar();
10464
        }
10465
10466
        ImGuiIO& io = ImGui::GetIO();
10467
        ImGui::SetNextWindowContentSize(ImVec2(0.0f, LayoutOuterPadding + LayoutLineCount * (LayoutItemSize.x + LayoutItemSpacing)));
10468
        if (ImGui::BeginChild("Assets", ImVec2(0.0f, -ImGui::GetTextLineHeightWithSpacing()), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove))
10469
        {
10470
            ImDrawList* draw_list = ImGui::GetWindowDrawList();
10471
10472
            const float avail_width = ImGui::GetContentRegionAvail().x;
10473
            UpdateLayoutSizes(avail_width);
10474
10475
            // Calculate and store start position.
10476
            ImVec2 start_pos = ImGui::GetCursorScreenPos();
10477
            start_pos = ImVec2(start_pos.x + LayoutOuterPadding, start_pos.y + LayoutOuterPadding);
10478
            ImGui::SetCursorScreenPos(start_pos);
10479
10480
            // Multi-select
10481
            ImGuiMultiSelectFlags ms_flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_ClearOnClickVoid;
10482
10483
            // - Enable box-select (in 2D mode, so that changing box-select rectangle X1/X2 boundaries will affect clipped items)
10484
            if (AllowBoxSelect)
10485
                ms_flags |= ImGuiMultiSelectFlags_BoxSelect2d;
10486
10487
            // - This feature allows dragging an unselected item without selecting it (rarely used)
10488
            if (AllowDragUnselected)
10489
                ms_flags |= ImGuiMultiSelectFlags_SelectOnClickRelease;
10490
10491
            // - Enable keyboard wrapping on X axis
10492
            // (FIXME-MULTISELECT: We haven't designed/exposed a general nav wrapping api yet, so this flag is provided as a courtesy to avoid doing:
10493
            //    ImGui::NavMoveRequestTryWrapping(ImGui::GetCurrentWindow(), ImGuiNavMoveFlags_WrapX);
10494
            // When we finish implementing a more general API for this, we will obsolete this flag in favor of the new system)
10495
            ms_flags |= ImGuiMultiSelectFlags_NavWrapX;
10496
10497
            ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(ms_flags, Selection.Size, Items.Size);
10498
10499
            // Use custom selection adapter: store ID in selection (recommended)
10500
            Selection.UserData = this;
10501
            Selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self_, int idx) { ExampleAssetsBrowser* self = (ExampleAssetsBrowser*)self_->UserData; return self->Items[idx].ID; };
10502
            Selection.ApplyRequests(ms_io);
10503
10504
            const bool want_delete = (ImGui::Shortcut(ImGuiKey_Delete, ImGuiInputFlags_Repeat) && (Selection.Size > 0)) || RequestDelete;
10505
            const int item_curr_idx_to_focus = want_delete ? Selection.ApplyDeletionPreLoop(ms_io, Items.Size) : -1;
10506
            RequestDelete = false;
10507
10508
            // Push LayoutSelectableSpacing (which is LayoutItemSpacing minus hit-spacing, if we decide to have hit gaps between items)
10509
            // Altering style ItemSpacing may seem unnecessary as we position every items using SetCursorScreenPos()...
10510
            // But it is necessary for two reasons:
10511
            // - Selectables uses it by default to visually fill the space between two items.
10512
            // - The vertical spacing would be measured by Clipper to calculate line height if we didn't provide it explicitly (here we do).
10513
            ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(LayoutSelectableSpacing, LayoutSelectableSpacing));
10514
10515
            // Rendering parameters
10516
            const ImU32 icon_type_overlay_colors[3] = { 0, IM_COL32(200, 70, 70, 255), IM_COL32(70, 170, 70, 255) };
10517
            const ImU32 icon_bg_color = ImGui::GetColorU32(IM_COL32(35, 35, 35, 220));
10518
            const ImVec2 icon_type_overlay_size = ImVec2(4.0f, 4.0f);
10519
            const bool display_label = (LayoutItemSize.x >= ImGui::CalcTextSize("999").x);
10520
10521
            const int column_count = LayoutColumnCount;
10522
            ImGuiListClipper clipper;
10523
            clipper.Begin(LayoutLineCount, LayoutItemStep.y);
10524
            if (item_curr_idx_to_focus != -1)
10525
                clipper.IncludeItemByIndex(item_curr_idx_to_focus / column_count); // Ensure focused item line is not clipped.
10526
            if (ms_io->RangeSrcItem != -1)
10527
                clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem / column_count); // Ensure RangeSrc item line is not clipped.
10528
            while (clipper.Step())
10529
            {
10530
                for (int line_idx = clipper.DisplayStart; line_idx < clipper.DisplayEnd; line_idx++)
10531
                {
10532
                    const int item_min_idx_for_current_line = line_idx * column_count;
10533
                    const int item_max_idx_for_current_line = IM_MIN((line_idx + 1) * column_count, Items.Size);
10534
                    for (int item_idx = item_min_idx_for_current_line; item_idx < item_max_idx_for_current_line; ++item_idx)
10535
                    {
10536
                        ExampleAsset* item_data = &Items[item_idx];
10537
                        ImGui::PushID((int)item_data->ID);
10538
10539
                        // Position item
10540
                        ImVec2 pos = ImVec2(start_pos.x + (item_idx % column_count) * LayoutItemStep.x, start_pos.y + line_idx * LayoutItemStep.y);
10541
                        ImGui::SetCursorScreenPos(pos);
10542
10543
                        ImGui::SetNextItemSelectionUserData(item_idx);
10544
                        bool item_is_selected = Selection.Contains((ImGuiID)item_data->ID);
10545
                        bool item_is_visible = ImGui::IsRectVisible(LayoutItemSize);
10546
                        ImGui::Selectable("", item_is_selected, ImGuiSelectableFlags_None, LayoutItemSize);
10547
10548
                        // Update our selection state immediately (without waiting for EndMultiSelect() requests)
10549
                        // because we use this to alter the color of our text/icon.
10550
                        if (ImGui::IsItemToggledSelection())
10551
                            item_is_selected = !item_is_selected;
10552
10553
                        // Focus (for after deletion)
10554
                        if (item_curr_idx_to_focus == item_idx)
10555
                            ImGui::SetKeyboardFocusHere(-1);
10556
10557
                        // Drag and drop
10558
                        if (ImGui::BeginDragDropSource())
10559
                        {
10560
                            // Create payload with full selection OR single unselected item.
10561
                            // (the later is only possible when using ImGuiMultiSelectFlags_SelectOnClickRelease)
10562
                            if (ImGui::GetDragDropPayload() == NULL)
10563
                            {
10564
                                ImVector<ImGuiID> payload_items;
10565
                                void* it = NULL;
10566
                                ImGuiID id = 0;
10567
                                if (!item_is_selected)
10568
                                    payload_items.push_back(item_data->ID);
10569
                                else
10570
                                    while (Selection.GetNextSelectedItem(&it, &id))
10571
                                        payload_items.push_back(id);
10572
                                ImGui::SetDragDropPayload("ASSETS_BROWSER_ITEMS", payload_items.Data, (size_t)payload_items.size_in_bytes());
10573
                            }
10574
10575
                            // Display payload content in tooltip, by extracting it from the payload data
10576
                            // (we could read from selection, but it is more correct and reusable to read from payload)
10577
                            const ImGuiPayload* payload = ImGui::GetDragDropPayload();
10578
                            const int payload_count = (int)payload->DataSize / (int)sizeof(ImGuiID);
10579
                            ImGui::Text("%d assets", payload_count);
10580
10581
                            ImGui::EndDragDropSource();
10582
                        }
10583
10584
                        // Render icon (a real app would likely display an image/thumbnail here)
10585
                        // Because we use ImGuiMultiSelectFlags_BoxSelect2d, clipping vertical may occasionally be larger, so we coarse-clip our rendering as well.
10586
                        if (item_is_visible)
10587
                        {
10588
                            ImVec2 box_min(pos.x - 1, pos.y - 1);
10589
                            ImVec2 box_max(box_min.x + LayoutItemSize.x + 2, box_min.y + LayoutItemSize.y + 2); // Dubious
10590
                            draw_list->AddRectFilled(box_min, box_max, icon_bg_color); // Background color
10591
                            if (ShowTypeOverlay && item_data->Type != 0)
10592
                            {
10593
                                ImU32 type_col = icon_type_overlay_colors[item_data->Type % IM_ARRAYSIZE(icon_type_overlay_colors)];
10594
                                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);
10595
                            }
10596
                            if (display_label)
10597
                            {
10598
                                ImU32 label_col = ImGui::GetColorU32(item_is_selected ? ImGuiCol_Text : ImGuiCol_TextDisabled);
10599
                                char label[32];
10600
                                sprintf(label, "%d", item_data->ID);
10601
                                draw_list->AddText(ImVec2(box_min.x, box_max.y - ImGui::GetFontSize()), label_col, label);
10602
                            }
10603
                        }
10604
10605
                        ImGui::PopID();
10606
                    }
10607
                }
10608
            }
10609
            clipper.End();
10610
            ImGui::PopStyleVar(); // ImGuiStyleVar_ItemSpacing
10611
10612
            // Context menu
10613
            if (ImGui::BeginPopupContextWindow())
10614
            {
10615
                ImGui::Text("Selection: %d items", Selection.Size);
10616
                ImGui::Separator();
10617
                if (ImGui::MenuItem("Delete", "Del", false, Selection.Size > 0))
10618
                    RequestDelete = true;
10619
                ImGui::EndPopup();
10620
            }
10621
10622
            ms_io = ImGui::EndMultiSelect();
10623
            Selection.ApplyRequests(ms_io);
10624
            if (want_delete)
10625
                Selection.ApplyDeletionPostLoop(ms_io, Items, item_curr_idx_to_focus);
10626
10627
            // Zooming with CTRL+Wheel
10628
            if (ImGui::IsWindowAppearing())
10629
                ZoomWheelAccum = 0.0f;
10630
            if (ImGui::IsWindowHovered() && io.MouseWheel != 0.0f && ImGui::IsKeyDown(ImGuiMod_Ctrl) && ImGui::IsAnyItemActive() == false)
10631
            {
10632
                ZoomWheelAccum += io.MouseWheel;
10633
                if (fabsf(ZoomWheelAccum) >= 1.0f)
10634
                {
10635
                    // Calculate hovered item index from mouse location
10636
                    // FIXME: Locking aiming on 'hovered_item_idx' (with a cool-down timer) would ensure zoom keeps on it.
10637
                    const float hovered_item_nx = (io.MousePos.x - start_pos.x + LayoutItemSpacing * 0.5f) / LayoutItemStep.x;
10638
                    const float hovered_item_ny = (io.MousePos.y - start_pos.y + LayoutItemSpacing * 0.5f) / LayoutItemStep.y;
10639
                    const int hovered_item_idx = ((int)hovered_item_ny * LayoutColumnCount) + (int)hovered_item_nx;
10640
                    //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
10641
10642
                    // Zoom
10643
                    IconSize *= powf(1.1f, (float)(int)ZoomWheelAccum);
10644
                    IconSize = IM_CLAMP(IconSize, 16.0f, 128.0f);
10645
                    ZoomWheelAccum -= (int)ZoomWheelAccum;
10646
                    UpdateLayoutSizes(avail_width);
10647
10648
                    // Manipulate scroll to that we will land at the same Y location of currently hovered item.
10649
                    // - Calculate next frame position of item under mouse
10650
                    // - Set new scroll position to be used in next ImGui::BeginChild() call.
10651
                    float hovered_item_rel_pos_y = ((float)(hovered_item_idx / LayoutColumnCount) + fmodf(hovered_item_ny, 1.0f)) * LayoutItemStep.y;
10652
                    hovered_item_rel_pos_y += ImGui::GetStyle().WindowPadding.y;
10653
                    float mouse_local_y = io.MousePos.y - ImGui::GetWindowPos().y;
10654
                    ImGui::SetScrollY(hovered_item_rel_pos_y - mouse_local_y);
10655
                }
10656
            }
10657
        }
10658
        ImGui::EndChild();
10659
10660
        ImGui::Text("Selected: %d/%d items", Selection.Size, Items.Size);
10661
        ImGui::End();
10662
    }
10663
};
10664
10665
void ShowExampleAppAssetsBrowser(bool* p_open)
10666
{
10667
    IMGUI_DEMO_MARKER("Examples/Assets Browser");
10668
    static ExampleAssetsBrowser assets_browser;
10669
    assets_browser.Draw("Example: Assets Browser", p_open);
10670
}
10671
10672
// End of Demo code
10673
#else
10674
10675
void ImGui::ShowAboutWindow(bool*) {}
10676
void ImGui::ShowDemoWindow(bool*) {}
10677
void ImGui::ShowUserGuide() {}
10678
void ImGui::ShowStyleEditor(ImGuiStyle*) {}
10679
10680
#endif
10681
10682
#endif // #ifndef IMGUI_DISABLE