Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/ext/imgui/imgui_demo.cpp
3186 views
1
// dear imgui, v1.91.6
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
static void ExampleTree_DestroyNode(ExampleTreeNode* node)
324
{
325
for (ExampleTreeNode* child_node : node->Childs)
326
ExampleTree_DestroyNode(child_node);
327
IM_DELETE(node);
328
}
329
330
// Create example tree data
331
// (this allocates _many_ more times than most other code in either Dear ImGui or others demo)
332
static ExampleTreeNode* ExampleTree_CreateDemoTree()
333
{
334
static const char* root_names[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pear", "Pineapple", "Strawberry", "Watermelon" };
335
const size_t NAME_MAX_LEN = sizeof(ExampleTreeNode::Name);
336
char name_buf[NAME_MAX_LEN];
337
int uid = 0;
338
ExampleTreeNode* node_L0 = ExampleTree_CreateNode("<ROOT>", ++uid, NULL);
339
const int root_items_multiplier = 2;
340
for (int idx_L0 = 0; idx_L0 < IM_ARRAYSIZE(root_names) * root_items_multiplier; idx_L0++)
341
{
342
snprintf(name_buf, IM_ARRAYSIZE(name_buf), "%s %d", root_names[idx_L0 / root_items_multiplier], idx_L0 % root_items_multiplier);
343
ExampleTreeNode* node_L1 = ExampleTree_CreateNode(name_buf, ++uid, node_L0);
344
const int number_of_childs = (int)strlen(node_L1->Name);
345
for (int idx_L1 = 0; idx_L1 < number_of_childs; idx_L1++)
346
{
347
snprintf(name_buf, IM_ARRAYSIZE(name_buf), "Child %d", idx_L1);
348
ExampleTreeNode* node_L2 = ExampleTree_CreateNode(name_buf, ++uid, node_L1);
349
node_L2->HasData = true;
350
if (idx_L1 == 0)
351
{
352
snprintf(name_buf, IM_ARRAYSIZE(name_buf), "Sub-child %d", 0);
353
ExampleTreeNode* node_L3 = ExampleTree_CreateNode(name_buf, ++uid, node_L2);
354
node_L3->HasData = true;
355
}
356
}
357
}
358
return node_L0;
359
}
360
361
//-----------------------------------------------------------------------------
362
// [SECTION] Demo Window / ShowDemoWindow()
363
//-----------------------------------------------------------------------------
364
365
// Data to be shared across different functions of the demo.
366
struct ImGuiDemoWindowData
367
{
368
// Examples Apps (accessible from the "Examples" menu)
369
bool ShowMainMenuBar = false;
370
bool ShowAppAssetsBrowser = false;
371
bool ShowAppConsole = false;
372
bool ShowAppCustomRendering = false;
373
bool ShowAppDocuments = false;
374
bool ShowAppDockSpace = false;
375
bool ShowAppLog = false;
376
bool ShowAppLayout = false;
377
bool ShowAppPropertyEditor = false;
378
bool ShowAppSimpleOverlay = false;
379
bool ShowAppAutoResize = false;
380
bool ShowAppConstrainedResize = false;
381
bool ShowAppFullscreen = false;
382
bool ShowAppLongText = false;
383
bool ShowAppWindowTitles = false;
384
385
// Dear ImGui Tools (accessible from the "Tools" menu)
386
bool ShowMetrics = false;
387
bool ShowDebugLog = false;
388
bool ShowIDStackTool = false;
389
bool ShowStyleEditor = false;
390
bool ShowAbout = false;
391
392
// Other data
393
ExampleTreeNode* DemoTree = NULL;
394
395
~ImGuiDemoWindowData() { if (DemoTree) ExampleTree_DestroyNode(DemoTree); }
396
};
397
398
// Demonstrate most Dear ImGui features (this is big function!)
399
// You may execute this function to experiment with the UI and understand what it does.
400
// You may then search for keywords in the code when you are interested by a specific feature.
401
void ImGui::ShowDemoWindow(bool* p_open)
402
{
403
// Exceptionally add an extra assert here for people confused about initial Dear ImGui setup
404
// Most functions would normally just assert/crash if the context is missing.
405
IM_ASSERT(ImGui::GetCurrentContext() != NULL && "Missing Dear ImGui context. Refer to examples app!");
406
407
// Verify ABI compatibility between caller code and compiled version of Dear ImGui. This helps detects some build issues.
408
IMGUI_CHECKVERSION();
409
410
// Stored data
411
static ImGuiDemoWindowData demo_data;
412
413
// Examples Apps (accessible from the "Examples" menu)
414
if (demo_data.ShowMainMenuBar) { ShowExampleAppMainMenuBar(); }
415
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)
416
if (demo_data.ShowAppDocuments) { ShowExampleAppDocuments(&demo_data.ShowAppDocuments); } // ...process the Document app next, as it may also use a DockSpace()
417
if (demo_data.ShowAppAssetsBrowser) { ShowExampleAppAssetsBrowser(&demo_data.ShowAppAssetsBrowser); }
418
if (demo_data.ShowAppConsole) { ShowExampleAppConsole(&demo_data.ShowAppConsole); }
419
if (demo_data.ShowAppCustomRendering) { ShowExampleAppCustomRendering(&demo_data.ShowAppCustomRendering); }
420
if (demo_data.ShowAppLog) { ShowExampleAppLog(&demo_data.ShowAppLog); }
421
if (demo_data.ShowAppLayout) { ShowExampleAppLayout(&demo_data.ShowAppLayout); }
422
if (demo_data.ShowAppPropertyEditor) { ShowExampleAppPropertyEditor(&demo_data.ShowAppPropertyEditor, &demo_data); }
423
if (demo_data.ShowAppSimpleOverlay) { ShowExampleAppSimpleOverlay(&demo_data.ShowAppSimpleOverlay); }
424
if (demo_data.ShowAppAutoResize) { ShowExampleAppAutoResize(&demo_data.ShowAppAutoResize); }
425
if (demo_data.ShowAppConstrainedResize) { ShowExampleAppConstrainedResize(&demo_data.ShowAppConstrainedResize); }
426
if (demo_data.ShowAppFullscreen) { ShowExampleAppFullscreen(&demo_data.ShowAppFullscreen); }
427
if (demo_data.ShowAppLongText) { ShowExampleAppLongText(&demo_data.ShowAppLongText); }
428
if (demo_data.ShowAppWindowTitles) { ShowExampleAppWindowTitles(&demo_data.ShowAppWindowTitles); }
429
430
// Dear ImGui Tools (accessible from the "Tools" menu)
431
if (demo_data.ShowMetrics) { ImGui::ShowMetricsWindow(&demo_data.ShowMetrics); }
432
if (demo_data.ShowDebugLog) { ImGui::ShowDebugLogWindow(&demo_data.ShowDebugLog); }
433
if (demo_data.ShowIDStackTool) { ImGui::ShowIDStackToolWindow(&demo_data.ShowIDStackTool); }
434
if (demo_data.ShowAbout) { ImGui::ShowAboutWindow(&demo_data.ShowAbout); }
435
if (demo_data.ShowStyleEditor)
436
{
437
ImGui::Begin("Dear ImGui Style Editor", &demo_data.ShowStyleEditor);
438
ImGui::ShowStyleEditor();
439
ImGui::End();
440
}
441
442
// Demonstrate the various window flags. Typically you would just use the default!
443
static bool no_titlebar = false;
444
static bool no_scrollbar = false;
445
static bool no_menu = false;
446
static bool no_move = false;
447
static bool no_resize = false;
448
static bool no_collapse = false;
449
static bool no_close = false;
450
static bool no_nav = false;
451
static bool no_background = false;
452
static bool no_bring_to_front = false;
453
static bool no_docking = false;
454
static bool unsaved_document = false;
455
456
ImGuiWindowFlags window_flags = 0;
457
if (no_titlebar) window_flags |= ImGuiWindowFlags_NoTitleBar;
458
if (no_scrollbar) window_flags |= ImGuiWindowFlags_NoScrollbar;
459
if (!no_menu) window_flags |= ImGuiWindowFlags_MenuBar;
460
if (no_move) window_flags |= ImGuiWindowFlags_NoMove;
461
if (no_resize) window_flags |= ImGuiWindowFlags_NoResize;
462
if (no_collapse) window_flags |= ImGuiWindowFlags_NoCollapse;
463
if (no_nav) window_flags |= ImGuiWindowFlags_NoNav;
464
if (no_background) window_flags |= ImGuiWindowFlags_NoBackground;
465
if (no_bring_to_front) window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus;
466
if (no_docking) window_flags |= ImGuiWindowFlags_NoDocking;
467
if (unsaved_document) window_flags |= ImGuiWindowFlags_UnsavedDocument;
468
if (no_close) p_open = NULL; // Don't pass our bool* to Begin
469
470
// We specify a default position/size in case there's no data in the .ini file.
471
// We only do it to make the demo applications a little more welcoming, but typically this isn't required.
472
const ImGuiViewport* main_viewport = ImGui::GetMainViewport();
473
ImGui::SetNextWindowPos(ImVec2(main_viewport->WorkPos.x + 650, main_viewport->WorkPos.y + 20), ImGuiCond_FirstUseEver);
474
ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver);
475
476
// Main body of the Demo window starts here.
477
if (!ImGui::Begin("Dear ImGui Demo", p_open, window_flags))
478
{
479
// Early out if the window is collapsed, as an optimization.
480
ImGui::End();
481
return;
482
}
483
484
// Most "big" widgets share a common width settings by default. See 'Demo->Layout->Widgets Width' for details.
485
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.
486
//ImGui::PushItemWidth(-ImGui::GetWindowWidth() * 0.35f); // e.g. Use 2/3 of the space for widgets and 1/3 for labels (right align)
487
488
// Menu Bar
489
ShowDemoWindowMenuBar(&demo_data);
490
491
ImGui::Text("dear imgui says hello! (%s) (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
492
ImGui::Spacing();
493
494
IMGUI_DEMO_MARKER("Help");
495
if (ImGui::CollapsingHeader("Help"))
496
{
497
ImGui::SeparatorText("ABOUT THIS DEMO:");
498
ImGui::BulletText("Sections below are demonstrating many aspects of the library.");
499
ImGui::BulletText("The \"Examples\" menu above leads to more demo contents.");
500
ImGui::BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n"
501
"and Metrics/Debugger (general purpose Dear ImGui debugging tool).");
502
503
ImGui::SeparatorText("PROGRAMMER GUIDE:");
504
ImGui::BulletText("See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!");
505
ImGui::BulletText("See comments in imgui.cpp.");
506
ImGui::BulletText("See example applications in the examples/ folder.");
507
ImGui::BulletText("Read the FAQ at ");
508
ImGui::SameLine(0, 0);
509
ImGui::TextLinkOpenURL("https://www.dearimgui.com/faq/");
510
ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls.");
511
ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls.");
512
513
ImGui::SeparatorText("USER GUIDE:");
514
ImGui::ShowUserGuide();
515
}
516
517
IMGUI_DEMO_MARKER("Configuration");
518
if (ImGui::CollapsingHeader("Configuration"))
519
{
520
ImGuiIO& io = ImGui::GetIO();
521
522
if (ImGui::TreeNode("Configuration##2"))
523
{
524
ImGui::SeparatorText("General");
525
ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard);
526
ImGui::SameLine(); HelpMarker("Enable keyboard controls.");
527
ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", &io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad);
528
ImGui::SameLine(); HelpMarker("Enable gamepad controls. Require backend to set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details.");
529
ImGui::CheckboxFlags("io.ConfigFlags: NoMouse", &io.ConfigFlags, ImGuiConfigFlags_NoMouse);
530
ImGui::SameLine(); HelpMarker("Instruct dear imgui to disable mouse inputs and interactions.");
531
532
// The "NoMouse" option can get us stuck with a disabled mouse! Let's provide an alternative way to fix it:
533
if (io.ConfigFlags & ImGuiConfigFlags_NoMouse)
534
{
535
if (fmodf((float)ImGui::GetTime(), 0.40f) < 0.20f)
536
{
537
ImGui::SameLine();
538
ImGui::Text("<<PRESS SPACE TO DISABLE>>");
539
}
540
// Prevent both being checked
541
if (ImGui::IsKeyPressed(ImGuiKey_Space) || (io.ConfigFlags & ImGuiConfigFlags_NoKeyboard))
542
io.ConfigFlags &= ~ImGuiConfigFlags_NoMouse;
543
}
544
545
ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", &io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange);
546
ImGui::SameLine(); HelpMarker("Instruct backend to not alter mouse cursor shape and visibility.");
547
ImGui::CheckboxFlags("io.ConfigFlags: NoKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NoKeyboard);
548
ImGui::SameLine(); HelpMarker("Instruct dear imgui to disable keyboard inputs and interactions.");
549
550
ImGui::Checkbox("io.ConfigInputTrickleEventQueue", &io.ConfigInputTrickleEventQueue);
551
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.");
552
ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor);
553
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).");
554
555
ImGui::SeparatorText("Keyboard/Gamepad Navigation");
556
ImGui::Checkbox("io.ConfigNavSwapGamepadButtons", &io.ConfigNavSwapGamepadButtons);
557
ImGui::Checkbox("io.ConfigNavMoveSetMousePos", &io.ConfigNavMoveSetMousePos);
558
ImGui::SameLine(); HelpMarker("Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is difficult");
559
ImGui::Checkbox("io.ConfigNavCaptureKeyboard", &io.ConfigNavCaptureKeyboard);
560
ImGui::Checkbox("io.ConfigNavEscapeClearFocusItem", &io.ConfigNavEscapeClearFocusItem);
561
ImGui::SameLine(); HelpMarker("Pressing Escape clears focused item.");
562
ImGui::Checkbox("io.ConfigNavEscapeClearFocusWindow", &io.ConfigNavEscapeClearFocusWindow);
563
ImGui::SameLine(); HelpMarker("Pressing Escape clears focused window.");
564
ImGui::Checkbox("io.ConfigNavCursorVisibleAuto", &io.ConfigNavCursorVisibleAuto);
565
ImGui::SameLine(); HelpMarker("Using directional navigation key makes the cursor visible. Mouse click hides the cursor.");
566
ImGui::Checkbox("io.ConfigNavCursorVisibleAlways", &io.ConfigNavCursorVisibleAlways);
567
ImGui::SameLine(); HelpMarker("Navigation cursor is always visible.");
568
569
ImGui::SeparatorText("Docking");
570
ImGui::CheckboxFlags("io.ConfigFlags: DockingEnable", &io.ConfigFlags, ImGuiConfigFlags_DockingEnable);
571
ImGui::SameLine();
572
if (io.ConfigDockingWithShift)
573
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).");
574
else
575
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).");
576
if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
577
{
578
ImGui::Indent();
579
ImGui::Checkbox("io.ConfigDockingNoSplit", &io.ConfigDockingNoSplit);
580
ImGui::SameLine(); HelpMarker("Simplified docking mode: disable window splitting, so docking is limited to merging multiple windows together into tab-bars.");
581
ImGui::Checkbox("io.ConfigDockingWithShift", &io.ConfigDockingWithShift);
582
ImGui::SameLine(); HelpMarker("Enable docking when holding Shift only (allow to drop in wider space, reduce visual noise)");
583
ImGui::Checkbox("io.ConfigDockingAlwaysTabBar", &io.ConfigDockingAlwaysTabBar);
584
ImGui::SameLine(); HelpMarker("Create a docking node and tab-bar on single floating windows.");
585
ImGui::Checkbox("io.ConfigDockingTransparentPayload", &io.ConfigDockingTransparentPayload);
586
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.");
587
ImGui::Unindent();
588
}
589
590
ImGui::SeparatorText("Multi-viewports");
591
ImGui::CheckboxFlags("io.ConfigFlags: ViewportsEnable", &io.ConfigFlags, ImGuiConfigFlags_ViewportsEnable);
592
ImGui::SameLine(); HelpMarker("[beta] Enable beta multi-viewports support. See ImGuiPlatformIO for details.");
593
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
594
{
595
ImGui::Indent();
596
ImGui::Checkbox("io.ConfigViewportsNoAutoMerge", &io.ConfigViewportsNoAutoMerge);
597
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.");
598
ImGui::Checkbox("io.ConfigViewportsNoTaskBarIcon", &io.ConfigViewportsNoTaskBarIcon);
599
ImGui::SameLine(); HelpMarker("Toggling this at runtime is normally unsupported (most platform backends won't refresh the task bar icon state right away).");
600
ImGui::Checkbox("io.ConfigViewportsNoDecoration", &io.ConfigViewportsNoDecoration);
601
ImGui::SameLine(); HelpMarker("Toggling this at runtime is normally unsupported (most platform backends won't refresh the decoration right away).");
602
ImGui::Checkbox("io.ConfigViewportsNoDefaultParent", &io.ConfigViewportsNoDefaultParent);
603
ImGui::SameLine(); HelpMarker("Toggling this at runtime is normally unsupported (most platform backends won't refresh the parenting right away).");
604
ImGui::Unindent();
605
}
606
607
ImGui::SeparatorText("Windows");
608
ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges);
609
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.");
610
ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly);
611
ImGui::Checkbox("io.ConfigWindowsCopyContentsWithCtrlC", &io.ConfigWindowsCopyContentsWithCtrlC); // [EXPERIMENTAL]
612
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.");
613
ImGui::Checkbox("io.ConfigScrollbarScrollByPage", &io.ConfigScrollbarScrollByPage);
614
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.");
615
616
ImGui::SeparatorText("Widgets");
617
ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink);
618
ImGui::SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting).");
619
ImGui::Checkbox("io.ConfigInputTextEnterKeepActive", &io.ConfigInputTextEnterKeepActive);
620
ImGui::SameLine(); HelpMarker("Pressing Enter will keep item active and select contents (single-line only).");
621
ImGui::Checkbox("io.ConfigDragClickToInputText", &io.ConfigDragClickToInputText);
622
ImGui::SameLine(); HelpMarker("Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving).");
623
ImGui::Checkbox("io.ConfigMacOSXBehaviors", &io.ConfigMacOSXBehaviors);
624
ImGui::SameLine(); HelpMarker("Swap Cmd<>Ctrl keys, enable various MacOS style behaviors.");
625
ImGui::Text("Also see Style->Rendering for rendering options.");
626
627
// Also read: https://github.com/ocornut/imgui/wiki/Error-Handling
628
ImGui::SeparatorText("Error Handling");
629
630
ImGui::Checkbox("io.ConfigErrorRecovery", &io.ConfigErrorRecovery);
631
ImGui::SameLine(); HelpMarker(
632
"Options to configure how we handle recoverable errors.\n"
633
"- Error recovery is not perfect nor guaranteed! It is a feature to ease development.\n"
634
"- You not are not supposed to rely on it in the course of a normal application run.\n"
635
"- Possible usage: facilitate recovery from errors triggered from a scripting language or after specific exceptions handlers.\n"
636
"- Always ensure that on programmers seat you have at minimum Asserts or Tooltips enabled when making direct imgui API call!"
637
"Otherwise it would severely hinder your ability to catch and correct mistakes!");
638
ImGui::Checkbox("io.ConfigErrorRecoveryEnableAssert", &io.ConfigErrorRecoveryEnableAssert);
639
ImGui::Checkbox("io.ConfigErrorRecoveryEnableDebugLog", &io.ConfigErrorRecoveryEnableDebugLog);
640
ImGui::Checkbox("io.ConfigErrorRecoveryEnableTooltip", &io.ConfigErrorRecoveryEnableTooltip);
641
if (!io.ConfigErrorRecoveryEnableAssert && !io.ConfigErrorRecoveryEnableDebugLog && !io.ConfigErrorRecoveryEnableTooltip)
642
io.ConfigErrorRecoveryEnableAssert = io.ConfigErrorRecoveryEnableDebugLog = io.ConfigErrorRecoveryEnableTooltip = true;
643
644
// Also read: https://github.com/ocornut/imgui/wiki/Debug-Tools
645
ImGui::SeparatorText("Debug");
646
ImGui::Checkbox("io.ConfigDebugIsDebuggerPresent", &io.ConfigDebugIsDebuggerPresent);
647
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.");
648
ImGui::Checkbox("io.ConfigDebugHighlightIdConflicts", &io.ConfigDebugHighlightIdConflicts);
649
ImGui::SameLine(); HelpMarker("Highlight and show an error message when multiple items have conflicting identifiers.");
650
ImGui::BeginDisabled();
651
ImGui::Checkbox("io.ConfigDebugBeginReturnValueOnce", &io.ConfigDebugBeginReturnValueOnce);
652
ImGui::EndDisabled();
653
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.");
654
ImGui::Checkbox("io.ConfigDebugBeginReturnValueLoop", &io.ConfigDebugBeginReturnValueLoop);
655
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.");
656
ImGui::Checkbox("io.ConfigDebugIgnoreFocusLoss", &io.ConfigDebugIgnoreFocusLoss);
657
ImGui::SameLine(); HelpMarker("Option to deactivate io.AddFocusEvent(false) handling. May facilitate interactions with a debugger when focus loss leads to clearing inputs data.");
658
ImGui::Checkbox("io.ConfigDebugIniSettings", &io.ConfigDebugIniSettings);
659
ImGui::SameLine(); HelpMarker("Option to save .ini data with extra comments (particularly helpful for Docking, but makes saving slower).");
660
661
ImGui::TreePop();
662
ImGui::Spacing();
663
}
664
665
IMGUI_DEMO_MARKER("Configuration/Backend Flags");
666
if (ImGui::TreeNode("Backend Flags"))
667
{
668
HelpMarker(
669
"Those flags are set by the backends (imgui_impl_xxx files) to specify their capabilities.\n"
670
"Here we expose them as read-only fields to avoid breaking interactions with your backend.");
671
672
// Make a local copy to avoid modifying actual backend flags.
673
// FIXME: Maybe we need a BeginReadonly() equivalent to keep label bright?
674
ImGui::BeginDisabled();
675
ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", &io.BackendFlags, ImGuiBackendFlags_HasGamepad);
676
ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors);
677
ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos", &io.BackendFlags, ImGuiBackendFlags_HasSetMousePos);
678
ImGui::CheckboxFlags("io.BackendFlags: PlatformHasViewports", &io.BackendFlags, ImGuiBackendFlags_PlatformHasViewports);
679
ImGui::CheckboxFlags("io.BackendFlags: HasMouseHoveredViewport",&io.BackendFlags, ImGuiBackendFlags_HasMouseHoveredViewport);
680
ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", &io.BackendFlags, ImGuiBackendFlags_RendererHasVtxOffset);
681
ImGui::CheckboxFlags("io.BackendFlags: RendererHasViewports", &io.BackendFlags, ImGuiBackendFlags_RendererHasViewports);
682
ImGui::EndDisabled();
683
684
ImGui::TreePop();
685
ImGui::Spacing();
686
}
687
688
IMGUI_DEMO_MARKER("Configuration/Style");
689
if (ImGui::TreeNode("Style"))
690
{
691
ImGui::Checkbox("Style Editor", &demo_data.ShowStyleEditor);
692
ImGui::SameLine();
693
HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function.");
694
ImGui::TreePop();
695
ImGui::Spacing();
696
}
697
698
IMGUI_DEMO_MARKER("Configuration/Capture, Logging");
699
if (ImGui::TreeNode("Capture/Logging"))
700
{
701
HelpMarker(
702
"The logging API redirects all text output so you can easily capture the content of "
703
"a window or a block. Tree nodes can be automatically expanded.\n"
704
"Try opening any of the contents below in this window and then click one of the \"Log To\" button.");
705
ImGui::LogButtons();
706
707
HelpMarker("You can also call ImGui::LogText() to output directly to the log without a visual output.");
708
if (ImGui::Button("Copy \"Hello, world!\" to clipboard"))
709
{
710
ImGui::LogToClipboard();
711
ImGui::LogText("Hello, world!");
712
ImGui::LogFinish();
713
}
714
ImGui::TreePop();
715
}
716
}
717
718
IMGUI_DEMO_MARKER("Window options");
719
if (ImGui::CollapsingHeader("Window options"))
720
{
721
if (ImGui::BeginTable("split", 3))
722
{
723
ImGui::TableNextColumn(); ImGui::Checkbox("No titlebar", &no_titlebar);
724
ImGui::TableNextColumn(); ImGui::Checkbox("No scrollbar", &no_scrollbar);
725
ImGui::TableNextColumn(); ImGui::Checkbox("No menu", &no_menu);
726
ImGui::TableNextColumn(); ImGui::Checkbox("No move", &no_move);
727
ImGui::TableNextColumn(); ImGui::Checkbox("No resize", &no_resize);
728
ImGui::TableNextColumn(); ImGui::Checkbox("No collapse", &no_collapse);
729
ImGui::TableNextColumn(); ImGui::Checkbox("No close", &no_close);
730
ImGui::TableNextColumn(); ImGui::Checkbox("No nav", &no_nav);
731
ImGui::TableNextColumn(); ImGui::Checkbox("No background", &no_background);
732
ImGui::TableNextColumn(); ImGui::Checkbox("No bring to front", &no_bring_to_front);
733
ImGui::TableNextColumn(); ImGui::Checkbox("No docking", &no_docking);
734
ImGui::TableNextColumn(); ImGui::Checkbox("Unsaved document", &unsaved_document);
735
ImGui::EndTable();
736
}
737
}
738
739
// All demo contents
740
ShowDemoWindowWidgets(&demo_data);
741
ShowDemoWindowLayout();
742
ShowDemoWindowPopups();
743
ShowDemoWindowTables();
744
ShowDemoWindowInputs();
745
746
// End of ShowDemoWindow()
747
ImGui::PopItemWidth();
748
ImGui::End();
749
}
750
751
//-----------------------------------------------------------------------------
752
// [SECTION] ShowDemoWindowMenuBar()
753
//-----------------------------------------------------------------------------
754
755
static void ShowDemoWindowMenuBar(ImGuiDemoWindowData* demo_data)
756
{
757
IMGUI_DEMO_MARKER("Menu");
758
if (ImGui::BeginMenuBar())
759
{
760
if (ImGui::BeginMenu("Menu"))
761
{
762
IMGUI_DEMO_MARKER("Menu/File");
763
ShowExampleMenuFile();
764
ImGui::EndMenu();
765
}
766
if (ImGui::BeginMenu("Examples"))
767
{
768
IMGUI_DEMO_MARKER("Menu/Examples");
769
ImGui::MenuItem("Main menu bar", NULL, &demo_data->ShowMainMenuBar);
770
771
ImGui::SeparatorText("Mini apps");
772
ImGui::MenuItem("Assets Browser", NULL, &demo_data->ShowAppAssetsBrowser);
773
ImGui::MenuItem("Console", NULL, &demo_data->ShowAppConsole);
774
ImGui::MenuItem("Custom rendering", NULL, &demo_data->ShowAppCustomRendering);
775
ImGui::MenuItem("Documents", NULL, &demo_data->ShowAppDocuments);
776
ImGui::MenuItem("Dockspace", NULL, &demo_data->ShowAppDockSpace);
777
ImGui::MenuItem("Log", NULL, &demo_data->ShowAppLog);
778
ImGui::MenuItem("Property editor", NULL, &demo_data->ShowAppPropertyEditor);
779
ImGui::MenuItem("Simple layout", NULL, &demo_data->ShowAppLayout);
780
ImGui::MenuItem("Simple overlay", NULL, &demo_data->ShowAppSimpleOverlay);
781
782
ImGui::SeparatorText("Concepts");
783
ImGui::MenuItem("Auto-resizing window", NULL, &demo_data->ShowAppAutoResize);
784
ImGui::MenuItem("Constrained-resizing window", NULL, &demo_data->ShowAppConstrainedResize);
785
ImGui::MenuItem("Fullscreen window", NULL, &demo_data->ShowAppFullscreen);
786
ImGui::MenuItem("Long text display", NULL, &demo_data->ShowAppLongText);
787
ImGui::MenuItem("Manipulating window titles", NULL, &demo_data->ShowAppWindowTitles);
788
789
ImGui::EndMenu();
790
}
791
//if (ImGui::MenuItem("MenuItem")) {} // You can also use MenuItem() inside a menu bar!
792
if (ImGui::BeginMenu("Tools"))
793
{
794
IMGUI_DEMO_MARKER("Menu/Tools");
795
ImGuiIO& io = ImGui::GetIO();
796
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
797
const bool has_debug_tools = true;
798
#else
799
const bool has_debug_tools = false;
800
#endif
801
ImGui::MenuItem("Metrics/Debugger", NULL, &demo_data->ShowMetrics, has_debug_tools);
802
ImGui::MenuItem("Debug Log", NULL, &demo_data->ShowDebugLog, has_debug_tools);
803
ImGui::MenuItem("ID Stack Tool", NULL, &demo_data->ShowIDStackTool, has_debug_tools);
804
bool is_debugger_present = io.ConfigDebugIsDebuggerPresent;
805
if (ImGui::MenuItem("Item Picker", NULL, false, has_debug_tools && is_debugger_present))
806
ImGui::DebugStartItemPicker();
807
if (!is_debugger_present)
808
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.");
809
ImGui::MenuItem("Style Editor", NULL, &demo_data->ShowStyleEditor);
810
ImGui::MenuItem("About Dear ImGui", NULL, &demo_data->ShowAbout);
811
812
ImGui::SeparatorText("Debug Options");
813
ImGui::MenuItem("Highlight ID Conflicts", NULL, &io.ConfigDebugHighlightIdConflicts, has_debug_tools);
814
ImGui::EndMenu();
815
}
816
ImGui::EndMenuBar();
817
}
818
}
819
820
//-----------------------------------------------------------------------------
821
// [SECTION] ShowDemoWindowWidgets()
822
//-----------------------------------------------------------------------------
823
824
static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data)
825
{
826
IMGUI_DEMO_MARKER("Widgets");
827
//ImGui::SetNextItemOpen(true, ImGuiCond_Once);
828
if (!ImGui::CollapsingHeader("Widgets"))
829
return;
830
831
static bool disable_all = false; // The Checkbox for that is inside the "Disabled" section at the bottom
832
if (disable_all)
833
ImGui::BeginDisabled();
834
835
IMGUI_DEMO_MARKER("Widgets/Basic");
836
if (ImGui::TreeNode("Basic"))
837
{
838
ImGui::SeparatorText("General");
839
840
IMGUI_DEMO_MARKER("Widgets/Basic/Button");
841
static int clicked = 0;
842
if (ImGui::Button("Button"))
843
clicked++;
844
if (clicked & 1)
845
{
846
ImGui::SameLine();
847
ImGui::Text("Thanks for clicking me!");
848
}
849
850
IMGUI_DEMO_MARKER("Widgets/Basic/Checkbox");
851
static bool check = true;
852
ImGui::Checkbox("checkbox", &check);
853
854
IMGUI_DEMO_MARKER("Widgets/Basic/RadioButton");
855
static int e = 0;
856
ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine();
857
ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine();
858
ImGui::RadioButton("radio c", &e, 2);
859
860
// Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style.
861
IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Colored)");
862
for (int i = 0; i < 7; i++)
863
{
864
if (i > 0)
865
ImGui::SameLine();
866
ImGui::PushID(i);
867
ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.6f));
868
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.7f));
869
ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.8f, 0.8f));
870
ImGui::Button("Click");
871
ImGui::PopStyleColor(3);
872
ImGui::PopID();
873
}
874
875
// Use AlignTextToFramePadding() to align text baseline to the baseline of framed widgets elements
876
// (otherwise a Text+SameLine+Button sequence will have the text a little too high by default!)
877
// See 'Demo->Layout->Text Baseline Alignment' for details.
878
ImGui::AlignTextToFramePadding();
879
ImGui::Text("Hold to repeat:");
880
ImGui::SameLine();
881
882
// Arrow buttons with Repeater
883
IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Repeating)");
884
static int counter = 0;
885
float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
886
ImGui::PushItemFlag(ImGuiItemFlags_ButtonRepeat, true);
887
if (ImGui::ArrowButton("##left", ImGuiDir_Left)) { counter--; }
888
ImGui::SameLine(0.0f, spacing);
889
if (ImGui::ArrowButton("##right", ImGuiDir_Right)) { counter++; }
890
ImGui::PopItemFlag();
891
ImGui::SameLine();
892
ImGui::Text("%d", counter);
893
894
ImGui::Button("Tooltip");
895
ImGui::SetItemTooltip("I am a tooltip");
896
897
ImGui::LabelText("label", "Value");
898
899
ImGui::SeparatorText("Inputs");
900
901
{
902
// To wire InputText() with std::string or any other custom string type,
903
// see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file.
904
IMGUI_DEMO_MARKER("Widgets/Basic/InputText");
905
static char str0[128] = "Hello, world!";
906
ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0));
907
ImGui::SameLine(); HelpMarker(
908
"USER:\n"
909
"Hold SHIFT or use mouse to select text.\n"
910
"CTRL+Left/Right to word jump.\n"
911
"CTRL+A or Double-Click to select all.\n"
912
"CTRL+X,CTRL+C,CTRL+V clipboard.\n"
913
"CTRL+Z,CTRL+Y undo/redo.\n"
914
"ESCAPE to revert.\n\n"
915
"PROGRAMMER:\n"
916
"You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() "
917
"to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example (this is not demonstrated "
918
"in imgui_demo.cpp).");
919
920
static char str1[128] = "";
921
ImGui::InputTextWithHint("input text (w/ hint)", "enter text here", str1, IM_ARRAYSIZE(str1));
922
923
IMGUI_DEMO_MARKER("Widgets/Basic/InputInt, InputFloat");
924
static int i0 = 123;
925
ImGui::InputInt("input int", &i0);
926
927
static float f0 = 0.001f;
928
ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f");
929
930
static double d0 = 999999.00000001;
931
ImGui::InputDouble("input double", &d0, 0.01f, 1.0f, "%.8f");
932
933
static float f1 = 1.e10f;
934
ImGui::InputFloat("input scientific", &f1, 0.0f, 0.0f, "%e");
935
ImGui::SameLine(); HelpMarker(
936
"You can input value using the scientific notation,\n"
937
" e.g. \"1e+8\" becomes \"100000000\".");
938
939
static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f };
940
ImGui::InputFloat3("input float3", vec4a);
941
}
942
943
ImGui::SeparatorText("Drags");
944
945
{
946
IMGUI_DEMO_MARKER("Widgets/Basic/DragInt, DragFloat");
947
static int i1 = 50, i2 = 42, i3 = 128;
948
ImGui::DragInt("drag int", &i1, 1);
949
ImGui::SameLine(); HelpMarker(
950
"Click and drag to edit value.\n"
951
"Hold SHIFT/ALT for faster/slower edit.\n"
952
"Double-click or CTRL+click to input value.");
953
ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp);
954
ImGui::DragInt("drag int wrap 100..200", &i3, 1, 100, 200, "%d", ImGuiSliderFlags_WrapAround);
955
956
static float f1 = 1.00f, f2 = 0.0067f;
957
ImGui::DragFloat("drag float", &f1, 0.005f);
958
ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns");
959
//ImGui::DragFloat("drag wrap -1..1", &f3, 0.005f, -1.0f, 1.0f, NULL, ImGuiSliderFlags_WrapAround);
960
}
961
962
ImGui::SeparatorText("Sliders");
963
964
{
965
IMGUI_DEMO_MARKER("Widgets/Basic/SliderInt, SliderFloat");
966
static int i1 = 0;
967
ImGui::SliderInt("slider int", &i1, -1, 3);
968
ImGui::SameLine(); HelpMarker("CTRL+click to input value.");
969
970
static float f1 = 0.123f, f2 = 0.0f;
971
ImGui::SliderFloat("slider float", &f1, 0.0f, 1.0f, "ratio = %.3f");
972
ImGui::SliderFloat("slider float (log)", &f2, -10.0f, 10.0f, "%.4f", ImGuiSliderFlags_Logarithmic);
973
974
IMGUI_DEMO_MARKER("Widgets/Basic/SliderAngle");
975
static float angle = 0.0f;
976
ImGui::SliderAngle("slider angle", &angle);
977
978
// Using the format string to display a name instead of an integer.
979
// Here we completely omit '%d' from the format string, so it'll only display a name.
980
// This technique can also be used with DragInt().
981
IMGUI_DEMO_MARKER("Widgets/Basic/Slider (enum)");
982
enum Element { Element_Fire, Element_Earth, Element_Air, Element_Water, Element_COUNT };
983
static int elem = Element_Fire;
984
const char* elems_names[Element_COUNT] = { "Fire", "Earth", "Air", "Water" };
985
const char* elem_name = (elem >= 0 && elem < Element_COUNT) ? elems_names[elem] : "Unknown";
986
ImGui::SliderInt("slider enum", &elem, 0, Element_COUNT - 1, elem_name); // Use ImGuiSliderFlags_NoInput flag to disable CTRL+Click here.
987
ImGui::SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer.");
988
}
989
990
ImGui::SeparatorText("Selectors/Pickers");
991
992
{
993
IMGUI_DEMO_MARKER("Widgets/Basic/ColorEdit3, ColorEdit4");
994
static float col1[3] = { 1.0f, 0.0f, 0.2f };
995
static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
996
ImGui::ColorEdit3("color 1", col1);
997
ImGui::SameLine(); HelpMarker(
998
"Click on the color square to open a color picker.\n"
999
"Click and hold to use drag and drop.\n"
1000
"Right-click on the color square to show options.\n"
1001
"CTRL+click on individual component to input value.\n");
1002
1003
ImGui::ColorEdit4("color 2", col2);
1004
}
1005
1006
{
1007
// Using the _simplified_ one-liner Combo() api here
1008
// See "Combo" section for examples of how to use the more flexible BeginCombo()/EndCombo() api.
1009
IMGUI_DEMO_MARKER("Widgets/Basic/Combo");
1010
const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" };
1011
static int item_current = 0;
1012
ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items));
1013
ImGui::SameLine(); HelpMarker(
1014
"Using the simplified one-liner Combo API here.\n"
1015
"Refer to the \"Combo\" section below for an explanation of how to use the more flexible and general BeginCombo/EndCombo API.");
1016
}
1017
1018
{
1019
// Using the _simplified_ one-liner ListBox() api here
1020
// See "List boxes" section for examples of how to use the more flexible BeginListBox()/EndListBox() api.
1021
IMGUI_DEMO_MARKER("Widgets/Basic/ListBox");
1022
const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" };
1023
static int item_current = 1;
1024
ImGui::ListBox("listbox", &item_current, items, IM_ARRAYSIZE(items), 4);
1025
ImGui::SameLine(); HelpMarker(
1026
"Using the simplified one-liner ListBox API here.\n"
1027
"Refer to the \"List boxes\" section below for an explanation of how to use the more flexible and general BeginListBox/EndListBox API.");
1028
}
1029
1030
ImGui::TreePop();
1031
}
1032
1033
IMGUI_DEMO_MARKER("Widgets/Tooltips");
1034
if (ImGui::TreeNode("Tooltips"))
1035
{
1036
// Tooltips are windows following the mouse. They do not take focus away.
1037
ImGui::SeparatorText("General");
1038
1039
// Typical use cases:
1040
// - Short-form (text only): SetItemTooltip("Hello");
1041
// - Short-form (any contents): if (BeginItemTooltip()) { Text("Hello"); EndTooltip(); }
1042
1043
// - Full-form (text only): if (IsItemHovered(...)) { SetTooltip("Hello"); }
1044
// - Full-form (any contents): if (IsItemHovered(...) && BeginTooltip()) { Text("Hello"); EndTooltip(); }
1045
1046
HelpMarker(
1047
"Tooltip are typically created by using a IsItemHovered() + SetTooltip() sequence.\n\n"
1048
"We provide a helper SetItemTooltip() function to perform the two with standards flags.");
1049
1050
ImVec2 sz = ImVec2(-FLT_MIN, 0.0f);
1051
1052
ImGui::Button("Basic", sz);
1053
ImGui::SetItemTooltip("I am a tooltip");
1054
1055
ImGui::Button("Fancy", sz);
1056
if (ImGui::BeginItemTooltip())
1057
{
1058
ImGui::Text("I am a fancy tooltip");
1059
static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
1060
ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr));
1061
ImGui::Text("Sin(time) = %f", sinf((float)ImGui::GetTime()));
1062
ImGui::EndTooltip();
1063
}
1064
1065
ImGui::SeparatorText("Always On");
1066
1067
// Showcase NOT relying on a IsItemHovered() to emit a tooltip.
1068
// Here the tooltip is always emitted when 'always_on == true'.
1069
static int always_on = 0;
1070
ImGui::RadioButton("Off", &always_on, 0);
1071
ImGui::SameLine();
1072
ImGui::RadioButton("Always On (Simple)", &always_on, 1);
1073
ImGui::SameLine();
1074
ImGui::RadioButton("Always On (Advanced)", &always_on, 2);
1075
if (always_on == 1)
1076
ImGui::SetTooltip("I am following you around.");
1077
else if (always_on == 2 && ImGui::BeginTooltip())
1078
{
1079
ImGui::ProgressBar(sinf((float)ImGui::GetTime()) * 0.5f + 0.5f, ImVec2(ImGui::GetFontSize() * 25, 0.0f));
1080
ImGui::EndTooltip();
1081
}
1082
1083
ImGui::SeparatorText("Custom");
1084
1085
HelpMarker(
1086
"Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() is the preferred way to standardize"
1087
"tooltip activation details across your application. You may however decide to use custom"
1088
"flags for a specific tooltip instance.");
1089
1090
// The following examples are passed for documentation purpose but may not be useful to most users.
1091
// Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() will pull ImGuiHoveredFlags flags values from
1092
// 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' depending on whether mouse or keyboard/gamepad is being used.
1093
// With default settings, ImGuiHoveredFlags_ForTooltip is equivalent to ImGuiHoveredFlags_DelayShort + ImGuiHoveredFlags_Stationary.
1094
ImGui::Button("Manual", sz);
1095
if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip))
1096
ImGui::SetTooltip("I am a manually emitted tooltip.");
1097
1098
ImGui::Button("DelayNone", sz);
1099
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNone))
1100
ImGui::SetTooltip("I am a tooltip with no delay.");
1101
1102
ImGui::Button("DelayShort", sz);
1103
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort | ImGuiHoveredFlags_NoSharedDelay))
1104
ImGui::SetTooltip("I am a tooltip with a short delay (%0.2f sec).", ImGui::GetStyle().HoverDelayShort);
1105
1106
ImGui::Button("DelayLong", sz);
1107
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal | ImGuiHoveredFlags_NoSharedDelay))
1108
ImGui::SetTooltip("I am a tooltip with a long delay (%0.2f sec).", ImGui::GetStyle().HoverDelayNormal);
1109
1110
ImGui::Button("Stationary", sz);
1111
if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary))
1112
ImGui::SetTooltip("I am a tooltip requiring mouse to be stationary before activating.");
1113
1114
// Using ImGuiHoveredFlags_ForTooltip will pull flags from 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav',
1115
// which default value include the ImGuiHoveredFlags_AllowWhenDisabled flag.
1116
ImGui::BeginDisabled();
1117
ImGui::Button("Disabled item", sz);
1118
if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip))
1119
ImGui::SetTooltip("I am a a tooltip for a disabled item.");
1120
ImGui::EndDisabled();
1121
1122
ImGui::TreePop();
1123
}
1124
1125
// Testing ImGuiOnceUponAFrame helper.
1126
//static ImGuiOnceUponAFrame once;
1127
//for (int i = 0; i < 5; i++)
1128
// if (once)
1129
// ImGui::Text("This will be displayed only once.");
1130
1131
IMGUI_DEMO_MARKER("Widgets/Tree Nodes");
1132
if (ImGui::TreeNode("Tree Nodes"))
1133
{
1134
IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Basic trees");
1135
if (ImGui::TreeNode("Basic trees"))
1136
{
1137
for (int i = 0; i < 5; i++)
1138
{
1139
// Use SetNextItemOpen() so set the default state of a node to be open. We could
1140
// also use TreeNodeEx() with the ImGuiTreeNodeFlags_DefaultOpen flag to achieve the same thing!
1141
if (i == 0)
1142
ImGui::SetNextItemOpen(true, ImGuiCond_Once);
1143
1144
// Here we use PushID() to generate a unique base ID, and then the "" used as TreeNode id won't conflict.
1145
// An alternative to using 'PushID() + TreeNode("", ...)' to generate a unique ID is to use 'TreeNode((void*)(intptr_t)i, ...)',
1146
// aka generate a dummy pointer-sized value to be hashed. The demo below uses that technique. Both are fine.
1147
ImGui::PushID(i);
1148
if (ImGui::TreeNode("", "Child %d", i))
1149
{
1150
ImGui::Text("blah blah");
1151
ImGui::SameLine();
1152
if (ImGui::SmallButton("button")) {}
1153
ImGui::TreePop();
1154
}
1155
ImGui::PopID();
1156
}
1157
ImGui::TreePop();
1158
}
1159
1160
IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Advanced, with Selectable nodes");
1161
if (ImGui::TreeNode("Advanced, with Selectable nodes"))
1162
{
1163
HelpMarker(
1164
"This is a more typical looking tree with selectable nodes.\n"
1165
"Click to select, CTRL+Click to toggle, click on arrows or double-click to open.");
1166
static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth;
1167
static bool align_label_with_current_x_position = false;
1168
static bool test_drag_and_drop = false;
1169
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnArrow", &base_flags, ImGuiTreeNodeFlags_OpenOnArrow);
1170
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", &base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick);
1171
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.");
1172
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &base_flags, ImGuiTreeNodeFlags_SpanFullWidth);
1173
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanTextWidth", &base_flags, ImGuiTreeNodeFlags_SpanTextWidth); ImGui::SameLine(); HelpMarker("Reduce hit area to the text label and a bit of margin.");
1174
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &base_flags, ImGuiTreeNodeFlags_SpanAllColumns); ImGui::SameLine(); HelpMarker("For use in Tables only.");
1175
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_AllowOverlap", &base_flags, ImGuiTreeNodeFlags_AllowOverlap);
1176
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_Framed", &base_flags, ImGuiTreeNodeFlags_Framed); ImGui::SameLine(); HelpMarker("Draw frame with background (e.g. for CollapsingHeader)");
1177
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_NavLeftJumpsBackHere", &base_flags, ImGuiTreeNodeFlags_NavLeftJumpsBackHere);
1178
ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position);
1179
ImGui::Checkbox("Test tree node as drag source", &test_drag_and_drop);
1180
ImGui::Text("Hello!");
1181
if (align_label_with_current_x_position)
1182
ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing());
1183
1184
// 'selection_mask' is dumb representation of what may be user-side selection state.
1185
// You may retain selection state inside or outside your objects in whatever format you see fit.
1186
// 'node_clicked' is temporary storage of what node we have clicked to process selection at the end
1187
/// of the loop. May be a pointer to your own node type, etc.
1188
static int selection_mask = (1 << 2);
1189
int node_clicked = -1;
1190
for (int i = 0; i < 6; i++)
1191
{
1192
// Disable the default "open on single-click behavior" + set Selected flag according to our selection.
1193
// To alter selection we use IsItemClicked() && !IsItemToggledOpen(), so clicking on an arrow doesn't alter selection.
1194
ImGuiTreeNodeFlags node_flags = base_flags;
1195
const bool is_selected = (selection_mask & (1 << i)) != 0;
1196
if (is_selected)
1197
node_flags |= ImGuiTreeNodeFlags_Selected;
1198
if (i < 3)
1199
{
1200
// Items 0..2 are Tree Node
1201
bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Node %d", i);
1202
if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen())
1203
node_clicked = i;
1204
if (test_drag_and_drop && ImGui::BeginDragDropSource())
1205
{
1206
ImGui::SetDragDropPayload("_TREENODE", NULL, 0);
1207
ImGui::Text("This is a drag and drop source");
1208
ImGui::EndDragDropSource();
1209
}
1210
if (i == 2 && (base_flags & ImGuiTreeNodeFlags_SpanTextWidth))
1211
{
1212
// Item 2 has an additional inline button to help demonstrate SpanTextWidth.
1213
ImGui::SameLine();
1214
if (ImGui::SmallButton("button")) {}
1215
}
1216
if (node_open)
1217
{
1218
ImGui::BulletText("Blah blah\nBlah Blah");
1219
ImGui::SameLine();
1220
ImGui::SmallButton("Button");
1221
ImGui::TreePop();
1222
}
1223
}
1224
else
1225
{
1226
// Items 3..5 are Tree Leaves
1227
// The only reason we use TreeNode at all is to allow selection of the leaf. Otherwise we can
1228
// use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text().
1229
node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet
1230
ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i);
1231
if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen())
1232
node_clicked = i;
1233
if (test_drag_and_drop && ImGui::BeginDragDropSource())
1234
{
1235
ImGui::SetDragDropPayload("_TREENODE", NULL, 0);
1236
ImGui::Text("This is a drag and drop source");
1237
ImGui::EndDragDropSource();
1238
}
1239
}
1240
}
1241
if (node_clicked != -1)
1242
{
1243
// Update selection state
1244
// (process outside of tree loop to avoid visual inconsistencies during the clicking frame)
1245
if (ImGui::GetIO().KeyCtrl)
1246
selection_mask ^= (1 << node_clicked); // CTRL+click to toggle
1247
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
1248
selection_mask = (1 << node_clicked); // Click to single-select
1249
}
1250
if (align_label_with_current_x_position)
1251
ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing());
1252
ImGui::TreePop();
1253
}
1254
ImGui::TreePop();
1255
}
1256
1257
IMGUI_DEMO_MARKER("Widgets/Collapsing Headers");
1258
if (ImGui::TreeNode("Collapsing Headers"))
1259
{
1260
static bool closable_group = true;
1261
ImGui::Checkbox("Show 2nd header", &closable_group);
1262
if (ImGui::CollapsingHeader("Header", ImGuiTreeNodeFlags_None))
1263
{
1264
ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
1265
for (int i = 0; i < 5; i++)
1266
ImGui::Text("Some content %d", i);
1267
}
1268
if (ImGui::CollapsingHeader("Header with a close button", &closable_group))
1269
{
1270
ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
1271
for (int i = 0; i < 5; i++)
1272
ImGui::Text("More content %d", i);
1273
}
1274
/*
1275
if (ImGui::CollapsingHeader("Header with a bullet", ImGuiTreeNodeFlags_Bullet))
1276
ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
1277
*/
1278
ImGui::TreePop();
1279
}
1280
1281
IMGUI_DEMO_MARKER("Widgets/Bullets");
1282
if (ImGui::TreeNode("Bullets"))
1283
{
1284
ImGui::BulletText("Bullet point 1");
1285
ImGui::BulletText("Bullet point 2\nOn multiple lines");
1286
if (ImGui::TreeNode("Tree node"))
1287
{
1288
ImGui::BulletText("Another bullet point");
1289
ImGui::TreePop();
1290
}
1291
ImGui::Bullet(); ImGui::Text("Bullet point 3 (two calls)");
1292
ImGui::Bullet(); ImGui::SmallButton("Button");
1293
ImGui::TreePop();
1294
}
1295
1296
IMGUI_DEMO_MARKER("Widgets/Text");
1297
if (ImGui::TreeNode("Text"))
1298
{
1299
IMGUI_DEMO_MARKER("Widgets/Text/Colored Text");
1300
if (ImGui::TreeNode("Colorful Text"))
1301
{
1302
// Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility.
1303
ImGui::TextColored(ImVec4(1.0f, 0.0f, 1.0f, 1.0f), "Pink");
1304
ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Yellow");
1305
ImGui::TextDisabled("Disabled");
1306
ImGui::SameLine(); HelpMarker("The TextDisabled color is stored in ImGuiStyle.");
1307
ImGui::TreePop();
1308
}
1309
1310
IMGUI_DEMO_MARKER("Widgets/Text/Word Wrapping");
1311
if (ImGui::TreeNode("Word Wrapping"))
1312
{
1313
// Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility.
1314
ImGui::TextWrapped(
1315
"This text should automatically wrap on the edge of the window. The current implementation "
1316
"for text wrapping follows simple rules suitable for English and possibly other languages.");
1317
ImGui::Spacing();
1318
1319
static float wrap_width = 200.0f;
1320
ImGui::SliderFloat("Wrap width", &wrap_width, -20, 600, "%.0f");
1321
1322
ImDrawList* draw_list = ImGui::GetWindowDrawList();
1323
for (int n = 0; n < 2; n++)
1324
{
1325
ImGui::Text("Test paragraph %d:", n);
1326
ImVec2 pos = ImGui::GetCursorScreenPos();
1327
ImVec2 marker_min = ImVec2(pos.x + wrap_width, pos.y);
1328
ImVec2 marker_max = ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight());
1329
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width);
1330
if (n == 0)
1331
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);
1332
else
1333
ImGui::Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh");
1334
1335
// Draw actual text bounding box, following by marker of our expected limit (should not overlap!)
1336
draw_list->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 255, 0, 255));
1337
draw_list->AddRectFilled(marker_min, marker_max, IM_COL32(255, 0, 255, 255));
1338
ImGui::PopTextWrapPos();
1339
}
1340
1341
ImGui::TreePop();
1342
}
1343
1344
IMGUI_DEMO_MARKER("Widgets/Text/UTF-8 Text");
1345
if (ImGui::TreeNode("UTF-8 Text"))
1346
{
1347
// UTF-8 test with Japanese characters
1348
// (Needs a suitable font? Try "Google Noto" or "Arial Unicode". See docs/FONTS.md for details.)
1349
// - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8
1350
// - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. in Visual Studio, you
1351
// can save your source files as 'UTF-8 without signature').
1352
// - FOR THIS DEMO FILE ONLY, BECAUSE WE WANT TO SUPPORT OLD COMPILERS, WE ARE *NOT* INCLUDING RAW UTF-8
1353
// CHARACTERS IN THIS SOURCE FILE. Instead we are encoding a few strings with hexadecimal constants.
1354
// Don't do this in your application! Please use u8"text in any language" in your application!
1355
// Note that characters values are preserved even by InputText() if the font cannot be displayed,
1356
// so you can safely copy & paste garbled characters into another application.
1357
ImGui::TextWrapped(
1358
"CJK text will only appear if the font was loaded with the appropriate CJK character ranges. "
1359
"Call io.Fonts->AddFontFromFileTTF() manually to load extra character ranges. "
1360
"Read docs/FONTS.md for details.");
1361
ImGui::Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)");
1362
ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)");
1363
static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e";
1364
//static char buf[32] = u8"NIHONGO"; // <- this is how you would write it with C++11, using real kanjis
1365
ImGui::InputText("UTF-8 input", buf, IM_ARRAYSIZE(buf));
1366
ImGui::TreePop();
1367
}
1368
ImGui::TreePop();
1369
}
1370
1371
IMGUI_DEMO_MARKER("Widgets/Images");
1372
if (ImGui::TreeNode("Images"))
1373
{
1374
ImGuiIO& io = ImGui::GetIO();
1375
ImGui::TextWrapped(
1376
"Below we are displaying the font texture (which is the only texture we have access to in this demo). "
1377
"Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. "
1378
"Hover the texture for a zoomed view!");
1379
1380
// Below we are displaying the font texture because it is the only texture we have access to inside the demo!
1381
// Remember that ImTextureID is just storage for whatever you want it to be. It is essentially a value that
1382
// will be passed to the rendering backend via the ImDrawCmd structure.
1383
// If you use one of the default imgui_impl_XXXX.cpp rendering backend, they all have comments at the top
1384
// of their respective source file to specify what they expect to be stored in ImTextureID, for example:
1385
// - The imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer
1386
// - The imgui_impl_opengl3.cpp renderer expect a GLuint OpenGL texture identifier, etc.
1387
// More:
1388
// - If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers
1389
// to ImGui::Image(), and gather width/height through your own functions, etc.
1390
// - You can use ShowMetricsWindow() to inspect the draw data that are being passed to your renderer,
1391
// it will help you debug issues if you are confused about it.
1392
// - Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage().
1393
// - Read https://github.com/ocornut/imgui/blob/master/docs/FAQ.md
1394
// - Read https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
1395
ImTextureID my_tex_id = io.Fonts->TexID;
1396
float my_tex_w = (float)io.Fonts->TexWidth;
1397
float my_tex_h = (float)io.Fonts->TexHeight;
1398
{
1399
static bool use_text_color_for_tint = false;
1400
ImGui::Checkbox("Use Text Color for Tint", &use_text_color_for_tint);
1401
ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h);
1402
ImVec2 pos = ImGui::GetCursorScreenPos();
1403
ImVec2 uv_min = ImVec2(0.0f, 0.0f); // Top-left
1404
ImVec2 uv_max = ImVec2(1.0f, 1.0f); // Lower-right
1405
ImVec4 tint_col = use_text_color_for_tint ? ImGui::GetStyleColorVec4(ImGuiCol_Text) : ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint
1406
ImVec4 border_col = ImGui::GetStyleColorVec4(ImGuiCol_Border);
1407
ImGui::Image(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, tint_col, border_col);
1408
if (ImGui::BeginItemTooltip())
1409
{
1410
float region_sz = 32.0f;
1411
float region_x = io.MousePos.x - pos.x - region_sz * 0.5f;
1412
float region_y = io.MousePos.y - pos.y - region_sz * 0.5f;
1413
float zoom = 4.0f;
1414
if (region_x < 0.0f) { region_x = 0.0f; }
1415
else if (region_x > my_tex_w - region_sz) { region_x = my_tex_w - region_sz; }
1416
if (region_y < 0.0f) { region_y = 0.0f; }
1417
else if (region_y > my_tex_h - region_sz) { region_y = my_tex_h - region_sz; }
1418
ImGui::Text("Min: (%.2f, %.2f)", region_x, region_y);
1419
ImGui::Text("Max: (%.2f, %.2f)", region_x + region_sz, region_y + region_sz);
1420
ImVec2 uv0 = ImVec2((region_x) / my_tex_w, (region_y) / my_tex_h);
1421
ImVec2 uv1 = ImVec2((region_x + region_sz) / my_tex_w, (region_y + region_sz) / my_tex_h);
1422
ImGui::Image(my_tex_id, ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, tint_col, border_col);
1423
ImGui::EndTooltip();
1424
}
1425
}
1426
1427
IMGUI_DEMO_MARKER("Widgets/Images/Textured buttons");
1428
ImGui::TextWrapped("And now some textured buttons..");
1429
static int pressed_count = 0;
1430
for (int i = 0; i < 8; i++)
1431
{
1432
// UV coordinates are often (0.0f, 0.0f) and (1.0f, 1.0f) to display an entire textures.
1433
// Here are trying to display only a 32x32 pixels area of the texture, hence the UV computation.
1434
// Read about UV coordinates here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
1435
ImGui::PushID(i);
1436
if (i > 0)
1437
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(i - 1.0f, i - 1.0f));
1438
ImVec2 size = ImVec2(32.0f, 32.0f); // Size of the image we want to make visible
1439
ImVec2 uv0 = ImVec2(0.0f, 0.0f); // UV coordinates for lower-left
1440
ImVec2 uv1 = ImVec2(32.0f / my_tex_w, 32.0f / my_tex_h); // UV coordinates for (32,32) in our texture
1441
ImVec4 bg_col = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); // Black background
1442
ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint
1443
if (ImGui::ImageButton("", my_tex_id, size, uv0, uv1, bg_col, tint_col))
1444
pressed_count += 1;
1445
if (i > 0)
1446
ImGui::PopStyleVar();
1447
ImGui::PopID();
1448
ImGui::SameLine();
1449
}
1450
ImGui::NewLine();
1451
ImGui::Text("Pressed %d times.", pressed_count);
1452
ImGui::TreePop();
1453
}
1454
1455
IMGUI_DEMO_MARKER("Widgets/Combo");
1456
if (ImGui::TreeNode("Combo"))
1457
{
1458
// Combo Boxes are also called "Dropdown" in other systems
1459
// Expose flags as checkbox for the demo
1460
static ImGuiComboFlags flags = 0;
1461
ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", &flags, ImGuiComboFlags_PopupAlignLeft);
1462
ImGui::SameLine(); HelpMarker("Only makes a difference if the popup is larger than the combo");
1463
if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", &flags, ImGuiComboFlags_NoArrowButton))
1464
flags &= ~ImGuiComboFlags_NoPreview; // Clear incompatible flags
1465
if (ImGui::CheckboxFlags("ImGuiComboFlags_NoPreview", &flags, ImGuiComboFlags_NoPreview))
1466
flags &= ~(ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_WidthFitPreview); // Clear incompatible flags
1467
if (ImGui::CheckboxFlags("ImGuiComboFlags_WidthFitPreview", &flags, ImGuiComboFlags_WidthFitPreview))
1468
flags &= ~ImGuiComboFlags_NoPreview;
1469
1470
// Override default popup height
1471
if (ImGui::CheckboxFlags("ImGuiComboFlags_HeightSmall", &flags, ImGuiComboFlags_HeightSmall))
1472
flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightSmall);
1473
if (ImGui::CheckboxFlags("ImGuiComboFlags_HeightRegular", &flags, ImGuiComboFlags_HeightRegular))
1474
flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightRegular);
1475
if (ImGui::CheckboxFlags("ImGuiComboFlags_HeightLargest", &flags, ImGuiComboFlags_HeightLargest))
1476
flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightLargest);
1477
1478
// Using the generic BeginCombo() API, you have full control over how to display the combo contents.
1479
// (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
1480
// stored in the object itself, etc.)
1481
const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" };
1482
static int item_selected_idx = 0; // Here we store our selection data as an index.
1483
1484
// Pass in the preview value visible before opening the combo (it could technically be different contents or not pulled from items[])
1485
const char* combo_preview_value = items[item_selected_idx];
1486
1487
if (ImGui::BeginCombo("combo 1", combo_preview_value, flags))
1488
{
1489
for (int n = 0; n < IM_ARRAYSIZE(items); n++)
1490
{
1491
const bool is_selected = (item_selected_idx == n);
1492
if (ImGui::Selectable(items[n], is_selected))
1493
item_selected_idx = n;
1494
1495
// Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
1496
if (is_selected)
1497
ImGui::SetItemDefaultFocus();
1498
}
1499
ImGui::EndCombo();
1500
}
1501
1502
ImGui::Spacing();
1503
ImGui::SeparatorText("One-liner variants");
1504
HelpMarker("Flags above don't apply to this section.");
1505
1506
// Simplified one-liner Combo() API, using values packed in a single constant string
1507
// This is a convenience for when the selection set is small and known at compile-time.
1508
static int item_current_2 = 0;
1509
ImGui::Combo("combo 2 (one-liner)", &item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
1510
1511
// Simplified one-liner Combo() using an array of const char*
1512
// This is not very useful (may obsolete): prefer using BeginCombo()/EndCombo() for full control.
1513
static int item_current_3 = -1; // If the selection isn't within 0..count, Combo won't display a preview
1514
ImGui::Combo("combo 3 (array)", &item_current_3, items, IM_ARRAYSIZE(items));
1515
1516
// Simplified one-liner Combo() using an accessor function
1517
static int item_current_4 = 0;
1518
ImGui::Combo("combo 4 (function)", &item_current_4, [](void* data, int n) { return ((const char**)data)[n]; }, items, IM_ARRAYSIZE(items));
1519
1520
ImGui::TreePop();
1521
}
1522
1523
IMGUI_DEMO_MARKER("Widgets/List Boxes");
1524
if (ImGui::TreeNode("List boxes"))
1525
{
1526
// BeginListBox() is essentially a thin wrapper to using BeginChild()/EndChild()
1527
// using the ImGuiChildFlags_FrameStyle flag for stylistic changes + displaying a label.
1528
// You may be tempted to simply use BeginChild() directly. However note that BeginChild() requires EndChild()
1529
// to always be called (inconsistent with BeginListBox()/EndListBox()).
1530
1531
// Using the generic BeginListBox() API, you have full control over how to display the combo contents.
1532
// (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
1533
// stored in the object itself, etc.)
1534
const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" };
1535
static int item_selected_idx = 0; // Here we store our selected data as an index.
1536
1537
static bool item_highlight = false;
1538
int item_highlighted_idx = -1; // Here we store our highlighted data as an index.
1539
ImGui::Checkbox("Highlight hovered item in second listbox", &item_highlight);
1540
1541
if (ImGui::BeginListBox("listbox 1"))
1542
{
1543
for (int n = 0; n < IM_ARRAYSIZE(items); n++)
1544
{
1545
const bool is_selected = (item_selected_idx == n);
1546
if (ImGui::Selectable(items[n], is_selected))
1547
item_selected_idx = n;
1548
1549
if (item_highlight && ImGui::IsItemHovered())
1550
item_highlighted_idx = n;
1551
1552
// Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
1553
if (is_selected)
1554
ImGui::SetItemDefaultFocus();
1555
}
1556
ImGui::EndListBox();
1557
}
1558
ImGui::SameLine(); HelpMarker("Here we are sharing selection state between both boxes.");
1559
1560
// Custom size: use all width, 5 items tall
1561
ImGui::Text("Full-width:");
1562
if (ImGui::BeginListBox("##listbox 2", ImVec2(-FLT_MIN, 5 * ImGui::GetTextLineHeightWithSpacing())))
1563
{
1564
for (int n = 0; n < IM_ARRAYSIZE(items); n++)
1565
{
1566
bool is_selected = (item_selected_idx == n);
1567
ImGuiSelectableFlags flags = (item_highlighted_idx == n) ? ImGuiSelectableFlags_Highlight : 0;
1568
if (ImGui::Selectable(items[n], is_selected, flags))
1569
item_selected_idx = n;
1570
1571
// Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
1572
if (is_selected)
1573
ImGui::SetItemDefaultFocus();
1574
}
1575
ImGui::EndListBox();
1576
}
1577
1578
ImGui::TreePop();
1579
}
1580
1581
IMGUI_DEMO_MARKER("Widgets/Selectables");
1582
//ImGui::SetNextItemOpen(true, ImGuiCond_Once);
1583
if (ImGui::TreeNode("Selectables"))
1584
{
1585
// Selectable() has 2 overloads:
1586
// - The one taking "bool selected" as a read-only selection information.
1587
// When Selectable() has been clicked it returns true and you can alter selection state accordingly.
1588
// - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases)
1589
// The earlier is more flexible, as in real application your selection may be stored in many different ways
1590
// and not necessarily inside a bool value (e.g. in flags within objects, as an external list, etc).
1591
IMGUI_DEMO_MARKER("Widgets/Selectables/Basic");
1592
if (ImGui::TreeNode("Basic"))
1593
{
1594
static bool selection[5] = { false, true, false, false };
1595
ImGui::Selectable("1. I am selectable", &selection[0]);
1596
ImGui::Selectable("2. I am selectable", &selection[1]);
1597
ImGui::Selectable("3. I am selectable", &selection[2]);
1598
if (ImGui::Selectable("4. I am double clickable", selection[3], ImGuiSelectableFlags_AllowDoubleClick))
1599
if (ImGui::IsMouseDoubleClicked(0))
1600
selection[3] = !selection[3];
1601
ImGui::TreePop();
1602
}
1603
1604
IMGUI_DEMO_MARKER("Widgets/Selectables/Rendering more items on the same line");
1605
if (ImGui::TreeNode("Rendering more items on the same line"))
1606
{
1607
// (1) Using SetNextItemAllowOverlap()
1608
// (2) Using the Selectable() override that takes "bool* p_selected" parameter, the bool value is toggled automatically.
1609
static bool selected[3] = { false, false, false };
1610
ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("main.c", &selected[0]); ImGui::SameLine(); ImGui::SmallButton("Link 1");
1611
ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("Hello.cpp", &selected[1]); ImGui::SameLine(); ImGui::SmallButton("Link 2");
1612
ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("Hello.h", &selected[2]); ImGui::SameLine(); ImGui::SmallButton("Link 3");
1613
ImGui::TreePop();
1614
}
1615
1616
IMGUI_DEMO_MARKER("Widgets/Selectables/In Tables");
1617
if (ImGui::TreeNode("In Tables"))
1618
{
1619
static bool selected[10] = {};
1620
1621
if (ImGui::BeginTable("split1", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders))
1622
{
1623
for (int i = 0; i < 10; i++)
1624
{
1625
char label[32];
1626
sprintf(label, "Item %d", i);
1627
ImGui::TableNextColumn();
1628
ImGui::Selectable(label, &selected[i]); // FIXME-TABLE: Selection overlap
1629
}
1630
ImGui::EndTable();
1631
}
1632
ImGui::Spacing();
1633
if (ImGui::BeginTable("split2", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders))
1634
{
1635
for (int i = 0; i < 10; i++)
1636
{
1637
char label[32];
1638
sprintf(label, "Item %d", i);
1639
ImGui::TableNextRow();
1640
ImGui::TableNextColumn();
1641
ImGui::Selectable(label, &selected[i], ImGuiSelectableFlags_SpanAllColumns);
1642
ImGui::TableNextColumn();
1643
ImGui::Text("Some other contents");
1644
ImGui::TableNextColumn();
1645
ImGui::Text("123456");
1646
}
1647
ImGui::EndTable();
1648
}
1649
ImGui::TreePop();
1650
}
1651
1652
IMGUI_DEMO_MARKER("Widgets/Selectables/Grid");
1653
if (ImGui::TreeNode("Grid"))
1654
{
1655
static char selected[4][4] = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } };
1656
1657
// Add in a bit of silly fun...
1658
const float time = (float)ImGui::GetTime();
1659
const bool winning_state = memchr(selected, 0, sizeof(selected)) == NULL; // If all cells are selected...
1660
if (winning_state)
1661
ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f + 0.5f * cosf(time * 2.0f), 0.5f + 0.5f * sinf(time * 3.0f)));
1662
1663
for (int y = 0; y < 4; y++)
1664
for (int x = 0; x < 4; x++)
1665
{
1666
if (x > 0)
1667
ImGui::SameLine();
1668
ImGui::PushID(y * 4 + x);
1669
if (ImGui::Selectable("Sailor", selected[y][x] != 0, 0, ImVec2(50, 50)))
1670
{
1671
// Toggle clicked cell + toggle neighbors
1672
selected[y][x] ^= 1;
1673
if (x > 0) { selected[y][x - 1] ^= 1; }
1674
if (x < 3) { selected[y][x + 1] ^= 1; }
1675
if (y > 0) { selected[y - 1][x] ^= 1; }
1676
if (y < 3) { selected[y + 1][x] ^= 1; }
1677
}
1678
ImGui::PopID();
1679
}
1680
1681
if (winning_state)
1682
ImGui::PopStyleVar();
1683
ImGui::TreePop();
1684
}
1685
IMGUI_DEMO_MARKER("Widgets/Selectables/Alignment");
1686
if (ImGui::TreeNode("Alignment"))
1687
{
1688
HelpMarker(
1689
"By default, Selectables uses style.SelectableTextAlign but it can be overridden on a per-item "
1690
"basis using PushStyleVar(). You'll probably want to always keep your default situation to "
1691
"left-align otherwise it becomes difficult to layout multiple items on a same line");
1692
static bool selected[3 * 3] = { true, false, true, false, true, false, true, false, true };
1693
for (int y = 0; y < 3; y++)
1694
{
1695
for (int x = 0; x < 3; x++)
1696
{
1697
ImVec2 alignment = ImVec2((float)x / 2.0f, (float)y / 2.0f);
1698
char name[32];
1699
sprintf(name, "(%.1f,%.1f)", alignment.x, alignment.y);
1700
if (x > 0) ImGui::SameLine();
1701
ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, alignment);
1702
ImGui::Selectable(name, &selected[3 * y + x], ImGuiSelectableFlags_None, ImVec2(80, 80));
1703
ImGui::PopStyleVar();
1704
}
1705
}
1706
ImGui::TreePop();
1707
}
1708
ImGui::TreePop();
1709
}
1710
1711
ShowDemoWindowMultiSelect(demo_data);
1712
1713
// To wire InputText() with std::string or any other custom string type,
1714
// see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file.
1715
IMGUI_DEMO_MARKER("Widgets/Text Input");
1716
if (ImGui::TreeNode("Text Input"))
1717
{
1718
IMGUI_DEMO_MARKER("Widgets/Text Input/Multi-line Text Input");
1719
if (ImGui::TreeNode("Multi-line Text Input"))
1720
{
1721
// Note: we are using a fixed-sized buffer for simplicity here. See ImGuiInputTextFlags_CallbackResize
1722
// and the code in misc/cpp/imgui_stdlib.h for how to setup InputText() for dynamically resizing strings.
1723
static char text[1024 * 16] =
1724
"/*\n"
1725
" The Pentium F00F bug, shorthand for F0 0F C7 C8,\n"
1726
" the hexadecimal encoding of one offending instruction,\n"
1727
" more formally, the invalid operand with locked CMPXCHG8B\n"
1728
" instruction bug, is a design flaw in the majority of\n"
1729
" Intel Pentium, Pentium MMX, and Pentium OverDrive\n"
1730
" processors (all in the P5 microarchitecture).\n"
1731
"*/\n\n"
1732
"label:\n"
1733
"\tlock cmpxchg8b eax\n";
1734
1735
static ImGuiInputTextFlags flags = ImGuiInputTextFlags_AllowTabInput;
1736
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)");
1737
ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly);
1738
ImGui::CheckboxFlags("ImGuiInputTextFlags_AllowTabInput", &flags, ImGuiInputTextFlags_AllowTabInput);
1739
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.");
1740
ImGui::CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", &flags, ImGuiInputTextFlags_CtrlEnterForNewLine);
1741
ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16), flags);
1742
ImGui::TreePop();
1743
}
1744
1745
IMGUI_DEMO_MARKER("Widgets/Text Input/Filtered Text Input");
1746
if (ImGui::TreeNode("Filtered Text Input"))
1747
{
1748
struct TextFilters
1749
{
1750
// Modify character input by altering 'data->Eventchar' (ImGuiInputTextFlags_CallbackCharFilter callback)
1751
static int FilterCasingSwap(ImGuiInputTextCallbackData* data)
1752
{
1753
if (data->EventChar >= 'a' && data->EventChar <= 'z') { data->EventChar -= 'a' - 'A'; } // Lowercase becomes uppercase
1754
else if (data->EventChar >= 'A' && data->EventChar <= 'Z') { data->EventChar += 'a' - 'A'; } // Uppercase becomes lowercase
1755
return 0;
1756
}
1757
1758
// Return 0 (pass) if the character is 'i' or 'm' or 'g' or 'u' or 'i', otherwise return 1 (filter out)
1759
static int FilterImGuiLetters(ImGuiInputTextCallbackData* data)
1760
{
1761
if (data->EventChar < 256 && strchr("imgui", (char)data->EventChar))
1762
return 0;
1763
return 1;
1764
}
1765
};
1766
1767
static char buf1[32] = ""; ImGui::InputText("default", buf1, 32);
1768
static char buf2[32] = ""; ImGui::InputText("decimal", buf2, 32, ImGuiInputTextFlags_CharsDecimal);
1769
static char buf3[32] = ""; ImGui::InputText("hexadecimal", buf3, 32, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase);
1770
static char buf4[32] = ""; ImGui::InputText("uppercase", buf4, 32, ImGuiInputTextFlags_CharsUppercase);
1771
static char buf5[32] = ""; ImGui::InputText("no blank", buf5, 32, ImGuiInputTextFlags_CharsNoBlank);
1772
static char buf6[32] = ""; ImGui::InputText("casing swap", buf6, 32, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterCasingSwap); // Use CharFilter callback to replace characters.
1773
static char buf7[32] = ""; ImGui::InputText("\"imgui\"", buf7, 32, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters); // Use CharFilter callback to disable some characters.
1774
ImGui::TreePop();
1775
}
1776
1777
IMGUI_DEMO_MARKER("Widgets/Text Input/Password input");
1778
if (ImGui::TreeNode("Password Input"))
1779
{
1780
static char password[64] = "password123";
1781
ImGui::InputText("password", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password);
1782
ImGui::SameLine(); HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n");
1783
ImGui::InputTextWithHint("password (w/ hint)", "<password>", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password);
1784
ImGui::InputText("password (clear)", password, IM_ARRAYSIZE(password));
1785
ImGui::TreePop();
1786
}
1787
1788
IMGUI_DEMO_MARKER("Widgets/Text Input/Completion, History, Edit Callbacks");
1789
if (ImGui::TreeNode("Completion, History, Edit Callbacks"))
1790
{
1791
struct Funcs
1792
{
1793
static int MyCallback(ImGuiInputTextCallbackData* data)
1794
{
1795
if (data->EventFlag == ImGuiInputTextFlags_CallbackCompletion)
1796
{
1797
data->InsertChars(data->CursorPos, "..");
1798
}
1799
else if (data->EventFlag == ImGuiInputTextFlags_CallbackHistory)
1800
{
1801
if (data->EventKey == ImGuiKey_UpArrow)
1802
{
1803
data->DeleteChars(0, data->BufTextLen);
1804
data->InsertChars(0, "Pressed Up!");
1805
data->SelectAll();
1806
}
1807
else if (data->EventKey == ImGuiKey_DownArrow)
1808
{
1809
data->DeleteChars(0, data->BufTextLen);
1810
data->InsertChars(0, "Pressed Down!");
1811
data->SelectAll();
1812
}
1813
}
1814
else if (data->EventFlag == ImGuiInputTextFlags_CallbackEdit)
1815
{
1816
// Toggle casing of first character
1817
char c = data->Buf[0];
1818
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) data->Buf[0] ^= 32;
1819
data->BufDirty = true;
1820
1821
// Increment a counter
1822
int* p_int = (int*)data->UserData;
1823
*p_int = *p_int + 1;
1824
}
1825
return 0;
1826
}
1827
};
1828
static char buf1[64];
1829
ImGui::InputText("Completion", buf1, 64, ImGuiInputTextFlags_CallbackCompletion, Funcs::MyCallback);
1830
ImGui::SameLine(); HelpMarker(
1831
"Here we append \"..\" each time Tab is pressed. "
1832
"See 'Examples>Console' for a more meaningful demonstration of using this callback.");
1833
1834
static char buf2[64];
1835
ImGui::InputText("History", buf2, 64, ImGuiInputTextFlags_CallbackHistory, Funcs::MyCallback);
1836
ImGui::SameLine(); HelpMarker(
1837
"Here we replace and select text each time Up/Down are pressed. "
1838
"See 'Examples>Console' for a more meaningful demonstration of using this callback.");
1839
1840
static char buf3[64];
1841
static int edit_count = 0;
1842
ImGui::InputText("Edit", buf3, 64, ImGuiInputTextFlags_CallbackEdit, Funcs::MyCallback, (void*)&edit_count);
1843
ImGui::SameLine(); HelpMarker(
1844
"Here we toggle the casing of the first character on every edit + count edits.");
1845
ImGui::SameLine(); ImGui::Text("(%d)", edit_count);
1846
1847
ImGui::TreePop();
1848
}
1849
1850
IMGUI_DEMO_MARKER("Widgets/Text Input/Resize Callback");
1851
if (ImGui::TreeNode("Resize Callback"))
1852
{
1853
// To wire InputText() with std::string or any other custom string type,
1854
// you can use the ImGuiInputTextFlags_CallbackResize flag + create a custom ImGui::InputText() wrapper
1855
// using your preferred type. See misc/cpp/imgui_stdlib.h for an implementation of this using std::string.
1856
HelpMarker(
1857
"Using ImGuiInputTextFlags_CallbackResize to wire your custom string type to InputText().\n\n"
1858
"See misc/cpp/imgui_stdlib.h for an implementation of this for std::string.");
1859
struct Funcs
1860
{
1861
static int MyResizeCallback(ImGuiInputTextCallbackData* data)
1862
{
1863
if (data->EventFlag == ImGuiInputTextFlags_CallbackResize)
1864
{
1865
ImVector<char>* my_str = (ImVector<char>*)data->UserData;
1866
IM_ASSERT(my_str->begin() == data->Buf);
1867
my_str->resize(data->BufSize); // NB: On resizing calls, generally data->BufSize == data->BufTextLen + 1
1868
data->Buf = my_str->begin();
1869
}
1870
return 0;
1871
}
1872
1873
// Note: Because ImGui:: is a namespace you would typically add your own function into the namespace.
1874
// For example, you code may declare a function 'ImGui::InputText(const char* label, MyString* my_str)'
1875
static bool MyInputTextMultiline(const char* label, ImVector<char>* my_str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0)
1876
{
1877
IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
1878
return ImGui::InputTextMultiline(label, my_str->begin(), (size_t)my_str->size(), size, flags | ImGuiInputTextFlags_CallbackResize, Funcs::MyResizeCallback, (void*)my_str);
1879
}
1880
};
1881
1882
// For this demo we are using ImVector as a string container.
1883
// Note that because we need to store a terminating zero character, our size/capacity are 1 more
1884
// than usually reported by a typical string class.
1885
static ImVector<char> my_str;
1886
if (my_str.empty())
1887
my_str.push_back(0);
1888
Funcs::MyInputTextMultiline("##MyStr", &my_str, ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16));
1889
ImGui::Text("Data: %p\nSize: %d\nCapacity: %d", (void*)my_str.begin(), my_str.size(), my_str.capacity());
1890
ImGui::TreePop();
1891
}
1892
1893
IMGUI_DEMO_MARKER("Widgets/Text Input/Eliding, Alignment");
1894
if (ImGui::TreeNode("Eliding, Alignment"))
1895
{
1896
static char buf1[128] = "/path/to/some/folder/with/long/filename.cpp";
1897
static ImGuiInputTextFlags flags = ImGuiInputTextFlags_ElideLeft;
1898
ImGui::CheckboxFlags("ImGuiInputTextFlags_ElideLeft", &flags, ImGuiInputTextFlags_ElideLeft);
1899
ImGui::InputText("Path", buf1, IM_ARRAYSIZE(buf1), flags);
1900
ImGui::TreePop();
1901
}
1902
1903
IMGUI_DEMO_MARKER("Widgets/Text Input/Miscellaneous");
1904
if (ImGui::TreeNode("Miscellaneous"))
1905
{
1906
static char buf1[16];
1907
static ImGuiInputTextFlags flags = ImGuiInputTextFlags_EscapeClearsAll;
1908
ImGui::CheckboxFlags("ImGuiInputTextFlags_EscapeClearsAll", &flags, ImGuiInputTextFlags_EscapeClearsAll);
1909
ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly);
1910
ImGui::CheckboxFlags("ImGuiInputTextFlags_NoUndoRedo", &flags, ImGuiInputTextFlags_NoUndoRedo);
1911
ImGui::InputText("Hello", buf1, IM_ARRAYSIZE(buf1), flags);
1912
ImGui::TreePop();
1913
}
1914
1915
ImGui::TreePop();
1916
}
1917
1918
// Tabs
1919
IMGUI_DEMO_MARKER("Widgets/Tabs");
1920
if (ImGui::TreeNode("Tabs"))
1921
{
1922
IMGUI_DEMO_MARKER("Widgets/Tabs/Basic");
1923
if (ImGui::TreeNode("Basic"))
1924
{
1925
ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None;
1926
if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
1927
{
1928
if (ImGui::BeginTabItem("Avocado"))
1929
{
1930
ImGui::Text("This is the Avocado tab!\nblah blah blah blah blah");
1931
ImGui::EndTabItem();
1932
}
1933
if (ImGui::BeginTabItem("Broccoli"))
1934
{
1935
ImGui::Text("This is the Broccoli tab!\nblah blah blah blah blah");
1936
ImGui::EndTabItem();
1937
}
1938
if (ImGui::BeginTabItem("Cucumber"))
1939
{
1940
ImGui::Text("This is the Cucumber tab!\nblah blah blah blah blah");
1941
ImGui::EndTabItem();
1942
}
1943
ImGui::EndTabBar();
1944
}
1945
ImGui::Separator();
1946
ImGui::TreePop();
1947
}
1948
1949
IMGUI_DEMO_MARKER("Widgets/Tabs/Advanced & Close Button");
1950
if (ImGui::TreeNode("Advanced & Close Button"))
1951
{
1952
// Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0).
1953
static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable;
1954
ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", &tab_bar_flags, ImGuiTabBarFlags_Reorderable);
1955
ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", &tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs);
1956
ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton);
1957
ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", &tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton);
1958
ImGui::CheckboxFlags("ImGuiTabBarFlags_DrawSelectedOverline", &tab_bar_flags, ImGuiTabBarFlags_DrawSelectedOverline);
1959
if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0)
1960
tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_;
1961
if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown))
1962
tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown);
1963
if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll))
1964
tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll);
1965
1966
// Tab Bar
1967
ImGui::AlignTextToFramePadding();
1968
ImGui::Text("Opened:");
1969
const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" };
1970
static bool opened[4] = { true, true, true, true }; // Persistent user state
1971
for (int n = 0; n < IM_ARRAYSIZE(opened); n++)
1972
{
1973
ImGui::SameLine();
1974
ImGui::Checkbox(names[n], &opened[n]);
1975
}
1976
1977
// Passing a bool* to BeginTabItem() is similar to passing one to Begin():
1978
// the underlying bool will be set to false when the tab is closed.
1979
if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
1980
{
1981
for (int n = 0; n < IM_ARRAYSIZE(opened); n++)
1982
if (opened[n] && ImGui::BeginTabItem(names[n], &opened[n], ImGuiTabItemFlags_None))
1983
{
1984
ImGui::Text("This is the %s tab!", names[n]);
1985
if (n & 1)
1986
ImGui::Text("I am an odd tab.");
1987
ImGui::EndTabItem();
1988
}
1989
ImGui::EndTabBar();
1990
}
1991
ImGui::Separator();
1992
ImGui::TreePop();
1993
}
1994
1995
IMGUI_DEMO_MARKER("Widgets/Tabs/TabItemButton & Leading-Trailing flags");
1996
if (ImGui::TreeNode("TabItemButton & Leading/Trailing flags"))
1997
{
1998
static ImVector<int> active_tabs;
1999
static int next_tab_id = 0;
2000
if (next_tab_id == 0) // Initialize with some default tabs
2001
for (int i = 0; i < 3; i++)
2002
active_tabs.push_back(next_tab_id++);
2003
2004
// TabItemButton() and Leading/Trailing flags are distinct features which we will demo together.
2005
// (It is possible to submit regular tabs with Leading/Trailing flags, or TabItemButton tabs without Leading/Trailing flags...
2006
// but they tend to make more sense together)
2007
static bool show_leading_button = true;
2008
static bool show_trailing_button = true;
2009
ImGui::Checkbox("Show Leading TabItemButton()", &show_leading_button);
2010
ImGui::Checkbox("Show Trailing TabItemButton()", &show_trailing_button);
2011
2012
// Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs
2013
static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_FittingPolicyResizeDown;
2014
ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton);
2015
if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown))
2016
tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown);
2017
if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll))
2018
tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll);
2019
2020
if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
2021
{
2022
// Demo a Leading TabItemButton(): click the "?" button to open a menu
2023
if (show_leading_button)
2024
if (ImGui::TabItemButton("?", ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_NoTooltip))
2025
ImGui::OpenPopup("MyHelpMenu");
2026
if (ImGui::BeginPopup("MyHelpMenu"))
2027
{
2028
ImGui::Selectable("Hello!");
2029
ImGui::EndPopup();
2030
}
2031
2032
// Demo Trailing Tabs: click the "+" button to add a new tab.
2033
// (In your app you may want to use a font icon instead of the "+")
2034
// We submit it before the regular tabs, but thanks to the ImGuiTabItemFlags_Trailing flag it will always appear at the end.
2035
if (show_trailing_button)
2036
if (ImGui::TabItemButton("+", ImGuiTabItemFlags_Trailing | ImGuiTabItemFlags_NoTooltip))
2037
active_tabs.push_back(next_tab_id++); // Add new tab
2038
2039
// Submit our regular tabs
2040
for (int n = 0; n < active_tabs.Size; )
2041
{
2042
bool open = true;
2043
char name[16];
2044
snprintf(name, IM_ARRAYSIZE(name), "%04d", active_tabs[n]);
2045
if (ImGui::BeginTabItem(name, &open, ImGuiTabItemFlags_None))
2046
{
2047
ImGui::Text("This is the %s tab!", name);
2048
ImGui::EndTabItem();
2049
}
2050
2051
if (!open)
2052
active_tabs.erase(active_tabs.Data + n);
2053
else
2054
n++;
2055
}
2056
2057
ImGui::EndTabBar();
2058
}
2059
ImGui::Separator();
2060
ImGui::TreePop();
2061
}
2062
ImGui::TreePop();
2063
}
2064
2065
// Plot/Graph widgets are not very good.
2066
// Consider using a third-party library such as ImPlot: https://github.com/epezent/implot
2067
// (see others https://github.com/ocornut/imgui/wiki/Useful-Extensions)
2068
IMGUI_DEMO_MARKER("Widgets/Plotting");
2069
if (ImGui::TreeNode("Plotting"))
2070
{
2071
static bool animate = true;
2072
ImGui::Checkbox("Animate", &animate);
2073
2074
// Plot as lines and plot as histogram
2075
static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
2076
ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr));
2077
ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0, 80.0f));
2078
//ImGui::SameLine(); HelpMarker("Consider using ImPlot instead!");
2079
2080
// Fill an array of contiguous float values to plot
2081
// Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float
2082
// and the sizeof() of your structure in the "stride" parameter.
2083
static float values[90] = {};
2084
static int values_offset = 0;
2085
static double refresh_time = 0.0;
2086
if (!animate || refresh_time == 0.0)
2087
refresh_time = ImGui::GetTime();
2088
while (refresh_time < ImGui::GetTime()) // Create data at fixed 60 Hz rate for the demo
2089
{
2090
static float phase = 0.0f;
2091
values[values_offset] = cosf(phase);
2092
values_offset = (values_offset + 1) % IM_ARRAYSIZE(values);
2093
phase += 0.10f * values_offset;
2094
refresh_time += 1.0f / 60.0f;
2095
}
2096
2097
// Plots can display overlay texts
2098
// (in this example, we will display an average value)
2099
{
2100
float average = 0.0f;
2101
for (int n = 0; n < IM_ARRAYSIZE(values); n++)
2102
average += values[n];
2103
average /= (float)IM_ARRAYSIZE(values);
2104
char overlay[32];
2105
sprintf(overlay, "avg %f", average);
2106
ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, overlay, -1.0f, 1.0f, ImVec2(0, 80.0f));
2107
}
2108
2109
// Use functions to generate output
2110
// FIXME: This is actually VERY awkward because current plot API only pass in indices.
2111
// We probably want an API passing floats and user provide sample rate/count.
2112
struct Funcs
2113
{
2114
static float Sin(void*, int i) { return sinf(i * 0.1f); }
2115
static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; }
2116
};
2117
static int func_type = 0, display_count = 70;
2118
ImGui::SeparatorText("Functions");
2119
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
2120
ImGui::Combo("func", &func_type, "Sin\0Saw\0");
2121
ImGui::SameLine();
2122
ImGui::SliderInt("Sample count", &display_count, 1, 400);
2123
float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw;
2124
ImGui::PlotLines("Lines##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
2125
ImGui::PlotHistogram("Histogram##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
2126
ImGui::Separator();
2127
2128
ImGui::Text("Need better plotting and graphing? Consider using ImPlot:");
2129
ImGui::TextLinkOpenURL("https://github.com/epezent/implot");
2130
ImGui::Separator();
2131
2132
ImGui::TreePop();
2133
}
2134
2135
IMGUI_DEMO_MARKER("Widgets/Progress Bars");
2136
if (ImGui::TreeNode("Progress Bars"))
2137
{
2138
// Animate a simple progress bar
2139
static float progress = 0.0f, progress_dir = 1.0f;
2140
progress += progress_dir * 0.4f * ImGui::GetIO().DeltaTime;
2141
if (progress >= +1.1f) { progress = +1.1f; progress_dir *= -1.0f; }
2142
if (progress <= -0.1f) { progress = -0.1f; progress_dir *= -1.0f; }
2143
2144
// Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width,
2145
// or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth.
2146
ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f));
2147
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
2148
ImGui::Text("Progress Bar");
2149
2150
float progress_saturated = IM_CLAMP(progress, 0.0f, 1.0f);
2151
char buf[32];
2152
sprintf(buf, "%d/%d", (int)(progress_saturated * 1753), 1753);
2153
ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), buf);
2154
2155
// Pass an animated negative value, e.g. -1.0f * (float)ImGui::GetTime() is the recommended value.
2156
// Adjust the factor if you want to adjust the animation speed.
2157
ImGui::ProgressBar(-1.0f * (float)ImGui::GetTime(), ImVec2(0.0f, 0.0f), "Searching..");
2158
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
2159
ImGui::Text("Indeterminate");
2160
2161
ImGui::TreePop();
2162
}
2163
2164
IMGUI_DEMO_MARKER("Widgets/Color");
2165
if (ImGui::TreeNode("Color/Picker Widgets"))
2166
{
2167
static ImVec4 color = ImVec4(114.0f / 255.0f, 144.0f / 255.0f, 154.0f / 255.0f, 200.0f / 255.0f);
2168
2169
static bool alpha_preview = true;
2170
static bool alpha_half_preview = false;
2171
static bool drag_and_drop = true;
2172
static bool options_menu = true;
2173
static bool hdr = false;
2174
ImGui::SeparatorText("Options");
2175
ImGui::Checkbox("With Alpha Preview", &alpha_preview);
2176
ImGui::Checkbox("With Half Alpha Preview", &alpha_half_preview);
2177
ImGui::Checkbox("With Drag and Drop", &drag_and_drop);
2178
ImGui::Checkbox("With Options Menu", &options_menu); ImGui::SameLine(); HelpMarker("Right-click on the individual color widget to show options.");
2179
ImGui::Checkbox("With HDR", &hdr); ImGui::SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets.");
2180
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);
2181
2182
IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit");
2183
ImGui::SeparatorText("Inline color editor");
2184
ImGui::Text("Color widget:");
2185
ImGui::SameLine(); HelpMarker(
2186
"Click on the color square to open a color picker.\n"
2187
"CTRL+click on individual component to input value.\n");
2188
ImGui::ColorEdit3("MyColor##1", (float*)&color, misc_flags);
2189
2190
IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (HSV, with Alpha)");
2191
ImGui::Text("Color widget HSV with Alpha:");
2192
ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_DisplayHSV | misc_flags);
2193
2194
IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (float display)");
2195
ImGui::Text("Color widget with Float Display:");
2196
ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | misc_flags);
2197
2198
IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with Picker)");
2199
ImGui::Text("Color button with Picker:");
2200
ImGui::SameLine(); HelpMarker(
2201
"With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\n"
2202
"With the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only "
2203
"be used for the tooltip and picker popup.");
2204
ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | misc_flags);
2205
2206
IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with custom Picker popup)");
2207
ImGui::Text("Color button with Custom Picker Popup:");
2208
2209
// Generate a default palette. The palette will persist and can be edited.
2210
static bool saved_palette_init = true;
2211
static ImVec4 saved_palette[32] = {};
2212
if (saved_palette_init)
2213
{
2214
for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++)
2215
{
2216
ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f,
2217
saved_palette[n].x, saved_palette[n].y, saved_palette[n].z);
2218
saved_palette[n].w = 1.0f; // Alpha
2219
}
2220
saved_palette_init = false;
2221
}
2222
2223
static ImVec4 backup_color;
2224
bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags);
2225
ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x);
2226
open_popup |= ImGui::Button("Palette");
2227
if (open_popup)
2228
{
2229
ImGui::OpenPopup("mypicker");
2230
backup_color = color;
2231
}
2232
if (ImGui::BeginPopup("mypicker"))
2233
{
2234
ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!");
2235
ImGui::Separator();
2236
ImGui::ColorPicker4("##picker", (float*)&color, misc_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview);
2237
ImGui::SameLine();
2238
2239
ImGui::BeginGroup(); // Lock X position
2240
ImGui::Text("Current");
2241
ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40));
2242
ImGui::Text("Previous");
2243
if (ImGui::ColorButton("##previous", backup_color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40)))
2244
color = backup_color;
2245
ImGui::Separator();
2246
ImGui::Text("Palette");
2247
for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++)
2248
{
2249
ImGui::PushID(n);
2250
if ((n % 8) != 0)
2251
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y);
2252
2253
ImGuiColorEditFlags palette_button_flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip;
2254
if (ImGui::ColorButton("##palette", saved_palette[n], palette_button_flags, ImVec2(20, 20)))
2255
color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha!
2256
2257
// Allow user to drop colors into each palette entry. Note that ColorButton() is already a
2258
// drag source by default, unless specifying the ImGuiColorEditFlags_NoDragDrop flag.
2259
if (ImGui::BeginDragDropTarget())
2260
{
2261
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
2262
memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3);
2263
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F))
2264
memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4);
2265
ImGui::EndDragDropTarget();
2266
}
2267
2268
ImGui::PopID();
2269
}
2270
ImGui::EndGroup();
2271
ImGui::EndPopup();
2272
}
2273
2274
IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (simple)");
2275
ImGui::Text("Color button only:");
2276
static bool no_border = false;
2277
ImGui::Checkbox("ImGuiColorEditFlags_NoBorder", &no_border);
2278
ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, misc_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80));
2279
2280
IMGUI_DEMO_MARKER("Widgets/Color/ColorPicker");
2281
ImGui::SeparatorText("Color picker");
2282
static bool alpha = true;
2283
static bool alpha_bar = true;
2284
static bool side_preview = true;
2285
static bool ref_color = false;
2286
static ImVec4 ref_color_v(1.0f, 0.0f, 1.0f, 0.5f);
2287
static int display_mode = 0;
2288
static int picker_mode = 0;
2289
ImGui::Checkbox("With Alpha", &alpha);
2290
ImGui::Checkbox("With Alpha Bar", &alpha_bar);
2291
ImGui::Checkbox("With Side Preview", &side_preview);
2292
if (side_preview)
2293
{
2294
ImGui::SameLine();
2295
ImGui::Checkbox("With Ref Color", &ref_color);
2296
if (ref_color)
2297
{
2298
ImGui::SameLine();
2299
ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | misc_flags);
2300
}
2301
}
2302
ImGui::Combo("Display Mode", &display_mode, "Auto/Current\0None\0RGB Only\0HSV Only\0Hex Only\0");
2303
ImGui::SameLine(); HelpMarker(
2304
"ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, "
2305
"but the user can change it with a right-click on those inputs.\n\nColorPicker defaults to displaying RGB+HSV+Hex "
2306
"if you don't specify a display mode.\n\nYou can change the defaults using SetColorEditOptions().");
2307
ImGui::SameLine(); HelpMarker("When not specified explicitly (Auto/Current mode), user can right-click the picker to change mode.");
2308
ImGuiColorEditFlags flags = misc_flags;
2309
if (!alpha) flags |= ImGuiColorEditFlags_NoAlpha; // This is by default if you call ColorPicker3() instead of ColorPicker4()
2310
if (alpha_bar) flags |= ImGuiColorEditFlags_AlphaBar;
2311
if (!side_preview) flags |= ImGuiColorEditFlags_NoSidePreview;
2312
if (picker_mode == 1) flags |= ImGuiColorEditFlags_PickerHueBar;
2313
if (picker_mode == 2) flags |= ImGuiColorEditFlags_PickerHueWheel;
2314
if (display_mode == 1) flags |= ImGuiColorEditFlags_NoInputs; // Disable all RGB/HSV/Hex displays
2315
if (display_mode == 2) flags |= ImGuiColorEditFlags_DisplayRGB; // Override display mode
2316
if (display_mode == 3) flags |= ImGuiColorEditFlags_DisplayHSV;
2317
if (display_mode == 4) flags |= ImGuiColorEditFlags_DisplayHex;
2318
ImGui::ColorPicker4("MyColor##4", (float*)&color, flags, ref_color ? &ref_color_v.x : NULL);
2319
2320
ImGui::Text("Set defaults in code:");
2321
ImGui::SameLine(); HelpMarker(
2322
"SetColorEditOptions() is designed to allow you to set boot-time default.\n"
2323
"We don't have Push/Pop functions because you can force options on a per-widget basis if needed,"
2324
"and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid"
2325
"encouraging you to persistently save values that aren't forward-compatible.");
2326
if (ImGui::Button("Default: Uint8 + HSV + Hue Bar"))
2327
ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_PickerHueBar);
2328
if (ImGui::Button("Default: Float + HDR + Hue Wheel"))
2329
ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel);
2330
2331
// Always display a small version of both types of pickers
2332
// (that's in order to make it more visible in the demo to people who are skimming quickly through it)
2333
ImGui::Text("Both types:");
2334
float w = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.y) * 0.40f;
2335
ImGui::SetNextItemWidth(w);
2336
ImGui::ColorPicker3("##MyColor##5", (float*)&color, ImGuiColorEditFlags_PickerHueBar | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha);
2337
ImGui::SameLine();
2338
ImGui::SetNextItemWidth(w);
2339
ImGui::ColorPicker3("##MyColor##6", (float*)&color, ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha);
2340
2341
// HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0)
2342
static ImVec4 color_hsv(0.23f, 1.0f, 1.0f, 1.0f); // Stored as HSV!
2343
ImGui::Spacing();
2344
ImGui::Text("HSV encoded colors");
2345
ImGui::SameLine(); HelpMarker(
2346
"By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV"
2347
"allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV. This comes with the"
2348
"added benefit that you can manipulate hue values with the picker even when saturation or value are zero.");
2349
ImGui::Text("Color widget with InputHSV:");
2350
ImGui::ColorEdit4("HSV shown as RGB##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float);
2351
ImGui::ColorEdit4("HSV shown as HSV##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float);
2352
ImGui::DragFloat4("Raw HSV values", (float*)&color_hsv, 0.01f, 0.0f, 1.0f);
2353
2354
ImGui::TreePop();
2355
}
2356
2357
IMGUI_DEMO_MARKER("Widgets/Drag and Slider Flags");
2358
if (ImGui::TreeNode("Drag/Slider Flags"))
2359
{
2360
// Demonstrate using advanced flags for DragXXX and SliderXXX functions. Note that the flags are the same!
2361
static ImGuiSliderFlags flags = ImGuiSliderFlags_None;
2362
ImGui::CheckboxFlags("ImGuiSliderFlags_AlwaysClamp", &flags, ImGuiSliderFlags_AlwaysClamp);
2363
ImGui::CheckboxFlags("ImGuiSliderFlags_ClampOnInput", &flags, ImGuiSliderFlags_ClampOnInput);
2364
ImGui::SameLine(); HelpMarker("Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds.");
2365
ImGui::CheckboxFlags("ImGuiSliderFlags_ClampZeroRange", &flags, ImGuiSliderFlags_ClampZeroRange);
2366
ImGui::SameLine(); HelpMarker("Clamp even if min==max==0.0f. Otherwise DragXXX functions don't clamp.");
2367
ImGui::CheckboxFlags("ImGuiSliderFlags_Logarithmic", &flags, ImGuiSliderFlags_Logarithmic);
2368
ImGui::SameLine(); HelpMarker("Enable logarithmic editing (more precision for small values).");
2369
ImGui::CheckboxFlags("ImGuiSliderFlags_NoRoundToFormat", &flags, ImGuiSliderFlags_NoRoundToFormat);
2370
ImGui::SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits).");
2371
ImGui::CheckboxFlags("ImGuiSliderFlags_NoInput", &flags, ImGuiSliderFlags_NoInput);
2372
ImGui::SameLine(); HelpMarker("Disable CTRL+Click or Enter key allowing to input text directly into the widget.");
2373
ImGui::CheckboxFlags("ImGuiSliderFlags_WrapAround", &flags, ImGuiSliderFlags_WrapAround);
2374
ImGui::SameLine(); HelpMarker("Enable wrapping around from max to min and from min to max (only supported by DragXXX() functions)");
2375
2376
// Drags
2377
static float drag_f = 0.5f;
2378
static int drag_i = 50;
2379
ImGui::Text("Underlying float value: %f", drag_f);
2380
ImGui::DragFloat("DragFloat (0 -> 1)", &drag_f, 0.005f, 0.0f, 1.0f, "%.3f", flags);
2381
ImGui::DragFloat("DragFloat (0 -> +inf)", &drag_f, 0.005f, 0.0f, FLT_MAX, "%.3f", flags);
2382
ImGui::DragFloat("DragFloat (-inf -> 1)", &drag_f, 0.005f, -FLT_MAX, 1.0f, "%.3f", flags);
2383
ImGui::DragFloat("DragFloat (-inf -> +inf)", &drag_f, 0.005f, -FLT_MAX, +FLT_MAX, "%.3f", flags);
2384
//ImGui::DragFloat("DragFloat (0 -> 0)", &drag_f, 0.005f, 0.0f, 0.0f, "%.3f", flags); // To test ClampZeroRange
2385
//ImGui::DragFloat("DragFloat (100 -> 100)", &drag_f, 0.005f, 100.0f, 100.0f, "%.3f", flags);
2386
ImGui::DragInt("DragInt (0 -> 100)", &drag_i, 0.5f, 0, 100, "%d", flags);
2387
2388
// Sliders
2389
static float slider_f = 0.5f;
2390
static int slider_i = 50;
2391
const ImGuiSliderFlags flags_for_sliders = flags & ~ImGuiSliderFlags_WrapAround;
2392
ImGui::Text("Underlying float value: %f", slider_f);
2393
ImGui::SliderFloat("SliderFloat (0 -> 1)", &slider_f, 0.0f, 1.0f, "%.3f", flags_for_sliders);
2394
ImGui::SliderInt("SliderInt (0 -> 100)", &slider_i, 0, 100, "%d", flags_for_sliders);
2395
2396
ImGui::TreePop();
2397
}
2398
2399
IMGUI_DEMO_MARKER("Widgets/Range Widgets");
2400
if (ImGui::TreeNode("Range Widgets"))
2401
{
2402
static float begin = 10, end = 90;
2403
static int begin_i = 100, end_i = 1000;
2404
ImGui::DragFloatRange2("range float", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%", ImGuiSliderFlags_AlwaysClamp);
2405
ImGui::DragIntRange2("range int", &begin_i, &end_i, 5, 0, 1000, "Min: %d units", "Max: %d units");
2406
ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %d units", "Max: %d units");
2407
ImGui::TreePop();
2408
}
2409
2410
IMGUI_DEMO_MARKER("Widgets/Data Types");
2411
if (ImGui::TreeNode("Data Types"))
2412
{
2413
// DragScalar/InputScalar/SliderScalar functions allow various data types
2414
// - signed/unsigned
2415
// - 8/16/32/64-bits
2416
// - integer/float/double
2417
// To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum
2418
// to pass the type, and passing all arguments by pointer.
2419
// This is the reason the test code below creates local variables to hold "zero" "one" etc. for each type.
2420
// In practice, if you frequently use a given type that is not covered by the normal API entry points,
2421
// you can wrap it yourself inside a 1 line function which can take typed argument as value instead of void*,
2422
// and then pass their address to the generic function. For example:
2423
// bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld")
2424
// {
2425
// return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format);
2426
// }
2427
2428
// Setup limits (as helper variables so we can take their address, as explained above)
2429
// Note: SliderScalar() functions have a maximum usable range of half the natural type maximum, hence the /2.
2430
#ifndef LLONG_MIN
2431
ImS64 LLONG_MIN = -9223372036854775807LL - 1;
2432
ImS64 LLONG_MAX = 9223372036854775807LL;
2433
ImU64 ULLONG_MAX = (2ULL * 9223372036854775807LL + 1);
2434
#endif
2435
const char s8_zero = 0, s8_one = 1, s8_fifty = 50, s8_min = -128, s8_max = 127;
2436
const ImU8 u8_zero = 0, u8_one = 1, u8_fifty = 50, u8_min = 0, u8_max = 255;
2437
const short s16_zero = 0, s16_one = 1, s16_fifty = 50, s16_min = -32768, s16_max = 32767;
2438
const ImU16 u16_zero = 0, u16_one = 1, u16_fifty = 50, u16_min = 0, u16_max = 65535;
2439
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;
2440
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;
2441
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;
2442
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;
2443
const float f32_zero = 0.f, f32_one = 1.f, f32_lo_a = -10000000000.0f, f32_hi_a = +10000000000.0f;
2444
const double f64_zero = 0., f64_one = 1., f64_lo_a = -1000000000000000.0, f64_hi_a = +1000000000000000.0;
2445
2446
// State
2447
static char s8_v = 127;
2448
static ImU8 u8_v = 255;
2449
static short s16_v = 32767;
2450
static ImU16 u16_v = 65535;
2451
static ImS32 s32_v = -1;
2452
static ImU32 u32_v = (ImU32)-1;
2453
static ImS64 s64_v = -1;
2454
static ImU64 u64_v = (ImU64)-1;
2455
static float f32_v = 0.123f;
2456
static double f64_v = 90000.01234567890123456789;
2457
2458
const float drag_speed = 0.2f;
2459
static bool drag_clamp = false;
2460
IMGUI_DEMO_MARKER("Widgets/Data Types/Drags");
2461
ImGui::SeparatorText("Drags");
2462
ImGui::Checkbox("Clamp integers to 0..50", &drag_clamp);
2463
ImGui::SameLine(); HelpMarker(
2464
"As with every widget in dear imgui, we never modify values unless there is a user interaction.\n"
2465
"You can override the clamping limits by using CTRL+Click to input a value.");
2466
ImGui::DragScalar("drag s8", ImGuiDataType_S8, &s8_v, drag_speed, drag_clamp ? &s8_zero : NULL, drag_clamp ? &s8_fifty : NULL);
2467
ImGui::DragScalar("drag u8", ImGuiDataType_U8, &u8_v, drag_speed, drag_clamp ? &u8_zero : NULL, drag_clamp ? &u8_fifty : NULL, "%u ms");
2468
ImGui::DragScalar("drag s16", ImGuiDataType_S16, &s16_v, drag_speed, drag_clamp ? &s16_zero : NULL, drag_clamp ? &s16_fifty : NULL);
2469
ImGui::DragScalar("drag u16", ImGuiDataType_U16, &u16_v, drag_speed, drag_clamp ? &u16_zero : NULL, drag_clamp ? &u16_fifty : NULL, "%u ms");
2470
ImGui::DragScalar("drag s32", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL);
2471
ImGui::DragScalar("drag s32 hex", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL, "0x%08X");
2472
ImGui::DragScalar("drag u32", ImGuiDataType_U32, &u32_v, drag_speed, drag_clamp ? &u32_zero : NULL, drag_clamp ? &u32_fifty : NULL, "%u ms");
2473
ImGui::DragScalar("drag s64", ImGuiDataType_S64, &s64_v, drag_speed, drag_clamp ? &s64_zero : NULL, drag_clamp ? &s64_fifty : NULL);
2474
ImGui::DragScalar("drag u64", ImGuiDataType_U64, &u64_v, drag_speed, drag_clamp ? &u64_zero : NULL, drag_clamp ? &u64_fifty : NULL);
2475
ImGui::DragScalar("drag float", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f");
2476
ImGui::DragScalar("drag float log", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f", ImGuiSliderFlags_Logarithmic);
2477
ImGui::DragScalar("drag double", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, NULL, "%.10f grams");
2478
ImGui::DragScalar("drag double log",ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", ImGuiSliderFlags_Logarithmic);
2479
2480
IMGUI_DEMO_MARKER("Widgets/Data Types/Sliders");
2481
ImGui::SeparatorText("Sliders");
2482
ImGui::SliderScalar("slider s8 full", ImGuiDataType_S8, &s8_v, &s8_min, &s8_max, "%d");
2483
ImGui::SliderScalar("slider u8 full", ImGuiDataType_U8, &u8_v, &u8_min, &u8_max, "%u");
2484
ImGui::SliderScalar("slider s16 full", ImGuiDataType_S16, &s16_v, &s16_min, &s16_max, "%d");
2485
ImGui::SliderScalar("slider u16 full", ImGuiDataType_U16, &u16_v, &u16_min, &u16_max, "%u");
2486
ImGui::SliderScalar("slider s32 low", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty,"%d");
2487
ImGui::SliderScalar("slider s32 high", ImGuiDataType_S32, &s32_v, &s32_hi_a, &s32_hi_b, "%d");
2488
ImGui::SliderScalar("slider s32 full", ImGuiDataType_S32, &s32_v, &s32_min, &s32_max, "%d");
2489
ImGui::SliderScalar("slider s32 hex", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty, "0x%04X");
2490
ImGui::SliderScalar("slider u32 low", ImGuiDataType_U32, &u32_v, &u32_zero, &u32_fifty,"%u");
2491
ImGui::SliderScalar("slider u32 high", ImGuiDataType_U32, &u32_v, &u32_hi_a, &u32_hi_b, "%u");
2492
ImGui::SliderScalar("slider u32 full", ImGuiDataType_U32, &u32_v, &u32_min, &u32_max, "%u");
2493
ImGui::SliderScalar("slider s64 low", ImGuiDataType_S64, &s64_v, &s64_zero, &s64_fifty,"%" PRId64);
2494
ImGui::SliderScalar("slider s64 high", ImGuiDataType_S64, &s64_v, &s64_hi_a, &s64_hi_b, "%" PRId64);
2495
ImGui::SliderScalar("slider s64 full", ImGuiDataType_S64, &s64_v, &s64_min, &s64_max, "%" PRId64);
2496
ImGui::SliderScalar("slider u64 low", ImGuiDataType_U64, &u64_v, &u64_zero, &u64_fifty,"%" PRIu64 " ms");
2497
ImGui::SliderScalar("slider u64 high", ImGuiDataType_U64, &u64_v, &u64_hi_a, &u64_hi_b, "%" PRIu64 " ms");
2498
ImGui::SliderScalar("slider u64 full", ImGuiDataType_U64, &u64_v, &u64_min, &u64_max, "%" PRIu64 " ms");
2499
ImGui::SliderScalar("slider float low", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one);
2500
ImGui::SliderScalar("slider float low log", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one, "%.10f", ImGuiSliderFlags_Logarithmic);
2501
ImGui::SliderScalar("slider float high", ImGuiDataType_Float, &f32_v, &f32_lo_a, &f32_hi_a, "%e");
2502
ImGui::SliderScalar("slider double low", ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f grams");
2503
ImGui::SliderScalar("slider double low log",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f", ImGuiSliderFlags_Logarithmic);
2504
ImGui::SliderScalar("slider double high", ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams");
2505
2506
ImGui::SeparatorText("Sliders (reverse)");
2507
ImGui::SliderScalar("slider s8 reverse", ImGuiDataType_S8, &s8_v, &s8_max, &s8_min, "%d");
2508
ImGui::SliderScalar("slider u8 reverse", ImGuiDataType_U8, &u8_v, &u8_max, &u8_min, "%u");
2509
ImGui::SliderScalar("slider s32 reverse", ImGuiDataType_S32, &s32_v, &s32_fifty, &s32_zero, "%d");
2510
ImGui::SliderScalar("slider u32 reverse", ImGuiDataType_U32, &u32_v, &u32_fifty, &u32_zero, "%u");
2511
ImGui::SliderScalar("slider s64 reverse", ImGuiDataType_S64, &s64_v, &s64_fifty, &s64_zero, "%" PRId64);
2512
ImGui::SliderScalar("slider u64 reverse", ImGuiDataType_U64, &u64_v, &u64_fifty, &u64_zero, "%" PRIu64 " ms");
2513
2514
IMGUI_DEMO_MARKER("Widgets/Data Types/Inputs");
2515
static bool inputs_step = true;
2516
static ImGuiInputTextFlags flags = ImGuiInputTextFlags_None;
2517
ImGui::SeparatorText("Inputs");
2518
ImGui::Checkbox("Show step buttons", &inputs_step);
2519
ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly);
2520
ImGui::CheckboxFlags("ImGuiInputTextFlags_ParseEmptyRefVal", &flags, ImGuiInputTextFlags_ParseEmptyRefVal);
2521
ImGui::CheckboxFlags("ImGuiInputTextFlags_DisplayEmptyRefVal", &flags, ImGuiInputTextFlags_DisplayEmptyRefVal);
2522
ImGui::InputScalar("input s8", ImGuiDataType_S8, &s8_v, inputs_step ? &s8_one : NULL, NULL, "%d", flags);
2523
ImGui::InputScalar("input u8", ImGuiDataType_U8, &u8_v, inputs_step ? &u8_one : NULL, NULL, "%u", flags);
2524
ImGui::InputScalar("input s16", ImGuiDataType_S16, &s16_v, inputs_step ? &s16_one : NULL, NULL, "%d", flags);
2525
ImGui::InputScalar("input u16", ImGuiDataType_U16, &u16_v, inputs_step ? &u16_one : NULL, NULL, "%u", flags);
2526
ImGui::InputScalar("input s32", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%d", flags);
2527
ImGui::InputScalar("input s32 hex", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%04X", flags);
2528
ImGui::InputScalar("input u32", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%u", flags);
2529
ImGui::InputScalar("input u32 hex", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%08X", flags);
2530
ImGui::InputScalar("input s64", ImGuiDataType_S64, &s64_v, inputs_step ? &s64_one : NULL, NULL, NULL, flags);
2531
ImGui::InputScalar("input u64", ImGuiDataType_U64, &u64_v, inputs_step ? &u64_one : NULL, NULL, NULL, flags);
2532
ImGui::InputScalar("input float", ImGuiDataType_Float, &f32_v, inputs_step ? &f32_one : NULL, NULL, NULL, flags);
2533
ImGui::InputScalar("input double", ImGuiDataType_Double, &f64_v, inputs_step ? &f64_one : NULL, NULL, NULL, flags);
2534
2535
ImGui::TreePop();
2536
}
2537
2538
IMGUI_DEMO_MARKER("Widgets/Multi-component Widgets");
2539
if (ImGui::TreeNode("Multi-component Widgets"))
2540
{
2541
static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f };
2542
static int vec4i[4] = { 1, 5, 100, 255 };
2543
2544
ImGui::SeparatorText("2-wide");
2545
ImGui::InputFloat2("input float2", vec4f);
2546
ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f);
2547
ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f);
2548
ImGui::InputInt2("input int2", vec4i);
2549
ImGui::DragInt2("drag int2", vec4i, 1, 0, 255);
2550
ImGui::SliderInt2("slider int2", vec4i, 0, 255);
2551
2552
ImGui::SeparatorText("3-wide");
2553
ImGui::InputFloat3("input float3", vec4f);
2554
ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f);
2555
ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f);
2556
ImGui::InputInt3("input int3", vec4i);
2557
ImGui::DragInt3("drag int3", vec4i, 1, 0, 255);
2558
ImGui::SliderInt3("slider int3", vec4i, 0, 255);
2559
2560
ImGui::SeparatorText("4-wide");
2561
ImGui::InputFloat4("input float4", vec4f);
2562
ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f);
2563
ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f);
2564
ImGui::InputInt4("input int4", vec4i);
2565
ImGui::DragInt4("drag int4", vec4i, 1, 0, 255);
2566
ImGui::SliderInt4("slider int4", vec4i, 0, 255);
2567
2568
ImGui::TreePop();
2569
}
2570
2571
IMGUI_DEMO_MARKER("Widgets/Vertical Sliders");
2572
if (ImGui::TreeNode("Vertical Sliders"))
2573
{
2574
const float spacing = 4;
2575
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
2576
2577
static int int_value = 0;
2578
ImGui::VSliderInt("##int", ImVec2(18, 160), &int_value, 0, 5);
2579
ImGui::SameLine();
2580
2581
static float values[7] = { 0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f };
2582
ImGui::PushID("set1");
2583
for (int i = 0; i < 7; i++)
2584
{
2585
if (i > 0) ImGui::SameLine();
2586
ImGui::PushID(i);
2587
ImGui::PushStyleColor(ImGuiCol_FrameBg, (ImVec4)ImColor::HSV(i / 7.0f, 0.5f, 0.5f));
2588
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.5f));
2589
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.5f));
2590
ImGui::PushStyleColor(ImGuiCol_SliderGrab, (ImVec4)ImColor::HSV(i / 7.0f, 0.9f, 0.9f));
2591
ImGui::VSliderFloat("##v", ImVec2(18, 160), &values[i], 0.0f, 1.0f, "");
2592
if (ImGui::IsItemActive() || ImGui::IsItemHovered())
2593
ImGui::SetTooltip("%.3f", values[i]);
2594
ImGui::PopStyleColor(4);
2595
ImGui::PopID();
2596
}
2597
ImGui::PopID();
2598
2599
ImGui::SameLine();
2600
ImGui::PushID("set2");
2601
static float values2[4] = { 0.20f, 0.80f, 0.40f, 0.25f };
2602
const int rows = 3;
2603
const ImVec2 small_slider_size(18, (float)(int)((160.0f - (rows - 1) * spacing) / rows));
2604
for (int nx = 0; nx < 4; nx++)
2605
{
2606
if (nx > 0) ImGui::SameLine();
2607
ImGui::BeginGroup();
2608
for (int ny = 0; ny < rows; ny++)
2609
{
2610
ImGui::PushID(nx * rows + ny);
2611
ImGui::VSliderFloat("##v", small_slider_size, &values2[nx], 0.0f, 1.0f, "");
2612
if (ImGui::IsItemActive() || ImGui::IsItemHovered())
2613
ImGui::SetTooltip("%.3f", values2[nx]);
2614
ImGui::PopID();
2615
}
2616
ImGui::EndGroup();
2617
}
2618
ImGui::PopID();
2619
2620
ImGui::SameLine();
2621
ImGui::PushID("set3");
2622
for (int i = 0; i < 4; i++)
2623
{
2624
if (i > 0) ImGui::SameLine();
2625
ImGui::PushID(i);
2626
ImGui::PushStyleVar(ImGuiStyleVar_GrabMinSize, 40);
2627
ImGui::VSliderFloat("##v", ImVec2(40, 160), &values[i], 0.0f, 1.0f, "%.2f\nsec");
2628
ImGui::PopStyleVar();
2629
ImGui::PopID();
2630
}
2631
ImGui::PopID();
2632
ImGui::PopStyleVar();
2633
ImGui::TreePop();
2634
}
2635
2636
IMGUI_DEMO_MARKER("Widgets/Drag and drop");
2637
if (ImGui::TreeNode("Drag and Drop"))
2638
{
2639
IMGUI_DEMO_MARKER("Widgets/Drag and drop/Standard widgets");
2640
if (ImGui::TreeNode("Drag and drop in standard widgets"))
2641
{
2642
// ColorEdit widgets automatically act as drag source and drag target.
2643
// They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F
2644
// to allow your own widgets to use colors in their drag and drop interaction.
2645
// Also see 'Demo->Widgets->Color/Picker Widgets->Palette' demo.
2646
HelpMarker("You can drag from the color squares.");
2647
static float col1[3] = { 1.0f, 0.0f, 0.2f };
2648
static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
2649
ImGui::ColorEdit3("color 1", col1);
2650
ImGui::ColorEdit4("color 2", col2);
2651
ImGui::TreePop();
2652
}
2653
2654
IMGUI_DEMO_MARKER("Widgets/Drag and drop/Copy-swap items");
2655
if (ImGui::TreeNode("Drag and drop to copy/swap items"))
2656
{
2657
enum Mode
2658
{
2659
Mode_Copy,
2660
Mode_Move,
2661
Mode_Swap
2662
};
2663
static int mode = 0;
2664
if (ImGui::RadioButton("Copy", mode == Mode_Copy)) { mode = Mode_Copy; } ImGui::SameLine();
2665
if (ImGui::RadioButton("Move", mode == Mode_Move)) { mode = Mode_Move; } ImGui::SameLine();
2666
if (ImGui::RadioButton("Swap", mode == Mode_Swap)) { mode = Mode_Swap; }
2667
static const char* names[9] =
2668
{
2669
"Bobby", "Beatrice", "Betty",
2670
"Brianna", "Barry", "Bernard",
2671
"Bibi", "Blaine", "Bryn"
2672
};
2673
for (int n = 0; n < IM_ARRAYSIZE(names); n++)
2674
{
2675
ImGui::PushID(n);
2676
if ((n % 3) != 0)
2677
ImGui::SameLine();
2678
ImGui::Button(names[n], ImVec2(60, 60));
2679
2680
// Our buttons are both drag sources and drag targets here!
2681
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None))
2682
{
2683
// Set payload to carry the index of our item (could be anything)
2684
ImGui::SetDragDropPayload("DND_DEMO_CELL", &n, sizeof(int));
2685
2686
// Display preview (could be anything, e.g. when dragging an image we could decide to display
2687
// the filename and a small preview of the image, etc.)
2688
if (mode == Mode_Copy) { ImGui::Text("Copy %s", names[n]); }
2689
if (mode == Mode_Move) { ImGui::Text("Move %s", names[n]); }
2690
if (mode == Mode_Swap) { ImGui::Text("Swap %s", names[n]); }
2691
ImGui::EndDragDropSource();
2692
}
2693
if (ImGui::BeginDragDropTarget())
2694
{
2695
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DND_DEMO_CELL"))
2696
{
2697
IM_ASSERT(payload->DataSize == sizeof(int));
2698
int payload_n = *(const int*)payload->Data;
2699
if (mode == Mode_Copy)
2700
{
2701
names[n] = names[payload_n];
2702
}
2703
if (mode == Mode_Move)
2704
{
2705
names[n] = names[payload_n];
2706
names[payload_n] = "";
2707
}
2708
if (mode == Mode_Swap)
2709
{
2710
const char* tmp = names[n];
2711
names[n] = names[payload_n];
2712
names[payload_n] = tmp;
2713
}
2714
}
2715
ImGui::EndDragDropTarget();
2716
}
2717
ImGui::PopID();
2718
}
2719
ImGui::TreePop();
2720
}
2721
2722
IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Drag to reorder items (simple)");
2723
if (ImGui::TreeNode("Drag to reorder items (simple)"))
2724
{
2725
// FIXME: there is temporary (usually single-frame) ID Conflict during reordering as a same item may be submitting twice.
2726
// This code was always slightly faulty but in a way which was not easily noticeable.
2727
// Until we fix this, enable ImGuiItemFlags_AllowDuplicateId to disable detecting the issue.
2728
ImGui::PushItemFlag(ImGuiItemFlags_AllowDuplicateId, true);
2729
2730
// Simple reordering
2731
HelpMarker(
2732
"We don't use the drag and drop api at all here! "
2733
"Instead we query when the item is held but not hovered, and order items accordingly.");
2734
static const char* item_names[] = { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" };
2735
for (int n = 0; n < IM_ARRAYSIZE(item_names); n++)
2736
{
2737
const char* item = item_names[n];
2738
ImGui::Selectable(item);
2739
2740
if (ImGui::IsItemActive() && !ImGui::IsItemHovered())
2741
{
2742
int n_next = n + (ImGui::GetMouseDragDelta(0).y < 0.f ? -1 : 1);
2743
if (n_next >= 0 && n_next < IM_ARRAYSIZE(item_names))
2744
{
2745
item_names[n] = item_names[n_next];
2746
item_names[n_next] = item;
2747
ImGui::ResetMouseDragDelta();
2748
}
2749
}
2750
}
2751
2752
ImGui::PopItemFlag();
2753
ImGui::TreePop();
2754
}
2755
2756
IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Tooltip at target location");
2757
if (ImGui::TreeNode("Tooltip at target location"))
2758
{
2759
for (int n = 0; n < 2; n++)
2760
{
2761
// Drop targets
2762
ImGui::Button(n ? "drop here##1" : "drop here##0");
2763
if (ImGui::BeginDragDropTarget())
2764
{
2765
ImGuiDragDropFlags drop_target_flags = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoPreviewTooltip;
2766
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, drop_target_flags))
2767
{
2768
IM_UNUSED(payload);
2769
ImGui::SetMouseCursor(ImGuiMouseCursor_NotAllowed);
2770
ImGui::SetTooltip("Cannot drop here!");
2771
}
2772
ImGui::EndDragDropTarget();
2773
}
2774
2775
// Drop source
2776
static ImVec4 col4 = { 1.0f, 0.0f, 0.2f, 1.0f };
2777
if (n == 0)
2778
ImGui::ColorButton("drag me", col4);
2779
2780
}
2781
ImGui::TreePop();
2782
}
2783
2784
ImGui::TreePop();
2785
}
2786
2787
IMGUI_DEMO_MARKER("Widgets/Querying Item Status (Edited,Active,Hovered etc.)");
2788
if (ImGui::TreeNode("Querying Item Status (Edited/Active/Hovered etc.)"))
2789
{
2790
// Select an item type
2791
const char* item_names[] =
2792
{
2793
"Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputTextMultiline", "InputFloat",
2794
"InputFloat3", "ColorEdit4", "Selectable", "MenuItem", "TreeNode", "TreeNode (w/ double-click)", "Combo", "ListBox"
2795
};
2796
static int item_type = 4;
2797
static bool item_disabled = false;
2798
ImGui::Combo("Item Type", &item_type, item_names, IM_ARRAYSIZE(item_names), IM_ARRAYSIZE(item_names));
2799
ImGui::SameLine();
2800
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().");
2801
ImGui::Checkbox("Item Disabled", &item_disabled);
2802
2803
// Submit selected items so we can query their status in the code following it.
2804
bool ret = false;
2805
static bool b = false;
2806
static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f };
2807
static char str[16] = {};
2808
if (item_disabled)
2809
ImGui::BeginDisabled(true);
2810
if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction
2811
if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); } // Testing button
2812
if (item_type == 2) { ImGui::PushItemFlag(ImGuiItemFlags_ButtonRepeat, true); ret = ImGui::Button("ITEM: Button"); ImGui::PopItemFlag(); } // Testing button (with repeater)
2813
if (item_type == 3) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); } // Testing checkbox
2814
if (item_type == 4) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item
2815
if (item_type == 5) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which handles tabbing)
2816
if (item_type == 6) { ret = ImGui::InputTextMultiline("ITEM: InputTextMultiline", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which uses a child window)
2817
if (item_type == 7) { ret = ImGui::InputFloat("ITEM: InputFloat", col4f, 1.0f); } // Testing +/- buttons on scalar input
2818
if (item_type == 8) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
2819
if (item_type == 9) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
2820
if (item_type == 10){ ret = ImGui::Selectable("ITEM: Selectable"); } // Testing selectable item
2821
if (item_type == 11){ ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy)
2822
if (item_type == 12){ ret = ImGui::TreeNode("ITEM: TreeNode"); if (ret) ImGui::TreePop(); } // Testing tree node
2823
if (item_type == 13){ ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy.
2824
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)); }
2825
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)); }
2826
2827
bool hovered_delay_none = ImGui::IsItemHovered();
2828
bool hovered_delay_stationary = ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary);
2829
bool hovered_delay_short = ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort);
2830
bool hovered_delay_normal = ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal);
2831
bool hovered_delay_tooltip = ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip); // = Normal + Stationary
2832
2833
// Display the values of IsItemHovered() and other common item state functions.
2834
// Note that the ImGuiHoveredFlags_XXX flags can be combined.
2835
// Because BulletText is an item itself and that would affect the output of IsItemXXX functions,
2836
// we query every state in a single call to avoid storing them and to simplify the code.
2837
ImGui::BulletText(
2838
"Return value = %d\n"
2839
"IsItemFocused() = %d\n"
2840
"IsItemHovered() = %d\n"
2841
"IsItemHovered(_AllowWhenBlockedByPopup) = %d\n"
2842
"IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n"
2843
"IsItemHovered(_AllowWhenOverlappedByItem) = %d\n"
2844
"IsItemHovered(_AllowWhenOverlappedByWindow) = %d\n"
2845
"IsItemHovered(_AllowWhenDisabled) = %d\n"
2846
"IsItemHovered(_RectOnly) = %d\n"
2847
"IsItemActive() = %d\n"
2848
"IsItemEdited() = %d\n"
2849
"IsItemActivated() = %d\n"
2850
"IsItemDeactivated() = %d\n"
2851
"IsItemDeactivatedAfterEdit() = %d\n"
2852
"IsItemVisible() = %d\n"
2853
"IsItemClicked() = %d\n"
2854
"IsItemToggledOpen() = %d\n"
2855
"GetItemRectMin() = (%.1f, %.1f)\n"
2856
"GetItemRectMax() = (%.1f, %.1f)\n"
2857
"GetItemRectSize() = (%.1f, %.1f)",
2858
ret,
2859
ImGui::IsItemFocused(),
2860
ImGui::IsItemHovered(),
2861
ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2862
ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
2863
ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlappedByItem),
2864
ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlappedByWindow),
2865
ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled),
2866
ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly),
2867
ImGui::IsItemActive(),
2868
ImGui::IsItemEdited(),
2869
ImGui::IsItemActivated(),
2870
ImGui::IsItemDeactivated(),
2871
ImGui::IsItemDeactivatedAfterEdit(),
2872
ImGui::IsItemVisible(),
2873
ImGui::IsItemClicked(),
2874
ImGui::IsItemToggledOpen(),
2875
ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y,
2876
ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y,
2877
ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y
2878
);
2879
ImGui::BulletText(
2880
"with Hovering Delay or Stationary test:\n"
2881
"IsItemHovered() = = %d\n"
2882
"IsItemHovered(_Stationary) = %d\n"
2883
"IsItemHovered(_DelayShort) = %d\n"
2884
"IsItemHovered(_DelayNormal) = %d\n"
2885
"IsItemHovered(_Tooltip) = %d",
2886
hovered_delay_none, hovered_delay_stationary, hovered_delay_short, hovered_delay_normal, hovered_delay_tooltip);
2887
2888
if (item_disabled)
2889
ImGui::EndDisabled();
2890
2891
char buf[1] = "";
2892
ImGui::InputText("unused", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_ReadOnly);
2893
ImGui::SameLine();
2894
HelpMarker("This widget is only here to be able to tab-out of the widgets above and see e.g. Deactivated() status.");
2895
2896
ImGui::TreePop();
2897
}
2898
2899
IMGUI_DEMO_MARKER("Widgets/Querying Window Status (Focused,Hovered etc.)");
2900
if (ImGui::TreeNode("Querying Window Status (Focused/Hovered etc.)"))
2901
{
2902
static bool embed_all_inside_a_child_window = false;
2903
ImGui::Checkbox("Embed everything inside a child window for testing _RootWindow flag.", &embed_all_inside_a_child_window);
2904
if (embed_all_inside_a_child_window)
2905
ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20.0f), ImGuiChildFlags_Borders);
2906
2907
// Testing IsWindowFocused() function with its various flags.
2908
ImGui::BulletText(
2909
"IsWindowFocused() = %d\n"
2910
"IsWindowFocused(_ChildWindows) = %d\n"
2911
"IsWindowFocused(_ChildWindows|_NoPopupHierarchy) = %d\n"
2912
"IsWindowFocused(_ChildWindows|_DockHierarchy) = %d\n"
2913
"IsWindowFocused(_ChildWindows|_RootWindow) = %d\n"
2914
"IsWindowFocused(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n"
2915
"IsWindowFocused(_ChildWindows|_RootWindow|_DockHierarchy) = %d\n"
2916
"IsWindowFocused(_RootWindow) = %d\n"
2917
"IsWindowFocused(_RootWindow|_NoPopupHierarchy) = %d\n"
2918
"IsWindowFocused(_RootWindow|_DockHierarchy) = %d\n"
2919
"IsWindowFocused(_AnyWindow) = %d\n",
2920
ImGui::IsWindowFocused(),
2921
ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows),
2922
ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_NoPopupHierarchy),
2923
ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_DockHierarchy),
2924
ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow),
2925
ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy),
2926
ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_DockHierarchy),
2927
ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow),
2928
ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy),
2929
ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_DockHierarchy),
2930
ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow));
2931
2932
// Testing IsWindowHovered() function with its various flags.
2933
ImGui::BulletText(
2934
"IsWindowHovered() = %d\n"
2935
"IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n"
2936
"IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n"
2937
"IsWindowHovered(_ChildWindows) = %d\n"
2938
"IsWindowHovered(_ChildWindows|_NoPopupHierarchy) = %d\n"
2939
"IsWindowHovered(_ChildWindows|_DockHierarchy) = %d\n"
2940
"IsWindowHovered(_ChildWindows|_RootWindow) = %d\n"
2941
"IsWindowHovered(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n"
2942
"IsWindowHovered(_ChildWindows|_RootWindow|_DockHierarchy) = %d\n"
2943
"IsWindowHovered(_RootWindow) = %d\n"
2944
"IsWindowHovered(_RootWindow|_NoPopupHierarchy) = %d\n"
2945
"IsWindowHovered(_RootWindow|_DockHierarchy) = %d\n"
2946
"IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n"
2947
"IsWindowHovered(_AnyWindow) = %d\n"
2948
"IsWindowHovered(_Stationary) = %d\n",
2949
ImGui::IsWindowHovered(),
2950
ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2951
ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
2952
ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows),
2953
ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy),
2954
ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_DockHierarchy),
2955
ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow),
2956
ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy),
2957
ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_DockHierarchy),
2958
ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow),
2959
ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy),
2960
ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_DockHierarchy),
2961
ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2962
ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow),
2963
ImGui::IsWindowHovered(ImGuiHoveredFlags_Stationary));
2964
2965
ImGui::BeginChild("child", ImVec2(0, 50), ImGuiChildFlags_Borders);
2966
ImGui::Text("This is another child window for testing the _ChildWindows flag.");
2967
ImGui::EndChild();
2968
if (embed_all_inside_a_child_window)
2969
ImGui::EndChild();
2970
2971
// Calling IsItemHovered() after begin returns the hovered status of the title bar.
2972
// This is useful in particular if you want to create a context menu associated to the title bar of a window.
2973
// This will also work when docked into a Tab (the Tab replace the Title Bar and guarantee the same properties).
2974
static bool test_window = false;
2975
ImGui::Checkbox("Hovered/Active tests after Begin() for title bar testing", &test_window);
2976
if (test_window)
2977
{
2978
// FIXME-DOCK: This window cannot be docked within the ImGui Demo window, this will cause a feedback loop and get them stuck.
2979
// Could we fix this through an ImGuiWindowClass feature? Or an API call to tag our parent as "don't skip items"?
2980
ImGui::Begin("Title bar Hovered/Active tests", &test_window);
2981
if (ImGui::BeginPopupContextItem()) // <-- This is using IsItemHovered()
2982
{
2983
if (ImGui::MenuItem("Close")) { test_window = false; }
2984
ImGui::EndPopup();
2985
}
2986
ImGui::Text(
2987
"IsItemHovered() after begin = %d (== is title bar hovered)\n"
2988
"IsItemActive() after begin = %d (== is window being clicked/moved)\n",
2989
ImGui::IsItemHovered(), ImGui::IsItemActive());
2990
ImGui::End();
2991
}
2992
2993
ImGui::TreePop();
2994
}
2995
2996
// Demonstrate BeginDisabled/EndDisabled using a checkbox located at the bottom of the section (which is a bit odd:
2997
// logically we'd have this checkbox at the top of the section, but we don't want this feature to steal that space)
2998
if (disable_all)
2999
ImGui::EndDisabled();
3000
3001
IMGUI_DEMO_MARKER("Widgets/Disable Block");
3002
if (ImGui::TreeNode("Disable block"))
3003
{
3004
ImGui::Checkbox("Disable entire section above", &disable_all);
3005
ImGui::SameLine(); HelpMarker("Demonstrate using BeginDisabled()/EndDisabled() across this section.");
3006
ImGui::TreePop();
3007
}
3008
3009
IMGUI_DEMO_MARKER("Widgets/Text Filter");
3010
if (ImGui::TreeNode("Text Filter"))
3011
{
3012
// Helper class to easy setup a text filter.
3013
// You may want to implement a more feature-full filtering scheme in your own application.
3014
HelpMarker("Not a widget per-se, but ImGuiTextFilter is a helper to perform simple filtering on text strings.");
3015
static ImGuiTextFilter filter;
3016
ImGui::Text("Filter usage:\n"
3017
" \"\" display all lines\n"
3018
" \"xxx\" display lines containing \"xxx\"\n"
3019
" \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n"
3020
" \"-xxx\" hide lines containing \"xxx\"");
3021
filter.Draw();
3022
const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" };
3023
for (int i = 0; i < IM_ARRAYSIZE(lines); i++)
3024
if (filter.PassFilter(lines[i]))
3025
ImGui::BulletText("%s", lines[i]);
3026
ImGui::TreePop();
3027
}
3028
}
3029
3030
static const char* ExampleNames[] =
3031
{
3032
"Artichoke", "Arugula", "Asparagus", "Avocado", "Bamboo Shoots", "Bean Sprouts", "Beans", "Beet", "Belgian Endive", "Bell Pepper",
3033
"Bitter Gourd", "Bok Choy", "Broccoli", "Brussels Sprouts", "Burdock Root", "Cabbage", "Calabash", "Capers", "Carrot", "Cassava",
3034
"Cauliflower", "Celery", "Celery Root", "Celcuce", "Chayote", "Chinese Broccoli", "Corn", "Cucumber"
3035
};
3036
3037
// Extra functions to add deletion support to ImGuiSelectionBasicStorage
3038
struct ExampleSelectionWithDeletion : ImGuiSelectionBasicStorage
3039
{
3040
// Find which item should be Focused after deletion.
3041
// Call _before_ item submission. Retunr an index in the before-deletion item list, your item loop should call SetKeyboardFocusHere() on it.
3042
// The subsequent ApplyDeletionPostLoop() code will use it to apply Selection.
3043
// - We cannot provide this logic in core Dear ImGui because we don't have access to selection data.
3044
// - We don't actually manipulate the ImVector<> here, only in ApplyDeletionPostLoop(), but using similar API for consistency and flexibility.
3045
// - 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.
3046
// FIXME-MULTISELECT: Doesn't take account of the possibility focus target will be moved during deletion. Need refocus or scroll offset.
3047
int ApplyDeletionPreLoop(ImGuiMultiSelectIO* ms_io, int items_count)
3048
{
3049
if (Size == 0)
3050
return -1;
3051
3052
// If focused item is not selected...
3053
const int focused_idx = (int)ms_io->NavIdItem; // Index of currently focused item
3054
if (ms_io->NavIdSelected == false) // This is merely a shortcut, == Contains(adapter->IndexToStorage(items, focused_idx))
3055
{
3056
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.
3057
return focused_idx; // Request to focus same item after deletion.
3058
}
3059
3060
// If focused item is selected: land on first unselected item after focused item.
3061
for (int idx = focused_idx + 1; idx < items_count; idx++)
3062
if (!Contains(GetStorageIdFromIndex(idx)))
3063
return idx;
3064
3065
// If focused item is selected: otherwise return last unselected item before focused item.
3066
for (int idx = IM_MIN(focused_idx, items_count) - 1; idx >= 0; idx--)
3067
if (!Contains(GetStorageIdFromIndex(idx)))
3068
return idx;
3069
3070
return -1;
3071
}
3072
3073
// Rewrite item list (delete items) + update selection.
3074
// - Call after EndMultiSelect()
3075
// - We cannot provide this logic in core Dear ImGui because we don't have access to your items, nor to selection data.
3076
template<typename ITEM_TYPE>
3077
void ApplyDeletionPostLoop(ImGuiMultiSelectIO* ms_io, ImVector<ITEM_TYPE>& items, int item_curr_idx_to_select)
3078
{
3079
// Rewrite item list (delete items) + convert old selection index (before deletion) to new selection index (after selection).
3080
// If NavId was not part of selection, we will stay on same item.
3081
ImVector<ITEM_TYPE> new_items;
3082
new_items.reserve(items.Size - Size);
3083
int item_next_idx_to_select = -1;
3084
for (int idx = 0; idx < items.Size; idx++)
3085
{
3086
if (!Contains(GetStorageIdFromIndex(idx)))
3087
new_items.push_back(items[idx]);
3088
if (item_curr_idx_to_select == idx)
3089
item_next_idx_to_select = new_items.Size - 1;
3090
}
3091
items.swap(new_items);
3092
3093
// Update selection
3094
Clear();
3095
if (item_next_idx_to_select != -1 && ms_io->NavIdSelected)
3096
SetItemSelected(GetStorageIdFromIndex(item_next_idx_to_select), true);
3097
}
3098
};
3099
3100
// Example: Implement dual list box storage and interface
3101
struct ExampleDualListBox
3102
{
3103
ImVector<ImGuiID> Items[2]; // ID is index into ExampleName[]
3104
ImGuiSelectionBasicStorage Selections[2]; // Store ExampleItemId into selection
3105
bool OptKeepSorted = true;
3106
3107
void MoveAll(int src, int dst)
3108
{
3109
IM_ASSERT((src == 0 && dst == 1) || (src == 1 && dst == 0));
3110
for (ImGuiID item_id : Items[src])
3111
Items[dst].push_back(item_id);
3112
Items[src].clear();
3113
SortItems(dst);
3114
Selections[src].Swap(Selections[dst]);
3115
Selections[src].Clear();
3116
}
3117
void MoveSelected(int src, int dst)
3118
{
3119
for (int src_n = 0; src_n < Items[src].Size; src_n++)
3120
{
3121
ImGuiID item_id = Items[src][src_n];
3122
if (!Selections[src].Contains(item_id))
3123
continue;
3124
Items[src].erase(&Items[src][src_n]); // FIXME-OPT: Could be implemented more optimally (rebuild src items and swap)
3125
Items[dst].push_back(item_id);
3126
src_n--;
3127
}
3128
if (OptKeepSorted)
3129
SortItems(dst);
3130
Selections[src].Swap(Selections[dst]);
3131
Selections[src].Clear();
3132
}
3133
void ApplySelectionRequests(ImGuiMultiSelectIO* ms_io, int side)
3134
{
3135
// In this example we store item id in selection (instead of item index)
3136
Selections[side].UserData = Items[side].Data;
3137
Selections[side].AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { ImGuiID* items = (ImGuiID*)self->UserData; return items[idx]; };
3138
Selections[side].ApplyRequests(ms_io);
3139
}
3140
static int IMGUI_CDECL CompareItemsByValue(const void* lhs, const void* rhs)
3141
{
3142
const int* a = (const int*)lhs;
3143
const int* b = (const int*)rhs;
3144
return (*a - *b) > 0 ? +1 : -1;
3145
}
3146
void SortItems(int n)
3147
{
3148
qsort(Items[n].Data, (size_t)Items[n].Size, sizeof(Items[n][0]), CompareItemsByValue);
3149
}
3150
void Show()
3151
{
3152
//ImGui::Checkbox("Sorted", &OptKeepSorted);
3153
if (ImGui::BeginTable("split", 3, ImGuiTableFlags_None))
3154
{
3155
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch); // Left side
3156
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed); // Buttons
3157
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch); // Right side
3158
ImGui::TableNextRow();
3159
3160
int request_move_selected = -1;
3161
int request_move_all = -1;
3162
float child_height_0 = 0.0f;
3163
for (int side = 0; side < 2; side++)
3164
{
3165
// FIXME-MULTISELECT: Dual List Box: Add context menus
3166
// FIXME-NAV: Using ImGuiWindowFlags_NavFlattened exhibit many issues.
3167
ImVector<ImGuiID>& items = Items[side];
3168
ImGuiSelectionBasicStorage& selection = Selections[side];
3169
3170
ImGui::TableSetColumnIndex((side == 0) ? 0 : 2);
3171
ImGui::Text("%s (%d)", (side == 0) ? "Available" : "Basket", items.Size);
3172
3173
// Submit scrolling range to avoid glitches on moving/deletion
3174
const float items_height = ImGui::GetTextLineHeightWithSpacing();
3175
ImGui::SetNextWindowContentSize(ImVec2(0.0f, items.Size * items_height));
3176
3177
bool child_visible;
3178
if (side == 0)
3179
{
3180
// Left child is resizable
3181
ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetFrameHeightWithSpacing() * 4), ImVec2(FLT_MAX, FLT_MAX));
3182
child_visible = ImGui::BeginChild("0", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY);
3183
child_height_0 = ImGui::GetWindowSize().y;
3184
}
3185
else
3186
{
3187
// Right child use same height as left one
3188
child_visible = ImGui::BeginChild("1", ImVec2(-FLT_MIN, child_height_0), ImGuiChildFlags_FrameStyle);
3189
}
3190
if (child_visible)
3191
{
3192
ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_None;
3193
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size);
3194
ApplySelectionRequests(ms_io, side);
3195
3196
for (int item_n = 0; item_n < items.Size; item_n++)
3197
{
3198
ImGuiID item_id = items[item_n];
3199
bool item_is_selected = selection.Contains(item_id);
3200
ImGui::SetNextItemSelectionUserData(item_n);
3201
ImGui::Selectable(ExampleNames[item_id], item_is_selected, ImGuiSelectableFlags_AllowDoubleClick);
3202
if (ImGui::IsItemFocused())
3203
{
3204
// FIXME-MULTISELECT: Dual List Box: Transfer focus
3205
if (ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_KeypadEnter))
3206
request_move_selected = side;
3207
if (ImGui::IsMouseDoubleClicked(0)) // FIXME-MULTISELECT: Double-click on multi-selection?
3208
request_move_selected = side;
3209
}
3210
}
3211
3212
ms_io = ImGui::EndMultiSelect();
3213
ApplySelectionRequests(ms_io, side);
3214
}
3215
ImGui::EndChild();
3216
}
3217
3218
// Buttons columns
3219
ImGui::TableSetColumnIndex(1);
3220
ImGui::NewLine();
3221
//ImVec2 button_sz = { ImGui::CalcTextSize(">>").x + ImGui::GetStyle().FramePadding.x * 2.0f, ImGui::GetFrameHeight() + padding.y * 2.0f };
3222
ImVec2 button_sz = { ImGui::GetFrameHeight(), ImGui::GetFrameHeight() };
3223
3224
// (Using BeginDisabled()/EndDisabled() works but feels distracting given how it is currently visualized)
3225
if (ImGui::Button(">>", button_sz))
3226
request_move_all = 0;
3227
if (ImGui::Button(">", button_sz))
3228
request_move_selected = 0;
3229
if (ImGui::Button("<", button_sz))
3230
request_move_selected = 1;
3231
if (ImGui::Button("<<", button_sz))
3232
request_move_all = 1;
3233
3234
// Process requests
3235
if (request_move_all != -1)
3236
MoveAll(request_move_all, request_move_all ^ 1);
3237
if (request_move_selected != -1)
3238
MoveSelected(request_move_selected, request_move_selected ^ 1);
3239
3240
// FIXME-MULTISELECT: Support action from outside
3241
/*
3242
if (OptKeepSorted == false)
3243
{
3244
ImGui::NewLine();
3245
if (ImGui::ArrowButton("MoveUp", ImGuiDir_Up)) {}
3246
if (ImGui::ArrowButton("MoveDown", ImGuiDir_Down)) {}
3247
}
3248
*/
3249
3250
ImGui::EndTable();
3251
}
3252
}
3253
};
3254
3255
//-----------------------------------------------------------------------------
3256
// [SECTION] ShowDemoWindowMultiSelect()
3257
//-----------------------------------------------------------------------------
3258
// Multi-selection demos
3259
// Also read: https://github.com/ocornut/imgui/wiki/Multi-Select
3260
//-----------------------------------------------------------------------------
3261
3262
static void ShowDemoWindowMultiSelect(ImGuiDemoWindowData* demo_data)
3263
{
3264
IMGUI_DEMO_MARKER("Widgets/Selection State & Multi-Select");
3265
if (ImGui::TreeNode("Selection State & Multi-Select"))
3266
{
3267
HelpMarker("Selections can be built using Selectable(), TreeNode() or other widgets. Selection state is owned by application code/data.");
3268
3269
// Without any fancy API: manage single-selection yourself.
3270
IMGUI_DEMO_MARKER("Widgets/Selection State/Single-Select");
3271
if (ImGui::TreeNode("Single-Select"))
3272
{
3273
static int selected = -1;
3274
for (int n = 0; n < 5; n++)
3275
{
3276
char buf[32];
3277
sprintf(buf, "Object %d", n);
3278
if (ImGui::Selectable(buf, selected == n))
3279
selected = n;
3280
}
3281
ImGui::TreePop();
3282
}
3283
3284
// Demonstrate implementation a most-basic form of multi-selection manually
3285
// This doesn't support the SHIFT modifier which requires BeginMultiSelect()!
3286
IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (manual/simplified, without BeginMultiSelect)");
3287
if (ImGui::TreeNode("Multi-Select (manual/simplified, without BeginMultiSelect)"))
3288
{
3289
HelpMarker("Hold CTRL and click to select multiple items.");
3290
static bool selection[5] = { false, false, false, false, false };
3291
for (int n = 0; n < 5; n++)
3292
{
3293
char buf[32];
3294
sprintf(buf, "Object %d", n);
3295
if (ImGui::Selectable(buf, selection[n]))
3296
{
3297
if (!ImGui::GetIO().KeyCtrl) // Clear selection when CTRL is not held
3298
memset(selection, 0, sizeof(selection));
3299
selection[n] ^= 1; // Toggle current item
3300
}
3301
}
3302
ImGui::TreePop();
3303
}
3304
3305
// Demonstrate handling proper multi-selection using the BeginMultiSelect/EndMultiSelect API.
3306
// SHIFT+Click w/ CTRL and other standard features are supported.
3307
// We use the ImGuiSelectionBasicStorage helper which you may freely reimplement.
3308
IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select");
3309
if (ImGui::TreeNode("Multi-Select"))
3310
{
3311
ImGui::Text("Supported features:");
3312
ImGui::BulletText("Keyboard navigation (arrows, page up/down, home/end, space).");
3313
ImGui::BulletText("Ctrl modifier to preserve and toggle selection.");
3314
ImGui::BulletText("Shift modifier for range selection.");
3315
ImGui::BulletText("CTRL+A to select all.");
3316
ImGui::BulletText("Escape to clear selection.");
3317
ImGui::BulletText("Click and drag to box-select.");
3318
ImGui::Text("Tip: Use 'Demo->Tools->Debug Log->Selection' to see selection requests as they happen.");
3319
3320
// Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection
3321
const int ITEMS_COUNT = 50;
3322
static ImGuiSelectionBasicStorage selection;
3323
ImGui::Text("Selection: %d/%d", selection.Size, ITEMS_COUNT);
3324
3325
// The BeginChild() has no purpose for selection logic, other that offering a scrolling region.
3326
if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
3327
{
3328
ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
3329
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT);
3330
selection.ApplyRequests(ms_io);
3331
3332
for (int n = 0; n < ITEMS_COUNT; n++)
3333
{
3334
char label[64];
3335
sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_ARRAYSIZE(ExampleNames)]);
3336
bool item_is_selected = selection.Contains((ImGuiID)n);
3337
ImGui::SetNextItemSelectionUserData(n);
3338
ImGui::Selectable(label, item_is_selected);
3339
}
3340
3341
ms_io = ImGui::EndMultiSelect();
3342
selection.ApplyRequests(ms_io);
3343
}
3344
ImGui::EndChild();
3345
ImGui::TreePop();
3346
}
3347
3348
// Demonstrate using the clipper with BeginMultiSelect()/EndMultiSelect()
3349
IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (with clipper)");
3350
if (ImGui::TreeNode("Multi-Select (with clipper)"))
3351
{
3352
// Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection
3353
static ImGuiSelectionBasicStorage selection;
3354
3355
ImGui::Text("Added features:");
3356
ImGui::BulletText("Using ImGuiListClipper.");
3357
3358
const int ITEMS_COUNT = 10000;
3359
ImGui::Text("Selection: %d/%d", selection.Size, ITEMS_COUNT);
3360
if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
3361
{
3362
ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
3363
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT);
3364
selection.ApplyRequests(ms_io);
3365
3366
ImGuiListClipper clipper;
3367
clipper.Begin(ITEMS_COUNT);
3368
if (ms_io->RangeSrcItem != -1)
3369
clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped.
3370
while (clipper.Step())
3371
{
3372
for (int n = clipper.DisplayStart; n < clipper.DisplayEnd; n++)
3373
{
3374
char label[64];
3375
sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_ARRAYSIZE(ExampleNames)]);
3376
bool item_is_selected = selection.Contains((ImGuiID)n);
3377
ImGui::SetNextItemSelectionUserData(n);
3378
ImGui::Selectable(label, item_is_selected);
3379
}
3380
}
3381
3382
ms_io = ImGui::EndMultiSelect();
3383
selection.ApplyRequests(ms_io);
3384
}
3385
ImGui::EndChild();
3386
ImGui::TreePop();
3387
}
3388
3389
// Demonstrate dynamic item list + deletion support using the BeginMultiSelect/EndMultiSelect API.
3390
// In order to support Deletion without any glitches you need to:
3391
// - (1) If items are submitted in their own scrolling area, submit contents size SetNextWindowContentSize() ahead of time to prevent one-frame readjustment of scrolling.
3392
// - (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.
3393
// - (3) BeginXXXX process
3394
// - (4) Focus process
3395
// - (5) EndXXXX process
3396
IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (with deletion)");
3397
if (ImGui::TreeNode("Multi-Select (with deletion)"))
3398
{
3399
// Storing items data separately from selection data.
3400
// (you may decide to store selection data inside your item (aka intrusive storage) if you don't need multiple views over same items)
3401
// Use a custom selection.Adapter: store item identifier in Selection (instead of index)
3402
static ImVector<ImGuiID> items;
3403
static ExampleSelectionWithDeletion selection;
3404
selection.UserData = (void*)&items;
3405
selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { ImVector<ImGuiID>* p_items = (ImVector<ImGuiID>*)self->UserData; return (*p_items)[idx]; }; // Index -> ID
3406
3407
ImGui::Text("Added features:");
3408
ImGui::BulletText("Dynamic list with Delete key support.");
3409
ImGui::Text("Selection size: %d/%d", selection.Size, items.Size);
3410
3411
// Initialize default list with 50 items + button to add/remove items.
3412
static ImGuiID items_next_id = 0;
3413
if (items_next_id == 0)
3414
for (ImGuiID n = 0; n < 50; n++)
3415
items.push_back(items_next_id++);
3416
if (ImGui::SmallButton("Add 20 items")) { for (int n = 0; n < 20; n++) { items.push_back(items_next_id++); } }
3417
ImGui::SameLine();
3418
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(); } }
3419
3420
// (1) Extra to support deletion: Submit scrolling range to avoid glitches on deletion
3421
const float items_height = ImGui::GetTextLineHeightWithSpacing();
3422
ImGui::SetNextWindowContentSize(ImVec2(0.0f, items.Size * items_height));
3423
3424
if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
3425
{
3426
ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
3427
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size);
3428
selection.ApplyRequests(ms_io);
3429
3430
const bool want_delete = ImGui::Shortcut(ImGuiKey_Delete, ImGuiInputFlags_Repeat) && (selection.Size > 0);
3431
const int item_curr_idx_to_focus = want_delete ? selection.ApplyDeletionPreLoop(ms_io, items.Size) : -1;
3432
3433
for (int n = 0; n < items.Size; n++)
3434
{
3435
const ImGuiID item_id = items[n];
3436
char label[64];
3437
sprintf(label, "Object %05u: %s", item_id, ExampleNames[item_id % IM_ARRAYSIZE(ExampleNames)]);
3438
3439
bool item_is_selected = selection.Contains(item_id);
3440
ImGui::SetNextItemSelectionUserData(n);
3441
ImGui::Selectable(label, item_is_selected);
3442
if (item_curr_idx_to_focus == n)
3443
ImGui::SetKeyboardFocusHere(-1);
3444
}
3445
3446
// Apply multi-select requests
3447
ms_io = ImGui::EndMultiSelect();
3448
selection.ApplyRequests(ms_io);
3449
if (want_delete)
3450
selection.ApplyDeletionPostLoop(ms_io, items, item_curr_idx_to_focus);
3451
}
3452
ImGui::EndChild();
3453
ImGui::TreePop();
3454
}
3455
3456
// Implement a Dual List Box (#6648)
3457
IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (dual list box)");
3458
if (ImGui::TreeNode("Multi-Select (dual list box)"))
3459
{
3460
// Init default state
3461
static ExampleDualListBox dlb;
3462
if (dlb.Items[0].Size == 0 && dlb.Items[1].Size == 0)
3463
for (int item_id = 0; item_id < IM_ARRAYSIZE(ExampleNames); item_id++)
3464
dlb.Items[0].push_back((ImGuiID)item_id);
3465
3466
// Show
3467
dlb.Show();
3468
3469
ImGui::TreePop();
3470
}
3471
3472
// Demonstrate using the clipper with BeginMultiSelect()/EndMultiSelect()
3473
IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (in a table)");
3474
if (ImGui::TreeNode("Multi-Select (in a table)"))
3475
{
3476
static ImGuiSelectionBasicStorage selection;
3477
3478
const int ITEMS_COUNT = 10000;
3479
ImGui::Text("Selection: %d/%d", selection.Size, ITEMS_COUNT);
3480
if (ImGui::BeginTable("##Basket", 2, ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter))
3481
{
3482
ImGui::TableSetupColumn("Object");
3483
ImGui::TableSetupColumn("Action");
3484
ImGui::TableSetupScrollFreeze(0, 1);
3485
ImGui::TableHeadersRow();
3486
3487
ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
3488
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT);
3489
selection.ApplyRequests(ms_io);
3490
3491
ImGuiListClipper clipper;
3492
clipper.Begin(ITEMS_COUNT);
3493
if (ms_io->RangeSrcItem != -1)
3494
clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped.
3495
while (clipper.Step())
3496
{
3497
for (int n = clipper.DisplayStart; n < clipper.DisplayEnd; n++)
3498
{
3499
ImGui::TableNextRow();
3500
ImGui::TableNextColumn();
3501
char label[64];
3502
sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_ARRAYSIZE(ExampleNames)]);
3503
bool item_is_selected = selection.Contains((ImGuiID)n);
3504
ImGui::SetNextItemSelectionUserData(n);
3505
ImGui::Selectable(label, item_is_selected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap);
3506
ImGui::TableNextColumn();
3507
ImGui::SmallButton("hello");
3508
}
3509
}
3510
3511
ms_io = ImGui::EndMultiSelect();
3512
selection.ApplyRequests(ms_io);
3513
ImGui::EndTable();
3514
}
3515
ImGui::TreePop();
3516
}
3517
3518
IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (checkboxes)");
3519
if (ImGui::TreeNode("Multi-Select (checkboxes)"))
3520
{
3521
ImGui::Text("In a list of checkboxes (not selectable):");
3522
ImGui::BulletText("Using _NoAutoSelect + _NoAutoClear flags.");
3523
ImGui::BulletText("Shift+Click to check multiple boxes.");
3524
ImGui::BulletText("Shift+Keyboard to copy current value to other boxes.");
3525
3526
// If you have an array of checkboxes, you may want to use NoAutoSelect + NoAutoClear and the ImGuiSelectionExternalStorage helper.
3527
static bool items[20] = {};
3528
static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_NoAutoSelect | ImGuiMultiSelectFlags_NoAutoClear | ImGuiMultiSelectFlags_ClearOnEscape;
3529
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoSelect", &flags, ImGuiMultiSelectFlags_NoAutoSelect);
3530
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoClear", &flags, ImGuiMultiSelectFlags_NoAutoClear);
3531
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect2d", &flags, ImGuiMultiSelectFlags_BoxSelect2d); // Cannot use ImGuiMultiSelectFlags_BoxSelect1d as checkboxes are varying width.
3532
3533
if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeY))
3534
{
3535
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, -1, IM_ARRAYSIZE(items));
3536
ImGuiSelectionExternalStorage storage_wrapper;
3537
storage_wrapper.UserData = (void*)items;
3538
storage_wrapper.AdapterSetItemSelected = [](ImGuiSelectionExternalStorage* self, int n, bool selected) { bool* array = (bool*)self->UserData; array[n] = selected; };
3539
storage_wrapper.ApplyRequests(ms_io);
3540
for (int n = 0; n < 20; n++)
3541
{
3542
char label[32];
3543
sprintf(label, "Item %d", n);
3544
ImGui::SetNextItemSelectionUserData(n);
3545
ImGui::Checkbox(label, &items[n]);
3546
}
3547
ms_io = ImGui::EndMultiSelect();
3548
storage_wrapper.ApplyRequests(ms_io);
3549
}
3550
ImGui::EndChild();
3551
3552
ImGui::TreePop();
3553
}
3554
3555
// Demonstrate individual selection scopes in same window
3556
IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (multiple scopes)");
3557
if (ImGui::TreeNode("Multi-Select (multiple scopes)"))
3558
{
3559
// Use default select: Pass index to SetNextItemSelectionUserData(), store index in Selection
3560
const int SCOPES_COUNT = 3;
3561
const int ITEMS_COUNT = 8; // Per scope
3562
static ImGuiSelectionBasicStorage selections_data[SCOPES_COUNT];
3563
3564
// Use ImGuiMultiSelectFlags_ScopeRect to not affect other selections in same window.
3565
static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ScopeRect | ImGuiMultiSelectFlags_ClearOnEscape;// | ImGuiMultiSelectFlags_ClearOnClickVoid;
3566
if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeWindow", &flags, ImGuiMultiSelectFlags_ScopeWindow) && (flags & ImGuiMultiSelectFlags_ScopeWindow))
3567
flags &= ~ImGuiMultiSelectFlags_ScopeRect;
3568
if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeRect", &flags, ImGuiMultiSelectFlags_ScopeRect) && (flags & ImGuiMultiSelectFlags_ScopeRect))
3569
flags &= ~ImGuiMultiSelectFlags_ScopeWindow;
3570
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnClickVoid", &flags, ImGuiMultiSelectFlags_ClearOnClickVoid);
3571
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect1d", &flags, ImGuiMultiSelectFlags_BoxSelect1d);
3572
3573
for (int selection_scope_n = 0; selection_scope_n < SCOPES_COUNT; selection_scope_n++)
3574
{
3575
ImGui::PushID(selection_scope_n);
3576
ImGuiSelectionBasicStorage* selection = &selections_data[selection_scope_n];
3577
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection->Size, ITEMS_COUNT);
3578
selection->ApplyRequests(ms_io);
3579
3580
ImGui::SeparatorText("Selection scope");
3581
ImGui::Text("Selection size: %d/%d", selection->Size, ITEMS_COUNT);
3582
3583
for (int n = 0; n < ITEMS_COUNT; n++)
3584
{
3585
char label[64];
3586
sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_ARRAYSIZE(ExampleNames)]);
3587
bool item_is_selected = selection->Contains((ImGuiID)n);
3588
ImGui::SetNextItemSelectionUserData(n);
3589
ImGui::Selectable(label, item_is_selected);
3590
}
3591
3592
// Apply multi-select requests
3593
ms_io = ImGui::EndMultiSelect();
3594
selection->ApplyRequests(ms_io);
3595
ImGui::PopID();
3596
}
3597
ImGui::TreePop();
3598
}
3599
3600
// See ShowExampleAppAssetsBrowser()
3601
if (ImGui::TreeNode("Multi-Select (tiled assets browser)"))
3602
{
3603
ImGui::Checkbox("Assets Browser", &demo_data->ShowAppAssetsBrowser);
3604
ImGui::Text("(also access from 'Examples->Assets Browser' in menu)");
3605
ImGui::TreePop();
3606
}
3607
3608
// Demonstrate supporting multiple-selection in a tree.
3609
// - We don't use linear indices for selection user data, but our ExampleTreeNode* pointer directly!
3610
// This showcase how SetNextItemSelectionUserData() never assume indices!
3611
// - The difficulty here is to "interpolate" from RangeSrcItem to RangeDstItem in the SetAll/SetRange request.
3612
// We want this interpolation to match what the user sees: in visible order, skipping closed nodes.
3613
// This is implemented by our TreeGetNextNodeInVisibleOrder() user-space helper.
3614
// - Important: In a real codebase aiming to implement full-featured selectable tree with custom filtering, you
3615
// are more likely to build an array mapping sequential indices to visible tree nodes, since your
3616
// filtering/search + clipping process will benefit from it. Having this will make this interpolation much easier.
3617
// - Consider this a prototype: we are working toward simplifying some of it.
3618
IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (trees)");
3619
if (ImGui::TreeNode("Multi-Select (trees)"))
3620
{
3621
HelpMarker(
3622
"This is rather advanced and experimental. If you are getting started with multi-select,"
3623
"please don't start by looking at how to use it for a tree!\n\n"
3624
"Future versions will try to simplify and formalize some of this.");
3625
3626
struct ExampleTreeFuncs
3627
{
3628
static void DrawNode(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection)
3629
{
3630
ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;
3631
tree_node_flags |= ImGuiTreeNodeFlags_NavLeftJumpsBackHere; // Enable pressing left to jump to parent
3632
if (node->Childs.Size == 0)
3633
tree_node_flags |= ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_Leaf;
3634
if (selection->Contains((ImGuiID)node->UID))
3635
tree_node_flags |= ImGuiTreeNodeFlags_Selected;
3636
3637
// Using SetNextItemStorageID() to specify storage id, so we can easily peek into
3638
// the storage holding open/close stage, using our TreeNodeGetOpen/TreeNodeSetOpen() functions.
3639
ImGui::SetNextItemSelectionUserData((ImGuiSelectionUserData)(intptr_t)node);
3640
ImGui::SetNextItemStorageID((ImGuiID)node->UID);
3641
if (ImGui::TreeNodeEx(node->Name, tree_node_flags))
3642
{
3643
for (ExampleTreeNode* child : node->Childs)
3644
DrawNode(child, selection);
3645
ImGui::TreePop();
3646
}
3647
else if (ImGui::IsItemToggledOpen())
3648
{
3649
TreeCloseAndUnselectChildNodes(node, selection);
3650
}
3651
}
3652
3653
static bool TreeNodeGetOpen(ExampleTreeNode* node)
3654
{
3655
return ImGui::GetStateStorage()->GetBool((ImGuiID)node->UID);
3656
}
3657
3658
static void TreeNodeSetOpen(ExampleTreeNode* node, bool open)
3659
{
3660
ImGui::GetStateStorage()->SetBool((ImGuiID)node->UID, open);
3661
}
3662
3663
// When closing a node: 1) close and unselect all child nodes, 2) select parent if any child was selected.
3664
// FIXME: This is currently handled by user logic but I'm hoping to eventually provide tree node
3665
// features to do this automatically, e.g. a ImGuiTreeNodeFlags_AutoCloseChildNodes etc.
3666
static int TreeCloseAndUnselectChildNodes(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection, int depth = 0)
3667
{
3668
// Recursive close (the test for depth == 0 is because we call this on a node that was just closed!)
3669
int unselected_count = selection->Contains((ImGuiID)node->UID) ? 1 : 0;
3670
if (depth == 0 || TreeNodeGetOpen(node))
3671
{
3672
for (ExampleTreeNode* child : node->Childs)
3673
unselected_count += TreeCloseAndUnselectChildNodes(child, selection, depth + 1);
3674
TreeNodeSetOpen(node, false);
3675
}
3676
3677
// Select root node if any of its child was selected, otherwise unselect
3678
selection->SetItemSelected((ImGuiID)node->UID, (depth == 0 && unselected_count > 0));
3679
return unselected_count;
3680
}
3681
3682
// Apply multi-selection requests
3683
static void ApplySelectionRequests(ImGuiMultiSelectIO* ms_io, ExampleTreeNode* tree, ImGuiSelectionBasicStorage* selection)
3684
{
3685
for (ImGuiSelectionRequest& req : ms_io->Requests)
3686
{
3687
if (req.Type == ImGuiSelectionRequestType_SetAll)
3688
{
3689
if (req.Selected)
3690
TreeSetAllInOpenNodes(tree, selection, req.Selected);
3691
else
3692
selection->Clear();
3693
}
3694
else if (req.Type == ImGuiSelectionRequestType_SetRange)
3695
{
3696
ExampleTreeNode* first_node = (ExampleTreeNode*)(intptr_t)req.RangeFirstItem;
3697
ExampleTreeNode* last_node = (ExampleTreeNode*)(intptr_t)req.RangeLastItem;
3698
for (ExampleTreeNode* node = first_node; node != NULL; node = TreeGetNextNodeInVisibleOrder(node, last_node))
3699
selection->SetItemSelected((ImGuiID)node->UID, req.Selected);
3700
}
3701
}
3702
}
3703
3704
static void TreeSetAllInOpenNodes(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection, bool selected)
3705
{
3706
if (node->Parent != NULL) // Root node isn't visible nor selectable in our scheme
3707
selection->SetItemSelected((ImGuiID)node->UID, selected);
3708
if (node->Parent == NULL || TreeNodeGetOpen(node))
3709
for (ExampleTreeNode* child : node->Childs)
3710
TreeSetAllInOpenNodes(child, selection, selected);
3711
}
3712
3713
// Interpolate in *user-visible order* AND only *over opened nodes*.
3714
// If you have a sequential mapping tables (e.g. generated after a filter/search pass) this would be simpler.
3715
// Here the tricks are that:
3716
// - we store/maintain ExampleTreeNode::IndexInParent which allows implementing a linear iterator easily, without searches, without recursion.
3717
// this could be replaced by a search in parent, aka 'int index_in_parent = curr_node->Parent->Childs.find_index(curr_node)'
3718
// which would only be called when crossing from child to a parent, aka not too much.
3719
// - we call SetNextItemStorageID() before our TreeNode() calls with an ID which doesn't relate to UI stack,
3720
// making it easier to call TreeNodeGetOpen()/TreeNodeSetOpen() from any location.
3721
static ExampleTreeNode* TreeGetNextNodeInVisibleOrder(ExampleTreeNode* curr_node, ExampleTreeNode* last_node)
3722
{
3723
// Reached last node
3724
if (curr_node == last_node)
3725
return NULL;
3726
3727
// Recurse into childs. Query storage to tell if the node is open.
3728
if (curr_node->Childs.Size > 0 && TreeNodeGetOpen(curr_node))
3729
return curr_node->Childs[0];
3730
3731
// Next sibling, then into our own parent
3732
while (curr_node->Parent != NULL)
3733
{
3734
if (curr_node->IndexInParent + 1 < curr_node->Parent->Childs.Size)
3735
return curr_node->Parent->Childs[curr_node->IndexInParent + 1];
3736
curr_node = curr_node->Parent;
3737
}
3738
return NULL;
3739
}
3740
3741
}; // ExampleTreeFuncs
3742
3743
static ImGuiSelectionBasicStorage selection;
3744
if (demo_data->DemoTree == NULL)
3745
demo_data->DemoTree = ExampleTree_CreateDemoTree(); // Create tree once
3746
ImGui::Text("Selection size: %d", selection.Size);
3747
3748
if (ImGui::BeginChild("##Tree", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
3749
{
3750
ExampleTreeNode* tree = demo_data->DemoTree;
3751
ImGuiMultiSelectFlags ms_flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect2d;
3752
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(ms_flags, selection.Size, -1);
3753
ExampleTreeFuncs::ApplySelectionRequests(ms_io, tree, &selection);
3754
for (ExampleTreeNode* node : tree->Childs)
3755
ExampleTreeFuncs::DrawNode(node, &selection);
3756
ms_io = ImGui::EndMultiSelect();
3757
ExampleTreeFuncs::ApplySelectionRequests(ms_io, tree, &selection);
3758
}
3759
ImGui::EndChild();
3760
3761
ImGui::TreePop();
3762
}
3763
3764
// Advanced demonstration of BeginMultiSelect()
3765
// - Showcase clipping.
3766
// - Showcase deletion.
3767
// - Showcase basic drag and drop.
3768
// - Showcase TreeNode variant (note that tree node don't expand in the demo: supporting expanding tree nodes + clipping a separate thing).
3769
// - Showcase using inside a table.
3770
IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (advanced)");
3771
//ImGui::SetNextItemOpen(true, ImGuiCond_Once);
3772
if (ImGui::TreeNode("Multi-Select (advanced)"))
3773
{
3774
// Options
3775
enum WidgetType { WidgetType_Selectable, WidgetType_TreeNode };
3776
static bool use_clipper = true;
3777
static bool use_deletion = true;
3778
static bool use_drag_drop = true;
3779
static bool show_in_table = false;
3780
static bool show_color_button = true;
3781
static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
3782
static WidgetType widget_type = WidgetType_Selectable;
3783
3784
if (ImGui::TreeNode("Options"))
3785
{
3786
if (ImGui::RadioButton("Selectables", widget_type == WidgetType_Selectable)) { widget_type = WidgetType_Selectable; }
3787
ImGui::SameLine();
3788
if (ImGui::RadioButton("Tree nodes", widget_type == WidgetType_TreeNode)) { widget_type = WidgetType_TreeNode; }
3789
ImGui::SameLine();
3790
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.");
3791
ImGui::Checkbox("Enable clipper", &use_clipper);
3792
ImGui::Checkbox("Enable deletion", &use_deletion);
3793
ImGui::Checkbox("Enable drag & drop", &use_drag_drop);
3794
ImGui::Checkbox("Show in a table", &show_in_table);
3795
ImGui::Checkbox("Show color button", &show_color_button);
3796
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SingleSelect", &flags, ImGuiMultiSelectFlags_SingleSelect);
3797
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoSelectAll", &flags, ImGuiMultiSelectFlags_NoSelectAll);
3798
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoRangeSelect", &flags, ImGuiMultiSelectFlags_NoRangeSelect);
3799
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoSelect", &flags, ImGuiMultiSelectFlags_NoAutoSelect);
3800
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoClear", &flags, ImGuiMultiSelectFlags_NoAutoClear);
3801
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoClearOnReselect", &flags, ImGuiMultiSelectFlags_NoAutoClearOnReselect);
3802
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect1d", &flags, ImGuiMultiSelectFlags_BoxSelect1d);
3803
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect2d", &flags, ImGuiMultiSelectFlags_BoxSelect2d);
3804
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelectNoScroll", &flags, ImGuiMultiSelectFlags_BoxSelectNoScroll);
3805
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnEscape", &flags, ImGuiMultiSelectFlags_ClearOnEscape);
3806
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnClickVoid", &flags, ImGuiMultiSelectFlags_ClearOnClickVoid);
3807
if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeWindow", &flags, ImGuiMultiSelectFlags_ScopeWindow) && (flags & ImGuiMultiSelectFlags_ScopeWindow))
3808
flags &= ~ImGuiMultiSelectFlags_ScopeRect;
3809
if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeRect", &flags, ImGuiMultiSelectFlags_ScopeRect) && (flags & ImGuiMultiSelectFlags_ScopeRect))
3810
flags &= ~ImGuiMultiSelectFlags_ScopeWindow;
3811
if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SelectOnClick", &flags, ImGuiMultiSelectFlags_SelectOnClick) && (flags & ImGuiMultiSelectFlags_SelectOnClick))
3812
flags &= ~ImGuiMultiSelectFlags_SelectOnClickRelease;
3813
if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SelectOnClickRelease", &flags, ImGuiMultiSelectFlags_SelectOnClickRelease) && (flags & ImGuiMultiSelectFlags_SelectOnClickRelease))
3814
flags &= ~ImGuiMultiSelectFlags_SelectOnClick;
3815
ImGui::SameLine(); HelpMarker("Allow dragging an unselected item without altering selection.");
3816
ImGui::TreePop();
3817
}
3818
3819
// Initialize default list with 1000 items.
3820
// Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection
3821
static ImVector<int> items;
3822
static int items_next_id = 0;
3823
if (items_next_id == 0) { for (int n = 0; n < 1000; n++) { items.push_back(items_next_id++); } }
3824
static ExampleSelectionWithDeletion selection;
3825
static bool request_deletion_from_menu = false; // Queue deletion triggered from context menu
3826
3827
ImGui::Text("Selection size: %d/%d", selection.Size, items.Size);
3828
3829
const float items_height = (widget_type == WidgetType_TreeNode) ? ImGui::GetTextLineHeight() : ImGui::GetTextLineHeightWithSpacing();
3830
ImGui::SetNextWindowContentSize(ImVec2(0.0f, items.Size * items_height));
3831
if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
3832
{
3833
ImVec2 color_button_sz(ImGui::GetFontSize(), ImGui::GetFontSize());
3834
if (widget_type == WidgetType_TreeNode)
3835
ImGui::PushStyleVarY(ImGuiStyleVar_ItemSpacing, 0.0f);
3836
3837
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size);
3838
selection.ApplyRequests(ms_io);
3839
3840
const bool want_delete = (ImGui::Shortcut(ImGuiKey_Delete, ImGuiInputFlags_Repeat) && (selection.Size > 0)) || request_deletion_from_menu;
3841
const int item_curr_idx_to_focus = want_delete ? selection.ApplyDeletionPreLoop(ms_io, items.Size) : -1;
3842
request_deletion_from_menu = false;
3843
3844
if (show_in_table)
3845
{
3846
if (widget_type == WidgetType_TreeNode)
3847
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(0.0f, 0.0f));
3848
ImGui::BeginTable("##Split", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_NoPadOuterX);
3849
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 0.70f);
3850
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 0.30f);
3851
//ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacingY, 0.0f);
3852
}
3853
3854
ImGuiListClipper clipper;
3855
if (use_clipper)
3856
{
3857
clipper.Begin(items.Size);
3858
if (item_curr_idx_to_focus != -1)
3859
clipper.IncludeItemByIndex(item_curr_idx_to_focus); // Ensure focused item is not clipped.
3860
if (ms_io->RangeSrcItem != -1)
3861
clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped.
3862
}
3863
3864
while (!use_clipper || clipper.Step())
3865
{
3866
const int item_begin = use_clipper ? clipper.DisplayStart : 0;
3867
const int item_end = use_clipper ? clipper.DisplayEnd : items.Size;
3868
for (int n = item_begin; n < item_end; n++)
3869
{
3870
if (show_in_table)
3871
ImGui::TableNextColumn();
3872
3873
const int item_id = items[n];
3874
const char* item_category = ExampleNames[item_id % IM_ARRAYSIZE(ExampleNames)];
3875
char label[64];
3876
sprintf(label, "Object %05d: %s", item_id, item_category);
3877
3878
// IMPORTANT: for deletion refocus to work we need object ID to be stable,
3879
// aka not depend on their index in the list. Here we use our persistent item_id
3880
// instead of index to build a unique ID that will persist.
3881
// (If we used PushID(index) instead, focus wouldn't be restored correctly after deletion).
3882
ImGui::PushID(item_id);
3883
3884
// Emit a color button, to test that Shift+LeftArrow landing on an item that is not part
3885
// of the selection scope doesn't erroneously alter our selection.
3886
if (show_color_button)
3887
{
3888
ImU32 dummy_col = (ImU32)((unsigned int)n * 0xC250B74B) | IM_COL32_A_MASK;
3889
ImGui::ColorButton("##", ImColor(dummy_col), ImGuiColorEditFlags_NoTooltip, color_button_sz);
3890
ImGui::SameLine();
3891
}
3892
3893
// Submit item
3894
bool item_is_selected = selection.Contains((ImGuiID)n);
3895
bool item_is_open = false;
3896
ImGui::SetNextItemSelectionUserData(n);
3897
if (widget_type == WidgetType_Selectable)
3898
{
3899
ImGui::Selectable(label, item_is_selected, ImGuiSelectableFlags_None);
3900
}
3901
else if (widget_type == WidgetType_TreeNode)
3902
{
3903
ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;
3904
if (item_is_selected)
3905
tree_node_flags |= ImGuiTreeNodeFlags_Selected;
3906
item_is_open = ImGui::TreeNodeEx(label, tree_node_flags);
3907
}
3908
3909
// Focus (for after deletion)
3910
if (item_curr_idx_to_focus == n)
3911
ImGui::SetKeyboardFocusHere(-1);
3912
3913
// Drag and Drop
3914
if (use_drag_drop && ImGui::BeginDragDropSource())
3915
{
3916
// Create payload with full selection OR single unselected item.
3917
// (the later is only possible when using ImGuiMultiSelectFlags_SelectOnClickRelease)
3918
if (ImGui::GetDragDropPayload() == NULL)
3919
{
3920
ImVector<int> payload_items;
3921
void* it = NULL;
3922
ImGuiID id = 0;
3923
if (!item_is_selected)
3924
payload_items.push_back(item_id);
3925
else
3926
while (selection.GetNextSelectedItem(&it, &id))
3927
payload_items.push_back((int)id);
3928
ImGui::SetDragDropPayload("MULTISELECT_DEMO_ITEMS", payload_items.Data, (size_t)payload_items.size_in_bytes());
3929
}
3930
3931
// Display payload content in tooltip
3932
const ImGuiPayload* payload = ImGui::GetDragDropPayload();
3933
const int* payload_items = (int*)payload->Data;
3934
const int payload_count = (int)payload->DataSize / (int)sizeof(int);
3935
if (payload_count == 1)
3936
ImGui::Text("Object %05d: %s", payload_items[0], ExampleNames[payload_items[0] % IM_ARRAYSIZE(ExampleNames)]);
3937
else
3938
ImGui::Text("Dragging %d objects", payload_count);
3939
3940
ImGui::EndDragDropSource();
3941
}
3942
3943
if (widget_type == WidgetType_TreeNode && item_is_open)
3944
ImGui::TreePop();
3945
3946
// Right-click: context menu
3947
if (ImGui::BeginPopupContextItem())
3948
{
3949
ImGui::BeginDisabled(!use_deletion || selection.Size == 0);
3950
sprintf(label, "Delete %d item(s)###DeleteSelected", selection.Size);
3951
if (ImGui::Selectable(label))
3952
request_deletion_from_menu = true;
3953
ImGui::EndDisabled();
3954
ImGui::Selectable("Close");
3955
ImGui::EndPopup();
3956
}
3957
3958
// Demo content within a table
3959
if (show_in_table)
3960
{
3961
ImGui::TableNextColumn();
3962
ImGui::SetNextItemWidth(-FLT_MIN);
3963
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
3964
ImGui::InputText("###NoLabel", (char*)(void*)item_category, strlen(item_category), ImGuiInputTextFlags_ReadOnly);
3965
ImGui::PopStyleVar();
3966
}
3967
3968
ImGui::PopID();
3969
}
3970
if (!use_clipper)
3971
break;
3972
}
3973
3974
if (show_in_table)
3975
{
3976
ImGui::EndTable();
3977
if (widget_type == WidgetType_TreeNode)
3978
ImGui::PopStyleVar();
3979
}
3980
3981
// Apply multi-select requests
3982
ms_io = ImGui::EndMultiSelect();
3983
selection.ApplyRequests(ms_io);
3984
if (want_delete)
3985
selection.ApplyDeletionPostLoop(ms_io, items, item_curr_idx_to_focus);
3986
3987
if (widget_type == WidgetType_TreeNode)
3988
ImGui::PopStyleVar();
3989
}
3990
ImGui::EndChild();
3991
ImGui::TreePop();
3992
}
3993
ImGui::TreePop();
3994
}
3995
}
3996
3997
//-----------------------------------------------------------------------------
3998
// [SECTION] ShowDemoWindowLayout()
3999
//-----------------------------------------------------------------------------
4000
4001
static void ShowDemoWindowLayout()
4002
{
4003
IMGUI_DEMO_MARKER("Layout");
4004
if (!ImGui::CollapsingHeader("Layout & Scrolling"))
4005
return;
4006
4007
IMGUI_DEMO_MARKER("Layout/Child windows");
4008
if (ImGui::TreeNode("Child windows"))
4009
{
4010
ImGui::SeparatorText("Child windows");
4011
4012
HelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window.");
4013
static bool disable_mouse_wheel = false;
4014
static bool disable_menu = false;
4015
ImGui::Checkbox("Disable Mouse Wheel", &disable_mouse_wheel);
4016
ImGui::Checkbox("Disable Menu", &disable_menu);
4017
4018
// Child 1: no border, enable horizontal scrollbar
4019
{
4020
ImGuiWindowFlags window_flags = ImGuiWindowFlags_HorizontalScrollbar;
4021
if (disable_mouse_wheel)
4022
window_flags |= ImGuiWindowFlags_NoScrollWithMouse;
4023
ImGui::BeginChild("ChildL", ImVec2(ImGui::GetContentRegionAvail().x * 0.5f, 260), ImGuiChildFlags_None, window_flags);
4024
for (int i = 0; i < 100; i++)
4025
ImGui::Text("%04d: scrollable region", i);
4026
ImGui::EndChild();
4027
}
4028
4029
ImGui::SameLine();
4030
4031
// Child 2: rounded border
4032
{
4033
ImGuiWindowFlags window_flags = ImGuiWindowFlags_None;
4034
if (disable_mouse_wheel)
4035
window_flags |= ImGuiWindowFlags_NoScrollWithMouse;
4036
if (!disable_menu)
4037
window_flags |= ImGuiWindowFlags_MenuBar;
4038
ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f);
4039
ImGui::BeginChild("ChildR", ImVec2(0, 260), ImGuiChildFlags_Borders, window_flags);
4040
if (!disable_menu && ImGui::BeginMenuBar())
4041
{
4042
if (ImGui::BeginMenu("Menu"))
4043
{
4044
ShowExampleMenuFile();
4045
ImGui::EndMenu();
4046
}
4047
ImGui::EndMenuBar();
4048
}
4049
if (ImGui::BeginTable("split", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings))
4050
{
4051
for (int i = 0; i < 100; i++)
4052
{
4053
char buf[32];
4054
sprintf(buf, "%03d", i);
4055
ImGui::TableNextColumn();
4056
ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f));
4057
}
4058
ImGui::EndTable();
4059
}
4060
ImGui::EndChild();
4061
ImGui::PopStyleVar();
4062
}
4063
4064
// Child 3: manual-resize
4065
ImGui::SeparatorText("Manual-resize");
4066
{
4067
HelpMarker("Drag bottom border to resize. Double-click bottom border to auto-fit to vertical contents.");
4068
//if (ImGui::Button("Set Height to 200"))
4069
// ImGui::SetNextWindowSize(ImVec2(-FLT_MIN, 200.0f));
4070
4071
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyleColorVec4(ImGuiCol_FrameBg));
4072
if (ImGui::BeginChild("ResizableChild", ImVec2(-FLT_MIN, ImGui::GetTextLineHeightWithSpacing() * 8), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeY))
4073
for (int n = 0; n < 10; n++)
4074
ImGui::Text("Line %04d", n);
4075
ImGui::PopStyleColor();
4076
ImGui::EndChild();
4077
}
4078
4079
// Child 4: auto-resizing height with a limit
4080
ImGui::SeparatorText("Auto-resize with constraints");
4081
{
4082
static int draw_lines = 3;
4083
static int max_height_in_lines = 10;
4084
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
4085
ImGui::DragInt("Lines Count", &draw_lines, 0.2f);
4086
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
4087
ImGui::DragInt("Max Height (in Lines)", &max_height_in_lines, 0.2f);
4088
4089
ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 1), ImVec2(FLT_MAX, ImGui::GetTextLineHeightWithSpacing() * max_height_in_lines));
4090
if (ImGui::BeginChild("ConstrainedChild", ImVec2(-FLT_MIN, 0.0f), ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeY))
4091
for (int n = 0; n < draw_lines; n++)
4092
ImGui::Text("Line %04d", n);
4093
ImGui::EndChild();
4094
}
4095
4096
ImGui::SeparatorText("Misc/Advanced");
4097
4098
// Demonstrate a few extra things
4099
// - Changing ImGuiCol_ChildBg (which is transparent black in default styles)
4100
// - Using SetCursorPos() to position child window (the child window is an item from the POV of parent window)
4101
// You can also call SetNextWindowPos() to position the child window. The parent window will effectively
4102
// layout from this position.
4103
// - Using ImGui::GetItemRectMin/Max() to query the "item" state (because the child window is an item from
4104
// the POV of the parent window). See 'Demo->Querying Status (Edited/Active/Hovered etc.)' for details.
4105
{
4106
static int offset_x = 0;
4107
static bool override_bg_color = true;
4108
static ImGuiChildFlags child_flags = ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY;
4109
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
4110
ImGui::DragInt("Offset X", &offset_x, 1.0f, -1000, 1000);
4111
ImGui::Checkbox("Override ChildBg color", &override_bg_color);
4112
ImGui::CheckboxFlags("ImGuiChildFlags_Borders", &child_flags, ImGuiChildFlags_Borders);
4113
ImGui::CheckboxFlags("ImGuiChildFlags_AlwaysUseWindowPadding", &child_flags, ImGuiChildFlags_AlwaysUseWindowPadding);
4114
ImGui::CheckboxFlags("ImGuiChildFlags_ResizeX", &child_flags, ImGuiChildFlags_ResizeX);
4115
ImGui::CheckboxFlags("ImGuiChildFlags_ResizeY", &child_flags, ImGuiChildFlags_ResizeY);
4116
ImGui::CheckboxFlags("ImGuiChildFlags_FrameStyle", &child_flags, ImGuiChildFlags_FrameStyle);
4117
ImGui::SameLine(); HelpMarker("Style the child window like a framed item: use FrameBg, FrameRounding, FrameBorderSize, FramePadding instead of ChildBg, ChildRounding, ChildBorderSize, WindowPadding.");
4118
if (child_flags & ImGuiChildFlags_FrameStyle)
4119
override_bg_color = false;
4120
4121
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (float)offset_x);
4122
if (override_bg_color)
4123
ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(255, 0, 0, 100));
4124
ImGui::BeginChild("Red", ImVec2(200, 100), child_flags, ImGuiWindowFlags_None);
4125
if (override_bg_color)
4126
ImGui::PopStyleColor();
4127
4128
for (int n = 0; n < 50; n++)
4129
ImGui::Text("Some test %d", n);
4130
ImGui::EndChild();
4131
bool child_is_hovered = ImGui::IsItemHovered();
4132
ImVec2 child_rect_min = ImGui::GetItemRectMin();
4133
ImVec2 child_rect_max = ImGui::GetItemRectMax();
4134
ImGui::Text("Hovered: %d", child_is_hovered);
4135
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);
4136
}
4137
4138
ImGui::TreePop();
4139
}
4140
4141
IMGUI_DEMO_MARKER("Layout/Widgets Width");
4142
if (ImGui::TreeNode("Widgets Width"))
4143
{
4144
static float f = 0.0f;
4145
static bool show_indented_items = true;
4146
ImGui::Checkbox("Show indented items", &show_indented_items);
4147
4148
// Use SetNextItemWidth() to set the width of a single upcoming item.
4149
// Use PushItemWidth()/PopItemWidth() to set the width of a group of items.
4150
// In real code use you'll probably want to choose width values that are proportional to your font size
4151
// e.g. Using '20.0f * GetFontSize()' as width instead of '200.0f', etc.
4152
4153
ImGui::Text("SetNextItemWidth/PushItemWidth(100)");
4154
ImGui::SameLine(); HelpMarker("Fixed width.");
4155
ImGui::PushItemWidth(100);
4156
ImGui::DragFloat("float##1b", &f);
4157
if (show_indented_items)
4158
{
4159
ImGui::Indent();
4160
ImGui::DragFloat("float (indented)##1b", &f);
4161
ImGui::Unindent();
4162
}
4163
ImGui::PopItemWidth();
4164
4165
ImGui::Text("SetNextItemWidth/PushItemWidth(-100)");
4166
ImGui::SameLine(); HelpMarker("Align to right edge minus 100");
4167
ImGui::PushItemWidth(-100);
4168
ImGui::DragFloat("float##2a", &f);
4169
if (show_indented_items)
4170
{
4171
ImGui::Indent();
4172
ImGui::DragFloat("float (indented)##2b", &f);
4173
ImGui::Unindent();
4174
}
4175
ImGui::PopItemWidth();
4176
4177
ImGui::Text("SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)");
4178
ImGui::SameLine(); HelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)");
4179
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * 0.5f);
4180
ImGui::DragFloat("float##3a", &f);
4181
if (show_indented_items)
4182
{
4183
ImGui::Indent();
4184
ImGui::DragFloat("float (indented)##3b", &f);
4185
ImGui::Unindent();
4186
}
4187
ImGui::PopItemWidth();
4188
4189
ImGui::Text("SetNextItemWidth/PushItemWidth(-GetContentRegionAvail().x * 0.5f)");
4190
ImGui::SameLine(); HelpMarker("Align to right edge minus half");
4191
ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.5f);
4192
ImGui::DragFloat("float##4a", &f);
4193
if (show_indented_items)
4194
{
4195
ImGui::Indent();
4196
ImGui::DragFloat("float (indented)##4b", &f);
4197
ImGui::Unindent();
4198
}
4199
ImGui::PopItemWidth();
4200
4201
// Demonstrate using PushItemWidth to surround three items.
4202
// Calling SetNextItemWidth() before each of them would have the same effect.
4203
ImGui::Text("SetNextItemWidth/PushItemWidth(-FLT_MIN)");
4204
ImGui::SameLine(); HelpMarker("Align to right edge");
4205
ImGui::PushItemWidth(-FLT_MIN);
4206
ImGui::DragFloat("##float5a", &f);
4207
if (show_indented_items)
4208
{
4209
ImGui::Indent();
4210
ImGui::DragFloat("float (indented)##5b", &f);
4211
ImGui::Unindent();
4212
}
4213
ImGui::PopItemWidth();
4214
4215
ImGui::TreePop();
4216
}
4217
4218
IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout");
4219
if (ImGui::TreeNode("Basic Horizontal Layout"))
4220
{
4221
ImGui::TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)");
4222
4223
// Text
4224
IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine");
4225
ImGui::Text("Two items: Hello"); ImGui::SameLine();
4226
ImGui::TextColored(ImVec4(1, 1, 0, 1), "Sailor");
4227
4228
// Adjust spacing
4229
ImGui::Text("More spacing: Hello"); ImGui::SameLine(0, 20);
4230
ImGui::TextColored(ImVec4(1, 1, 0, 1), "Sailor");
4231
4232
// Button
4233
ImGui::AlignTextToFramePadding();
4234
ImGui::Text("Normal buttons"); ImGui::SameLine();
4235
ImGui::Button("Banana"); ImGui::SameLine();
4236
ImGui::Button("Apple"); ImGui::SameLine();
4237
ImGui::Button("Corniflower");
4238
4239
// Button
4240
ImGui::Text("Small buttons"); ImGui::SameLine();
4241
ImGui::SmallButton("Like this one"); ImGui::SameLine();
4242
ImGui::Text("can fit within a text block.");
4243
4244
// Aligned to arbitrary position. Easy/cheap column.
4245
IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (with offset)");
4246
ImGui::Text("Aligned");
4247
ImGui::SameLine(150); ImGui::Text("x=150");
4248
ImGui::SameLine(300); ImGui::Text("x=300");
4249
ImGui::Text("Aligned");
4250
ImGui::SameLine(150); ImGui::SmallButton("x=150");
4251
ImGui::SameLine(300); ImGui::SmallButton("x=300");
4252
4253
// Checkbox
4254
IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (more)");
4255
static bool c1 = false, c2 = false, c3 = false, c4 = false;
4256
ImGui::Checkbox("My", &c1); ImGui::SameLine();
4257
ImGui::Checkbox("Tailor", &c2); ImGui::SameLine();
4258
ImGui::Checkbox("Is", &c3); ImGui::SameLine();
4259
ImGui::Checkbox("Rich", &c4);
4260
4261
// Various
4262
static float f0 = 1.0f, f1 = 2.0f, f2 = 3.0f;
4263
ImGui::PushItemWidth(80);
4264
const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD" };
4265
static int item = -1;
4266
ImGui::Combo("Combo", &item, items, IM_ARRAYSIZE(items)); ImGui::SameLine();
4267
ImGui::SliderFloat("X", &f0, 0.0f, 5.0f); ImGui::SameLine();
4268
ImGui::SliderFloat("Y", &f1, 0.0f, 5.0f); ImGui::SameLine();
4269
ImGui::SliderFloat("Z", &f2, 0.0f, 5.0f);
4270
ImGui::PopItemWidth();
4271
4272
ImGui::PushItemWidth(80);
4273
ImGui::Text("Lists:");
4274
static int selection[4] = { 0, 1, 2, 3 };
4275
for (int i = 0; i < 4; i++)
4276
{
4277
if (i > 0) ImGui::SameLine();
4278
ImGui::PushID(i);
4279
ImGui::ListBox("", &selection[i], items, IM_ARRAYSIZE(items));
4280
ImGui::PopID();
4281
//ImGui::SetItemTooltip("ListBox %d hovered", i);
4282
}
4283
ImGui::PopItemWidth();
4284
4285
// Dummy
4286
IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Dummy");
4287
ImVec2 button_sz(40, 40);
4288
ImGui::Button("A", button_sz); ImGui::SameLine();
4289
ImGui::Dummy(button_sz); ImGui::SameLine();
4290
ImGui::Button("B", button_sz);
4291
4292
// Manually wrapping
4293
// (we should eventually provide this as an automatic layout feature, but for now you can do it manually)
4294
IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Manual wrapping");
4295
ImGui::Text("Manual wrapping:");
4296
ImGuiStyle& style = ImGui::GetStyle();
4297
int buttons_count = 20;
4298
float window_visible_x2 = ImGui::GetCursorScreenPos().x + ImGui::GetContentRegionAvail().x;
4299
for (int n = 0; n < buttons_count; n++)
4300
{
4301
ImGui::PushID(n);
4302
ImGui::Button("Box", button_sz);
4303
float last_button_x2 = ImGui::GetItemRectMax().x;
4304
float next_button_x2 = last_button_x2 + style.ItemSpacing.x + button_sz.x; // Expected position if next button was on same line
4305
if (n + 1 < buttons_count && next_button_x2 < window_visible_x2)
4306
ImGui::SameLine();
4307
ImGui::PopID();
4308
}
4309
4310
ImGui::TreePop();
4311
}
4312
4313
IMGUI_DEMO_MARKER("Layout/Groups");
4314
if (ImGui::TreeNode("Groups"))
4315
{
4316
HelpMarker(
4317
"BeginGroup() basically locks the horizontal position for new line. "
4318
"EndGroup() bundles the whole group so that you can use \"item\" functions such as "
4319
"IsItemHovered()/IsItemActive() or SameLine() etc. on the whole group.");
4320
ImGui::BeginGroup();
4321
{
4322
ImGui::BeginGroup();
4323
ImGui::Button("AAA");
4324
ImGui::SameLine();
4325
ImGui::Button("BBB");
4326
ImGui::SameLine();
4327
ImGui::BeginGroup();
4328
ImGui::Button("CCC");
4329
ImGui::Button("DDD");
4330
ImGui::EndGroup();
4331
ImGui::SameLine();
4332
ImGui::Button("EEE");
4333
ImGui::EndGroup();
4334
ImGui::SetItemTooltip("First group hovered");
4335
}
4336
// Capture the group size and create widgets using the same size
4337
ImVec2 size = ImGui::GetItemRectSize();
4338
const float values[5] = { 0.5f, 0.20f, 0.80f, 0.60f, 0.25f };
4339
ImGui::PlotHistogram("##values", values, IM_ARRAYSIZE(values), 0, NULL, 0.0f, 1.0f, size);
4340
4341
ImGui::Button("ACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y));
4342
ImGui::SameLine();
4343
ImGui::Button("REACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y));
4344
ImGui::EndGroup();
4345
ImGui::SameLine();
4346
4347
ImGui::Button("LEVERAGE\nBUZZWORD", size);
4348
ImGui::SameLine();
4349
4350
if (ImGui::BeginListBox("List", size))
4351
{
4352
ImGui::Selectable("Selected", true);
4353
ImGui::Selectable("Not Selected", false);
4354
ImGui::EndListBox();
4355
}
4356
4357
ImGui::TreePop();
4358
}
4359
4360
IMGUI_DEMO_MARKER("Layout/Text Baseline Alignment");
4361
if (ImGui::TreeNode("Text Baseline Alignment"))
4362
{
4363
{
4364
ImGui::BulletText("Text baseline:");
4365
ImGui::SameLine(); HelpMarker(
4366
"This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. "
4367
"Lines only composed of text or \"small\" widgets use less vertical space than lines with framed widgets.");
4368
ImGui::Indent();
4369
4370
ImGui::Text("KO Blahblah"); ImGui::SameLine();
4371
ImGui::Button("Some framed item"); ImGui::SameLine();
4372
HelpMarker("Baseline of button will look misaligned with text..");
4373
4374
// If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets.
4375
// (because we don't know what's coming after the Text() statement, we need to move the text baseline
4376
// down by FramePadding.y ahead of time)
4377
ImGui::AlignTextToFramePadding();
4378
ImGui::Text("OK Blahblah"); ImGui::SameLine();
4379
ImGui::Button("Some framed item##2"); ImGui::SameLine();
4380
HelpMarker("We call AlignTextToFramePadding() to vertically align the text baseline by +FramePadding.y");
4381
4382
// SmallButton() uses the same vertical padding as Text
4383
ImGui::Button("TEST##1"); ImGui::SameLine();
4384
ImGui::Text("TEST"); ImGui::SameLine();
4385
ImGui::SmallButton("TEST##2");
4386
4387
// If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets.
4388
ImGui::AlignTextToFramePadding();
4389
ImGui::Text("Text aligned to framed item"); ImGui::SameLine();
4390
ImGui::Button("Item##1"); ImGui::SameLine();
4391
ImGui::Text("Item"); ImGui::SameLine();
4392
ImGui::SmallButton("Item##2"); ImGui::SameLine();
4393
ImGui::Button("Item##3");
4394
4395
ImGui::Unindent();
4396
}
4397
4398
ImGui::Spacing();
4399
4400
{
4401
ImGui::BulletText("Multi-line text:");
4402
ImGui::Indent();
4403
ImGui::Text("One\nTwo\nThree"); ImGui::SameLine();
4404
ImGui::Text("Hello\nWorld"); ImGui::SameLine();
4405
ImGui::Text("Banana");
4406
4407
ImGui::Text("Banana"); ImGui::SameLine();
4408
ImGui::Text("Hello\nWorld"); ImGui::SameLine();
4409
ImGui::Text("One\nTwo\nThree");
4410
4411
ImGui::Button("HOP##1"); ImGui::SameLine();
4412
ImGui::Text("Banana"); ImGui::SameLine();
4413
ImGui::Text("Hello\nWorld"); ImGui::SameLine();
4414
ImGui::Text("Banana");
4415
4416
ImGui::Button("HOP##2"); ImGui::SameLine();
4417
ImGui::Text("Hello\nWorld"); ImGui::SameLine();
4418
ImGui::Text("Banana");
4419
ImGui::Unindent();
4420
}
4421
4422
ImGui::Spacing();
4423
4424
{
4425
ImGui::BulletText("Misc items:");
4426
ImGui::Indent();
4427
4428
// SmallButton() sets FramePadding to zero. Text baseline is aligned to match baseline of previous Button.
4429
ImGui::Button("80x80", ImVec2(80, 80));
4430
ImGui::SameLine();
4431
ImGui::Button("50x50", ImVec2(50, 50));
4432
ImGui::SameLine();
4433
ImGui::Button("Button()");
4434
ImGui::SameLine();
4435
ImGui::SmallButton("SmallButton()");
4436
4437
// Tree
4438
const float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
4439
ImGui::Button("Button##1");
4440
ImGui::SameLine(0.0f, spacing);
4441
if (ImGui::TreeNode("Node##1"))
4442
{
4443
// Placeholder tree data
4444
for (int i = 0; i < 6; i++)
4445
ImGui::BulletText("Item %d..", i);
4446
ImGui::TreePop();
4447
}
4448
4449
// Vertically align text node a bit lower so it'll be vertically centered with upcoming widget.
4450
// Otherwise you can use SmallButton() (smaller fit).
4451
ImGui::AlignTextToFramePadding();
4452
4453
// Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add
4454
// other contents below the node.
4455
bool node_open = ImGui::TreeNode("Node##2");
4456
ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##2");
4457
if (node_open)
4458
{
4459
// Placeholder tree data
4460
for (int i = 0; i < 6; i++)
4461
ImGui::BulletText("Item %d..", i);
4462
ImGui::TreePop();
4463
}
4464
4465
// Bullet
4466
ImGui::Button("Button##3");
4467
ImGui::SameLine(0.0f, spacing);
4468
ImGui::BulletText("Bullet text");
4469
4470
ImGui::AlignTextToFramePadding();
4471
ImGui::BulletText("Node");
4472
ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##4");
4473
ImGui::Unindent();
4474
}
4475
4476
ImGui::TreePop();
4477
}
4478
4479
IMGUI_DEMO_MARKER("Layout/Scrolling");
4480
if (ImGui::TreeNode("Scrolling"))
4481
{
4482
// Vertical scroll functions
4483
IMGUI_DEMO_MARKER("Layout/Scrolling/Vertical");
4484
HelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given vertical position.");
4485
4486
static int track_item = 50;
4487
static bool enable_track = true;
4488
static bool enable_extra_decorations = false;
4489
static float scroll_to_off_px = 0.0f;
4490
static float scroll_to_pos_px = 200.0f;
4491
4492
ImGui::Checkbox("Decoration", &enable_extra_decorations);
4493
4494
ImGui::Checkbox("Track", &enable_track);
4495
ImGui::PushItemWidth(100);
4496
ImGui::SameLine(140); enable_track |= ImGui::DragInt("##item", &track_item, 0.25f, 0, 99, "Item = %d");
4497
4498
bool scroll_to_off = ImGui::Button("Scroll Offset");
4499
ImGui::SameLine(140); scroll_to_off |= ImGui::DragFloat("##off", &scroll_to_off_px, 1.00f, 0, FLT_MAX, "+%.0f px");
4500
4501
bool scroll_to_pos = ImGui::Button("Scroll To Pos");
4502
ImGui::SameLine(140); scroll_to_pos |= ImGui::DragFloat("##pos", &scroll_to_pos_px, 1.00f, -10, FLT_MAX, "X/Y = %.0f px");
4503
ImGui::PopItemWidth();
4504
4505
if (scroll_to_off || scroll_to_pos)
4506
enable_track = false;
4507
4508
ImGuiStyle& style = ImGui::GetStyle();
4509
float child_w = (ImGui::GetContentRegionAvail().x - 4 * style.ItemSpacing.x) / 5;
4510
if (child_w < 1.0f)
4511
child_w = 1.0f;
4512
ImGui::PushID("##VerticalScrolling");
4513
for (int i = 0; i < 5; i++)
4514
{
4515
if (i > 0) ImGui::SameLine();
4516
ImGui::BeginGroup();
4517
const char* names[] = { "Top", "25%", "Center", "75%", "Bottom" };
4518
ImGui::TextUnformatted(names[i]);
4519
4520
const ImGuiWindowFlags child_flags = enable_extra_decorations ? ImGuiWindowFlags_MenuBar : 0;
4521
const ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i);
4522
const bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(child_w, 200.0f), ImGuiChildFlags_Borders, child_flags);
4523
if (ImGui::BeginMenuBar())
4524
{
4525
ImGui::TextUnformatted("abc");
4526
ImGui::EndMenuBar();
4527
}
4528
if (scroll_to_off)
4529
ImGui::SetScrollY(scroll_to_off_px);
4530
if (scroll_to_pos)
4531
ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_pos_px, i * 0.25f);
4532
if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items
4533
{
4534
for (int item = 0; item < 100; item++)
4535
{
4536
if (enable_track && item == track_item)
4537
{
4538
ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item);
4539
ImGui::SetScrollHereY(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom
4540
}
4541
else
4542
{
4543
ImGui::Text("Item %d", item);
4544
}
4545
}
4546
}
4547
float scroll_y = ImGui::GetScrollY();
4548
float scroll_max_y = ImGui::GetScrollMaxY();
4549
ImGui::EndChild();
4550
ImGui::Text("%.0f/%.0f", scroll_y, scroll_max_y);
4551
ImGui::EndGroup();
4552
}
4553
ImGui::PopID();
4554
4555
// Horizontal scroll functions
4556
IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal");
4557
ImGui::Spacing();
4558
HelpMarker(
4559
"Use SetScrollHereX() or SetScrollFromPosX() to scroll to a given horizontal position.\n\n"
4560
"Because the clipping rectangle of most window hides half worth of WindowPadding on the "
4561
"left/right, using SetScrollFromPosX(+1) will usually result in clipped text whereas the "
4562
"equivalent SetScrollFromPosY(+1) wouldn't.");
4563
ImGui::PushID("##HorizontalScrolling");
4564
for (int i = 0; i < 5; i++)
4565
{
4566
float child_height = ImGui::GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0f;
4567
ImGuiWindowFlags child_flags = ImGuiWindowFlags_HorizontalScrollbar | (enable_extra_decorations ? ImGuiWindowFlags_AlwaysVerticalScrollbar : 0);
4568
ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i);
4569
bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(-100, child_height), ImGuiChildFlags_Borders, child_flags);
4570
if (scroll_to_off)
4571
ImGui::SetScrollX(scroll_to_off_px);
4572
if (scroll_to_pos)
4573
ImGui::SetScrollFromPosX(ImGui::GetCursorStartPos().x + scroll_to_pos_px, i * 0.25f);
4574
if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items
4575
{
4576
for (int item = 0; item < 100; item++)
4577
{
4578
if (item > 0)
4579
ImGui::SameLine();
4580
if (enable_track && item == track_item)
4581
{
4582
ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item);
4583
ImGui::SetScrollHereX(i * 0.25f); // 0.0f:left, 0.5f:center, 1.0f:right
4584
}
4585
else
4586
{
4587
ImGui::Text("Item %d", item);
4588
}
4589
}
4590
}
4591
float scroll_x = ImGui::GetScrollX();
4592
float scroll_max_x = ImGui::GetScrollMaxX();
4593
ImGui::EndChild();
4594
ImGui::SameLine();
4595
const char* names[] = { "Left", "25%", "Center", "75%", "Right" };
4596
ImGui::Text("%s\n%.0f/%.0f", names[i], scroll_x, scroll_max_x);
4597
ImGui::Spacing();
4598
}
4599
ImGui::PopID();
4600
4601
// Miscellaneous Horizontal Scrolling Demo
4602
IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal (more)");
4603
HelpMarker(
4604
"Horizontal scrolling for a window is enabled via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\n"
4605
"You may want to also explicitly specify content width by using SetNextWindowContentWidth() before Begin().");
4606
static int lines = 7;
4607
ImGui::SliderInt("Lines", &lines, 1, 15);
4608
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
4609
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f));
4610
ImVec2 scrolling_child_size = ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30);
4611
ImGui::BeginChild("scrolling", scrolling_child_size, ImGuiChildFlags_Borders, ImGuiWindowFlags_HorizontalScrollbar);
4612
for (int line = 0; line < lines; line++)
4613
{
4614
// Display random stuff. For the sake of this trivial demo we are using basic Button() + SameLine()
4615
// If you want to create your own time line for a real application you may be better off manipulating
4616
// the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets
4617
// yourself. You may also want to use the lower-level ImDrawList API.
4618
int num_buttons = 10 + ((line & 1) ? line * 9 : line * 3);
4619
for (int n = 0; n < num_buttons; n++)
4620
{
4621
if (n > 0) ImGui::SameLine();
4622
ImGui::PushID(n + line * 1000);
4623
char num_buf[16];
4624
sprintf(num_buf, "%d", n);
4625
const char* label = (!(n % 15)) ? "FizzBuzz" : (!(n % 3)) ? "Fizz" : (!(n % 5)) ? "Buzz" : num_buf;
4626
float hue = n * 0.05f;
4627
ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(hue, 0.6f, 0.6f));
4628
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(hue, 0.7f, 0.7f));
4629
ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(hue, 0.8f, 0.8f));
4630
ImGui::Button(label, ImVec2(40.0f + sinf((float)(line + n)) * 20.0f, 0.0f));
4631
ImGui::PopStyleColor(3);
4632
ImGui::PopID();
4633
}
4634
}
4635
float scroll_x = ImGui::GetScrollX();
4636
float scroll_max_x = ImGui::GetScrollMaxX();
4637
ImGui::EndChild();
4638
ImGui::PopStyleVar(2);
4639
float scroll_x_delta = 0.0f;
4640
ImGui::SmallButton("<<");
4641
if (ImGui::IsItemActive())
4642
scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f;
4643
ImGui::SameLine();
4644
ImGui::Text("Scroll from code"); ImGui::SameLine();
4645
ImGui::SmallButton(">>");
4646
if (ImGui::IsItemActive())
4647
scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f;
4648
ImGui::SameLine();
4649
ImGui::Text("%.0f/%.0f", scroll_x, scroll_max_x);
4650
if (scroll_x_delta != 0.0f)
4651
{
4652
// Demonstrate a trick: you can use Begin to set yourself in the context of another window
4653
// (here we are already out of your child window)
4654
ImGui::BeginChild("scrolling");
4655
ImGui::SetScrollX(ImGui::GetScrollX() + scroll_x_delta);
4656
ImGui::EndChild();
4657
}
4658
ImGui::Spacing();
4659
4660
static bool show_horizontal_contents_size_demo_window = false;
4661
ImGui::Checkbox("Show Horizontal contents size demo window", &show_horizontal_contents_size_demo_window);
4662
4663
if (show_horizontal_contents_size_demo_window)
4664
{
4665
static bool show_h_scrollbar = true;
4666
static bool show_button = true;
4667
static bool show_tree_nodes = true;
4668
static bool show_text_wrapped = false;
4669
static bool show_columns = true;
4670
static bool show_tab_bar = true;
4671
static bool show_child = false;
4672
static bool explicit_content_size = false;
4673
static float contents_size_x = 300.0f;
4674
if (explicit_content_size)
4675
ImGui::SetNextWindowContentSize(ImVec2(contents_size_x, 0.0f));
4676
ImGui::Begin("Horizontal contents size demo window", &show_horizontal_contents_size_demo_window, show_h_scrollbar ? ImGuiWindowFlags_HorizontalScrollbar : 0);
4677
IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal contents size demo window");
4678
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 0));
4679
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 0));
4680
HelpMarker(
4681
"Test how different widgets react and impact the work rectangle growing when horizontal scrolling is enabled.\n\n"
4682
"Use 'Metrics->Tools->Show windows rectangles' to visualize rectangles.");
4683
ImGui::Checkbox("H-scrollbar", &show_h_scrollbar);
4684
ImGui::Checkbox("Button", &show_button); // Will grow contents size (unless explicitly overwritten)
4685
ImGui::Checkbox("Tree nodes", &show_tree_nodes); // Will grow contents size and display highlight over full width
4686
ImGui::Checkbox("Text wrapped", &show_text_wrapped);// Will grow and use contents size
4687
ImGui::Checkbox("Columns", &show_columns); // Will use contents size
4688
ImGui::Checkbox("Tab bar", &show_tab_bar); // Will use contents size
4689
ImGui::Checkbox("Child", &show_child); // Will grow and use contents size
4690
ImGui::Checkbox("Explicit content size", &explicit_content_size);
4691
ImGui::Text("Scroll %.1f/%.1f %.1f/%.1f", ImGui::GetScrollX(), ImGui::GetScrollMaxX(), ImGui::GetScrollY(), ImGui::GetScrollMaxY());
4692
if (explicit_content_size)
4693
{
4694
ImGui::SameLine();
4695
ImGui::SetNextItemWidth(100);
4696
ImGui::DragFloat("##csx", &contents_size_x);
4697
ImVec2 p = ImGui::GetCursorScreenPos();
4698
ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + 10, p.y + 10), IM_COL32_WHITE);
4699
ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(p.x + contents_size_x - 10, p.y), ImVec2(p.x + contents_size_x, p.y + 10), IM_COL32_WHITE);
4700
ImGui::Dummy(ImVec2(0, 10));
4701
}
4702
ImGui::PopStyleVar(2);
4703
ImGui::Separator();
4704
if (show_button)
4705
{
4706
ImGui::Button("this is a 300-wide button", ImVec2(300, 0));
4707
}
4708
if (show_tree_nodes)
4709
{
4710
bool open = true;
4711
if (ImGui::TreeNode("this is a tree node"))
4712
{
4713
if (ImGui::TreeNode("another one of those tree node..."))
4714
{
4715
ImGui::Text("Some tree contents");
4716
ImGui::TreePop();
4717
}
4718
ImGui::TreePop();
4719
}
4720
ImGui::CollapsingHeader("CollapsingHeader", &open);
4721
}
4722
if (show_text_wrapped)
4723
{
4724
ImGui::TextWrapped("This text should automatically wrap on the edge of the work rectangle.");
4725
}
4726
if (show_columns)
4727
{
4728
ImGui::Text("Tables:");
4729
if (ImGui::BeginTable("table", 4, ImGuiTableFlags_Borders))
4730
{
4731
for (int n = 0; n < 4; n++)
4732
{
4733
ImGui::TableNextColumn();
4734
ImGui::Text("Width %.2f", ImGui::GetContentRegionAvail().x);
4735
}
4736
ImGui::EndTable();
4737
}
4738
ImGui::Text("Columns:");
4739
ImGui::Columns(4);
4740
for (int n = 0; n < 4; n++)
4741
{
4742
ImGui::Text("Width %.2f", ImGui::GetColumnWidth());
4743
ImGui::NextColumn();
4744
}
4745
ImGui::Columns(1);
4746
}
4747
if (show_tab_bar && ImGui::BeginTabBar("Hello"))
4748
{
4749
if (ImGui::BeginTabItem("OneOneOne")) { ImGui::EndTabItem(); }
4750
if (ImGui::BeginTabItem("TwoTwoTwo")) { ImGui::EndTabItem(); }
4751
if (ImGui::BeginTabItem("ThreeThreeThree")) { ImGui::EndTabItem(); }
4752
if (ImGui::BeginTabItem("FourFourFour")) { ImGui::EndTabItem(); }
4753
ImGui::EndTabBar();
4754
}
4755
if (show_child)
4756
{
4757
ImGui::BeginChild("child", ImVec2(0, 0), ImGuiChildFlags_Borders);
4758
ImGui::EndChild();
4759
}
4760
ImGui::End();
4761
}
4762
4763
ImGui::TreePop();
4764
}
4765
4766
IMGUI_DEMO_MARKER("Layout/Text Clipping");
4767
if (ImGui::TreeNode("Text Clipping"))
4768
{
4769
static ImVec2 size(100.0f, 100.0f);
4770
static ImVec2 offset(30.0f, 30.0f);
4771
ImGui::DragFloat2("size", (float*)&size, 0.5f, 1.0f, 200.0f, "%.0f");
4772
ImGui::TextWrapped("(Click and drag to scroll)");
4773
4774
HelpMarker(
4775
"(Left) Using ImGui::PushClipRect():\n"
4776
"Will alter ImGui hit-testing logic + ImDrawList rendering.\n"
4777
"(use this if you want your clipping rectangle to affect interactions)\n\n"
4778
"(Center) Using ImDrawList::PushClipRect():\n"
4779
"Will alter ImDrawList rendering only.\n"
4780
"(use this as a shortcut if you are only using ImDrawList calls)\n\n"
4781
"(Right) Using ImDrawList::AddText() with a fine ClipRect:\n"
4782
"Will alter only this specific ImDrawList::AddText() rendering.\n"
4783
"This is often used internally to avoid altering the clipping rectangle and minimize draw calls.");
4784
4785
for (int n = 0; n < 3; n++)
4786
{
4787
if (n > 0)
4788
ImGui::SameLine();
4789
4790
ImGui::PushID(n);
4791
ImGui::InvisibleButton("##canvas", size);
4792
if (ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left))
4793
{
4794
offset.x += ImGui::GetIO().MouseDelta.x;
4795
offset.y += ImGui::GetIO().MouseDelta.y;
4796
}
4797
ImGui::PopID();
4798
if (!ImGui::IsItemVisible()) // Skip rendering as ImDrawList elements are not clipped.
4799
continue;
4800
4801
const ImVec2 p0 = ImGui::GetItemRectMin();
4802
const ImVec2 p1 = ImGui::GetItemRectMax();
4803
const char* text_str = "Line 1 hello\nLine 2 clip me!";
4804
const ImVec2 text_pos = ImVec2(p0.x + offset.x, p0.y + offset.y);
4805
ImDrawList* draw_list = ImGui::GetWindowDrawList();
4806
switch (n)
4807
{
4808
case 0:
4809
ImGui::PushClipRect(p0, p1, true);
4810
draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
4811
draw_list->AddText(text_pos, IM_COL32_WHITE, text_str);
4812
ImGui::PopClipRect();
4813
break;
4814
case 1:
4815
draw_list->PushClipRect(p0, p1, true);
4816
draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
4817
draw_list->AddText(text_pos, IM_COL32_WHITE, text_str);
4818
draw_list->PopClipRect();
4819
break;
4820
case 2:
4821
ImVec4 clip_rect(p0.x, p0.y, p1.x, p1.y); // AddText() takes a ImVec4* here so let's convert.
4822
draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
4823
draw_list->AddText(ImGui::GetFont(), ImGui::GetFontSize(), text_pos, IM_COL32_WHITE, text_str, NULL, 0.0f, &clip_rect);
4824
break;
4825
}
4826
}
4827
4828
ImGui::TreePop();
4829
}
4830
4831
IMGUI_DEMO_MARKER("Layout/Overlap Mode");
4832
if (ImGui::TreeNode("Overlap Mode"))
4833
{
4834
static bool enable_allow_overlap = true;
4835
4836
HelpMarker(
4837
"Hit-testing is by default performed in item submission order, which generally is perceived as 'back-to-front'.\n\n"
4838
"By using SetNextItemAllowOverlap() you can notify that an item may be overlapped by another. "
4839
"Doing so alters the hovering logic: items using AllowOverlap mode requires an extra frame to accept hovered state.");
4840
ImGui::Checkbox("Enable AllowOverlap", &enable_allow_overlap);
4841
4842
ImVec2 button1_pos = ImGui::GetCursorScreenPos();
4843
ImVec2 button2_pos = ImVec2(button1_pos.x + 50.0f, button1_pos.y + 50.0f);
4844
if (enable_allow_overlap)
4845
ImGui::SetNextItemAllowOverlap();
4846
ImGui::Button("Button 1", ImVec2(80, 80));
4847
ImGui::SetCursorScreenPos(button2_pos);
4848
ImGui::Button("Button 2", ImVec2(80, 80));
4849
4850
// This is typically used with width-spanning items.
4851
// (note that Selectable() has a dedicated flag ImGuiSelectableFlags_AllowOverlap, which is a shortcut
4852
// for using SetNextItemAllowOverlap(). For demo purpose we use SetNextItemAllowOverlap() here.)
4853
if (enable_allow_overlap)
4854
ImGui::SetNextItemAllowOverlap();
4855
ImGui::Selectable("Some Selectable", false);
4856
ImGui::SameLine();
4857
ImGui::SmallButton("++");
4858
4859
ImGui::TreePop();
4860
}
4861
}
4862
4863
//-----------------------------------------------------------------------------
4864
// [SECTION] ShowDemoWindowPopups()
4865
//-----------------------------------------------------------------------------
4866
4867
static void ShowDemoWindowPopups()
4868
{
4869
IMGUI_DEMO_MARKER("Popups");
4870
if (!ImGui::CollapsingHeader("Popups & Modal windows"))
4871
return;
4872
4873
// The properties of popups windows are:
4874
// - They block normal mouse hovering detection outside them. (*)
4875
// - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE.
4876
// - Their visibility state (~bool) is held internally by Dear ImGui instead of being held by the programmer as
4877
// we are used to with regular Begin() calls. User can manipulate the visibility state by calling OpenPopup().
4878
// (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even
4879
// when normally blocked by a popup.
4880
// Those three properties are connected. The library needs to hold their visibility state BECAUSE it can close
4881
// popups at any time.
4882
4883
// Typical use for regular windows:
4884
// 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();
4885
// Typical use for popups:
4886
// if (ImGui::Button("Open")) ImGui::OpenPopup("MyPopup"); if (ImGui::BeginPopup("MyPopup") { [...] EndPopup(); }
4887
4888
// With popups we have to go through a library call (here OpenPopup) to manipulate the visibility state.
4889
// This may be a bit confusing at first but it should quickly make sense. Follow on the examples below.
4890
4891
IMGUI_DEMO_MARKER("Popups/Popups");
4892
if (ImGui::TreeNode("Popups"))
4893
{
4894
ImGui::TextWrapped(
4895
"When a popup is active, it inhibits interacting with windows that are behind the popup. "
4896
"Clicking outside the popup closes it.");
4897
4898
static int selected_fish = -1;
4899
const char* names[] = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" };
4900
static bool toggles[] = { true, false, false, false, false };
4901
4902
// Simple selection popup (if you want to show the current selection inside the Button itself,
4903
// you may want to build a string using the "###" operator to preserve a constant ID with a variable label)
4904
if (ImGui::Button("Select.."))
4905
ImGui::OpenPopup("my_select_popup");
4906
ImGui::SameLine();
4907
ImGui::TextUnformatted(selected_fish == -1 ? "<None>" : names[selected_fish]);
4908
if (ImGui::BeginPopup("my_select_popup"))
4909
{
4910
ImGui::SeparatorText("Aquarium");
4911
for (int i = 0; i < IM_ARRAYSIZE(names); i++)
4912
if (ImGui::Selectable(names[i]))
4913
selected_fish = i;
4914
ImGui::EndPopup();
4915
}
4916
4917
// Showing a menu with toggles
4918
if (ImGui::Button("Toggle.."))
4919
ImGui::OpenPopup("my_toggle_popup");
4920
if (ImGui::BeginPopup("my_toggle_popup"))
4921
{
4922
for (int i = 0; i < IM_ARRAYSIZE(names); i++)
4923
ImGui::MenuItem(names[i], "", &toggles[i]);
4924
if (ImGui::BeginMenu("Sub-menu"))
4925
{
4926
ImGui::MenuItem("Click me");
4927
ImGui::EndMenu();
4928
}
4929
4930
ImGui::Separator();
4931
ImGui::Text("Tooltip here");
4932
ImGui::SetItemTooltip("I am a tooltip over a popup");
4933
4934
if (ImGui::Button("Stacked Popup"))
4935
ImGui::OpenPopup("another popup");
4936
if (ImGui::BeginPopup("another popup"))
4937
{
4938
for (int i = 0; i < IM_ARRAYSIZE(names); i++)
4939
ImGui::MenuItem(names[i], "", &toggles[i]);
4940
if (ImGui::BeginMenu("Sub-menu"))
4941
{
4942
ImGui::MenuItem("Click me");
4943
if (ImGui::Button("Stacked Popup"))
4944
ImGui::OpenPopup("another popup");
4945
if (ImGui::BeginPopup("another popup"))
4946
{
4947
ImGui::Text("I am the last one here.");
4948
ImGui::EndPopup();
4949
}
4950
ImGui::EndMenu();
4951
}
4952
ImGui::EndPopup();
4953
}
4954
ImGui::EndPopup();
4955
}
4956
4957
// Call the more complete ShowExampleMenuFile which we use in various places of this demo
4958
if (ImGui::Button("With a menu.."))
4959
ImGui::OpenPopup("my_file_popup");
4960
if (ImGui::BeginPopup("my_file_popup", ImGuiWindowFlags_MenuBar))
4961
{
4962
if (ImGui::BeginMenuBar())
4963
{
4964
if (ImGui::BeginMenu("File"))
4965
{
4966
ShowExampleMenuFile();
4967
ImGui::EndMenu();
4968
}
4969
if (ImGui::BeginMenu("Edit"))
4970
{
4971
ImGui::MenuItem("Dummy");
4972
ImGui::EndMenu();
4973
}
4974
ImGui::EndMenuBar();
4975
}
4976
ImGui::Text("Hello from popup!");
4977
ImGui::Button("This is a dummy button..");
4978
ImGui::EndPopup();
4979
}
4980
4981
ImGui::TreePop();
4982
}
4983
4984
IMGUI_DEMO_MARKER("Popups/Context menus");
4985
if (ImGui::TreeNode("Context menus"))
4986
{
4987
HelpMarker("\"Context\" functions are simple helpers to associate a Popup to a given Item or Window identifier.");
4988
4989
// BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing:
4990
// if (id == 0)
4991
// id = GetItemID(); // Use last item id
4992
// if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right))
4993
// OpenPopup(id);
4994
// return BeginPopup(id);
4995
// For advanced uses you may want to replicate and customize this code.
4996
// See more details in BeginPopupContextItem().
4997
4998
// Example 1
4999
// When used after an item that has an ID (e.g. Button), we can skip providing an ID to BeginPopupContextItem(),
5000
// and BeginPopupContextItem() will use the last item ID as the popup ID.
5001
{
5002
const char* names[5] = { "Label1", "Label2", "Label3", "Label4", "Label5" };
5003
static int selected = -1;
5004
for (int n = 0; n < 5; n++)
5005
{
5006
if (ImGui::Selectable(names[n], selected == n))
5007
selected = n;
5008
if (ImGui::BeginPopupContextItem()) // <-- use last item id as popup id
5009
{
5010
selected = n;
5011
ImGui::Text("This a popup for \"%s\"!", names[n]);
5012
if (ImGui::Button("Close"))
5013
ImGui::CloseCurrentPopup();
5014
ImGui::EndPopup();
5015
}
5016
ImGui::SetItemTooltip("Right-click to open popup");
5017
}
5018
}
5019
5020
// Example 2
5021
// Popup on a Text() element which doesn't have an identifier: we need to provide an identifier to BeginPopupContextItem().
5022
// Using an explicit identifier is also convenient if you want to activate the popups from different locations.
5023
{
5024
HelpMarker("Text() elements don't have stable identifiers so we need to provide one.");
5025
static float value = 0.5f;
5026
ImGui::Text("Value = %.3f <-- (1) right-click this text", value);
5027
if (ImGui::BeginPopupContextItem("my popup"))
5028
{
5029
if (ImGui::Selectable("Set to zero")) value = 0.0f;
5030
if (ImGui::Selectable("Set to PI")) value = 3.1415f;
5031
ImGui::SetNextItemWidth(-FLT_MIN);
5032
ImGui::DragFloat("##Value", &value, 0.1f, 0.0f, 0.0f);
5033
ImGui::EndPopup();
5034
}
5035
5036
// We can also use OpenPopupOnItemClick() to toggle the visibility of a given popup.
5037
// Here we make it that right-clicking this other text element opens the same popup as above.
5038
// The popup itself will be submitted by the code above.
5039
ImGui::Text("(2) Or right-click this text");
5040
ImGui::OpenPopupOnItemClick("my popup", ImGuiPopupFlags_MouseButtonRight);
5041
5042
// Back to square one: manually open the same popup.
5043
if (ImGui::Button("(3) Or click this button"))
5044
ImGui::OpenPopup("my popup");
5045
}
5046
5047
// Example 3
5048
// When using BeginPopupContextItem() with an implicit identifier (NULL == use last item ID),
5049
// we need to make sure your item identifier is stable.
5050
// In this example we showcase altering the item label while preserving its identifier, using the ### operator (see FAQ).
5051
{
5052
HelpMarker("Showcase using a popup ID linked to item ID, with the item having a changing label + stable ID using the ### operator.");
5053
static char name[32] = "Label1";
5054
char buf[64];
5055
sprintf(buf, "Button: %s###Button", name); // ### operator override ID ignoring the preceding label
5056
ImGui::Button(buf);
5057
if (ImGui::BeginPopupContextItem())
5058
{
5059
ImGui::Text("Edit name:");
5060
ImGui::InputText("##edit", name, IM_ARRAYSIZE(name));
5061
if (ImGui::Button("Close"))
5062
ImGui::CloseCurrentPopup();
5063
ImGui::EndPopup();
5064
}
5065
ImGui::SameLine(); ImGui::Text("(<-- right-click here)");
5066
}
5067
5068
ImGui::TreePop();
5069
}
5070
5071
IMGUI_DEMO_MARKER("Popups/Modals");
5072
if (ImGui::TreeNode("Modals"))
5073
{
5074
ImGui::TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside.");
5075
5076
if (ImGui::Button("Delete.."))
5077
ImGui::OpenPopup("Delete?");
5078
5079
// Always center this window when appearing
5080
ImVec2 center = ImGui::GetMainViewport()->GetCenter();
5081
ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
5082
5083
if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize))
5084
{
5085
ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!");
5086
ImGui::Separator();
5087
5088
//static int unused_i = 0;
5089
//ImGui::Combo("Combo", &unused_i, "Delete\0Delete harder\0");
5090
5091
static bool dont_ask_me_next_time = false;
5092
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
5093
ImGui::Checkbox("Don't ask me next time", &dont_ask_me_next_time);
5094
ImGui::PopStyleVar();
5095
5096
if (ImGui::Button("OK", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); }
5097
ImGui::SetItemDefaultFocus();
5098
ImGui::SameLine();
5099
if (ImGui::Button("Cancel", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); }
5100
ImGui::EndPopup();
5101
}
5102
5103
if (ImGui::Button("Stacked modals.."))
5104
ImGui::OpenPopup("Stacked 1");
5105
if (ImGui::BeginPopupModal("Stacked 1", NULL, ImGuiWindowFlags_MenuBar))
5106
{
5107
if (ImGui::BeginMenuBar())
5108
{
5109
if (ImGui::BeginMenu("File"))
5110
{
5111
if (ImGui::MenuItem("Some menu item")) {}
5112
ImGui::EndMenu();
5113
}
5114
ImGui::EndMenuBar();
5115
}
5116
ImGui::Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it.");
5117
5118
// Testing behavior of widgets stacking their own regular popups over the modal.
5119
static int item = 1;
5120
static float color[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
5121
ImGui::Combo("Combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
5122
ImGui::ColorEdit4("Color", color);
5123
5124
if (ImGui::Button("Add another modal.."))
5125
ImGui::OpenPopup("Stacked 2");
5126
5127
// Also demonstrate passing a bool* to BeginPopupModal(), this will create a regular close button which
5128
// will close the popup. Note that the visibility state of popups is owned by imgui, so the input value
5129
// of the bool actually doesn't matter here.
5130
bool unused_open = true;
5131
if (ImGui::BeginPopupModal("Stacked 2", &unused_open))
5132
{
5133
ImGui::Text("Hello from Stacked The Second!");
5134
ImGui::ColorEdit4("Color", color); // Allow opening another nested popup
5135
if (ImGui::Button("Close"))
5136
ImGui::CloseCurrentPopup();
5137
ImGui::EndPopup();
5138
}
5139
5140
if (ImGui::Button("Close"))
5141
ImGui::CloseCurrentPopup();
5142
ImGui::EndPopup();
5143
}
5144
5145
ImGui::TreePop();
5146
}
5147
5148
IMGUI_DEMO_MARKER("Popups/Menus inside a regular window");
5149
if (ImGui::TreeNode("Menus inside a regular window"))
5150
{
5151
ImGui::TextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!");
5152
ImGui::Separator();
5153
5154
ImGui::MenuItem("Menu item", "CTRL+M");
5155
if (ImGui::BeginMenu("Menu inside a regular window"))
5156
{
5157
ShowExampleMenuFile();
5158
ImGui::EndMenu();
5159
}
5160
ImGui::Separator();
5161
ImGui::TreePop();
5162
}
5163
}
5164
5165
// Dummy data structure that we use for the Table demo.
5166
// (pre-C++11 doesn't allow us to instantiate ImVector<MyItem> template if this structure is defined inside the demo function)
5167
namespace
5168
{
5169
// We are passing our own identifier to TableSetupColumn() to facilitate identifying columns in the sorting code.
5170
// This identifier will be passed down into ImGuiTableSortSpec::ColumnUserID.
5171
// But it is possible to omit the user id parameter of TableSetupColumn() and just use the column index instead! (ImGuiTableSortSpec::ColumnIndex)
5172
// If you don't use sorting, you will generally never care about giving column an ID!
5173
enum MyItemColumnID
5174
{
5175
MyItemColumnID_ID,
5176
MyItemColumnID_Name,
5177
MyItemColumnID_Action,
5178
MyItemColumnID_Quantity,
5179
MyItemColumnID_Description
5180
};
5181
5182
struct MyItem
5183
{
5184
int ID;
5185
const char* Name;
5186
int Quantity;
5187
5188
// We have a problem which is affecting _only this demo_ and should not affect your code:
5189
// As we don't rely on std:: or other third-party library to compile dear imgui, we only have reliable access to qsort(),
5190
// however qsort doesn't allow passing user data to comparing function.
5191
// As a workaround, we are storing the sort specs in a static/global for the comparing function to access.
5192
// In your own use case you would probably pass the sort specs to your sorting/comparing functions directly and not use a global.
5193
// We could technically call ImGui::TableGetSortSpecs() in CompareWithSortSpecs(), but considering that this function is called
5194
// very often by the sorting algorithm it would be a little wasteful.
5195
static const ImGuiTableSortSpecs* s_current_sort_specs;
5196
5197
static void SortWithSortSpecs(ImGuiTableSortSpecs* sort_specs, MyItem* items, int items_count)
5198
{
5199
s_current_sort_specs = sort_specs; // Store in variable accessible by the sort function.
5200
if (items_count > 1)
5201
qsort(items, (size_t)items_count, sizeof(items[0]), MyItem::CompareWithSortSpecs);
5202
s_current_sort_specs = NULL;
5203
}
5204
5205
// Compare function to be used by qsort()
5206
static int IMGUI_CDECL CompareWithSortSpecs(const void* lhs, const void* rhs)
5207
{
5208
const MyItem* a = (const MyItem*)lhs;
5209
const MyItem* b = (const MyItem*)rhs;
5210
for (int n = 0; n < s_current_sort_specs->SpecsCount; n++)
5211
{
5212
// Here we identify columns using the ColumnUserID value that we ourselves passed to TableSetupColumn()
5213
// We could also choose to identify columns based on their index (sort_spec->ColumnIndex), which is simpler!
5214
const ImGuiTableColumnSortSpecs* sort_spec = &s_current_sort_specs->Specs[n];
5215
int delta = 0;
5216
switch (sort_spec->ColumnUserID)
5217
{
5218
case MyItemColumnID_ID: delta = (a->ID - b->ID); break;
5219
case MyItemColumnID_Name: delta = (strcmp(a->Name, b->Name)); break;
5220
case MyItemColumnID_Quantity: delta = (a->Quantity - b->Quantity); break;
5221
case MyItemColumnID_Description: delta = (strcmp(a->Name, b->Name)); break;
5222
default: IM_ASSERT(0); break;
5223
}
5224
if (delta > 0)
5225
return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? +1 : -1;
5226
if (delta < 0)
5227
return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? -1 : +1;
5228
}
5229
5230
// qsort() is instable so always return a way to differenciate items.
5231
// Your own compare function may want to avoid fallback on implicit sort specs.
5232
// e.g. a Name compare if it wasn't already part of the sort specs.
5233
return (a->ID - b->ID);
5234
}
5235
};
5236
const ImGuiTableSortSpecs* MyItem::s_current_sort_specs = NULL;
5237
}
5238
5239
// Make the UI compact because there are so many fields
5240
static void PushStyleCompact()
5241
{
5242
ImGuiStyle& style = ImGui::GetStyle();
5243
ImGui::PushStyleVarY(ImGuiStyleVar_FramePadding, (float)(int)(style.FramePadding.y * 0.60f));
5244
ImGui::PushStyleVarY(ImGuiStyleVar_ItemSpacing, (float)(int)(style.ItemSpacing.y * 0.60f));
5245
}
5246
5247
static void PopStyleCompact()
5248
{
5249
ImGui::PopStyleVar(2);
5250
}
5251
5252
// Show a combo box with a choice of sizing policies
5253
static void EditTableSizingFlags(ImGuiTableFlags* p_flags)
5254
{
5255
struct EnumDesc { ImGuiTableFlags Value; const char* Name; const char* Tooltip; };
5256
static const EnumDesc policies[] =
5257
{
5258
{ 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." },
5259
{ ImGuiTableFlags_SizingFixedFit, "ImGuiTableFlags_SizingFixedFit", "Columns default to _WidthFixed (if resizable) or _WidthAuto (if not resizable), matching contents width." },
5260
{ ImGuiTableFlags_SizingFixedSame, "ImGuiTableFlags_SizingFixedSame", "Columns are all the same width, matching the maximum contents width.\nImplicitly disable ImGuiTableFlags_Resizable and enable ImGuiTableFlags_NoKeepColumnsVisible." },
5261
{ ImGuiTableFlags_SizingStretchProp, "ImGuiTableFlags_SizingStretchProp", "Columns default to _WidthStretch with weights proportional to their widths." },
5262
{ ImGuiTableFlags_SizingStretchSame, "ImGuiTableFlags_SizingStretchSame", "Columns default to _WidthStretch with same weights." }
5263
};
5264
int idx;
5265
for (idx = 0; idx < IM_ARRAYSIZE(policies); idx++)
5266
if (policies[idx].Value == (*p_flags & ImGuiTableFlags_SizingMask_))
5267
break;
5268
const char* preview_text = (idx < IM_ARRAYSIZE(policies)) ? policies[idx].Name + (idx > 0 ? strlen("ImGuiTableFlags") : 0) : "";
5269
if (ImGui::BeginCombo("Sizing Policy", preview_text))
5270
{
5271
for (int n = 0; n < IM_ARRAYSIZE(policies); n++)
5272
if (ImGui::Selectable(policies[n].Name, idx == n))
5273
*p_flags = (*p_flags & ~ImGuiTableFlags_SizingMask_) | policies[n].Value;
5274
ImGui::EndCombo();
5275
}
5276
ImGui::SameLine();
5277
ImGui::TextDisabled("(?)");
5278
if (ImGui::BeginItemTooltip())
5279
{
5280
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 50.0f);
5281
for (int m = 0; m < IM_ARRAYSIZE(policies); m++)
5282
{
5283
ImGui::Separator();
5284
ImGui::Text("%s:", policies[m].Name);
5285
ImGui::Separator();
5286
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetStyle().IndentSpacing * 0.5f);
5287
ImGui::TextUnformatted(policies[m].Tooltip);
5288
}
5289
ImGui::PopTextWrapPos();
5290
ImGui::EndTooltip();
5291
}
5292
}
5293
5294
static void EditTableColumnsFlags(ImGuiTableColumnFlags* p_flags)
5295
{
5296
ImGui::CheckboxFlags("_Disabled", p_flags, ImGuiTableColumnFlags_Disabled); ImGui::SameLine(); HelpMarker("Master disable flag (also hide from context menu)");
5297
ImGui::CheckboxFlags("_DefaultHide", p_flags, ImGuiTableColumnFlags_DefaultHide);
5298
ImGui::CheckboxFlags("_DefaultSort", p_flags, ImGuiTableColumnFlags_DefaultSort);
5299
if (ImGui::CheckboxFlags("_WidthStretch", p_flags, ImGuiTableColumnFlags_WidthStretch))
5300
*p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthStretch);
5301
if (ImGui::CheckboxFlags("_WidthFixed", p_flags, ImGuiTableColumnFlags_WidthFixed))
5302
*p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthFixed);
5303
ImGui::CheckboxFlags("_NoResize", p_flags, ImGuiTableColumnFlags_NoResize);
5304
ImGui::CheckboxFlags("_NoReorder", p_flags, ImGuiTableColumnFlags_NoReorder);
5305
ImGui::CheckboxFlags("_NoHide", p_flags, ImGuiTableColumnFlags_NoHide);
5306
ImGui::CheckboxFlags("_NoClip", p_flags, ImGuiTableColumnFlags_NoClip);
5307
ImGui::CheckboxFlags("_NoSort", p_flags, ImGuiTableColumnFlags_NoSort);
5308
ImGui::CheckboxFlags("_NoSortAscending", p_flags, ImGuiTableColumnFlags_NoSortAscending);
5309
ImGui::CheckboxFlags("_NoSortDescending", p_flags, ImGuiTableColumnFlags_NoSortDescending);
5310
ImGui::CheckboxFlags("_NoHeaderLabel", p_flags, ImGuiTableColumnFlags_NoHeaderLabel);
5311
ImGui::CheckboxFlags("_NoHeaderWidth", p_flags, ImGuiTableColumnFlags_NoHeaderWidth);
5312
ImGui::CheckboxFlags("_PreferSortAscending", p_flags, ImGuiTableColumnFlags_PreferSortAscending);
5313
ImGui::CheckboxFlags("_PreferSortDescending", p_flags, ImGuiTableColumnFlags_PreferSortDescending);
5314
ImGui::CheckboxFlags("_IndentEnable", p_flags, ImGuiTableColumnFlags_IndentEnable); ImGui::SameLine(); HelpMarker("Default for column 0");
5315
ImGui::CheckboxFlags("_IndentDisable", p_flags, ImGuiTableColumnFlags_IndentDisable); ImGui::SameLine(); HelpMarker("Default for column >0");
5316
ImGui::CheckboxFlags("_AngledHeader", p_flags, ImGuiTableColumnFlags_AngledHeader);
5317
}
5318
5319
static void ShowTableColumnsStatusFlags(ImGuiTableColumnFlags flags)
5320
{
5321
ImGui::CheckboxFlags("_IsEnabled", &flags, ImGuiTableColumnFlags_IsEnabled);
5322
ImGui::CheckboxFlags("_IsVisible", &flags, ImGuiTableColumnFlags_IsVisible);
5323
ImGui::CheckboxFlags("_IsSorted", &flags, ImGuiTableColumnFlags_IsSorted);
5324
ImGui::CheckboxFlags("_IsHovered", &flags, ImGuiTableColumnFlags_IsHovered);
5325
}
5326
5327
//-----------------------------------------------------------------------------
5328
// [SECTION] ShowDemoWindowTables()
5329
//-----------------------------------------------------------------------------
5330
5331
static void ShowDemoWindowTables()
5332
{
5333
//ImGui::SetNextItemOpen(true, ImGuiCond_Once);
5334
IMGUI_DEMO_MARKER("Tables");
5335
if (!ImGui::CollapsingHeader("Tables & Columns"))
5336
return;
5337
5338
// Using those as a base value to create width/height that are factor of the size of our font
5339
const float TEXT_BASE_WIDTH = ImGui::CalcTextSize("A").x;
5340
const float TEXT_BASE_HEIGHT = ImGui::GetTextLineHeightWithSpacing();
5341
5342
ImGui::PushID("Tables");
5343
5344
int open_action = -1;
5345
if (ImGui::Button("Expand all"))
5346
open_action = 1;
5347
ImGui::SameLine();
5348
if (ImGui::Button("Collapse all"))
5349
open_action = 0;
5350
ImGui::SameLine();
5351
5352
// Options
5353
static bool disable_indent = false;
5354
ImGui::Checkbox("Disable tree indentation", &disable_indent);
5355
ImGui::SameLine();
5356
HelpMarker("Disable the indenting of tree nodes so demo tables can use the full window width.");
5357
ImGui::Separator();
5358
if (disable_indent)
5359
ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0.0f);
5360
5361
// About Styling of tables
5362
// Most settings are configured on a per-table basis via the flags passed to BeginTable() and TableSetupColumns APIs.
5363
// There are however a few settings that a shared and part of the ImGuiStyle structure:
5364
// style.CellPadding // Padding within each cell
5365
// style.Colors[ImGuiCol_TableHeaderBg] // Table header background
5366
// style.Colors[ImGuiCol_TableBorderStrong] // Table outer and header borders
5367
// style.Colors[ImGuiCol_TableBorderLight] // Table inner borders
5368
// style.Colors[ImGuiCol_TableRowBg] // Table row background when ImGuiTableFlags_RowBg is enabled (even rows)
5369
// style.Colors[ImGuiCol_TableRowBgAlt] // Table row background when ImGuiTableFlags_RowBg is enabled (odds rows)
5370
5371
// Demos
5372
if (open_action != -1)
5373
ImGui::SetNextItemOpen(open_action != 0);
5374
IMGUI_DEMO_MARKER("Tables/Basic");
5375
if (ImGui::TreeNode("Basic"))
5376
{
5377
// Here we will showcase three different ways to output a table.
5378
// They are very simple variations of a same thing!
5379
5380
// [Method 1] Using TableNextRow() to create a new row, and TableSetColumnIndex() to select the column.
5381
// In many situations, this is the most flexible and easy to use pattern.
5382
HelpMarker("Using TableNextRow() + calling TableSetColumnIndex() _before_ each cell, in a loop.");
5383
if (ImGui::BeginTable("table1", 3))
5384
{
5385
for (int row = 0; row < 4; row++)
5386
{
5387
ImGui::TableNextRow();
5388
for (int column = 0; column < 3; column++)
5389
{
5390
ImGui::TableSetColumnIndex(column);
5391
ImGui::Text("Row %d Column %d", row, column);
5392
}
5393
}
5394
ImGui::EndTable();
5395
}
5396
5397
// [Method 2] Using TableNextColumn() called multiple times, instead of using a for loop + TableSetColumnIndex().
5398
// This is generally more convenient when you have code manually submitting the contents of each column.
5399
HelpMarker("Using TableNextRow() + calling TableNextColumn() _before_ each cell, manually.");
5400
if (ImGui::BeginTable("table2", 3))
5401
{
5402
for (int row = 0; row < 4; row++)
5403
{
5404
ImGui::TableNextRow();
5405
ImGui::TableNextColumn();
5406
ImGui::Text("Row %d", row);
5407
ImGui::TableNextColumn();
5408
ImGui::Text("Some contents");
5409
ImGui::TableNextColumn();
5410
ImGui::Text("123.456");
5411
}
5412
ImGui::EndTable();
5413
}
5414
5415
// [Method 3] We call TableNextColumn() _before_ each cell. We never call TableNextRow(),
5416
// as TableNextColumn() will automatically wrap around and create new rows as needed.
5417
// This is generally more convenient when your cells all contains the same type of data.
5418
HelpMarker(
5419
"Only using TableNextColumn(), which tends to be convenient for tables where every cell contains "
5420
"the same type of contents.\n This is also more similar to the old NextColumn() function of the "
5421
"Columns API, and provided to facilitate the Columns->Tables API transition.");
5422
if (ImGui::BeginTable("table3", 3))
5423
{
5424
for (int item = 0; item < 14; item++)
5425
{
5426
ImGui::TableNextColumn();
5427
ImGui::Text("Item %d", item);
5428
}
5429
ImGui::EndTable();
5430
}
5431
5432
ImGui::TreePop();
5433
}
5434
5435
if (open_action != -1)
5436
ImGui::SetNextItemOpen(open_action != 0);
5437
IMGUI_DEMO_MARKER("Tables/Borders, background");
5438
if (ImGui::TreeNode("Borders, background"))
5439
{
5440
// Expose a few Borders related flags interactively
5441
enum ContentsType { CT_Text, CT_FillButton };
5442
static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg;
5443
static bool display_headers = false;
5444
static int contents_type = CT_Text;
5445
5446
PushStyleCompact();
5447
ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg);
5448
ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags, ImGuiTableFlags_Borders);
5449
ImGui::SameLine(); HelpMarker("ImGuiTableFlags_Borders\n = ImGuiTableFlags_BordersInnerV\n | ImGuiTableFlags_BordersOuterV\n | ImGuiTableFlags_BordersInnerH\n | ImGuiTableFlags_BordersOuterH");
5450
ImGui::Indent();
5451
5452
ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags, ImGuiTableFlags_BordersH);
5453
ImGui::Indent();
5454
ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterH", &flags, ImGuiTableFlags_BordersOuterH);
5455
ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerH", &flags, ImGuiTableFlags_BordersInnerH);
5456
ImGui::Unindent();
5457
5458
ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV);
5459
ImGui::Indent();
5460
ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags, ImGuiTableFlags_BordersOuterV);
5461
ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags, ImGuiTableFlags_BordersInnerV);
5462
ImGui::Unindent();
5463
5464
ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuter", &flags, ImGuiTableFlags_BordersOuter);
5465
ImGui::CheckboxFlags("ImGuiTableFlags_BordersInner", &flags, ImGuiTableFlags_BordersInner);
5466
ImGui::Unindent();
5467
5468
ImGui::AlignTextToFramePadding(); ImGui::Text("Cell contents:");
5469
ImGui::SameLine(); ImGui::RadioButton("Text", &contents_type, CT_Text);
5470
ImGui::SameLine(); ImGui::RadioButton("FillButton", &contents_type, CT_FillButton);
5471
ImGui::Checkbox("Display headers", &display_headers);
5472
ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers");
5473
PopStyleCompact();
5474
5475
if (ImGui::BeginTable("table1", 3, flags))
5476
{
5477
// Display headers so we can inspect their interaction with borders
5478
// (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)
5479
if (display_headers)
5480
{
5481
ImGui::TableSetupColumn("One");
5482
ImGui::TableSetupColumn("Two");
5483
ImGui::TableSetupColumn("Three");
5484
ImGui::TableHeadersRow();
5485
}
5486
5487
for (int row = 0; row < 5; row++)
5488
{
5489
ImGui::TableNextRow();
5490
for (int column = 0; column < 3; column++)
5491
{
5492
ImGui::TableSetColumnIndex(column);
5493
char buf[32];
5494
sprintf(buf, "Hello %d,%d", column, row);
5495
if (contents_type == CT_Text)
5496
ImGui::TextUnformatted(buf);
5497
else if (contents_type == CT_FillButton)
5498
ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f));
5499
}
5500
}
5501
ImGui::EndTable();
5502
}
5503
ImGui::TreePop();
5504
}
5505
5506
if (open_action != -1)
5507
ImGui::SetNextItemOpen(open_action != 0);
5508
IMGUI_DEMO_MARKER("Tables/Resizable, stretch");
5509
if (ImGui::TreeNode("Resizable, stretch"))
5510
{
5511
// By default, if we don't enable ScrollX the sizing policy for each column is "Stretch"
5512
// All columns maintain a sizing weight, and they will occupy all available width.
5513
static ImGuiTableFlags flags = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody;
5514
PushStyleCompact();
5515
ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
5516
ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV);
5517
ImGui::SameLine(); HelpMarker(
5518
"Using the _Resizable flag automatically enables the _BordersInnerV flag as well, "
5519
"this is why the resize borders are still showing when unchecking this.");
5520
PopStyleCompact();
5521
5522
if (ImGui::BeginTable("table1", 3, flags))
5523
{
5524
for (int row = 0; row < 5; row++)
5525
{
5526
ImGui::TableNextRow();
5527
for (int column = 0; column < 3; column++)
5528
{
5529
ImGui::TableSetColumnIndex(column);
5530
ImGui::Text("Hello %d,%d", column, row);
5531
}
5532
}
5533
ImGui::EndTable();
5534
}
5535
ImGui::TreePop();
5536
}
5537
5538
if (open_action != -1)
5539
ImGui::SetNextItemOpen(open_action != 0);
5540
IMGUI_DEMO_MARKER("Tables/Resizable, fixed");
5541
if (ImGui::TreeNode("Resizable, fixed"))
5542
{
5543
// Here we use ImGuiTableFlags_SizingFixedFit (even though _ScrollX is not set)
5544
// So columns will adopt the "Fixed" policy and will maintain a fixed width regardless of the whole available width (unless table is small)
5545
// If there is not enough available width to fit all columns, they will however be resized down.
5546
// FIXME-TABLE: Providing a stretch-on-init would make sense especially for tables which don't have saved settings
5547
HelpMarker(
5548
"Using _Resizable + _SizingFixedFit flags.\n"
5549
"Fixed-width columns generally makes more sense if you want to use horizontal scrolling.\n\n"
5550
"Double-click a column border to auto-fit the column to its contents.");
5551
PushStyleCompact();
5552
static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody;
5553
ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX);
5554
PopStyleCompact();
5555
5556
if (ImGui::BeginTable("table1", 3, flags))
5557
{
5558
for (int row = 0; row < 5; row++)
5559
{
5560
ImGui::TableNextRow();
5561
for (int column = 0; column < 3; column++)
5562
{
5563
ImGui::TableSetColumnIndex(column);
5564
ImGui::Text("Hello %d,%d", column, row);
5565
}
5566
}
5567
ImGui::EndTable();
5568
}
5569
ImGui::TreePop();
5570
}
5571
5572
if (open_action != -1)
5573
ImGui::SetNextItemOpen(open_action != 0);
5574
IMGUI_DEMO_MARKER("Tables/Resizable, mixed");
5575
if (ImGui::TreeNode("Resizable, mixed"))
5576
{
5577
HelpMarker(
5578
"Using TableSetupColumn() to alter resizing policy on a per-column basis.\n\n"
5579
"When combining Fixed and Stretch columns, generally you only want one, maybe two trailing columns to use _WidthStretch.");
5580
static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
5581
5582
if (ImGui::BeginTable("table1", 3, flags))
5583
{
5584
ImGui::TableSetupColumn("AAA", ImGuiTableColumnFlags_WidthFixed);
5585
ImGui::TableSetupColumn("BBB", ImGuiTableColumnFlags_WidthFixed);
5586
ImGui::TableSetupColumn("CCC", ImGuiTableColumnFlags_WidthStretch);
5587
ImGui::TableHeadersRow();
5588
for (int row = 0; row < 5; row++)
5589
{
5590
ImGui::TableNextRow();
5591
for (int column = 0; column < 3; column++)
5592
{
5593
ImGui::TableSetColumnIndex(column);
5594
ImGui::Text("%s %d,%d", (column == 2) ? "Stretch" : "Fixed", column, row);
5595
}
5596
}
5597
ImGui::EndTable();
5598
}
5599
if (ImGui::BeginTable("table2", 6, flags))
5600
{
5601
ImGui::TableSetupColumn("AAA", ImGuiTableColumnFlags_WidthFixed);
5602
ImGui::TableSetupColumn("BBB", ImGuiTableColumnFlags_WidthFixed);
5603
ImGui::TableSetupColumn("CCC", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_DefaultHide);
5604
ImGui::TableSetupColumn("DDD", ImGuiTableColumnFlags_WidthStretch);
5605
ImGui::TableSetupColumn("EEE", ImGuiTableColumnFlags_WidthStretch);
5606
ImGui::TableSetupColumn("FFF", ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_DefaultHide);
5607
ImGui::TableHeadersRow();
5608
for (int row = 0; row < 5; row++)
5609
{
5610
ImGui::TableNextRow();
5611
for (int column = 0; column < 6; column++)
5612
{
5613
ImGui::TableSetColumnIndex(column);
5614
ImGui::Text("%s %d,%d", (column >= 3) ? "Stretch" : "Fixed", column, row);
5615
}
5616
}
5617
ImGui::EndTable();
5618
}
5619
ImGui::TreePop();
5620
}
5621
5622
if (open_action != -1)
5623
ImGui::SetNextItemOpen(open_action != 0);
5624
IMGUI_DEMO_MARKER("Tables/Reorderable, hideable, with headers");
5625
if (ImGui::TreeNode("Reorderable, hideable, with headers"))
5626
{
5627
HelpMarker(
5628
"Click and drag column headers to reorder columns.\n\n"
5629
"Right-click on a header to open a context menu.");
5630
static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV;
5631
PushStyleCompact();
5632
ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
5633
ImGui::CheckboxFlags("ImGuiTableFlags_Reorderable", &flags, ImGuiTableFlags_Reorderable);
5634
ImGui::CheckboxFlags("ImGuiTableFlags_Hideable", &flags, ImGuiTableFlags_Hideable);
5635
ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody);
5636
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)");
5637
ImGui::CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", &flags, ImGuiTableFlags_HighlightHoveredColumn);
5638
PopStyleCompact();
5639
5640
if (ImGui::BeginTable("table1", 3, flags))
5641
{
5642
// Submit columns name with TableSetupColumn() and call TableHeadersRow() to create a row with a header in each column.
5643
// (Later we will show how TableSetupColumn() has other uses, optional flags, sizing weight etc.)
5644
ImGui::TableSetupColumn("One");
5645
ImGui::TableSetupColumn("Two");
5646
ImGui::TableSetupColumn("Three");
5647
ImGui::TableHeadersRow();
5648
for (int row = 0; row < 6; row++)
5649
{
5650
ImGui::TableNextRow();
5651
for (int column = 0; column < 3; column++)
5652
{
5653
ImGui::TableSetColumnIndex(column);
5654
ImGui::Text("Hello %d,%d", column, row);
5655
}
5656
}
5657
ImGui::EndTable();
5658
}
5659
5660
// Use outer_size.x == 0.0f instead of default to make the table as tight as possible
5661
// (only valid when no scrolling and no stretch column)
5662
if (ImGui::BeginTable("table2", 3, flags | ImGuiTableFlags_SizingFixedFit, ImVec2(0.0f, 0.0f)))
5663
{
5664
ImGui::TableSetupColumn("One");
5665
ImGui::TableSetupColumn("Two");
5666
ImGui::TableSetupColumn("Three");
5667
ImGui::TableHeadersRow();
5668
for (int row = 0; row < 6; row++)
5669
{
5670
ImGui::TableNextRow();
5671
for (int column = 0; column < 3; column++)
5672
{
5673
ImGui::TableSetColumnIndex(column);
5674
ImGui::Text("Fixed %d,%d", column, row);
5675
}
5676
}
5677
ImGui::EndTable();
5678
}
5679
ImGui::TreePop();
5680
}
5681
5682
if (open_action != -1)
5683
ImGui::SetNextItemOpen(open_action != 0);
5684
IMGUI_DEMO_MARKER("Tables/Padding");
5685
if (ImGui::TreeNode("Padding"))
5686
{
5687
// First example: showcase use of padding flags and effect of BorderOuterV/BorderInnerV on X padding.
5688
// We don't expose BorderOuterH/BorderInnerH here because they have no effect on X padding.
5689
HelpMarker(
5690
"We often want outer padding activated when any using features which makes the edges of a column visible:\n"
5691
"e.g.:\n"
5692
"- BorderOuterV\n"
5693
"- any form of row selection\n"
5694
"Because of this, activating BorderOuterV sets the default to PadOuterX. "
5695
"Using PadOuterX or NoPadOuterX you can override the default.\n\n"
5696
"Actual padding values are using style.CellPadding.\n\n"
5697
"In this demo we don't show horizontal borders to emphasize how they don't affect default horizontal padding.");
5698
5699
static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV;
5700
PushStyleCompact();
5701
ImGui::CheckboxFlags("ImGuiTableFlags_PadOuterX", &flags1, ImGuiTableFlags_PadOuterX);
5702
ImGui::SameLine(); HelpMarker("Enable outer-most padding (default if ImGuiTableFlags_BordersOuterV is set)");
5703
ImGui::CheckboxFlags("ImGuiTableFlags_NoPadOuterX", &flags1, ImGuiTableFlags_NoPadOuterX);
5704
ImGui::SameLine(); HelpMarker("Disable outer-most padding (default if ImGuiTableFlags_BordersOuterV is not set)");
5705
ImGui::CheckboxFlags("ImGuiTableFlags_NoPadInnerX", &flags1, ImGuiTableFlags_NoPadInnerX);
5706
ImGui::SameLine(); HelpMarker("Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off)");
5707
ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags1, ImGuiTableFlags_BordersOuterV);
5708
ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags1, ImGuiTableFlags_BordersInnerV);
5709
static bool show_headers = false;
5710
ImGui::Checkbox("show_headers", &show_headers);
5711
PopStyleCompact();
5712
5713
if (ImGui::BeginTable("table_padding", 3, flags1))
5714
{
5715
if (show_headers)
5716
{
5717
ImGui::TableSetupColumn("One");
5718
ImGui::TableSetupColumn("Two");
5719
ImGui::TableSetupColumn("Three");
5720
ImGui::TableHeadersRow();
5721
}
5722
5723
for (int row = 0; row < 5; row++)
5724
{
5725
ImGui::TableNextRow();
5726
for (int column = 0; column < 3; column++)
5727
{
5728
ImGui::TableSetColumnIndex(column);
5729
if (row == 0)
5730
{
5731
ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x);
5732
}
5733
else
5734
{
5735
char buf[32];
5736
sprintf(buf, "Hello %d,%d", column, row);
5737
ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f));
5738
}
5739
//if (ImGui::TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered)
5740
// ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, IM_COL32(0, 100, 0, 255));
5741
}
5742
}
5743
ImGui::EndTable();
5744
}
5745
5746
// Second example: set style.CellPadding to (0.0) or a custom value.
5747
// FIXME-TABLE: Vertical border effectively not displayed the same way as horizontal one...
5748
HelpMarker("Setting style.CellPadding to (0,0) or a custom value.");
5749
static ImGuiTableFlags flags2 = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg;
5750
static ImVec2 cell_padding(0.0f, 0.0f);
5751
static bool show_widget_frame_bg = true;
5752
5753
PushStyleCompact();
5754
ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags2, ImGuiTableFlags_Borders);
5755
ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags2, ImGuiTableFlags_BordersH);
5756
ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags2, ImGuiTableFlags_BordersV);
5757
ImGui::CheckboxFlags("ImGuiTableFlags_BordersInner", &flags2, ImGuiTableFlags_BordersInner);
5758
ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuter", &flags2, ImGuiTableFlags_BordersOuter);
5759
ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags2, ImGuiTableFlags_RowBg);
5760
ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags2, ImGuiTableFlags_Resizable);
5761
ImGui::Checkbox("show_widget_frame_bg", &show_widget_frame_bg);
5762
ImGui::SliderFloat2("CellPadding", &cell_padding.x, 0.0f, 10.0f, "%.0f");
5763
PopStyleCompact();
5764
5765
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, cell_padding);
5766
if (ImGui::BeginTable("table_padding_2", 3, flags2))
5767
{
5768
static char text_bufs[3 * 5][16]; // Mini text storage for 3x5 cells
5769
static bool init = true;
5770
if (!show_widget_frame_bg)
5771
ImGui::PushStyleColor(ImGuiCol_FrameBg, 0);
5772
for (int cell = 0; cell < 3 * 5; cell++)
5773
{
5774
ImGui::TableNextColumn();
5775
if (init)
5776
strcpy(text_bufs[cell], "edit me");
5777
ImGui::SetNextItemWidth(-FLT_MIN);
5778
ImGui::PushID(cell);
5779
ImGui::InputText("##cell", text_bufs[cell], IM_ARRAYSIZE(text_bufs[cell]));
5780
ImGui::PopID();
5781
}
5782
if (!show_widget_frame_bg)
5783
ImGui::PopStyleColor();
5784
init = false;
5785
ImGui::EndTable();
5786
}
5787
ImGui::PopStyleVar();
5788
5789
ImGui::TreePop();
5790
}
5791
5792
if (open_action != -1)
5793
ImGui::SetNextItemOpen(open_action != 0);
5794
IMGUI_DEMO_MARKER("Tables/Explicit widths");
5795
if (ImGui::TreeNode("Sizing policies"))
5796
{
5797
static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody;
5798
PushStyleCompact();
5799
ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags1, ImGuiTableFlags_Resizable);
5800
ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags1, ImGuiTableFlags_NoHostExtendX);
5801
PopStyleCompact();
5802
5803
static ImGuiTableFlags sizing_policy_flags[4] = { ImGuiTableFlags_SizingFixedFit, ImGuiTableFlags_SizingFixedSame, ImGuiTableFlags_SizingStretchProp, ImGuiTableFlags_SizingStretchSame };
5804
for (int table_n = 0; table_n < 4; table_n++)
5805
{
5806
ImGui::PushID(table_n);
5807
ImGui::SetNextItemWidth(TEXT_BASE_WIDTH * 30);
5808
EditTableSizingFlags(&sizing_policy_flags[table_n]);
5809
5810
// To make it easier to understand the different sizing policy,
5811
// For each policy: we display one table where the columns have equal contents width,
5812
// and one where the columns have different contents width.
5813
if (ImGui::BeginTable("table1", 3, sizing_policy_flags[table_n] | flags1))
5814
{
5815
for (int row = 0; row < 3; row++)
5816
{
5817
ImGui::TableNextRow();
5818
ImGui::TableNextColumn(); ImGui::Text("Oh dear");
5819
ImGui::TableNextColumn(); ImGui::Text("Oh dear");
5820
ImGui::TableNextColumn(); ImGui::Text("Oh dear");
5821
}
5822
ImGui::EndTable();
5823
}
5824
if (ImGui::BeginTable("table2", 3, sizing_policy_flags[table_n] | flags1))
5825
{
5826
for (int row = 0; row < 3; row++)
5827
{
5828
ImGui::TableNextRow();
5829
ImGui::TableNextColumn(); ImGui::Text("AAAA");
5830
ImGui::TableNextColumn(); ImGui::Text("BBBBBBBB");
5831
ImGui::TableNextColumn(); ImGui::Text("CCCCCCCCCCCC");
5832
}
5833
ImGui::EndTable();
5834
}
5835
ImGui::PopID();
5836
}
5837
5838
ImGui::Spacing();
5839
ImGui::TextUnformatted("Advanced");
5840
ImGui::SameLine();
5841
HelpMarker(
5842
"This section allows you to interact and see the effect of various sizing policies "
5843
"depending on whether Scroll is enabled and the contents of your columns.");
5844
5845
enum ContentsType { CT_ShowWidth, CT_ShortText, CT_LongText, CT_Button, CT_FillButton, CT_InputText };
5846
static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable;
5847
static int contents_type = CT_ShowWidth;
5848
static int column_count = 3;
5849
5850
PushStyleCompact();
5851
ImGui::PushID("Advanced");
5852
ImGui::PushItemWidth(TEXT_BASE_WIDTH * 30);
5853
EditTableSizingFlags(&flags);
5854
ImGui::Combo("Contents", &contents_type, "Show width\0Short Text\0Long Text\0Button\0Fill Button\0InputText\0");
5855
if (contents_type == CT_FillButton)
5856
{
5857
ImGui::SameLine();
5858
HelpMarker(
5859
"Be mindful that using right-alignment (e.g. size.x = -FLT_MIN) creates a feedback loop "
5860
"where contents width can feed into auto-column width can feed into contents width.");
5861
}
5862
ImGui::DragInt("Columns", &column_count, 0.1f, 1, 64, "%d", ImGuiSliderFlags_AlwaysClamp);
5863
ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
5864
ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths);
5865
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.");
5866
ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX);
5867
ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
5868
ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip);
5869
ImGui::PopItemWidth();
5870
ImGui::PopID();
5871
PopStyleCompact();
5872
5873
if (ImGui::BeginTable("table2", column_count, flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 7)))
5874
{
5875
for (int cell = 0; cell < 10 * column_count; cell++)
5876
{
5877
ImGui::TableNextColumn();
5878
int column = ImGui::TableGetColumnIndex();
5879
int row = ImGui::TableGetRowIndex();
5880
5881
ImGui::PushID(cell);
5882
char label[32];
5883
static char text_buf[32] = "";
5884
sprintf(label, "Hello %d,%d", column, row);
5885
switch (contents_type)
5886
{
5887
case CT_ShortText: ImGui::TextUnformatted(label); break;
5888
case CT_LongText: ImGui::Text("Some %s text %d,%d\nOver two lines..", column == 0 ? "long" : "longeeer", column, row); break;
5889
case CT_ShowWidth: ImGui::Text("W: %.1f", ImGui::GetContentRegionAvail().x); break;
5890
case CT_Button: ImGui::Button(label); break;
5891
case CT_FillButton: ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f)); break;
5892
case CT_InputText: ImGui::SetNextItemWidth(-FLT_MIN); ImGui::InputText("##", text_buf, IM_ARRAYSIZE(text_buf)); break;
5893
}
5894
ImGui::PopID();
5895
}
5896
ImGui::EndTable();
5897
}
5898
ImGui::TreePop();
5899
}
5900
5901
if (open_action != -1)
5902
ImGui::SetNextItemOpen(open_action != 0);
5903
IMGUI_DEMO_MARKER("Tables/Vertical scrolling, with clipping");
5904
if (ImGui::TreeNode("Vertical scrolling, with clipping"))
5905
{
5906
HelpMarker(
5907
"Here we activate ScrollY, which will create a child window container to allow hosting scrollable contents.\n\n"
5908
"We also demonstrate using ImGuiListClipper to virtualize the submission of many items.");
5909
static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
5910
5911
PushStyleCompact();
5912
ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
5913
PopStyleCompact();
5914
5915
// When using ScrollX or ScrollY we need to specify a size for our table container!
5916
// Otherwise by default the table will fit all available space, like a BeginChild() call.
5917
ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 8);
5918
if (ImGui::BeginTable("table_scrolly", 3, flags, outer_size))
5919
{
5920
ImGui::TableSetupScrollFreeze(0, 1); // Make top row always visible
5921
ImGui::TableSetupColumn("One", ImGuiTableColumnFlags_None);
5922
ImGui::TableSetupColumn("Two", ImGuiTableColumnFlags_None);
5923
ImGui::TableSetupColumn("Three", ImGuiTableColumnFlags_None);
5924
ImGui::TableHeadersRow();
5925
5926
// Demonstrate using clipper for large vertical lists
5927
ImGuiListClipper clipper;
5928
clipper.Begin(1000);
5929
while (clipper.Step())
5930
{
5931
for (int row = clipper.DisplayStart; row < clipper.DisplayEnd; row++)
5932
{
5933
ImGui::TableNextRow();
5934
for (int column = 0; column < 3; column++)
5935
{
5936
ImGui::TableSetColumnIndex(column);
5937
ImGui::Text("Hello %d,%d", column, row);
5938
}
5939
}
5940
}
5941
ImGui::EndTable();
5942
}
5943
ImGui::TreePop();
5944
}
5945
5946
if (open_action != -1)
5947
ImGui::SetNextItemOpen(open_action != 0);
5948
IMGUI_DEMO_MARKER("Tables/Horizontal scrolling");
5949
if (ImGui::TreeNode("Horizontal scrolling"))
5950
{
5951
HelpMarker(
5952
"When ScrollX is enabled, the default sizing policy becomes ImGuiTableFlags_SizingFixedFit, "
5953
"as automatically stretching columns doesn't make much sense with horizontal scrolling.\n\n"
5954
"Also note that as of the current version, you will almost always want to enable ScrollY along with ScrollX, "
5955
"because the container window won't automatically extend vertically to fix contents "
5956
"(this may be improved in future versions).");
5957
static ImGuiTableFlags flags = ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
5958
static int freeze_cols = 1;
5959
static int freeze_rows = 1;
5960
5961
PushStyleCompact();
5962
ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
5963
ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX);
5964
ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
5965
ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
5966
ImGui::DragInt("freeze_cols", &freeze_cols, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
5967
ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
5968
ImGui::DragInt("freeze_rows", &freeze_rows, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
5969
PopStyleCompact();
5970
5971
// When using ScrollX or ScrollY we need to specify a size for our table container!
5972
// Otherwise by default the table will fit all available space, like a BeginChild() call.
5973
ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 8);
5974
if (ImGui::BeginTable("table_scrollx", 7, flags, outer_size))
5975
{
5976
ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows);
5977
ImGui::TableSetupColumn("Line #", ImGuiTableColumnFlags_NoHide); // Make the first column not hideable to match our use of TableSetupScrollFreeze()
5978
ImGui::TableSetupColumn("One");
5979
ImGui::TableSetupColumn("Two");
5980
ImGui::TableSetupColumn("Three");
5981
ImGui::TableSetupColumn("Four");
5982
ImGui::TableSetupColumn("Five");
5983
ImGui::TableSetupColumn("Six");
5984
ImGui::TableHeadersRow();
5985
for (int row = 0; row < 20; row++)
5986
{
5987
ImGui::TableNextRow();
5988
for (int column = 0; column < 7; column++)
5989
{
5990
// Both TableNextColumn() and TableSetColumnIndex() return true when a column is visible or performing width measurement.
5991
// Because here we know that:
5992
// - A) all our columns are contributing the same to row height
5993
// - B) column 0 is always visible,
5994
// We only always submit this one column and can skip others.
5995
// More advanced per-column clipping behaviors may benefit from polling the status flags via TableGetColumnFlags().
5996
if (!ImGui::TableSetColumnIndex(column) && column > 0)
5997
continue;
5998
if (column == 0)
5999
ImGui::Text("Line %d", row);
6000
else
6001
ImGui::Text("Hello world %d,%d", column, row);
6002
}
6003
}
6004
ImGui::EndTable();
6005
}
6006
6007
ImGui::Spacing();
6008
ImGui::TextUnformatted("Stretch + ScrollX");
6009
ImGui::SameLine();
6010
HelpMarker(
6011
"Showcase using Stretch columns + ScrollX together: "
6012
"this is rather unusual and only makes sense when specifying an 'inner_width' for the table!\n"
6013
"Without an explicit value, inner_width is == outer_size.x and therefore using Stretch columns "
6014
"along with ScrollX doesn't make sense.");
6015
static ImGuiTableFlags flags2 = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody;
6016
static float inner_width = 1000.0f;
6017
PushStyleCompact();
6018
ImGui::PushID("flags3");
6019
ImGui::PushItemWidth(TEXT_BASE_WIDTH * 30);
6020
ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags2, ImGuiTableFlags_ScrollX);
6021
ImGui::DragFloat("inner_width", &inner_width, 1.0f, 0.0f, FLT_MAX, "%.1f");
6022
ImGui::PopItemWidth();
6023
ImGui::PopID();
6024
PopStyleCompact();
6025
if (ImGui::BeginTable("table2", 7, flags2, outer_size, inner_width))
6026
{
6027
for (int cell = 0; cell < 20 * 7; cell++)
6028
{
6029
ImGui::TableNextColumn();
6030
ImGui::Text("Hello world %d,%d", ImGui::TableGetColumnIndex(), ImGui::TableGetRowIndex());
6031
}
6032
ImGui::EndTable();
6033
}
6034
ImGui::TreePop();
6035
}
6036
6037
if (open_action != -1)
6038
ImGui::SetNextItemOpen(open_action != 0);
6039
IMGUI_DEMO_MARKER("Tables/Columns flags");
6040
if (ImGui::TreeNode("Columns flags"))
6041
{
6042
// Create a first table just to show all the options/flags we want to make visible in our example!
6043
const int column_count = 3;
6044
const char* column_names[column_count] = { "One", "Two", "Three" };
6045
static ImGuiTableColumnFlags column_flags[column_count] = { ImGuiTableColumnFlags_DefaultSort, ImGuiTableColumnFlags_None, ImGuiTableColumnFlags_DefaultHide };
6046
static ImGuiTableColumnFlags column_flags_out[column_count] = { 0, 0, 0 }; // Output from TableGetColumnFlags()
6047
6048
if (ImGui::BeginTable("table_columns_flags_checkboxes", column_count, ImGuiTableFlags_None))
6049
{
6050
PushStyleCompact();
6051
for (int column = 0; column < column_count; column++)
6052
{
6053
ImGui::TableNextColumn();
6054
ImGui::PushID(column);
6055
ImGui::AlignTextToFramePadding(); // FIXME-TABLE: Workaround for wrong text baseline propagation across columns
6056
ImGui::Text("'%s'", column_names[column]);
6057
ImGui::Spacing();
6058
ImGui::Text("Input flags:");
6059
EditTableColumnsFlags(&column_flags[column]);
6060
ImGui::Spacing();
6061
ImGui::Text("Output flags:");
6062
ImGui::BeginDisabled();
6063
ShowTableColumnsStatusFlags(column_flags_out[column]);
6064
ImGui::EndDisabled();
6065
ImGui::PopID();
6066
}
6067
PopStyleCompact();
6068
ImGui::EndTable();
6069
}
6070
6071
// Create the real table we care about for the example!
6072
// We use a scrolling table to be able to showcase the difference between the _IsEnabled and _IsVisible flags above,
6073
// otherwise in a non-scrolling table columns are always visible (unless using ImGuiTableFlags_NoKeepColumnsVisible
6074
// + resizing the parent window down).
6075
const ImGuiTableFlags flags
6076
= ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY
6077
| ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV
6078
| ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable;
6079
ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 9);
6080
if (ImGui::BeginTable("table_columns_flags", column_count, flags, outer_size))
6081
{
6082
bool has_angled_header = false;
6083
for (int column = 0; column < column_count; column++)
6084
{
6085
has_angled_header |= (column_flags[column] & ImGuiTableColumnFlags_AngledHeader) != 0;
6086
ImGui::TableSetupColumn(column_names[column], column_flags[column]);
6087
}
6088
if (has_angled_header)
6089
ImGui::TableAngledHeadersRow();
6090
ImGui::TableHeadersRow();
6091
for (int column = 0; column < column_count; column++)
6092
column_flags_out[column] = ImGui::TableGetColumnFlags(column);
6093
float indent_step = (float)((int)TEXT_BASE_WIDTH / 2);
6094
for (int row = 0; row < 8; row++)
6095
{
6096
// Add some indentation to demonstrate usage of per-column IndentEnable/IndentDisable flags.
6097
ImGui::Indent(indent_step);
6098
ImGui::TableNextRow();
6099
for (int column = 0; column < column_count; column++)
6100
{
6101
ImGui::TableSetColumnIndex(column);
6102
ImGui::Text("%s %s", (column == 0) ? "Indented" : "Hello", ImGui::TableGetColumnName(column));
6103
}
6104
}
6105
ImGui::Unindent(indent_step * 8.0f);
6106
6107
ImGui::EndTable();
6108
}
6109
ImGui::TreePop();
6110
}
6111
6112
if (open_action != -1)
6113
ImGui::SetNextItemOpen(open_action != 0);
6114
IMGUI_DEMO_MARKER("Tables/Columns widths");
6115
if (ImGui::TreeNode("Columns widths"))
6116
{
6117
HelpMarker("Using TableSetupColumn() to setup default width.");
6118
6119
static ImGuiTableFlags flags1 = ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBodyUntilResize;
6120
PushStyleCompact();
6121
ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags1, ImGuiTableFlags_Resizable);
6122
ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags1, ImGuiTableFlags_NoBordersInBodyUntilResize);
6123
PopStyleCompact();
6124
if (ImGui::BeginTable("table1", 3, flags1))
6125
{
6126
// We could also set ImGuiTableFlags_SizingFixedFit on the table and all columns will default to ImGuiTableColumnFlags_WidthFixed.
6127
ImGui::TableSetupColumn("one", ImGuiTableColumnFlags_WidthFixed, 100.0f); // Default to 100.0f
6128
ImGui::TableSetupColumn("two", ImGuiTableColumnFlags_WidthFixed, 200.0f); // Default to 200.0f
6129
ImGui::TableSetupColumn("three", ImGuiTableColumnFlags_WidthFixed); // Default to auto
6130
ImGui::TableHeadersRow();
6131
for (int row = 0; row < 4; row++)
6132
{
6133
ImGui::TableNextRow();
6134
for (int column = 0; column < 3; column++)
6135
{
6136
ImGui::TableSetColumnIndex(column);
6137
if (row == 0)
6138
ImGui::Text("(w: %5.1f)", ImGui::GetContentRegionAvail().x);
6139
else
6140
ImGui::Text("Hello %d,%d", column, row);
6141
}
6142
}
6143
ImGui::EndTable();
6144
}
6145
6146
HelpMarker(
6147
"Using TableSetupColumn() to setup explicit width.\n\nUnless _NoKeepColumnsVisible is set, "
6148
"fixed columns with set width may still be shrunk down if there's not enough space in the host.");
6149
6150
static ImGuiTableFlags flags2 = ImGuiTableFlags_None;
6151
PushStyleCompact();
6152
ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags2, ImGuiTableFlags_NoKeepColumnsVisible);
6153
ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags2, ImGuiTableFlags_BordersInnerV);
6154
ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags2, ImGuiTableFlags_BordersOuterV);
6155
PopStyleCompact();
6156
if (ImGui::BeginTable("table2", 4, flags2))
6157
{
6158
// We could also set ImGuiTableFlags_SizingFixedFit on the table and then all columns
6159
// will default to ImGuiTableColumnFlags_WidthFixed.
6160
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 100.0f);
6161
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f);
6162
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 30.0f);
6163
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f);
6164
for (int row = 0; row < 5; row++)
6165
{
6166
ImGui::TableNextRow();
6167
for (int column = 0; column < 4; column++)
6168
{
6169
ImGui::TableSetColumnIndex(column);
6170
if (row == 0)
6171
ImGui::Text("(w: %5.1f)", ImGui::GetContentRegionAvail().x);
6172
else
6173
ImGui::Text("Hello %d,%d", column, row);
6174
}
6175
}
6176
ImGui::EndTable();
6177
}
6178
ImGui::TreePop();
6179
}
6180
6181
if (open_action != -1)
6182
ImGui::SetNextItemOpen(open_action != 0);
6183
IMGUI_DEMO_MARKER("Tables/Nested tables");
6184
if (ImGui::TreeNode("Nested tables"))
6185
{
6186
HelpMarker("This demonstrates embedding a table into another table cell.");
6187
6188
if (ImGui::BeginTable("table_nested1", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
6189
{
6190
ImGui::TableSetupColumn("A0");
6191
ImGui::TableSetupColumn("A1");
6192
ImGui::TableHeadersRow();
6193
6194
ImGui::TableNextColumn();
6195
ImGui::Text("A0 Row 0");
6196
{
6197
float rows_height = TEXT_BASE_HEIGHT * 2;
6198
if (ImGui::BeginTable("table_nested2", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
6199
{
6200
ImGui::TableSetupColumn("B0");
6201
ImGui::TableSetupColumn("B1");
6202
ImGui::TableHeadersRow();
6203
6204
ImGui::TableNextRow(ImGuiTableRowFlags_None, rows_height);
6205
ImGui::TableNextColumn();
6206
ImGui::Text("B0 Row 0");
6207
ImGui::TableNextColumn();
6208
ImGui::Text("B1 Row 0");
6209
ImGui::TableNextRow(ImGuiTableRowFlags_None, rows_height);
6210
ImGui::TableNextColumn();
6211
ImGui::Text("B0 Row 1");
6212
ImGui::TableNextColumn();
6213
ImGui::Text("B1 Row 1");
6214
6215
ImGui::EndTable();
6216
}
6217
}
6218
ImGui::TableNextColumn(); ImGui::Text("A1 Row 0");
6219
ImGui::TableNextColumn(); ImGui::Text("A0 Row 1");
6220
ImGui::TableNextColumn(); ImGui::Text("A1 Row 1");
6221
ImGui::EndTable();
6222
}
6223
ImGui::TreePop();
6224
}
6225
6226
if (open_action != -1)
6227
ImGui::SetNextItemOpen(open_action != 0);
6228
IMGUI_DEMO_MARKER("Tables/Row height");
6229
if (ImGui::TreeNode("Row height"))
6230
{
6231
HelpMarker(
6232
"You can pass a 'min_row_height' to TableNextRow().\n\nRows are padded with 'style.CellPadding.y' on top and bottom, "
6233
"so effectively the minimum row height will always be >= 'style.CellPadding.y * 2.0f'.\n\n"
6234
"We cannot honor a _maximum_ row height as that would require a unique clipping rectangle per row.");
6235
if (ImGui::BeginTable("table_row_height", 1, ImGuiTableFlags_Borders))
6236
{
6237
for (int row = 0; row < 8; row++)
6238
{
6239
float min_row_height = (float)(int)(TEXT_BASE_HEIGHT * 0.30f * row);
6240
ImGui::TableNextRow(ImGuiTableRowFlags_None, min_row_height);
6241
ImGui::TableNextColumn();
6242
ImGui::Text("min_row_height = %.2f", min_row_height);
6243
}
6244
ImGui::EndTable();
6245
}
6246
6247
HelpMarker(
6248
"Showcase using SameLine(0,0) to share Current Line Height between cells.\n\n"
6249
"Please note that Tables Row Height is not the same thing as Current Line Height, "
6250
"as a table cell may contains multiple lines.");
6251
if (ImGui::BeginTable("table_share_lineheight", 2, ImGuiTableFlags_Borders))
6252
{
6253
ImGui::TableNextRow();
6254
ImGui::TableNextColumn();
6255
ImGui::ColorButton("##1", ImVec4(0.13f, 0.26f, 0.40f, 1.0f), ImGuiColorEditFlags_None, ImVec2(40, 40));
6256
ImGui::TableNextColumn();
6257
ImGui::Text("Line 1");
6258
ImGui::Text("Line 2");
6259
6260
ImGui::TableNextRow();
6261
ImGui::TableNextColumn();
6262
ImGui::ColorButton("##2", ImVec4(0.13f, 0.26f, 0.40f, 1.0f), ImGuiColorEditFlags_None, ImVec2(40, 40));
6263
ImGui::TableNextColumn();
6264
ImGui::SameLine(0.0f, 0.0f); // Reuse line height from previous column
6265
ImGui::Text("Line 1, with SameLine(0,0)");
6266
ImGui::Text("Line 2");
6267
6268
ImGui::EndTable();
6269
}
6270
6271
HelpMarker("Showcase altering CellPadding.y between rows. Note that CellPadding.x is locked for the entire table.");
6272
if (ImGui::BeginTable("table_changing_cellpadding_y", 1, ImGuiTableFlags_Borders))
6273
{
6274
ImGuiStyle& style = ImGui::GetStyle();
6275
for (int row = 0; row < 8; row++)
6276
{
6277
if ((row % 3) == 2)
6278
ImGui::PushStyleVarY(ImGuiStyleVar_CellPadding, 20.0f);
6279
ImGui::TableNextRow(ImGuiTableRowFlags_None);
6280
ImGui::TableNextColumn();
6281
ImGui::Text("CellPadding.y = %.2f", style.CellPadding.y);
6282
if ((row % 3) == 2)
6283
ImGui::PopStyleVar();
6284
}
6285
ImGui::EndTable();
6286
}
6287
6288
ImGui::TreePop();
6289
}
6290
6291
if (open_action != -1)
6292
ImGui::SetNextItemOpen(open_action != 0);
6293
IMGUI_DEMO_MARKER("Tables/Outer size");
6294
if (ImGui::TreeNode("Outer size"))
6295
{
6296
// Showcasing use of ImGuiTableFlags_NoHostExtendX and ImGuiTableFlags_NoHostExtendY
6297
// Important to that note how the two flags have slightly different behaviors!
6298
ImGui::Text("Using NoHostExtendX and NoHostExtendY:");
6299
PushStyleCompact();
6300
static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_ContextMenuInBody | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX;
6301
ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX);
6302
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.");
6303
ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendY", &flags, ImGuiTableFlags_NoHostExtendY);
6304
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.");
6305
PopStyleCompact();
6306
6307
ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 5.5f);
6308
if (ImGui::BeginTable("table1", 3, flags, outer_size))
6309
{
6310
for (int row = 0; row < 10; 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
ImGui::Text("Hello!");
6323
6324
ImGui::Spacing();
6325
6326
ImGui::Text("Using explicit size:");
6327
if (ImGui::BeginTable("table2", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(TEXT_BASE_WIDTH * 30, 0.0f)))
6328
{
6329
for (int row = 0; row < 5; row++)
6330
{
6331
ImGui::TableNextRow();
6332
for (int column = 0; column < 3; column++)
6333
{
6334
ImGui::TableNextColumn();
6335
ImGui::Text("Cell %d,%d", column, row);
6336
}
6337
}
6338
ImGui::EndTable();
6339
}
6340
ImGui::SameLine();
6341
if (ImGui::BeginTable("table3", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(TEXT_BASE_WIDTH * 30, 0.0f)))
6342
{
6343
for (int row = 0; row < 3; row++)
6344
{
6345
ImGui::TableNextRow(0, TEXT_BASE_HEIGHT * 1.5f);
6346
for (int column = 0; column < 3; column++)
6347
{
6348
ImGui::TableNextColumn();
6349
ImGui::Text("Cell %d,%d", column, row);
6350
}
6351
}
6352
ImGui::EndTable();
6353
}
6354
6355
ImGui::TreePop();
6356
}
6357
6358
if (open_action != -1)
6359
ImGui::SetNextItemOpen(open_action != 0);
6360
IMGUI_DEMO_MARKER("Tables/Background color");
6361
if (ImGui::TreeNode("Background color"))
6362
{
6363
static ImGuiTableFlags flags = ImGuiTableFlags_RowBg;
6364
static int row_bg_type = 1;
6365
static int row_bg_target = 1;
6366
static int cell_bg_type = 1;
6367
6368
PushStyleCompact();
6369
ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags, ImGuiTableFlags_Borders);
6370
ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg);
6371
ImGui::SameLine(); HelpMarker("ImGuiTableFlags_RowBg automatically sets RowBg0 to alternative colors pulled from the Style.");
6372
ImGui::Combo("row bg type", (int*)&row_bg_type, "None\0Red\0Gradient\0");
6373
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.");
6374
ImGui::Combo("cell bg type", (int*)&cell_bg_type, "None\0Blue\0"); ImGui::SameLine(); HelpMarker("We are colorizing cells to B1->C2 here.");
6375
IM_ASSERT(row_bg_type >= 0 && row_bg_type <= 2);
6376
IM_ASSERT(row_bg_target >= 0 && row_bg_target <= 1);
6377
IM_ASSERT(cell_bg_type >= 0 && cell_bg_type <= 1);
6378
PopStyleCompact();
6379
6380
if (ImGui::BeginTable("table1", 5, flags))
6381
{
6382
for (int row = 0; row < 6; row++)
6383
{
6384
ImGui::TableNextRow();
6385
6386
// Demonstrate setting a row background color with 'ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBgX, ...)'
6387
// 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.
6388
if (row_bg_type != 0)
6389
{
6390
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?
6391
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0 + row_bg_target, row_bg_color);
6392
}
6393
6394
// Fill cells
6395
for (int column = 0; column < 5; column++)
6396
{
6397
ImGui::TableSetColumnIndex(column);
6398
ImGui::Text("%c%c", 'A' + row, '0' + column);
6399
6400
// Change background of Cells B1->C2
6401
// Demonstrate setting a cell background color with 'ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ...)'
6402
// (the CellBg color will be blended over the RowBg and ColumnBg colors)
6403
// We can also pass a column number as a third parameter to TableSetBgColor() and do this outside the column loop.
6404
if (row >= 1 && row <= 2 && column >= 1 && column <= 2 && cell_bg_type == 1)
6405
{
6406
ImU32 cell_bg_color = ImGui::GetColorU32(ImVec4(0.3f, 0.3f, 0.7f, 0.65f));
6407
ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, cell_bg_color);
6408
}
6409
}
6410
}
6411
ImGui::EndTable();
6412
}
6413
ImGui::TreePop();
6414
}
6415
6416
if (open_action != -1)
6417
ImGui::SetNextItemOpen(open_action != 0);
6418
IMGUI_DEMO_MARKER("Tables/Tree view");
6419
if (ImGui::TreeNode("Tree view"))
6420
{
6421
static ImGuiTableFlags flags = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody;
6422
6423
static ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAllColumns;
6424
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &tree_node_flags, ImGuiTreeNodeFlags_SpanFullWidth);
6425
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanTextWidth", &tree_node_flags, ImGuiTreeNodeFlags_SpanTextWidth);
6426
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &tree_node_flags, ImGuiTreeNodeFlags_SpanAllColumns);
6427
6428
HelpMarker("See \"Columns flags\" section to configure how indentation is applied to individual columns.");
6429
if (ImGui::BeginTable("3ways", 3, flags))
6430
{
6431
// The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On
6432
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_NoHide);
6433
ImGui::TableSetupColumn("Size", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f);
6434
ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 18.0f);
6435
ImGui::TableHeadersRow();
6436
6437
// Simple storage to output a dummy file-system.
6438
struct MyTreeNode
6439
{
6440
const char* Name;
6441
const char* Type;
6442
int Size;
6443
int ChildIdx;
6444
int ChildCount;
6445
static void DisplayNode(const MyTreeNode* node, const MyTreeNode* all_nodes)
6446
{
6447
ImGui::TableNextRow();
6448
ImGui::TableNextColumn();
6449
const bool is_folder = (node->ChildCount > 0);
6450
if (is_folder)
6451
{
6452
bool open = ImGui::TreeNodeEx(node->Name, tree_node_flags);
6453
ImGui::TableNextColumn();
6454
ImGui::TextDisabled("--");
6455
ImGui::TableNextColumn();
6456
ImGui::TextUnformatted(node->Type);
6457
if (open)
6458
{
6459
for (int child_n = 0; child_n < node->ChildCount; child_n++)
6460
DisplayNode(&all_nodes[node->ChildIdx + child_n], all_nodes);
6461
ImGui::TreePop();
6462
}
6463
}
6464
else
6465
{
6466
ImGui::TreeNodeEx(node->Name, tree_node_flags | ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_NoTreePushOnOpen);
6467
ImGui::TableNextColumn();
6468
ImGui::Text("%d", node->Size);
6469
ImGui::TableNextColumn();
6470
ImGui::TextUnformatted(node->Type);
6471
}
6472
}
6473
};
6474
static const MyTreeNode nodes[] =
6475
{
6476
{ "Root", "Folder", -1, 1, 3 }, // 0
6477
{ "Music", "Folder", -1, 4, 2 }, // 1
6478
{ "Textures", "Folder", -1, 6, 3 }, // 2
6479
{ "desktop.ini", "System file", 1024, -1,-1 }, // 3
6480
{ "File1_a.wav", "Audio file", 123000, -1,-1 }, // 4
6481
{ "File1_b.wav", "Audio file", 456000, -1,-1 }, // 5
6482
{ "Image001.png", "Image file", 203128, -1,-1 }, // 6
6483
{ "Copy of Image001.png", "Image file", 203256, -1,-1 }, // 7
6484
{ "Copy of Image001 (Final2).png","Image file", 203512, -1,-1 }, // 8
6485
};
6486
6487
MyTreeNode::DisplayNode(&nodes[0], nodes);
6488
6489
ImGui::EndTable();
6490
}
6491
ImGui::TreePop();
6492
}
6493
6494
if (open_action != -1)
6495
ImGui::SetNextItemOpen(open_action != 0);
6496
IMGUI_DEMO_MARKER("Tables/Item width");
6497
if (ImGui::TreeNode("Item width"))
6498
{
6499
HelpMarker(
6500
"Showcase using PushItemWidth() and how it is preserved on a per-column basis.\n\n"
6501
"Note that on auto-resizing non-resizable fixed columns, querying the content width for "
6502
"e.g. right-alignment doesn't make sense.");
6503
if (ImGui::BeginTable("table_item_width", 3, ImGuiTableFlags_Borders))
6504
{
6505
ImGui::TableSetupColumn("small");
6506
ImGui::TableSetupColumn("half");
6507
ImGui::TableSetupColumn("right-align");
6508
ImGui::TableHeadersRow();
6509
6510
for (int row = 0; row < 3; row++)
6511
{
6512
ImGui::TableNextRow();
6513
if (row == 0)
6514
{
6515
// Setup ItemWidth once (instead of setting up every time, which is also possible but less efficient)
6516
ImGui::TableSetColumnIndex(0);
6517
ImGui::PushItemWidth(TEXT_BASE_WIDTH * 3.0f); // Small
6518
ImGui::TableSetColumnIndex(1);
6519
ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.5f);
6520
ImGui::TableSetColumnIndex(2);
6521
ImGui::PushItemWidth(-FLT_MIN); // Right-aligned
6522
}
6523
6524
// Draw our contents
6525
static float dummy_f = 0.0f;
6526
ImGui::PushID(row);
6527
ImGui::TableSetColumnIndex(0);
6528
ImGui::SliderFloat("float0", &dummy_f, 0.0f, 1.0f);
6529
ImGui::TableSetColumnIndex(1);
6530
ImGui::SliderFloat("float1", &dummy_f, 0.0f, 1.0f);
6531
ImGui::TableSetColumnIndex(2);
6532
ImGui::SliderFloat("##float2", &dummy_f, 0.0f, 1.0f); // No visible label since right-aligned
6533
ImGui::PopID();
6534
}
6535
ImGui::EndTable();
6536
}
6537
ImGui::TreePop();
6538
}
6539
6540
// Demonstrate using TableHeader() calls instead of TableHeadersRow()
6541
if (open_action != -1)
6542
ImGui::SetNextItemOpen(open_action != 0);
6543
IMGUI_DEMO_MARKER("Tables/Custom headers");
6544
if (ImGui::TreeNode("Custom headers"))
6545
{
6546
const int COLUMNS_COUNT = 3;
6547
if (ImGui::BeginTable("table_custom_headers", COLUMNS_COUNT, ImGuiTableFlags_Borders | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
6548
{
6549
ImGui::TableSetupColumn("Apricot");
6550
ImGui::TableSetupColumn("Banana");
6551
ImGui::TableSetupColumn("Cherry");
6552
6553
// Dummy entire-column selection storage
6554
// FIXME: It would be nice to actually demonstrate full-featured selection using those checkbox.
6555
static bool column_selected[3] = {};
6556
6557
// Instead of calling TableHeadersRow() we'll submit custom headers ourselves.
6558
// (A different approach is also possible:
6559
// - Specify ImGuiTableColumnFlags_NoHeaderLabel in some TableSetupColumn() call.
6560
// - Call TableHeadersRow() normally. This will submit TableHeader() with no name.
6561
// - Then call TableSetColumnIndex() to position yourself in the column and submit your stuff e.g. Checkbox().)
6562
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
6563
for (int column = 0; column < COLUMNS_COUNT; column++)
6564
{
6565
ImGui::TableSetColumnIndex(column);
6566
const char* column_name = ImGui::TableGetColumnName(column); // Retrieve name passed to TableSetupColumn()
6567
ImGui::PushID(column);
6568
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
6569
ImGui::Checkbox("##checkall", &column_selected[column]);
6570
ImGui::PopStyleVar();
6571
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
6572
ImGui::TableHeader(column_name);
6573
ImGui::PopID();
6574
}
6575
6576
// Submit table contents
6577
for (int row = 0; row < 5; row++)
6578
{
6579
ImGui::TableNextRow();
6580
for (int column = 0; column < 3; column++)
6581
{
6582
char buf[32];
6583
sprintf(buf, "Cell %d,%d", column, row);
6584
ImGui::TableSetColumnIndex(column);
6585
ImGui::Selectable(buf, column_selected[column]);
6586
}
6587
}
6588
ImGui::EndTable();
6589
}
6590
ImGui::TreePop();
6591
}
6592
6593
// Demonstrate using ImGuiTableColumnFlags_AngledHeader flag to create angled headers
6594
if (open_action != -1)
6595
ImGui::SetNextItemOpen(open_action != 0);
6596
IMGUI_DEMO_MARKER("Tables/Angled headers");
6597
if (ImGui::TreeNode("Angled headers"))
6598
{
6599
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" };
6600
const int columns_count = IM_ARRAYSIZE(column_names);
6601
const int rows_count = 12;
6602
6603
static ImGuiTableFlags table_flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_Hideable | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_HighlightHoveredColumn;
6604
static ImGuiTableColumnFlags column_flags = ImGuiTableColumnFlags_AngledHeader | ImGuiTableColumnFlags_WidthFixed;
6605
static bool bools[columns_count * rows_count] = {}; // Dummy storage selection storage
6606
static int frozen_cols = 1;
6607
static int frozen_rows = 2;
6608
ImGui::CheckboxFlags("_ScrollX", &table_flags, ImGuiTableFlags_ScrollX);
6609
ImGui::CheckboxFlags("_ScrollY", &table_flags, ImGuiTableFlags_ScrollY);
6610
ImGui::CheckboxFlags("_Resizable", &table_flags, ImGuiTableFlags_Resizable);
6611
ImGui::CheckboxFlags("_Sortable", &table_flags, ImGuiTableFlags_Sortable);
6612
ImGui::CheckboxFlags("_NoBordersInBody", &table_flags, ImGuiTableFlags_NoBordersInBody);
6613
ImGui::CheckboxFlags("_HighlightHoveredColumn", &table_flags, ImGuiTableFlags_HighlightHoveredColumn);
6614
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
6615
ImGui::SliderInt("Frozen columns", &frozen_cols, 0, 2);
6616
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
6617
ImGui::SliderInt("Frozen rows", &frozen_rows, 0, 2);
6618
ImGui::CheckboxFlags("Disable header contributing to column width", &column_flags, ImGuiTableColumnFlags_NoHeaderWidth);
6619
6620
if (ImGui::TreeNode("Style settings"))
6621
{
6622
ImGui::SameLine();
6623
HelpMarker("Giving access to some ImGuiStyle value in this demo for convenience.");
6624
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
6625
ImGui::SliderAngle("style.TableAngledHeadersAngle", &ImGui::GetStyle().TableAngledHeadersAngle, -50.0f, +50.0f);
6626
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
6627
ImGui::SliderFloat2("style.TableAngledHeadersTextAlign", (float*)&ImGui::GetStyle().TableAngledHeadersTextAlign, 0.0f, 1.0f, "%.2f");
6628
ImGui::TreePop();
6629
}
6630
6631
if (ImGui::BeginTable("table_angled_headers", columns_count, table_flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 12)))
6632
{
6633
ImGui::TableSetupColumn(column_names[0], ImGuiTableColumnFlags_NoHide | ImGuiTableColumnFlags_NoReorder);
6634
for (int n = 1; n < columns_count; n++)
6635
ImGui::TableSetupColumn(column_names[n], column_flags);
6636
ImGui::TableSetupScrollFreeze(frozen_cols, frozen_rows);
6637
6638
ImGui::TableAngledHeadersRow(); // Draw angled headers for all columns with the ImGuiTableColumnFlags_AngledHeader flag.
6639
ImGui::TableHeadersRow(); // Draw remaining headers and allow access to context-menu and other functions.
6640
for (int row = 0; row < rows_count; row++)
6641
{
6642
ImGui::PushID(row);
6643
ImGui::TableNextRow();
6644
ImGui::TableSetColumnIndex(0);
6645
ImGui::AlignTextToFramePadding();
6646
ImGui::Text("Track %d", row);
6647
for (int column = 1; column < columns_count; column++)
6648
if (ImGui::TableSetColumnIndex(column))
6649
{
6650
ImGui::PushID(column);
6651
ImGui::Checkbox("", &bools[row * columns_count + column]);
6652
ImGui::PopID();
6653
}
6654
ImGui::PopID();
6655
}
6656
ImGui::EndTable();
6657
}
6658
ImGui::TreePop();
6659
}
6660
6661
// Demonstrate creating custom context menus inside columns,
6662
// while playing it nice with context menus provided by TableHeadersRow()/TableHeader()
6663
if (open_action != -1)
6664
ImGui::SetNextItemOpen(open_action != 0);
6665
IMGUI_DEMO_MARKER("Tables/Context menus");
6666
if (ImGui::TreeNode("Context menus"))
6667
{
6668
HelpMarker(
6669
"By default, right-clicking over a TableHeadersRow()/TableHeader() line will open the default context-menu.\n"
6670
"Using ImGuiTableFlags_ContextMenuInBody we also allow right-clicking over columns body.");
6671
static ImGuiTableFlags flags1 = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_ContextMenuInBody;
6672
6673
PushStyleCompact();
6674
ImGui::CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", &flags1, ImGuiTableFlags_ContextMenuInBody);
6675
PopStyleCompact();
6676
6677
// Context Menus: first example
6678
// [1.1] Right-click on the TableHeadersRow() line to open the default table context menu.
6679
// [1.2] Right-click in columns also open the default table context menu (if ImGuiTableFlags_ContextMenuInBody is set)
6680
const int COLUMNS_COUNT = 3;
6681
if (ImGui::BeginTable("table_context_menu", COLUMNS_COUNT, flags1))
6682
{
6683
ImGui::TableSetupColumn("One");
6684
ImGui::TableSetupColumn("Two");
6685
ImGui::TableSetupColumn("Three");
6686
6687
// [1.1]] Right-click on the TableHeadersRow() line to open the default table context menu.
6688
ImGui::TableHeadersRow();
6689
6690
// Submit dummy contents
6691
for (int row = 0; row < 4; row++)
6692
{
6693
ImGui::TableNextRow();
6694
for (int column = 0; column < COLUMNS_COUNT; column++)
6695
{
6696
ImGui::TableSetColumnIndex(column);
6697
ImGui::Text("Cell %d,%d", column, row);
6698
}
6699
}
6700
ImGui::EndTable();
6701
}
6702
6703
// Context Menus: second example
6704
// [2.1] Right-click on the TableHeadersRow() line to open the default table context menu.
6705
// [2.2] Right-click on the ".." to open a custom popup
6706
// [2.3] Right-click in columns to open another custom popup
6707
HelpMarker(
6708
"Demonstrate mixing table context menu (over header), item context button (over button) "
6709
"and custom per-colunm context menu (over column body).");
6710
ImGuiTableFlags flags2 = ImGuiTableFlags_Resizable | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders;
6711
if (ImGui::BeginTable("table_context_menu_2", COLUMNS_COUNT, flags2))
6712
{
6713
ImGui::TableSetupColumn("One");
6714
ImGui::TableSetupColumn("Two");
6715
ImGui::TableSetupColumn("Three");
6716
6717
// [2.1] Right-click on the TableHeadersRow() line to open the default table context menu.
6718
ImGui::TableHeadersRow();
6719
for (int row = 0; row < 4; row++)
6720
{
6721
ImGui::TableNextRow();
6722
for (int column = 0; column < COLUMNS_COUNT; column++)
6723
{
6724
// Submit dummy contents
6725
ImGui::TableSetColumnIndex(column);
6726
ImGui::Text("Cell %d,%d", column, row);
6727
ImGui::SameLine();
6728
6729
// [2.2] Right-click on the ".." to open a custom popup
6730
ImGui::PushID(row * COLUMNS_COUNT + column);
6731
ImGui::SmallButton("..");
6732
if (ImGui::BeginPopupContextItem())
6733
{
6734
ImGui::Text("This is the popup for Button(\"..\") in Cell %d,%d", column, row);
6735
if (ImGui::Button("Close"))
6736
ImGui::CloseCurrentPopup();
6737
ImGui::EndPopup();
6738
}
6739
ImGui::PopID();
6740
}
6741
}
6742
6743
// [2.3] Right-click anywhere in columns to open another custom popup
6744
// (instead of testing for !IsAnyItemHovered() we could also call OpenPopup() with ImGuiPopupFlags_NoOpenOverExistingPopup
6745
// to manage popup priority as the popups triggers, here "are we hovering a column" are overlapping)
6746
int hovered_column = -1;
6747
for (int column = 0; column < COLUMNS_COUNT + 1; column++)
6748
{
6749
ImGui::PushID(column);
6750
if (ImGui::TableGetColumnFlags(column) & ImGuiTableColumnFlags_IsHovered)
6751
hovered_column = column;
6752
if (hovered_column == column && !ImGui::IsAnyItemHovered() && ImGui::IsMouseReleased(1))
6753
ImGui::OpenPopup("MyPopup");
6754
if (ImGui::BeginPopup("MyPopup"))
6755
{
6756
if (column == COLUMNS_COUNT)
6757
ImGui::Text("This is a custom popup for unused space after the last column.");
6758
else
6759
ImGui::Text("This is a custom popup for Column %d", column);
6760
if (ImGui::Button("Close"))
6761
ImGui::CloseCurrentPopup();
6762
ImGui::EndPopup();
6763
}
6764
ImGui::PopID();
6765
}
6766
6767
ImGui::EndTable();
6768
ImGui::Text("Hovered column: %d", hovered_column);
6769
}
6770
ImGui::TreePop();
6771
}
6772
6773
// Demonstrate creating multiple tables with the same ID
6774
if (open_action != -1)
6775
ImGui::SetNextItemOpen(open_action != 0);
6776
IMGUI_DEMO_MARKER("Tables/Synced instances");
6777
if (ImGui::TreeNode("Synced instances"))
6778
{
6779
HelpMarker("Multiple tables with the same identifier will share their settings, width, visibility, order etc.");
6780
6781
static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoSavedSettings;
6782
ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
6783
ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
6784
ImGui::CheckboxFlags("ImGuiTableFlags_SizingFixedFit", &flags, ImGuiTableFlags_SizingFixedFit);
6785
ImGui::CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", &flags, ImGuiTableFlags_HighlightHoveredColumn);
6786
for (int n = 0; n < 3; n++)
6787
{
6788
char buf[32];
6789
sprintf(buf, "Synced Table %d", n);
6790
bool open = ImGui::CollapsingHeader(buf, ImGuiTreeNodeFlags_DefaultOpen);
6791
if (open && ImGui::BeginTable("Table", 3, flags, ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 5)))
6792
{
6793
ImGui::TableSetupColumn("One");
6794
ImGui::TableSetupColumn("Two");
6795
ImGui::TableSetupColumn("Three");
6796
ImGui::TableHeadersRow();
6797
const int cell_count = (n == 1) ? 27 : 9; // Make second table have a scrollbar to verify that additional decoration is not affecting column positions.
6798
for (int cell = 0; cell < cell_count; cell++)
6799
{
6800
ImGui::TableNextColumn();
6801
ImGui::Text("this cell %d", cell);
6802
}
6803
ImGui::EndTable();
6804
}
6805
}
6806
ImGui::TreePop();
6807
}
6808
6809
// Demonstrate using Sorting facilities
6810
// This is a simplified version of the "Advanced" example, where we mostly focus on the code necessary to handle sorting.
6811
// Note that the "Advanced" example also showcase manually triggering a sort (e.g. if item quantities have been modified)
6812
static const char* template_items_names[] =
6813
{
6814
"Banana", "Apple", "Cherry", "Watermelon", "Grapefruit", "Strawberry", "Mango",
6815
"Kiwi", "Orange", "Pineapple", "Blueberry", "Plum", "Coconut", "Pear", "Apricot"
6816
};
6817
if (open_action != -1)
6818
ImGui::SetNextItemOpen(open_action != 0);
6819
IMGUI_DEMO_MARKER("Tables/Sorting");
6820
if (ImGui::TreeNode("Sorting"))
6821
{
6822
// Create item list
6823
static ImVector<MyItem> items;
6824
if (items.Size == 0)
6825
{
6826
items.resize(50, MyItem());
6827
for (int n = 0; n < items.Size; n++)
6828
{
6829
const int template_n = n % IM_ARRAYSIZE(template_items_names);
6830
MyItem& item = items[n];
6831
item.ID = n;
6832
item.Name = template_items_names[template_n];
6833
item.Quantity = (n * n - n) % 20; // Assign default quantities
6834
}
6835
}
6836
6837
// Options
6838
static ImGuiTableFlags flags =
6839
ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti
6840
| ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_NoBordersInBody
6841
| ImGuiTableFlags_ScrollY;
6842
PushStyleCompact();
6843
ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti);
6844
ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).");
6845
ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate);
6846
ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).");
6847
PopStyleCompact();
6848
6849
if (ImGui::BeginTable("table_sorting", 4, flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 15), 0.0f))
6850
{
6851
// Declare columns
6852
// We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications.
6853
// This is so our sort function can identify a column given our own identifier. We could also identify them based on their index!
6854
// Demonstrate using a mixture of flags among available sort-related flags:
6855
// - ImGuiTableColumnFlags_DefaultSort
6856
// - ImGuiTableColumnFlags_NoSort / ImGuiTableColumnFlags_NoSortAscending / ImGuiTableColumnFlags_NoSortDescending
6857
// - ImGuiTableColumnFlags_PreferSortAscending / ImGuiTableColumnFlags_PreferSortDescending
6858
ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_ID);
6859
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Name);
6860
ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Action);
6861
ImGui::TableSetupColumn("Quantity", ImGuiTableColumnFlags_PreferSortDescending | ImGuiTableColumnFlags_WidthStretch, 0.0f, MyItemColumnID_Quantity);
6862
ImGui::TableSetupScrollFreeze(0, 1); // Make row always visible
6863
ImGui::TableHeadersRow();
6864
6865
// Sort our data if sort specs have been changed!
6866
if (ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs())
6867
if (sort_specs->SpecsDirty)
6868
{
6869
MyItem::SortWithSortSpecs(sort_specs, items.Data, items.Size);
6870
sort_specs->SpecsDirty = false;
6871
}
6872
6873
// Demonstrate using clipper for large vertical lists
6874
ImGuiListClipper clipper;
6875
clipper.Begin(items.Size);
6876
while (clipper.Step())
6877
for (int row_n = clipper.DisplayStart; row_n < clipper.DisplayEnd; row_n++)
6878
{
6879
// Display a data item
6880
MyItem* item = &items[row_n];
6881
ImGui::PushID(item->ID);
6882
ImGui::TableNextRow();
6883
ImGui::TableNextColumn();
6884
ImGui::Text("%04d", item->ID);
6885
ImGui::TableNextColumn();
6886
ImGui::TextUnformatted(item->Name);
6887
ImGui::TableNextColumn();
6888
ImGui::SmallButton("None");
6889
ImGui::TableNextColumn();
6890
ImGui::Text("%d", item->Quantity);
6891
ImGui::PopID();
6892
}
6893
ImGui::EndTable();
6894
}
6895
ImGui::TreePop();
6896
}
6897
6898
// In this example we'll expose most table flags and settings.
6899
// For specific flags and settings refer to the corresponding section for more detailed explanation.
6900
// This section is mostly useful to experiment with combining certain flags or settings with each others.
6901
//ImGui::SetNextItemOpen(true, ImGuiCond_Once); // [DEBUG]
6902
if (open_action != -1)
6903
ImGui::SetNextItemOpen(open_action != 0);
6904
IMGUI_DEMO_MARKER("Tables/Advanced");
6905
if (ImGui::TreeNode("Advanced"))
6906
{
6907
static ImGuiTableFlags flags =
6908
ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable
6909
| ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti
6910
| ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBody
6911
| ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY
6912
| ImGuiTableFlags_SizingFixedFit;
6913
static ImGuiTableColumnFlags columns_base_flags = ImGuiTableColumnFlags_None;
6914
6915
enum ContentsType { CT_Text, CT_Button, CT_SmallButton, CT_FillButton, CT_Selectable, CT_SelectableSpanRow };
6916
static int contents_type = CT_SelectableSpanRow;
6917
const char* contents_type_names[] = { "Text", "Button", "SmallButton", "FillButton", "Selectable", "Selectable (span row)" };
6918
static int freeze_cols = 1;
6919
static int freeze_rows = 1;
6920
static int items_count = IM_ARRAYSIZE(template_items_names) * 2;
6921
static ImVec2 outer_size_value = ImVec2(0.0f, TEXT_BASE_HEIGHT * 12);
6922
static float row_min_height = 0.0f; // Auto
6923
static float inner_width_with_scroll = 0.0f; // Auto-extend
6924
static bool outer_size_enabled = true;
6925
static bool show_headers = true;
6926
static bool show_wrapped_text = false;
6927
//static ImGuiTextFilter filter;
6928
//ImGui::SetNextItemOpen(true, ImGuiCond_Once); // FIXME-TABLE: Enabling this results in initial clipped first pass on table which tend to affect column sizing
6929
if (ImGui::TreeNode("Options"))
6930
{
6931
// Make the UI compact because there are so many fields
6932
PushStyleCompact();
6933
ImGui::PushItemWidth(TEXT_BASE_WIDTH * 28.0f);
6934
6935
if (ImGui::TreeNodeEx("Features:", ImGuiTreeNodeFlags_DefaultOpen))
6936
{
6937
ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
6938
ImGui::CheckboxFlags("ImGuiTableFlags_Reorderable", &flags, ImGuiTableFlags_Reorderable);
6939
ImGui::CheckboxFlags("ImGuiTableFlags_Hideable", &flags, ImGuiTableFlags_Hideable);
6940
ImGui::CheckboxFlags("ImGuiTableFlags_Sortable", &flags, ImGuiTableFlags_Sortable);
6941
ImGui::CheckboxFlags("ImGuiTableFlags_NoSavedSettings", &flags, ImGuiTableFlags_NoSavedSettings);
6942
ImGui::CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", &flags, ImGuiTableFlags_ContextMenuInBody);
6943
ImGui::TreePop();
6944
}
6945
6946
if (ImGui::TreeNodeEx("Decorations:", ImGuiTreeNodeFlags_DefaultOpen))
6947
{
6948
ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg);
6949
ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV);
6950
ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags, ImGuiTableFlags_BordersOuterV);
6951
ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags, ImGuiTableFlags_BordersInnerV);
6952
ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags, ImGuiTableFlags_BordersH);
6953
ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterH", &flags, ImGuiTableFlags_BordersOuterH);
6954
ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerH", &flags, ImGuiTableFlags_BordersInnerH);
6955
ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers");
6956
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)");
6957
ImGui::TreePop();
6958
}
6959
6960
if (ImGui::TreeNodeEx("Sizing:", ImGuiTreeNodeFlags_DefaultOpen))
6961
{
6962
EditTableSizingFlags(&flags);
6963
ImGui::SameLine(); HelpMarker("In the Advanced demo we override the policy of each column so those table-wide settings have less effect that typical.");
6964
ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX);
6965
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.");
6966
ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendY", &flags, ImGuiTableFlags_NoHostExtendY);
6967
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.");
6968
ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags, ImGuiTableFlags_NoKeepColumnsVisible);
6969
ImGui::SameLine(); HelpMarker("Only available if ScrollX is disabled.");
6970
ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths);
6971
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.");
6972
ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip);
6973
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.");
6974
ImGui::TreePop();
6975
}
6976
6977
if (ImGui::TreeNodeEx("Padding:", ImGuiTreeNodeFlags_DefaultOpen))
6978
{
6979
ImGui::CheckboxFlags("ImGuiTableFlags_PadOuterX", &flags, ImGuiTableFlags_PadOuterX);
6980
ImGui::CheckboxFlags("ImGuiTableFlags_NoPadOuterX", &flags, ImGuiTableFlags_NoPadOuterX);
6981
ImGui::CheckboxFlags("ImGuiTableFlags_NoPadInnerX", &flags, ImGuiTableFlags_NoPadInnerX);
6982
ImGui::TreePop();
6983
}
6984
6985
if (ImGui::TreeNodeEx("Scrolling:", ImGuiTreeNodeFlags_DefaultOpen))
6986
{
6987
ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX);
6988
ImGui::SameLine();
6989
ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
6990
ImGui::DragInt("freeze_cols", &freeze_cols, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
6991
ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
6992
ImGui::SameLine();
6993
ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
6994
ImGui::DragInt("freeze_rows", &freeze_rows, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
6995
ImGui::TreePop();
6996
}
6997
6998
if (ImGui::TreeNodeEx("Sorting:", ImGuiTreeNodeFlags_DefaultOpen))
6999
{
7000
ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti);
7001
ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).");
7002
ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate);
7003
ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).");
7004
ImGui::TreePop();
7005
}
7006
7007
if (ImGui::TreeNodeEx("Headers:", ImGuiTreeNodeFlags_DefaultOpen))
7008
{
7009
ImGui::Checkbox("show_headers", &show_headers);
7010
ImGui::CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", &flags, ImGuiTableFlags_HighlightHoveredColumn);
7011
ImGui::CheckboxFlags("ImGuiTableColumnFlags_AngledHeader", &columns_base_flags, ImGuiTableColumnFlags_AngledHeader);
7012
ImGui::SameLine(); HelpMarker("Enable AngledHeader on all columns. Best enabled on selected narrow columns (see \"Angled headers\" section of the demo).");
7013
ImGui::TreePop();
7014
}
7015
7016
if (ImGui::TreeNodeEx("Other:", ImGuiTreeNodeFlags_DefaultOpen))
7017
{
7018
ImGui::Checkbox("show_wrapped_text", &show_wrapped_text);
7019
7020
ImGui::DragFloat2("##OuterSize", &outer_size_value.x);
7021
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
7022
ImGui::Checkbox("outer_size", &outer_size_enabled);
7023
ImGui::SameLine();
7024
HelpMarker("If scrolling is disabled (ScrollX and ScrollY not set):\n"
7025
"- The table is output directly in the parent window.\n"
7026
"- OuterSize.x < 0.0f will right-align the table.\n"
7027
"- OuterSize.x = 0.0f will narrow fit the table unless there are any Stretch columns.\n"
7028
"- OuterSize.y then becomes the minimum size for the table, which will extend vertically if there are more rows (unless NoHostExtendY is set).");
7029
7030
// From a user point of view we will tend to use 'inner_width' differently depending on whether our table is embedding scrolling.
7031
// To facilitate toying with this demo we will actually pass 0.0f to the BeginTable() when ScrollX is disabled.
7032
ImGui::DragFloat("inner_width (when ScrollX active)", &inner_width_with_scroll, 1.0f, 0.0f, FLT_MAX);
7033
7034
ImGui::DragFloat("row_min_height", &row_min_height, 1.0f, 0.0f, FLT_MAX);
7035
ImGui::SameLine(); HelpMarker("Specify height of the Selectable item.");
7036
7037
ImGui::DragInt("items_count", &items_count, 0.1f, 0, 9999);
7038
ImGui::Combo("items_type (first column)", &contents_type, contents_type_names, IM_ARRAYSIZE(contents_type_names));
7039
//filter.Draw("filter");
7040
ImGui::TreePop();
7041
}
7042
7043
ImGui::PopItemWidth();
7044
PopStyleCompact();
7045
ImGui::Spacing();
7046
ImGui::TreePop();
7047
}
7048
7049
// Update item list if we changed the number of items
7050
static ImVector<MyItem> items;
7051
static ImVector<int> selection;
7052
static bool items_need_sort = false;
7053
if (items.Size != items_count)
7054
{
7055
items.resize(items_count, MyItem());
7056
for (int n = 0; n < items_count; n++)
7057
{
7058
const int template_n = n % IM_ARRAYSIZE(template_items_names);
7059
MyItem& item = items[n];
7060
item.ID = n;
7061
item.Name = template_items_names[template_n];
7062
item.Quantity = (template_n == 3) ? 10 : (template_n == 4) ? 20 : 0; // Assign default quantities
7063
}
7064
}
7065
7066
const ImDrawList* parent_draw_list = ImGui::GetWindowDrawList();
7067
const int parent_draw_list_draw_cmd_count = parent_draw_list->CmdBuffer.Size;
7068
ImVec2 table_scroll_cur, table_scroll_max; // For debug display
7069
const ImDrawList* table_draw_list = NULL; // "
7070
7071
// Submit table
7072
const float inner_width_to_use = (flags & ImGuiTableFlags_ScrollX) ? inner_width_with_scroll : 0.0f;
7073
if (ImGui::BeginTable("table_advanced", 6, flags, outer_size_enabled ? outer_size_value : ImVec2(0, 0), inner_width_to_use))
7074
{
7075
// Declare columns
7076
// We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications.
7077
// This is so our sort function can identify a column given our own identifier. We could also identify them based on their index!
7078
ImGui::TableSetupColumn("ID", columns_base_flags | ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoHide, 0.0f, MyItemColumnID_ID);
7079
ImGui::TableSetupColumn("Name", columns_base_flags | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Name);
7080
ImGui::TableSetupColumn("Action", columns_base_flags | ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Action);
7081
ImGui::TableSetupColumn("Quantity", columns_base_flags | ImGuiTableColumnFlags_PreferSortDescending, 0.0f, MyItemColumnID_Quantity);
7082
ImGui::TableSetupColumn("Description", columns_base_flags | ((flags & ImGuiTableFlags_NoHostExtendX) ? 0 : ImGuiTableColumnFlags_WidthStretch), 0.0f, MyItemColumnID_Description);
7083
ImGui::TableSetupColumn("Hidden", columns_base_flags | ImGuiTableColumnFlags_DefaultHide | ImGuiTableColumnFlags_NoSort);
7084
ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows);
7085
7086
// Sort our data if sort specs have been changed!
7087
ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs();
7088
if (sort_specs && sort_specs->SpecsDirty)
7089
items_need_sort = true;
7090
if (sort_specs && items_need_sort && items.Size > 1)
7091
{
7092
MyItem::SortWithSortSpecs(sort_specs, items.Data, items.Size);
7093
sort_specs->SpecsDirty = false;
7094
}
7095
items_need_sort = false;
7096
7097
// Take note of whether we are currently sorting based on the Quantity field,
7098
// we will use this to trigger sorting when we know the data of this column has been modified.
7099
const bool sorts_specs_using_quantity = (ImGui::TableGetColumnFlags(3) & ImGuiTableColumnFlags_IsSorted) != 0;
7100
7101
// Show headers
7102
if (show_headers && (columns_base_flags & ImGuiTableColumnFlags_AngledHeader) != 0)
7103
ImGui::TableAngledHeadersRow();
7104
if (show_headers)
7105
ImGui::TableHeadersRow();
7106
7107
// Show data
7108
// FIXME-TABLE FIXME-NAV: How we can get decent up/down even though we have the buttons here?
7109
#if 1
7110
// Demonstrate using clipper for large vertical lists
7111
ImGuiListClipper clipper;
7112
clipper.Begin(items.Size);
7113
while (clipper.Step())
7114
{
7115
for (int row_n = clipper.DisplayStart; row_n < clipper.DisplayEnd; row_n++)
7116
#else
7117
// Without clipper
7118
{
7119
for (int row_n = 0; row_n < items.Size; row_n++)
7120
#endif
7121
{
7122
MyItem* item = &items[row_n];
7123
//if (!filter.PassFilter(item->Name))
7124
// continue;
7125
7126
const bool item_is_selected = selection.contains(item->ID);
7127
ImGui::PushID(item->ID);
7128
ImGui::TableNextRow(ImGuiTableRowFlags_None, row_min_height);
7129
7130
// For the demo purpose we can select among different type of items submitted in the first column
7131
ImGui::TableSetColumnIndex(0);
7132
char label[32];
7133
sprintf(label, "%04d", item->ID);
7134
if (contents_type == CT_Text)
7135
ImGui::TextUnformatted(label);
7136
else if (contents_type == CT_Button)
7137
ImGui::Button(label);
7138
else if (contents_type == CT_SmallButton)
7139
ImGui::SmallButton(label);
7140
else if (contents_type == CT_FillButton)
7141
ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f));
7142
else if (contents_type == CT_Selectable || contents_type == CT_SelectableSpanRow)
7143
{
7144
ImGuiSelectableFlags selectable_flags = (contents_type == CT_SelectableSpanRow) ? ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap : ImGuiSelectableFlags_None;
7145
if (ImGui::Selectable(label, item_is_selected, selectable_flags, ImVec2(0, row_min_height)))
7146
{
7147
if (ImGui::GetIO().KeyCtrl)
7148
{
7149
if (item_is_selected)
7150
selection.find_erase_unsorted(item->ID);
7151
else
7152
selection.push_back(item->ID);
7153
}
7154
else
7155
{
7156
selection.clear();
7157
selection.push_back(item->ID);
7158
}
7159
}
7160
}
7161
7162
if (ImGui::TableSetColumnIndex(1))
7163
ImGui::TextUnformatted(item->Name);
7164
7165
// Here we demonstrate marking our data set as needing to be sorted again if we modified a quantity,
7166
// and we are currently sorting on the column showing the Quantity.
7167
// To avoid triggering a sort while holding the button, we only trigger it when the button has been released.
7168
// You will probably need some extra logic if you want to automatically sort when a specific entry changes.
7169
if (ImGui::TableSetColumnIndex(2))
7170
{
7171
if (ImGui::SmallButton("Chop")) { item->Quantity += 1; }
7172
if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) { items_need_sort = true; }
7173
ImGui::SameLine();
7174
if (ImGui::SmallButton("Eat")) { item->Quantity -= 1; }
7175
if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) { items_need_sort = true; }
7176
}
7177
7178
if (ImGui::TableSetColumnIndex(3))
7179
ImGui::Text("%d", item->Quantity);
7180
7181
ImGui::TableSetColumnIndex(4);
7182
if (show_wrapped_text)
7183
ImGui::TextWrapped("Lorem ipsum dolor sit amet");
7184
else
7185
ImGui::Text("Lorem ipsum dolor sit amet");
7186
7187
if (ImGui::TableSetColumnIndex(5))
7188
ImGui::Text("1234");
7189
7190
ImGui::PopID();
7191
}
7192
}
7193
7194
// Store some info to display debug details below
7195
table_scroll_cur = ImVec2(ImGui::GetScrollX(), ImGui::GetScrollY());
7196
table_scroll_max = ImVec2(ImGui::GetScrollMaxX(), ImGui::GetScrollMaxY());
7197
table_draw_list = ImGui::GetWindowDrawList();
7198
ImGui::EndTable();
7199
}
7200
static bool show_debug_details = false;
7201
ImGui::Checkbox("Debug details", &show_debug_details);
7202
if (show_debug_details && table_draw_list)
7203
{
7204
ImGui::SameLine(0.0f, 0.0f);
7205
const int table_draw_list_draw_cmd_count = table_draw_list->CmdBuffer.Size;
7206
if (table_draw_list == parent_draw_list)
7207
ImGui::Text(": DrawCmd: +%d (in same window)",
7208
table_draw_list_draw_cmd_count - parent_draw_list_draw_cmd_count);
7209
else
7210
ImGui::Text(": DrawCmd: +%d (in child window), Scroll: (%.f/%.f) (%.f/%.f)",
7211
table_draw_list_draw_cmd_count - 1, table_scroll_cur.x, table_scroll_max.x, table_scroll_cur.y, table_scroll_max.y);
7212
}
7213
ImGui::TreePop();
7214
}
7215
7216
ImGui::PopID();
7217
7218
ShowDemoWindowColumns();
7219
7220
if (disable_indent)
7221
ImGui::PopStyleVar();
7222
}
7223
7224
// Demonstrate old/legacy Columns API!
7225
// [2020: Columns are under-featured and not maintained. Prefer using the more flexible and powerful BeginTable() API!]
7226
static void ShowDemoWindowColumns()
7227
{
7228
IMGUI_DEMO_MARKER("Columns (legacy API)");
7229
bool open = ImGui::TreeNode("Legacy Columns API");
7230
ImGui::SameLine();
7231
HelpMarker("Columns() is an old API! Prefer using the more flexible and powerful BeginTable() API!");
7232
if (!open)
7233
return;
7234
7235
// Basic columns
7236
IMGUI_DEMO_MARKER("Columns (legacy API)/Basic");
7237
if (ImGui::TreeNode("Basic"))
7238
{
7239
ImGui::Text("Without border:");
7240
ImGui::Columns(3, "mycolumns3", false); // 3-ways, no border
7241
ImGui::Separator();
7242
for (int n = 0; n < 14; n++)
7243
{
7244
char label[32];
7245
sprintf(label, "Item %d", n);
7246
if (ImGui::Selectable(label)) {}
7247
//if (ImGui::Button(label, ImVec2(-FLT_MIN,0.0f))) {}
7248
ImGui::NextColumn();
7249
}
7250
ImGui::Columns(1);
7251
ImGui::Separator();
7252
7253
ImGui::Text("With border:");
7254
ImGui::Columns(4, "mycolumns"); // 4-ways, with border
7255
ImGui::Separator();
7256
ImGui::Text("ID"); ImGui::NextColumn();
7257
ImGui::Text("Name"); ImGui::NextColumn();
7258
ImGui::Text("Path"); ImGui::NextColumn();
7259
ImGui::Text("Hovered"); ImGui::NextColumn();
7260
ImGui::Separator();
7261
const char* names[3] = { "One", "Two", "Three" };
7262
const char* paths[3] = { "/path/one", "/path/two", "/path/three" };
7263
static int selected = -1;
7264
for (int i = 0; i < 3; i++)
7265
{
7266
char label[32];
7267
sprintf(label, "%04d", i);
7268
if (ImGui::Selectable(label, selected == i, ImGuiSelectableFlags_SpanAllColumns))
7269
selected = i;
7270
bool hovered = ImGui::IsItemHovered();
7271
ImGui::NextColumn();
7272
ImGui::Text(names[i]); ImGui::NextColumn();
7273
ImGui::Text(paths[i]); ImGui::NextColumn();
7274
ImGui::Text("%d", hovered); ImGui::NextColumn();
7275
}
7276
ImGui::Columns(1);
7277
ImGui::Separator();
7278
ImGui::TreePop();
7279
}
7280
7281
IMGUI_DEMO_MARKER("Columns (legacy API)/Borders");
7282
if (ImGui::TreeNode("Borders"))
7283
{
7284
// NB: Future columns API should allow automatic horizontal borders.
7285
static bool h_borders = true;
7286
static bool v_borders = true;
7287
static int columns_count = 4;
7288
const int lines_count = 3;
7289
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
7290
ImGui::DragInt("##columns_count", &columns_count, 0.1f, 2, 10, "%d columns");
7291
if (columns_count < 2)
7292
columns_count = 2;
7293
ImGui::SameLine();
7294
ImGui::Checkbox("horizontal", &h_borders);
7295
ImGui::SameLine();
7296
ImGui::Checkbox("vertical", &v_borders);
7297
ImGui::Columns(columns_count, NULL, v_borders);
7298
for (int i = 0; i < columns_count * lines_count; i++)
7299
{
7300
if (h_borders && ImGui::GetColumnIndex() == 0)
7301
ImGui::Separator();
7302
ImGui::PushID(i);
7303
ImGui::Text("%c%c%c", 'a' + i, 'a' + i, 'a' + i);
7304
ImGui::Text("Width %.2f", ImGui::GetColumnWidth());
7305
ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x);
7306
ImGui::Text("Offset %.2f", ImGui::GetColumnOffset());
7307
ImGui::Text("Long text that is likely to clip");
7308
ImGui::Button("Button", ImVec2(-FLT_MIN, 0.0f));
7309
ImGui::PopID();
7310
ImGui::NextColumn();
7311
}
7312
ImGui::Columns(1);
7313
if (h_borders)
7314
ImGui::Separator();
7315
ImGui::TreePop();
7316
}
7317
7318
// Create multiple items in a same cell before switching to next column
7319
IMGUI_DEMO_MARKER("Columns (legacy API)/Mixed items");
7320
if (ImGui::TreeNode("Mixed items"))
7321
{
7322
ImGui::Columns(3, "mixed");
7323
ImGui::Separator();
7324
7325
ImGui::Text("Hello");
7326
ImGui::Button("Banana");
7327
ImGui::NextColumn();
7328
7329
ImGui::Text("ImGui");
7330
ImGui::Button("Apple");
7331
static float foo = 1.0f;
7332
ImGui::InputFloat("red", &foo, 0.05f, 0, "%.3f");
7333
ImGui::Text("An extra line here.");
7334
ImGui::NextColumn();
7335
7336
ImGui::Text("Sailor");
7337
ImGui::Button("Corniflower");
7338
static float bar = 1.0f;
7339
ImGui::InputFloat("blue", &bar, 0.05f, 0, "%.3f");
7340
ImGui::NextColumn();
7341
7342
if (ImGui::CollapsingHeader("Category A")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
7343
if (ImGui::CollapsingHeader("Category B")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
7344
if (ImGui::CollapsingHeader("Category C")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
7345
ImGui::Columns(1);
7346
ImGui::Separator();
7347
ImGui::TreePop();
7348
}
7349
7350
// Word wrapping
7351
IMGUI_DEMO_MARKER("Columns (legacy API)/Word-wrapping");
7352
if (ImGui::TreeNode("Word-wrapping"))
7353
{
7354
ImGui::Columns(2, "word-wrapping");
7355
ImGui::Separator();
7356
ImGui::TextWrapped("The quick brown fox jumps over the lazy dog.");
7357
ImGui::TextWrapped("Hello Left");
7358
ImGui::NextColumn();
7359
ImGui::TextWrapped("The quick brown fox jumps over the lazy dog.");
7360
ImGui::TextWrapped("Hello Right");
7361
ImGui::Columns(1);
7362
ImGui::Separator();
7363
ImGui::TreePop();
7364
}
7365
7366
IMGUI_DEMO_MARKER("Columns (legacy API)/Horizontal Scrolling");
7367
if (ImGui::TreeNode("Horizontal Scrolling"))
7368
{
7369
ImGui::SetNextWindowContentSize(ImVec2(1500.0f, 0.0f));
7370
ImVec2 child_size = ImVec2(0, ImGui::GetFontSize() * 20.0f);
7371
ImGui::BeginChild("##ScrollingRegion", child_size, ImGuiChildFlags_None, ImGuiWindowFlags_HorizontalScrollbar);
7372
ImGui::Columns(10);
7373
7374
// Also demonstrate using clipper for large vertical lists
7375
int ITEMS_COUNT = 2000;
7376
ImGuiListClipper clipper;
7377
clipper.Begin(ITEMS_COUNT);
7378
while (clipper.Step())
7379
{
7380
for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
7381
for (int j = 0; j < 10; j++)
7382
{
7383
ImGui::Text("Line %d Column %d...", i, j);
7384
ImGui::NextColumn();
7385
}
7386
}
7387
ImGui::Columns(1);
7388
ImGui::EndChild();
7389
ImGui::TreePop();
7390
}
7391
7392
IMGUI_DEMO_MARKER("Columns (legacy API)/Tree");
7393
if (ImGui::TreeNode("Tree"))
7394
{
7395
ImGui::Columns(2, "tree", true);
7396
for (int x = 0; x < 3; x++)
7397
{
7398
bool open1 = ImGui::TreeNode((void*)(intptr_t)x, "Node%d", x);
7399
ImGui::NextColumn();
7400
ImGui::Text("Node contents");
7401
ImGui::NextColumn();
7402
if (open1)
7403
{
7404
for (int y = 0; y < 3; y++)
7405
{
7406
bool open2 = ImGui::TreeNode((void*)(intptr_t)y, "Node%d.%d", x, y);
7407
ImGui::NextColumn();
7408
ImGui::Text("Node contents");
7409
if (open2)
7410
{
7411
ImGui::Text("Even more contents");
7412
if (ImGui::TreeNode("Tree in column"))
7413
{
7414
ImGui::Text("The quick brown fox jumps over the lazy dog");
7415
ImGui::TreePop();
7416
}
7417
}
7418
ImGui::NextColumn();
7419
if (open2)
7420
ImGui::TreePop();
7421
}
7422
ImGui::TreePop();
7423
}
7424
}
7425
ImGui::Columns(1);
7426
ImGui::TreePop();
7427
}
7428
7429
ImGui::TreePop();
7430
}
7431
7432
//-----------------------------------------------------------------------------
7433
// [SECTION] ShowDemoWindowInputs()
7434
//-----------------------------------------------------------------------------
7435
7436
static void ShowDemoWindowInputs()
7437
{
7438
IMGUI_DEMO_MARKER("Inputs & Focus");
7439
if (ImGui::CollapsingHeader("Inputs & Focus"))
7440
{
7441
ImGuiIO& io = ImGui::GetIO();
7442
7443
// Display inputs submitted to ImGuiIO
7444
IMGUI_DEMO_MARKER("Inputs & Focus/Inputs");
7445
ImGui::SetNextItemOpen(true, ImGuiCond_Once);
7446
bool inputs_opened = ImGui::TreeNode("Inputs");
7447
ImGui::SameLine();
7448
HelpMarker(
7449
"This is a simplified view. See more detailed input state:\n"
7450
"- in 'Tools->Metrics/Debugger->Inputs'.\n"
7451
"- in 'Tools->Debug Log->IO'.");
7452
if (inputs_opened)
7453
{
7454
if (ImGui::IsMousePosValid())
7455
ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y);
7456
else
7457
ImGui::Text("Mouse pos: <INVALID>");
7458
ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y);
7459
ImGui::Text("Mouse down:");
7460
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]); }
7461
ImGui::Text("Mouse wheel: %.1f", io.MouseWheel);
7462
7463
// We iterate both legacy native range and named ImGuiKey ranges. This is a little unusual/odd but this allows
7464
// displaying the data for old/new backends.
7465
// User code should never have to go through such hoops!
7466
// You can generally iterate between ImGuiKey_NamedKey_BEGIN and ImGuiKey_NamedKey_END.
7467
struct funcs { static bool IsLegacyNativeDupe(ImGuiKey) { return false; } };
7468
ImGuiKey start_key = ImGuiKey_NamedKey_BEGIN;
7469
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); }
7470
ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : "");
7471
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.
7472
7473
ImGui::TreePop();
7474
}
7475
7476
// Display ImGuiIO output flags
7477
IMGUI_DEMO_MARKER("Inputs & Focus/Outputs");
7478
ImGui::SetNextItemOpen(true, ImGuiCond_Once);
7479
bool outputs_opened = ImGui::TreeNode("Outputs");
7480
ImGui::SameLine();
7481
HelpMarker(
7482
"The value of io.WantCaptureMouse and io.WantCaptureKeyboard are normally set by Dear ImGui "
7483
"to instruct your application of how to route inputs. Typically, when a value is true, it means "
7484
"Dear ImGui wants the corresponding inputs and we expect the underlying application to ignore them.\n\n"
7485
"The most typical case is: when hovering a window, Dear ImGui set io.WantCaptureMouse to true, "
7486
"and underlying application should ignore mouse inputs (in practice there are many and more subtle "
7487
"rules leading to how those flags are set).");
7488
if (outputs_opened)
7489
{
7490
ImGui::Text("io.WantCaptureMouse: %d", io.WantCaptureMouse);
7491
ImGui::Text("io.WantCaptureMouseUnlessPopupClose: %d", io.WantCaptureMouseUnlessPopupClose);
7492
ImGui::Text("io.WantCaptureKeyboard: %d", io.WantCaptureKeyboard);
7493
ImGui::Text("io.WantTextInput: %d", io.WantTextInput);
7494
ImGui::Text("io.WantSetMousePos: %d", io.WantSetMousePos);
7495
ImGui::Text("io.NavActive: %d, io.NavVisible: %d", io.NavActive, io.NavVisible);
7496
7497
IMGUI_DEMO_MARKER("Inputs & Focus/Outputs/WantCapture override");
7498
if (ImGui::TreeNode("WantCapture override"))
7499
{
7500
HelpMarker(
7501
"Hovering the colored canvas will override io.WantCaptureXXX fields.\n"
7502
"Notice how normally (when set to none), the value of io.WantCaptureKeyboard would be false when hovering "
7503
"and true when clicking.");
7504
static int capture_override_mouse = -1;
7505
static int capture_override_keyboard = -1;
7506
const char* capture_override_desc[] = { "None", "Set to false", "Set to true" };
7507
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15);
7508
ImGui::SliderInt("SetNextFrameWantCaptureMouse() on hover", &capture_override_mouse, -1, +1, capture_override_desc[capture_override_mouse + 1], ImGuiSliderFlags_AlwaysClamp);
7509
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15);
7510
ImGui::SliderInt("SetNextFrameWantCaptureKeyboard() on hover", &capture_override_keyboard, -1, +1, capture_override_desc[capture_override_keyboard + 1], ImGuiSliderFlags_AlwaysClamp);
7511
7512
ImGui::ColorButton("##panel", ImVec4(0.7f, 0.1f, 0.7f, 1.0f), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop, ImVec2(128.0f, 96.0f)); // Dummy item
7513
if (ImGui::IsItemHovered() && capture_override_mouse != -1)
7514
ImGui::SetNextFrameWantCaptureMouse(capture_override_mouse == 1);
7515
if (ImGui::IsItemHovered() && capture_override_keyboard != -1)
7516
ImGui::SetNextFrameWantCaptureKeyboard(capture_override_keyboard == 1);
7517
7518
ImGui::TreePop();
7519
}
7520
ImGui::TreePop();
7521
}
7522
7523
// Demonstrate using Shortcut() and Routing Policies.
7524
// The general flow is:
7525
// - Code interested in a chord (e.g. "Ctrl+A") declares their intent.
7526
// - Multiple locations may be interested in same chord! Routing helps find a winner.
7527
// - Every frame, we resolve all claims and assign one owner if the modifiers are matching.
7528
// - The lower-level function is 'bool SetShortcutRouting()', returns true when caller got the route.
7529
// - Most of the times, SetShortcutRouting() is not called directly. User mostly calls Shortcut() with routing flags.
7530
// - If you call Shortcut() WITHOUT any routing option, it uses ImGuiInputFlags_RouteFocused.
7531
// TL;DR: Most uses will simply be:
7532
// - Shortcut(ImGuiMod_Ctrl | ImGuiKey_A); // Use ImGuiInputFlags_RouteFocused policy.
7533
IMGUI_DEMO_MARKER("Inputs & Focus/Shortcuts");
7534
if (ImGui::TreeNode("Shortcuts"))
7535
{
7536
static ImGuiInputFlags route_options = ImGuiInputFlags_Repeat;
7537
static ImGuiInputFlags route_type = ImGuiInputFlags_RouteFocused;
7538
ImGui::CheckboxFlags("ImGuiInputFlags_Repeat", &route_options, ImGuiInputFlags_Repeat);
7539
ImGui::RadioButton("ImGuiInputFlags_RouteActive", &route_type, ImGuiInputFlags_RouteActive);
7540
ImGui::RadioButton("ImGuiInputFlags_RouteFocused (default)", &route_type, ImGuiInputFlags_RouteFocused);
7541
ImGui::RadioButton("ImGuiInputFlags_RouteGlobal", &route_type, ImGuiInputFlags_RouteGlobal);
7542
ImGui::Indent();
7543
ImGui::BeginDisabled(route_type != ImGuiInputFlags_RouteGlobal);
7544
ImGui::CheckboxFlags("ImGuiInputFlags_RouteOverFocused", &route_options, ImGuiInputFlags_RouteOverFocused);
7545
ImGui::CheckboxFlags("ImGuiInputFlags_RouteOverActive", &route_options, ImGuiInputFlags_RouteOverActive);
7546
ImGui::CheckboxFlags("ImGuiInputFlags_RouteUnlessBgFocused", &route_options, ImGuiInputFlags_RouteUnlessBgFocused);
7547
ImGui::EndDisabled();
7548
ImGui::Unindent();
7549
ImGui::RadioButton("ImGuiInputFlags_RouteAlways", &route_type, ImGuiInputFlags_RouteAlways);
7550
ImGuiInputFlags flags = route_type | route_options; // Merged flags
7551
if (route_type != ImGuiInputFlags_RouteGlobal)
7552
flags &= ~(ImGuiInputFlags_RouteOverFocused | ImGuiInputFlags_RouteOverActive | ImGuiInputFlags_RouteUnlessBgFocused);
7553
7554
ImGui::SeparatorText("Using SetNextItemShortcut()");
7555
ImGui::Text("Ctrl+S");
7556
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_S, flags | ImGuiInputFlags_Tooltip);
7557
ImGui::Button("Save");
7558
ImGui::Text("Alt+F");
7559
ImGui::SetNextItemShortcut(ImGuiMod_Alt | ImGuiKey_F, flags | ImGuiInputFlags_Tooltip);
7560
static float f = 0.5f;
7561
ImGui::SliderFloat("Factor", &f, 0.0f, 1.0f);
7562
7563
ImGui::SeparatorText("Using Shortcut()");
7564
const float line_height = ImGui::GetTextLineHeightWithSpacing();
7565
const ImGuiKeyChord key_chord = ImGuiMod_Ctrl | ImGuiKey_A;
7566
7567
ImGui::Text("Ctrl+A");
7568
ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "...");
7569
7570
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 0.0f, 1.0f, 0.1f));
7571
7572
ImGui::BeginChild("WindowA", ImVec2(-FLT_MIN, line_height * 14), true);
7573
ImGui::Text("Press CTRL+A and see who receives it!");
7574
ImGui::Separator();
7575
7576
// 1: Window polling for CTRL+A
7577
ImGui::Text("(in WindowA)");
7578
ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "...");
7579
7580
// 2: InputText also polling for CTRL+A: it always uses _RouteFocused internally (gets priority when active)
7581
// (Commmented because the owner-aware version of Shortcut() is still in imgui_internal.h)
7582
//char str[16] = "Press CTRL+A";
7583
//ImGui::Spacing();
7584
//ImGui::InputText("InputTextB", str, IM_ARRAYSIZE(str), ImGuiInputTextFlags_ReadOnly);
7585
//ImGuiID item_id = ImGui::GetItemID();
7586
//ImGui::SameLine(); HelpMarker("Internal widgets always use _RouteFocused");
7587
//ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags, item_id) ? "PRESSED" : "...");
7588
7589
// 3: Dummy child is not claiming the route: focusing them shouldn't steal route away from WindowA
7590
ImGui::BeginChild("ChildD", ImVec2(-FLT_MIN, line_height * 4), true);
7591
ImGui::Text("(in ChildD: not using same Shortcut)");
7592
ImGui::Text("IsWindowFocused: %d", ImGui::IsWindowFocused());
7593
ImGui::EndChild();
7594
7595
// 4: Child window polling for CTRL+A. It is deeper than WindowA and gets priority when focused.
7596
ImGui::BeginChild("ChildE", ImVec2(-FLT_MIN, line_height * 4), true);
7597
ImGui::Text("(in ChildE: using same Shortcut)");
7598
ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "...");
7599
ImGui::EndChild();
7600
7601
// 5: In a popup
7602
if (ImGui::Button("Open Popup"))
7603
ImGui::OpenPopup("PopupF");
7604
if (ImGui::BeginPopup("PopupF"))
7605
{
7606
ImGui::Text("(in PopupF)");
7607
ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "...");
7608
// (Commmented because the owner-aware version of Shortcut() is still in imgui_internal.h)
7609
//ImGui::InputText("InputTextG", str, IM_ARRAYSIZE(str), ImGuiInputTextFlags_ReadOnly);
7610
//ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags, ImGui::GetItemID()) ? "PRESSED" : "...");
7611
ImGui::EndPopup();
7612
}
7613
ImGui::EndChild();
7614
ImGui::PopStyleColor();
7615
7616
ImGui::TreePop();
7617
}
7618
7619
// Display mouse cursors
7620
IMGUI_DEMO_MARKER("Inputs & Focus/Mouse Cursors");
7621
if (ImGui::TreeNode("Mouse Cursors"))
7622
{
7623
const char* mouse_cursors_names[] = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "NotAllowed" };
7624
IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT);
7625
7626
ImGuiMouseCursor current = ImGui::GetMouseCursor();
7627
const char* cursor_name = (current >= ImGuiMouseCursor_Arrow) && (current < ImGuiMouseCursor_COUNT) ? mouse_cursors_names[current] : "N/A";
7628
ImGui::Text("Current mouse cursor = %d: %s", current, cursor_name);
7629
ImGui::BeginDisabled(true);
7630
ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors);
7631
ImGui::EndDisabled();
7632
7633
ImGui::Text("Hover to see mouse cursors:");
7634
ImGui::SameLine(); HelpMarker(
7635
"Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. "
7636
"If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, "
7637
"otherwise your backend needs to handle it.");
7638
for (int i = 0; i < ImGuiMouseCursor_COUNT; i++)
7639
{
7640
char label[32];
7641
sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]);
7642
ImGui::Bullet(); ImGui::Selectable(label, false);
7643
if (ImGui::IsItemHovered())
7644
ImGui::SetMouseCursor(i);
7645
}
7646
ImGui::TreePop();
7647
}
7648
7649
IMGUI_DEMO_MARKER("Inputs & Focus/Tabbing");
7650
if (ImGui::TreeNode("Tabbing"))
7651
{
7652
ImGui::Text("Use TAB/SHIFT+TAB to cycle through keyboard editable fields.");
7653
static char buf[32] = "hello";
7654
ImGui::InputText("1", buf, IM_ARRAYSIZE(buf));
7655
ImGui::InputText("2", buf, IM_ARRAYSIZE(buf));
7656
ImGui::InputText("3", buf, IM_ARRAYSIZE(buf));
7657
ImGui::PushItemFlag(ImGuiItemFlags_NoTabStop, true);
7658
ImGui::InputText("4 (tab skip)", buf, IM_ARRAYSIZE(buf));
7659
ImGui::SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab.");
7660
ImGui::PopItemFlag();
7661
ImGui::InputText("5", buf, IM_ARRAYSIZE(buf));
7662
ImGui::TreePop();
7663
}
7664
7665
IMGUI_DEMO_MARKER("Inputs & Focus/Focus from code");
7666
if (ImGui::TreeNode("Focus from code"))
7667
{
7668
bool focus_1 = ImGui::Button("Focus on 1"); ImGui::SameLine();
7669
bool focus_2 = ImGui::Button("Focus on 2"); ImGui::SameLine();
7670
bool focus_3 = ImGui::Button("Focus on 3");
7671
int has_focus = 0;
7672
static char buf[128] = "click on a button to set focus";
7673
7674
if (focus_1) ImGui::SetKeyboardFocusHere();
7675
ImGui::InputText("1", buf, IM_ARRAYSIZE(buf));
7676
if (ImGui::IsItemActive()) has_focus = 1;
7677
7678
if (focus_2) ImGui::SetKeyboardFocusHere();
7679
ImGui::InputText("2", buf, IM_ARRAYSIZE(buf));
7680
if (ImGui::IsItemActive()) has_focus = 2;
7681
7682
ImGui::PushItemFlag(ImGuiItemFlags_NoTabStop, true);
7683
if (focus_3) ImGui::SetKeyboardFocusHere();
7684
ImGui::InputText("3 (tab skip)", buf, IM_ARRAYSIZE(buf));
7685
if (ImGui::IsItemActive()) has_focus = 3;
7686
ImGui::SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab.");
7687
ImGui::PopItemFlag();
7688
7689
if (has_focus)
7690
ImGui::Text("Item with focus: %d", has_focus);
7691
else
7692
ImGui::Text("Item with focus: <none>");
7693
7694
// Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item
7695
static float f3[3] = { 0.0f, 0.0f, 0.0f };
7696
int focus_ahead = -1;
7697
if (ImGui::Button("Focus on X")) { focus_ahead = 0; } ImGui::SameLine();
7698
if (ImGui::Button("Focus on Y")) { focus_ahead = 1; } ImGui::SameLine();
7699
if (ImGui::Button("Focus on Z")) { focus_ahead = 2; }
7700
if (focus_ahead != -1) ImGui::SetKeyboardFocusHere(focus_ahead);
7701
ImGui::SliderFloat3("Float3", &f3[0], 0.0f, 1.0f);
7702
7703
ImGui::TextWrapped("NB: Cursor & selection are preserved when refocusing last used item in code.");
7704
ImGui::TreePop();
7705
}
7706
7707
IMGUI_DEMO_MARKER("Inputs & Focus/Dragging");
7708
if (ImGui::TreeNode("Dragging"))
7709
{
7710
ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget.");
7711
for (int button = 0; button < 3; button++)
7712
{
7713
ImGui::Text("IsMouseDragging(%d):", button);
7714
ImGui::Text(" w/ default threshold: %d,", ImGui::IsMouseDragging(button));
7715
ImGui::Text(" w/ zero threshold: %d,", ImGui::IsMouseDragging(button, 0.0f));
7716
ImGui::Text(" w/ large threshold: %d,", ImGui::IsMouseDragging(button, 20.0f));
7717
}
7718
7719
ImGui::Button("Drag Me");
7720
if (ImGui::IsItemActive())
7721
ImGui::GetForegroundDrawList()->AddLine(io.MouseClickedPos[0], io.MousePos, ImGui::GetColorU32(ImGuiCol_Button), 4.0f); // Draw a line between the button and the mouse cursor
7722
7723
// Drag operations gets "unlocked" when the mouse has moved past a certain threshold
7724
// (the default threshold is stored in io.MouseDragThreshold). You can request a lower or higher
7725
// threshold using the second parameter of IsMouseDragging() and GetMouseDragDelta().
7726
ImVec2 value_raw = ImGui::GetMouseDragDelta(0, 0.0f);
7727
ImVec2 value_with_lock_threshold = ImGui::GetMouseDragDelta(0);
7728
ImVec2 mouse_delta = io.MouseDelta;
7729
ImGui::Text("GetMouseDragDelta(0):");
7730
ImGui::Text(" w/ default threshold: (%.1f, %.1f)", value_with_lock_threshold.x, value_with_lock_threshold.y);
7731
ImGui::Text(" w/ zero threshold: (%.1f, %.1f)", value_raw.x, value_raw.y);
7732
ImGui::Text("io.MouseDelta: (%.1f, %.1f)", mouse_delta.x, mouse_delta.y);
7733
ImGui::TreePop();
7734
}
7735
}
7736
}
7737
7738
//-----------------------------------------------------------------------------
7739
// [SECTION] About Window / ShowAboutWindow()
7740
// Access from Dear ImGui Demo -> Tools -> About
7741
//-----------------------------------------------------------------------------
7742
7743
void ImGui::ShowAboutWindow(bool* p_open)
7744
{
7745
if (!ImGui::Begin("About Dear ImGui", p_open, ImGuiWindowFlags_AlwaysAutoResize))
7746
{
7747
ImGui::End();
7748
return;
7749
}
7750
IMGUI_DEMO_MARKER("Tools/About Dear ImGui");
7751
ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
7752
7753
ImGui::TextLinkOpenURL("Homepage", "https://github.com/ocornut/imgui");
7754
ImGui::SameLine();
7755
ImGui::TextLinkOpenURL("FAQ", "https://github.com/ocornut/imgui/blob/master/docs/FAQ.md");
7756
ImGui::SameLine();
7757
ImGui::TextLinkOpenURL("Wiki", "https://github.com/ocornut/imgui/wiki");
7758
ImGui::SameLine();
7759
ImGui::TextLinkOpenURL("Releases", "https://github.com/ocornut/imgui/releases");
7760
ImGui::SameLine();
7761
ImGui::TextLinkOpenURL("Funding", "https://github.com/ocornut/imgui/wiki/Funding");
7762
7763
ImGui::Separator();
7764
ImGui::Text("By Omar Cornut and all Dear ImGui contributors.");
7765
ImGui::Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information.");
7766
ImGui::Text("If your company uses this, please consider funding the project.");
7767
7768
static bool show_config_info = false;
7769
ImGui::Checkbox("Config/Build Information", &show_config_info);
7770
if (show_config_info)
7771
{
7772
ImGuiIO& io = ImGui::GetIO();
7773
ImGuiStyle& style = ImGui::GetStyle();
7774
7775
bool copy_to_clipboard = ImGui::Button("Copy to clipboard");
7776
ImVec2 child_size = ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 18);
7777
ImGui::BeginChild(ImGui::GetID("cfg_infos"), child_size, ImGuiChildFlags_FrameStyle);
7778
if (copy_to_clipboard)
7779
{
7780
ImGui::LogToClipboard();
7781
ImGui::LogText("```\n"); // Back quotes will make text appears without formatting when pasting on GitHub
7782
}
7783
7784
ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
7785
ImGui::Separator();
7786
ImGui::Text("sizeof(size_t): %d, sizeof(ImDrawIdx): %d, sizeof(ImDrawVert): %d", (int)sizeof(size_t), (int)sizeof(ImDrawIdx), (int)sizeof(ImDrawVert));
7787
ImGui::Text("define: __cplusplus=%d", (int)__cplusplus);
7788
#ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
7789
ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_FUNCTIONS");
7790
#endif
7791
#ifdef IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS
7792
ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS");
7793
#endif
7794
#ifdef IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
7795
ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS");
7796
#endif
7797
#ifdef IMGUI_DISABLE_WIN32_FUNCTIONS
7798
ImGui::Text("define: IMGUI_DISABLE_WIN32_FUNCTIONS");
7799
#endif
7800
#ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
7801
ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS");
7802
#endif
7803
#ifdef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS
7804
ImGui::Text("define: IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS");
7805
#endif
7806
#ifdef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
7807
ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS");
7808
#endif
7809
#ifdef IMGUI_DISABLE_FILE_FUNCTIONS
7810
ImGui::Text("define: IMGUI_DISABLE_FILE_FUNCTIONS");
7811
#endif
7812
#ifdef IMGUI_DISABLE_DEFAULT_ALLOCATORS
7813
ImGui::Text("define: IMGUI_DISABLE_DEFAULT_ALLOCATORS");
7814
#endif
7815
#ifdef IMGUI_USE_BGRA_PACKED_COLOR
7816
ImGui::Text("define: IMGUI_USE_BGRA_PACKED_COLOR");
7817
#endif
7818
#ifdef _WIN32
7819
ImGui::Text("define: _WIN32");
7820
#endif
7821
#ifdef _WIN64
7822
ImGui::Text("define: _WIN64");
7823
#endif
7824
#ifdef __linux__
7825
ImGui::Text("define: __linux__");
7826
#endif
7827
#ifdef __APPLE__
7828
ImGui::Text("define: __APPLE__");
7829
#endif
7830
#ifdef _MSC_VER
7831
ImGui::Text("define: _MSC_VER=%d", _MSC_VER);
7832
#endif
7833
#ifdef _MSVC_LANG
7834
ImGui::Text("define: _MSVC_LANG=%d", (int)_MSVC_LANG);
7835
#endif
7836
#ifdef __MINGW32__
7837
ImGui::Text("define: __MINGW32__");
7838
#endif
7839
#ifdef __MINGW64__
7840
ImGui::Text("define: __MINGW64__");
7841
#endif
7842
#ifdef __GNUC__
7843
ImGui::Text("define: __GNUC__=%d", (int)__GNUC__);
7844
#endif
7845
#ifdef __clang_version__
7846
ImGui::Text("define: __clang_version__=%s", __clang_version__);
7847
#endif
7848
#ifdef __EMSCRIPTEN__
7849
ImGui::Text("define: __EMSCRIPTEN__");
7850
ImGui::Text("Emscripten: %d.%d.%d", __EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__);
7851
#endif
7852
#ifdef IMGUI_HAS_VIEWPORT
7853
ImGui::Text("define: IMGUI_HAS_VIEWPORT");
7854
#endif
7855
#ifdef IMGUI_HAS_DOCK
7856
ImGui::Text("define: IMGUI_HAS_DOCK");
7857
#endif
7858
ImGui::Separator();
7859
ImGui::Text("io.BackendPlatformName: %s", io.BackendPlatformName ? io.BackendPlatformName : "NULL");
7860
ImGui::Text("io.BackendRendererName: %s", io.BackendRendererName ? io.BackendRendererName : "NULL");
7861
ImGui::Text("io.ConfigFlags: 0x%08X", io.ConfigFlags);
7862
if (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) ImGui::Text(" NavEnableKeyboard");
7863
if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) ImGui::Text(" NavEnableGamepad");
7864
if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) ImGui::Text(" NoMouse");
7865
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) ImGui::Text(" NoMouseCursorChange");
7866
if (io.ConfigFlags & ImGuiConfigFlags_NoKeyboard) ImGui::Text(" NoKeyboard");
7867
if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable) ImGui::Text(" DockingEnable");
7868
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) ImGui::Text(" ViewportsEnable");
7869
if (io.ConfigFlags & ImGuiConfigFlags_DpiEnableScaleViewports) ImGui::Text(" DpiEnableScaleViewports");
7870
if (io.ConfigFlags & ImGuiConfigFlags_DpiEnableScaleFonts) ImGui::Text(" DpiEnableScaleFonts");
7871
if (io.MouseDrawCursor) ImGui::Text("io.MouseDrawCursor");
7872
if (io.ConfigViewportsNoAutoMerge) ImGui::Text("io.ConfigViewportsNoAutoMerge");
7873
if (io.ConfigViewportsNoTaskBarIcon) ImGui::Text("io.ConfigViewportsNoTaskBarIcon");
7874
if (io.ConfigViewportsNoDecoration) ImGui::Text("io.ConfigViewportsNoDecoration");
7875
if (io.ConfigViewportsNoDefaultParent) ImGui::Text("io.ConfigViewportsNoDefaultParent");
7876
if (io.ConfigDockingNoSplit) ImGui::Text("io.ConfigDockingNoSplit");
7877
if (io.ConfigDockingWithShift) ImGui::Text("io.ConfigDockingWithShift");
7878
if (io.ConfigDockingAlwaysTabBar) ImGui::Text("io.ConfigDockingAlwaysTabBar");
7879
if (io.ConfigDockingTransparentPayload) ImGui::Text("io.ConfigDockingTransparentPayload");
7880
if (io.ConfigMacOSXBehaviors) ImGui::Text("io.ConfigMacOSXBehaviors");
7881
if (io.ConfigNavMoveSetMousePos) ImGui::Text("io.ConfigNavMoveSetMousePos");
7882
if (io.ConfigNavCaptureKeyboard) ImGui::Text("io.ConfigNavCaptureKeyboard");
7883
if (io.ConfigInputTextCursorBlink) ImGui::Text("io.ConfigInputTextCursorBlink");
7884
if (io.ConfigWindowsResizeFromEdges) ImGui::Text("io.ConfigWindowsResizeFromEdges");
7885
if (io.ConfigWindowsMoveFromTitleBarOnly) ImGui::Text("io.ConfigWindowsMoveFromTitleBarOnly");
7886
if (io.ConfigMemoryCompactTimer >= 0.0f) ImGui::Text("io.ConfigMemoryCompactTimer = %.1f", io.ConfigMemoryCompactTimer);
7887
ImGui::Text("io.BackendFlags: 0x%08X", io.BackendFlags);
7888
if (io.BackendFlags & ImGuiBackendFlags_HasGamepad) ImGui::Text(" HasGamepad");
7889
if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) ImGui::Text(" HasMouseCursors");
7890
if (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos) ImGui::Text(" HasSetMousePos");
7891
if (io.BackendFlags & ImGuiBackendFlags_PlatformHasViewports) ImGui::Text(" PlatformHasViewports");
7892
if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport)ImGui::Text(" HasMouseHoveredViewport");
7893
if (io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) ImGui::Text(" RendererHasVtxOffset");
7894
if (io.BackendFlags & ImGuiBackendFlags_RendererHasViewports) ImGui::Text(" RendererHasViewports");
7895
ImGui::Separator();
7896
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);
7897
ImGui::Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y);
7898
ImGui::Text("io.DisplayFramebufferScale: %.2f,%.2f", io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y);
7899
ImGui::Separator();
7900
ImGui::Text("style.WindowPadding: %.2f,%.2f", style.WindowPadding.x, style.WindowPadding.y);
7901
ImGui::Text("style.WindowBorderSize: %.2f", style.WindowBorderSize);
7902
ImGui::Text("style.FramePadding: %.2f,%.2f", style.FramePadding.x, style.FramePadding.y);
7903
ImGui::Text("style.FrameRounding: %.2f", style.FrameRounding);
7904
ImGui::Text("style.FrameBorderSize: %.2f", style.FrameBorderSize);
7905
ImGui::Text("style.ItemSpacing: %.2f,%.2f", style.ItemSpacing.x, style.ItemSpacing.y);
7906
ImGui::Text("style.ItemInnerSpacing: %.2f,%.2f", style.ItemInnerSpacing.x, style.ItemInnerSpacing.y);
7907
7908
if (copy_to_clipboard)
7909
{
7910
ImGui::LogText("\n```\n");
7911
ImGui::LogFinish();
7912
}
7913
ImGui::EndChild();
7914
}
7915
ImGui::End();
7916
}
7917
7918
//-----------------------------------------------------------------------------
7919
// [SECTION] Style Editor / ShowStyleEditor()
7920
//-----------------------------------------------------------------------------
7921
// - ShowFontSelector()
7922
// - ShowStyleSelector()
7923
// - ShowStyleEditor()
7924
//-----------------------------------------------------------------------------
7925
7926
// Forward declare ShowFontAtlas() which isn't worth putting in public API yet
7927
namespace ImGui { IMGUI_API void ShowFontAtlas(ImFontAtlas* atlas); }
7928
7929
// Demo helper function to select among loaded fonts.
7930
// Here we use the regular BeginCombo()/EndCombo() api which is the more flexible one.
7931
void ImGui::ShowFontSelector(const char* label)
7932
{
7933
ImGuiIO& io = ImGui::GetIO();
7934
ImFont* font_current = ImGui::GetFont();
7935
if (ImGui::BeginCombo(label, font_current->GetDebugName()))
7936
{
7937
for (ImFont* font : io.Fonts->Fonts)
7938
{
7939
ImGui::PushID((void*)font);
7940
if (ImGui::Selectable(font->GetDebugName(), font == font_current))
7941
io.FontDefault = font;
7942
ImGui::PopID();
7943
}
7944
ImGui::EndCombo();
7945
}
7946
ImGui::SameLine();
7947
HelpMarker(
7948
"- Load additional fonts with io.Fonts->AddFontFromFileTTF().\n"
7949
"- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n"
7950
"- Read FAQ and docs/FONTS.md for more details.\n"
7951
"- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame().");
7952
}
7953
7954
// Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options.
7955
// Here we use the simplified Combo() api that packs items into a single literal string.
7956
// Useful for quick combo boxes where the choices are known locally.
7957
bool ImGui::ShowStyleSelector(const char* label)
7958
{
7959
static int style_idx = -1;
7960
if (ImGui::Combo(label, &style_idx, "Dark\0Light\0Classic\0"))
7961
{
7962
switch (style_idx)
7963
{
7964
case 0: ImGui::StyleColorsDark(); break;
7965
case 1: ImGui::StyleColorsLight(); break;
7966
case 2: ImGui::StyleColorsClassic(); break;
7967
}
7968
return true;
7969
}
7970
return false;
7971
}
7972
7973
void ImGui::ShowStyleEditor(ImGuiStyle* ref)
7974
{
7975
IMGUI_DEMO_MARKER("Tools/Style Editor");
7976
// You can pass in a reference ImGuiStyle structure to compare to, revert to and save to
7977
// (without a reference style pointer, we will use one compared locally as a reference)
7978
ImGuiStyle& style = ImGui::GetStyle();
7979
static ImGuiStyle ref_saved_style;
7980
7981
// Default to using internal storage as reference
7982
static bool init = true;
7983
if (init && ref == NULL)
7984
ref_saved_style = style;
7985
init = false;
7986
if (ref == NULL)
7987
ref = &ref_saved_style;
7988
7989
ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.50f);
7990
7991
if (ImGui::ShowStyleSelector("Colors##Selector"))
7992
ref_saved_style = style;
7993
ImGui::ShowFontSelector("Fonts##Selector");
7994
7995
// Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f)
7996
if (ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"))
7997
style.GrabRounding = style.FrameRounding; // Make GrabRounding always the same value as FrameRounding
7998
{ bool border = (style.WindowBorderSize > 0.0f); if (ImGui::Checkbox("WindowBorder", &border)) { style.WindowBorderSize = border ? 1.0f : 0.0f; } }
7999
ImGui::SameLine();
8000
{ bool border = (style.FrameBorderSize > 0.0f); if (ImGui::Checkbox("FrameBorder", &border)) { style.FrameBorderSize = border ? 1.0f : 0.0f; } }
8001
ImGui::SameLine();
8002
{ bool border = (style.PopupBorderSize > 0.0f); if (ImGui::Checkbox("PopupBorder", &border)) { style.PopupBorderSize = border ? 1.0f : 0.0f; } }
8003
8004
// Save/Revert button
8005
if (ImGui::Button("Save Ref"))
8006
*ref = ref_saved_style = style;
8007
ImGui::SameLine();
8008
if (ImGui::Button("Revert Ref"))
8009
style = *ref;
8010
ImGui::SameLine();
8011
HelpMarker(
8012
"Save/Revert in local non-persistent storage. Default Colors definition are not affected. "
8013
"Use \"Export\" below to save them somewhere.");
8014
8015
ImGui::Separator();
8016
8017
if (ImGui::BeginTabBar("##tabs", ImGuiTabBarFlags_None))
8018
{
8019
if (ImGui::BeginTabItem("Sizes"))
8020
{
8021
ImGui::SeparatorText("Main");
8022
ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f");
8023
ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f");
8024
ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f");
8025
ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f");
8026
ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f");
8027
ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f");
8028
ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f");
8029
ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f");
8030
8031
ImGui::SeparatorText("Borders");
8032
ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f");
8033
ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f");
8034
ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f");
8035
ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f");
8036
ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f");
8037
ImGui::SliderFloat("TabBarBorderSize", &style.TabBarBorderSize, 0.0f, 2.0f, "%.0f");
8038
ImGui::SliderFloat("TabBarOverlineSize", &style.TabBarOverlineSize, 0.0f, 2.0f, "%.0f");
8039
ImGui::SameLine(); HelpMarker("Overline is only drawn over the selected tab when ImGuiTabBarFlags_DrawSelectedOverline is set.");
8040
8041
ImGui::SeparatorText("Rounding");
8042
ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f");
8043
ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f");
8044
ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f");
8045
ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f, "%.0f");
8046
ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f");
8047
ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f");
8048
ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f");
8049
8050
ImGui::SeparatorText("Tables");
8051
ImGui::SliderFloat2("CellPadding", (float*)&style.CellPadding, 0.0f, 20.0f, "%.0f");
8052
ImGui::SliderAngle("TableAngledHeadersAngle", &style.TableAngledHeadersAngle, -50.0f, +50.0f);
8053
ImGui::SliderFloat2("TableAngledHeadersTextAlign", (float*)&style.TableAngledHeadersTextAlign, 0.0f, 1.0f, "%.2f");
8054
8055
ImGui::SeparatorText("Widgets");
8056
ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f");
8057
int window_menu_button_position = style.WindowMenuButtonPosition + 1;
8058
if (ImGui::Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0"))
8059
style.WindowMenuButtonPosition = (ImGuiDir)(window_menu_button_position - 1);
8060
ImGui::Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, "Left\0Right\0");
8061
ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f");
8062
ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content.");
8063
ImGui::SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f");
8064
ImGui::SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content.");
8065
ImGui::SliderFloat("SeparatorTextBorderSize", &style.SeparatorTextBorderSize, 0.0f, 10.0f, "%.0f");
8066
ImGui::SliderFloat2("SeparatorTextAlign", (float*)&style.SeparatorTextAlign, 0.0f, 1.0f, "%.2f");
8067
ImGui::SliderFloat2("SeparatorTextPadding", (float*)&style.SeparatorTextPadding, 0.0f, 40.0f, "%.0f");
8068
ImGui::SliderFloat("LogSliderDeadzone", &style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f");
8069
8070
ImGui::SeparatorText("Docking");
8071
ImGui::SliderFloat("DockingSplitterSize", &style.DockingSeparatorSize, 0.0f, 12.0f, "%.0f");
8072
8073
ImGui::SeparatorText("Tooltips");
8074
for (int n = 0; n < 2; n++)
8075
if (ImGui::TreeNodeEx(n == 0 ? "HoverFlagsForTooltipMouse" : "HoverFlagsForTooltipNav"))
8076
{
8077
ImGuiHoveredFlags* p = (n == 0) ? &style.HoverFlagsForTooltipMouse : &style.HoverFlagsForTooltipNav;
8078
ImGui::CheckboxFlags("ImGuiHoveredFlags_DelayNone", p, ImGuiHoveredFlags_DelayNone);
8079
ImGui::CheckboxFlags("ImGuiHoveredFlags_DelayShort", p, ImGuiHoveredFlags_DelayShort);
8080
ImGui::CheckboxFlags("ImGuiHoveredFlags_DelayNormal", p, ImGuiHoveredFlags_DelayNormal);
8081
ImGui::CheckboxFlags("ImGuiHoveredFlags_Stationary", p, ImGuiHoveredFlags_Stationary);
8082
ImGui::CheckboxFlags("ImGuiHoveredFlags_NoSharedDelay", p, ImGuiHoveredFlags_NoSharedDelay);
8083
ImGui::TreePop();
8084
}
8085
8086
ImGui::SeparatorText("Misc");
8087
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.");
8088
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).");
8089
8090
ImGui::EndTabItem();
8091
}
8092
8093
if (ImGui::BeginTabItem("Colors"))
8094
{
8095
static int output_dest = 0;
8096
static bool output_only_modified = true;
8097
if (ImGui::Button("Export"))
8098
{
8099
if (output_dest == 0)
8100
ImGui::LogToClipboard();
8101
else
8102
ImGui::LogToTTY();
8103
ImGui::LogText("ImVec4* colors = ImGui::GetStyle().Colors;" IM_NEWLINE);
8104
for (int i = 0; i < ImGuiCol_COUNT; i++)
8105
{
8106
const ImVec4& col = style.Colors[i];
8107
const char* name = ImGui::GetStyleColorName(i);
8108
if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0)
8109
ImGui::LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE,
8110
name, 23 - (int)strlen(name), "", col.x, col.y, col.z, col.w);
8111
}
8112
ImGui::LogFinish();
8113
}
8114
ImGui::SameLine(); ImGui::SetNextItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0");
8115
ImGui::SameLine(); ImGui::Checkbox("Only Modified Colors", &output_only_modified);
8116
8117
static ImGuiTextFilter filter;
8118
filter.Draw("Filter colors", ImGui::GetFontSize() * 16);
8119
8120
static ImGuiColorEditFlags alpha_flags = 0;
8121
if (ImGui::RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_None)) { alpha_flags = ImGuiColorEditFlags_None; } ImGui::SameLine();
8122
if (ImGui::RadioButton("Alpha", alpha_flags == ImGuiColorEditFlags_AlphaPreview)) { alpha_flags = ImGuiColorEditFlags_AlphaPreview; } ImGui::SameLine();
8123
if (ImGui::RadioButton("Both", alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } ImGui::SameLine();
8124
HelpMarker(
8125
"In the color list:\n"
8126
"Left-click on color square to open color picker,\n"
8127
"Right-click to open edit options menu.");
8128
8129
ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 10), ImVec2(FLT_MAX, FLT_MAX));
8130
ImGui::BeginChild("##colors", ImVec2(0, 0), ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar);
8131
ImGui::PushItemWidth(ImGui::GetFontSize() * -12);
8132
for (int i = 0; i < ImGuiCol_COUNT; i++)
8133
{
8134
const char* name = ImGui::GetStyleColorName(i);
8135
if (!filter.PassFilter(name))
8136
continue;
8137
ImGui::PushID(i);
8138
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
8139
if (ImGui::Button("?"))
8140
ImGui::DebugFlashStyleColor((ImGuiCol)i);
8141
ImGui::SetItemTooltip("Flash given color to identify places where it is used.");
8142
ImGui::SameLine();
8143
#endif
8144
ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags);
8145
if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0)
8146
{
8147
// Tips: in a real user application, you may want to merge and use an icon font into the main font,
8148
// so instead of "Save"/"Revert" you'd use icons!
8149
// Read the FAQ and docs/FONTS.md about using icon fonts. It's really easy and super convenient!
8150
ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) { ref->Colors[i] = style.Colors[i]; }
8151
ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) { style.Colors[i] = ref->Colors[i]; }
8152
}
8153
ImGui::SameLine(0.0f, style.ItemInnerSpacing.x);
8154
ImGui::TextUnformatted(name);
8155
ImGui::PopID();
8156
}
8157
ImGui::PopItemWidth();
8158
ImGui::EndChild();
8159
8160
ImGui::EndTabItem();
8161
}
8162
8163
if (ImGui::BeginTabItem("Fonts"))
8164
{
8165
ImGuiIO& io = ImGui::GetIO();
8166
ImFontAtlas* atlas = io.Fonts;
8167
HelpMarker("Read FAQ and docs/FONTS.md for details on font loading.");
8168
ImGui::ShowFontAtlas(atlas);
8169
8170
// Post-baking font scaling. Note that this is NOT the nice way of scaling fonts, read below.
8171
// (we enforce hard clamping manually as by default DragFloat/SliderFloat allows CTRL+Click text to get out of bounds).
8172
const float MIN_SCALE = 0.3f;
8173
const float MAX_SCALE = 2.0f;
8174
HelpMarker(
8175
"Those are old settings provided for convenience.\n"
8176
"However, the _correct_ way of scaling your UI is currently to reload your font at the designed size, "
8177
"rebuild the font atlas, and call style.ScaleAllSizes() on a reference ImGuiStyle structure.\n"
8178
"Using those settings here will give you poor quality results.");
8179
static float window_scale = 1.0f;
8180
ImGui::PushItemWidth(ImGui::GetFontSize() * 8);
8181
if (ImGui::DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp)) // Scale only this window
8182
ImGui::SetWindowFontScale(window_scale);
8183
ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp); // Scale everything
8184
ImGui::PopItemWidth();
8185
8186
ImGui::EndTabItem();
8187
}
8188
8189
if (ImGui::BeginTabItem("Rendering"))
8190
{
8191
ImGui::Checkbox("Anti-aliased lines", &style.AntiAliasedLines);
8192
ImGui::SameLine();
8193
HelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well.");
8194
8195
ImGui::Checkbox("Anti-aliased lines use texture", &style.AntiAliasedLinesUseTex);
8196
ImGui::SameLine();
8197
HelpMarker("Faster lines using texture data. Require backend to render with bilinear filtering (not point/nearest filtering).");
8198
8199
ImGui::Checkbox("Anti-aliased fill", &style.AntiAliasedFill);
8200
ImGui::PushItemWidth(ImGui::GetFontSize() * 8);
8201
ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, 10.0f, "%.2f");
8202
if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f;
8203
8204
// When editing the "Circle Segment Max Error" value, draw a preview of its effect on auto-tessellated circles.
8205
ImGui::DragFloat("Circle Tessellation Max Error", &style.CircleTessellationMaxError , 0.005f, 0.10f, 5.0f, "%.2f", ImGuiSliderFlags_AlwaysClamp);
8206
const bool show_samples = ImGui::IsItemActive();
8207
if (show_samples)
8208
ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos());
8209
if (show_samples && ImGui::BeginTooltip())
8210
{
8211
ImGui::TextUnformatted("(R = radius, N = approx number of segments)");
8212
ImGui::Spacing();
8213
ImDrawList* draw_list = ImGui::GetWindowDrawList();
8214
const float min_widget_width = ImGui::CalcTextSize("R: MMM\nN: MMM").x;
8215
for (int n = 0; n < 8; n++)
8216
{
8217
const float RAD_MIN = 5.0f;
8218
const float RAD_MAX = 70.0f;
8219
const float rad = RAD_MIN + (RAD_MAX - RAD_MIN) * (float)n / (8.0f - 1.0f);
8220
8221
ImGui::BeginGroup();
8222
8223
// N is not always exact here due to how PathArcTo() function work internally
8224
ImGui::Text("R: %.f\nN: %d", rad, draw_list->_CalcCircleAutoSegmentCount(rad));
8225
8226
const float canvas_width = IM_MAX(min_widget_width, rad * 2.0f);
8227
const float offset_x = floorf(canvas_width * 0.5f);
8228
const float offset_y = floorf(RAD_MAX);
8229
8230
const ImVec2 p1 = ImGui::GetCursorScreenPos();
8231
draw_list->AddCircle(ImVec2(p1.x + offset_x, p1.y + offset_y), rad, ImGui::GetColorU32(ImGuiCol_Text));
8232
ImGui::Dummy(ImVec2(canvas_width, RAD_MAX * 2));
8233
8234
/*
8235
const ImVec2 p2 = ImGui::GetCursorScreenPos();
8236
draw_list->AddCircleFilled(ImVec2(p2.x + offset_x, p2.y + offset_y), rad, ImGui::GetColorU32(ImGuiCol_Text));
8237
ImGui::Dummy(ImVec2(canvas_width, RAD_MAX * 2));
8238
*/
8239
8240
ImGui::EndGroup();
8241
ImGui::SameLine();
8242
}
8243
ImGui::EndTooltip();
8244
}
8245
ImGui::SameLine();
8246
HelpMarker("When drawing circle primitives with \"num_segments == 0\" tesselation will be calculated automatically.");
8247
8248
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.
8249
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).");
8250
ImGui::PopItemWidth();
8251
8252
ImGui::EndTabItem();
8253
}
8254
8255
ImGui::EndTabBar();
8256
}
8257
8258
ImGui::PopItemWidth();
8259
}
8260
8261
//-----------------------------------------------------------------------------
8262
// [SECTION] User Guide / ShowUserGuide()
8263
//-----------------------------------------------------------------------------
8264
8265
void ImGui::ShowUserGuide()
8266
{
8267
ImGuiIO& io = ImGui::GetIO();
8268
ImGui::BulletText("Double-click on title bar to collapse window.");
8269
ImGui::BulletText(
8270
"Click and drag on lower corner to resize window\n"
8271
"(double-click to auto fit window to its contents).");
8272
ImGui::BulletText("CTRL+Click on a slider or drag box to input value as text.");
8273
ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields.");
8274
ImGui::BulletText("CTRL+Tab to select a window.");
8275
if (io.FontAllowUserScaling)
8276
ImGui::BulletText("CTRL+Mouse Wheel to zoom window contents.");
8277
ImGui::BulletText("While inputing text:\n");
8278
ImGui::Indent();
8279
ImGui::BulletText("CTRL+Left/Right to word jump.");
8280
ImGui::BulletText("CTRL+A or double-click to select all.");
8281
ImGui::BulletText("CTRL+X/C/V to use clipboard cut/copy/paste.");
8282
ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo.");
8283
ImGui::BulletText("ESCAPE to revert.");
8284
ImGui::Unindent();
8285
ImGui::BulletText("With keyboard navigation enabled:");
8286
ImGui::Indent();
8287
ImGui::BulletText("Arrow keys to navigate.");
8288
ImGui::BulletText("Space to activate a widget.");
8289
ImGui::BulletText("Return to input text into a widget.");
8290
ImGui::BulletText("Escape to deactivate a widget, close popup, exit child window.");
8291
ImGui::BulletText("Alt to jump to the menu layer of a window.");
8292
ImGui::Unindent();
8293
}
8294
8295
//-----------------------------------------------------------------------------
8296
// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar()
8297
//-----------------------------------------------------------------------------
8298
// - ShowExampleAppMainMenuBar()
8299
// - ShowExampleMenuFile()
8300
//-----------------------------------------------------------------------------
8301
8302
// Demonstrate creating a "main" fullscreen menu bar and populating it.
8303
// Note the difference between BeginMainMenuBar() and BeginMenuBar():
8304
// - BeginMenuBar() = menu-bar inside current window (which needs the ImGuiWindowFlags_MenuBar flag!)
8305
// - BeginMainMenuBar() = helper to create menu-bar-sized window at the top of the main viewport + call BeginMenuBar() into it.
8306
static void ShowExampleAppMainMenuBar()
8307
{
8308
if (ImGui::BeginMainMenuBar())
8309
{
8310
if (ImGui::BeginMenu("File"))
8311
{
8312
ShowExampleMenuFile();
8313
ImGui::EndMenu();
8314
}
8315
if (ImGui::BeginMenu("Edit"))
8316
{
8317
if (ImGui::MenuItem("Undo", "CTRL+Z")) {}
8318
if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) {} // Disabled item
8319
ImGui::Separator();
8320
if (ImGui::MenuItem("Cut", "CTRL+X")) {}
8321
if (ImGui::MenuItem("Copy", "CTRL+C")) {}
8322
if (ImGui::MenuItem("Paste", "CTRL+V")) {}
8323
ImGui::EndMenu();
8324
}
8325
ImGui::EndMainMenuBar();
8326
}
8327
}
8328
8329
// Note that shortcuts are currently provided for display only
8330
// (future version will add explicit flags to BeginMenu() to request processing shortcuts)
8331
static void ShowExampleMenuFile()
8332
{
8333
IMGUI_DEMO_MARKER("Examples/Menu");
8334
ImGui::MenuItem("(demo menu)", NULL, false, false);
8335
if (ImGui::MenuItem("New")) {}
8336
if (ImGui::MenuItem("Open", "Ctrl+O")) {}
8337
if (ImGui::BeginMenu("Open Recent"))
8338
{
8339
ImGui::MenuItem("fish_hat.c");
8340
ImGui::MenuItem("fish_hat.inl");
8341
ImGui::MenuItem("fish_hat.h");
8342
if (ImGui::BeginMenu("More.."))
8343
{
8344
ImGui::MenuItem("Hello");
8345
ImGui::MenuItem("Sailor");
8346
if (ImGui::BeginMenu("Recurse.."))
8347
{
8348
ShowExampleMenuFile();
8349
ImGui::EndMenu();
8350
}
8351
ImGui::EndMenu();
8352
}
8353
ImGui::EndMenu();
8354
}
8355
if (ImGui::MenuItem("Save", "Ctrl+S")) {}
8356
if (ImGui::MenuItem("Save As..")) {}
8357
8358
ImGui::Separator();
8359
IMGUI_DEMO_MARKER("Examples/Menu/Options");
8360
if (ImGui::BeginMenu("Options"))
8361
{
8362
static bool enabled = true;
8363
ImGui::MenuItem("Enabled", "", &enabled);
8364
ImGui::BeginChild("child", ImVec2(0, 60), ImGuiChildFlags_Borders);
8365
for (int i = 0; i < 10; i++)
8366
ImGui::Text("Scrolling Text %d", i);
8367
ImGui::EndChild();
8368
static float f = 0.5f;
8369
static int n = 0;
8370
ImGui::SliderFloat("Value", &f, 0.0f, 1.0f);
8371
ImGui::InputFloat("Input", &f, 0.1f);
8372
ImGui::Combo("Combo", &n, "Yes\0No\0Maybe\0\0");
8373
ImGui::EndMenu();
8374
}
8375
8376
IMGUI_DEMO_MARKER("Examples/Menu/Colors");
8377
if (ImGui::BeginMenu("Colors"))
8378
{
8379
float sz = ImGui::GetTextLineHeight();
8380
for (int i = 0; i < ImGuiCol_COUNT; i++)
8381
{
8382
const char* name = ImGui::GetStyleColorName((ImGuiCol)i);
8383
ImVec2 p = ImGui::GetCursorScreenPos();
8384
ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + sz, p.y + sz), ImGui::GetColorU32((ImGuiCol)i));
8385
ImGui::Dummy(ImVec2(sz, sz));
8386
ImGui::SameLine();
8387
ImGui::MenuItem(name);
8388
}
8389
ImGui::EndMenu();
8390
}
8391
8392
// Here we demonstrate appending again to the "Options" menu (which we already created above)
8393
// Of course in this demo it is a little bit silly that this function calls BeginMenu("Options") twice.
8394
// In a real code-base using it would make senses to use this feature from very different code locations.
8395
if (ImGui::BeginMenu("Options")) // <-- Append!
8396
{
8397
IMGUI_DEMO_MARKER("Examples/Menu/Append to an existing menu");
8398
static bool b = true;
8399
ImGui::Checkbox("SomeOption", &b);
8400
ImGui::EndMenu();
8401
}
8402
8403
if (ImGui::BeginMenu("Disabled", false)) // Disabled
8404
{
8405
IM_ASSERT(0);
8406
}
8407
if (ImGui::MenuItem("Checked", NULL, true)) {}
8408
ImGui::Separator();
8409
if (ImGui::MenuItem("Quit", "Alt+F4")) {}
8410
}
8411
8412
//-----------------------------------------------------------------------------
8413
// [SECTION] Example App: Debug Console / ShowExampleAppConsole()
8414
//-----------------------------------------------------------------------------
8415
8416
// Demonstrate creating a simple console window, with scrolling, filtering, completion and history.
8417
// For the console example, we are using a more C++ like approach of declaring a class to hold both data and functions.
8418
struct ExampleAppConsole
8419
{
8420
char InputBuf[256];
8421
ImVector<char*> Items;
8422
ImVector<const char*> Commands;
8423
ImVector<char*> History;
8424
int HistoryPos; // -1: new line, 0..History.Size-1 browsing history.
8425
ImGuiTextFilter Filter;
8426
bool AutoScroll;
8427
bool ScrollToBottom;
8428
8429
ExampleAppConsole()
8430
{
8431
IMGUI_DEMO_MARKER("Examples/Console");
8432
ClearLog();
8433
memset(InputBuf, 0, sizeof(InputBuf));
8434
HistoryPos = -1;
8435
8436
// "CLASSIFY" is here to provide the test case where "C"+[tab] completes to "CL" and display multiple matches.
8437
Commands.push_back("HELP");
8438
Commands.push_back("HISTORY");
8439
Commands.push_back("CLEAR");
8440
Commands.push_back("CLASSIFY");
8441
AutoScroll = true;
8442
ScrollToBottom = false;
8443
AddLog("Welcome to Dear ImGui!");
8444
}
8445
~ExampleAppConsole()
8446
{
8447
ClearLog();
8448
for (int i = 0; i < History.Size; i++)
8449
ImGui::MemFree(History[i]);
8450
}
8451
8452
// Portable helpers
8453
static int Stricmp(const char* s1, const char* s2) { int d; while ((d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; } return d; }
8454
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; }
8455
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); }
8456
static void Strtrim(char* s) { char* str_end = s + strlen(s); while (str_end > s && str_end[-1] == ' ') str_end--; *str_end = 0; }
8457
8458
void ClearLog()
8459
{
8460
for (int i = 0; i < Items.Size; i++)
8461
ImGui::MemFree(Items[i]);
8462
Items.clear();
8463
}
8464
8465
void AddLog(const char* fmt, ...) IM_FMTARGS(2)
8466
{
8467
// FIXME-OPT
8468
char buf[1024];
8469
va_list args;
8470
va_start(args, fmt);
8471
vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args);
8472
buf[IM_ARRAYSIZE(buf)-1] = 0;
8473
va_end(args);
8474
Items.push_back(Strdup(buf));
8475
}
8476
8477
void Draw(const char* title, bool* p_open)
8478
{
8479
ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
8480
if (!ImGui::Begin(title, p_open))
8481
{
8482
ImGui::End();
8483
return;
8484
}
8485
8486
// As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar.
8487
// So e.g. IsItemHovered() will return true when hovering the title bar.
8488
// Here we create a context menu only available from the title bar.
8489
if (ImGui::BeginPopupContextItem())
8490
{
8491
if (ImGui::MenuItem("Close Console"))
8492
*p_open = false;
8493
ImGui::EndPopup();
8494
}
8495
8496
ImGui::TextWrapped(
8497
"This example implements a console with basic coloring, completion (TAB key) and history (Up/Down keys). A more elaborate "
8498
"implementation may want to store entries along with extra data such as timestamp, emitter, etc.");
8499
ImGui::TextWrapped("Enter 'HELP' for help.");
8500
8501
// TODO: display items starting from the bottom
8502
8503
if (ImGui::SmallButton("Add Debug Text")) { AddLog("%d some text", Items.Size); AddLog("some more text"); AddLog("display very important message here!"); }
8504
ImGui::SameLine();
8505
if (ImGui::SmallButton("Add Debug Error")) { AddLog("[error] something went wrong"); }
8506
ImGui::SameLine();
8507
if (ImGui::SmallButton("Clear")) { ClearLog(); }
8508
ImGui::SameLine();
8509
bool copy_to_clipboard = ImGui::SmallButton("Copy");
8510
//static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); }
8511
8512
ImGui::Separator();
8513
8514
// Options menu
8515
if (ImGui::BeginPopup("Options"))
8516
{
8517
ImGui::Checkbox("Auto-scroll", &AutoScroll);
8518
ImGui::EndPopup();
8519
}
8520
8521
// Options, Filter
8522
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_O, ImGuiInputFlags_Tooltip);
8523
if (ImGui::Button("Options"))
8524
ImGui::OpenPopup("Options");
8525
ImGui::SameLine();
8526
Filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180);
8527
ImGui::Separator();
8528
8529
// Reserve enough left-over height for 1 separator + 1 input text
8530
const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
8531
if (ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_HorizontalScrollbar))
8532
{
8533
if (ImGui::BeginPopupContextWindow())
8534
{
8535
if (ImGui::Selectable("Clear")) ClearLog();
8536
ImGui::EndPopup();
8537
}
8538
8539
// Display every line as a separate entry so we can change their color or add custom widgets.
8540
// If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end());
8541
// NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping
8542
// to only process visible items. The clipper will automatically measure the height of your first item and then
8543
// "seek" to display only items in the visible area.
8544
// To use the clipper we can replace your standard loop:
8545
// for (int i = 0; i < Items.Size; i++)
8546
// With:
8547
// ImGuiListClipper clipper;
8548
// clipper.Begin(Items.Size);
8549
// while (clipper.Step())
8550
// for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
8551
// - That your items are evenly spaced (same height)
8552
// - That you have cheap random access to your elements (you can access them given their index,
8553
// without processing all the ones before)
8554
// You cannot this code as-is if a filter is active because it breaks the 'cheap random-access' property.
8555
// We would need random-access on the post-filtered list.
8556
// A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices
8557
// or offsets of items that passed the filtering test, recomputing this array when user changes the filter,
8558
// and appending newly elements as they are inserted. This is left as a task to the user until we can manage
8559
// to improve this example code!
8560
// If your items are of variable height:
8561
// - Split them into same height items would be simpler and facilitate random-seeking into your list.
8562
// - Consider using manual call to IsRectVisible() and skipping extraneous decoration from your items.
8563
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing
8564
if (copy_to_clipboard)
8565
ImGui::LogToClipboard();
8566
for (const char* item : Items)
8567
{
8568
if (!Filter.PassFilter(item))
8569
continue;
8570
8571
// Normally you would store more information in your item than just a string.
8572
// (e.g. make Items[] an array of structure, store color/type etc.)
8573
ImVec4 color;
8574
bool has_color = false;
8575
if (strstr(item, "[error]")) { color = ImVec4(1.0f, 0.4f, 0.4f, 1.0f); has_color = true; }
8576
else if (strncmp(item, "# ", 2) == 0) { color = ImVec4(1.0f, 0.8f, 0.6f, 1.0f); has_color = true; }
8577
if (has_color)
8578
ImGui::PushStyleColor(ImGuiCol_Text, color);
8579
ImGui::TextUnformatted(item);
8580
if (has_color)
8581
ImGui::PopStyleColor();
8582
}
8583
if (copy_to_clipboard)
8584
ImGui::LogFinish();
8585
8586
// Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame.
8587
// Using a scrollbar or mouse-wheel will take away from the bottom edge.
8588
if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()))
8589
ImGui::SetScrollHereY(1.0f);
8590
ScrollToBottom = false;
8591
8592
ImGui::PopStyleVar();
8593
}
8594
ImGui::EndChild();
8595
ImGui::Separator();
8596
8597
// Command-line
8598
bool reclaim_focus = false;
8599
ImGuiInputTextFlags input_text_flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_EscapeClearsAll | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory;
8600
if (ImGui::InputText("Input", InputBuf, IM_ARRAYSIZE(InputBuf), input_text_flags, &TextEditCallbackStub, (void*)this))
8601
{
8602
char* s = InputBuf;
8603
Strtrim(s);
8604
if (s[0])
8605
ExecCommand(s);
8606
strcpy(s, "");
8607
reclaim_focus = true;
8608
}
8609
8610
// Auto-focus on window apparition
8611
ImGui::SetItemDefaultFocus();
8612
if (reclaim_focus)
8613
ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget
8614
8615
ImGui::End();
8616
}
8617
8618
void ExecCommand(const char* command_line)
8619
{
8620
AddLog("# %s\n", command_line);
8621
8622
// Insert into history. First find match and delete it so it can be pushed to the back.
8623
// This isn't trying to be smart or optimal.
8624
HistoryPos = -1;
8625
for (int i = History.Size - 1; i >= 0; i--)
8626
if (Stricmp(History[i], command_line) == 0)
8627
{
8628
ImGui::MemFree(History[i]);
8629
History.erase(History.begin() + i);
8630
break;
8631
}
8632
History.push_back(Strdup(command_line));
8633
8634
// Process command
8635
if (Stricmp(command_line, "CLEAR") == 0)
8636
{
8637
ClearLog();
8638
}
8639
else if (Stricmp(command_line, "HELP") == 0)
8640
{
8641
AddLog("Commands:");
8642
for (int i = 0; i < Commands.Size; i++)
8643
AddLog("- %s", Commands[i]);
8644
}
8645
else if (Stricmp(command_line, "HISTORY") == 0)
8646
{
8647
int first = History.Size - 10;
8648
for (int i = first > 0 ? first : 0; i < History.Size; i++)
8649
AddLog("%3d: %s\n", i, History[i]);
8650
}
8651
else
8652
{
8653
AddLog("Unknown command: '%s'\n", command_line);
8654
}
8655
8656
// On command input, we scroll to bottom even if AutoScroll==false
8657
ScrollToBottom = true;
8658
}
8659
8660
// In C++11 you'd be better off using lambdas for this sort of forwarding callbacks
8661
static int TextEditCallbackStub(ImGuiInputTextCallbackData* data)
8662
{
8663
ExampleAppConsole* console = (ExampleAppConsole*)data->UserData;
8664
return console->TextEditCallback(data);
8665
}
8666
8667
int TextEditCallback(ImGuiInputTextCallbackData* data)
8668
{
8669
//AddLog("cursor: %d, selection: %d-%d", data->CursorPos, data->SelectionStart, data->SelectionEnd);
8670
switch (data->EventFlag)
8671
{
8672
case ImGuiInputTextFlags_CallbackCompletion:
8673
{
8674
// Example of TEXT COMPLETION
8675
8676
// Locate beginning of current word
8677
const char* word_end = data->Buf + data->CursorPos;
8678
const char* word_start = word_end;
8679
while (word_start > data->Buf)
8680
{
8681
const char c = word_start[-1];
8682
if (c == ' ' || c == '\t' || c == ',' || c == ';')
8683
break;
8684
word_start--;
8685
}
8686
8687
// Build a list of candidates
8688
ImVector<const char*> candidates;
8689
for (int i = 0; i < Commands.Size; i++)
8690
if (Strnicmp(Commands[i], word_start, (int)(word_end - word_start)) == 0)
8691
candidates.push_back(Commands[i]);
8692
8693
if (candidates.Size == 0)
8694
{
8695
// No match
8696
AddLog("No match for \"%.*s\"!\n", (int)(word_end - word_start), word_start);
8697
}
8698
else if (candidates.Size == 1)
8699
{
8700
// Single match. Delete the beginning of the word and replace it entirely so we've got nice casing.
8701
data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start));
8702
data->InsertChars(data->CursorPos, candidates[0]);
8703
data->InsertChars(data->CursorPos, " ");
8704
}
8705
else
8706
{
8707
// Multiple matches. Complete as much as we can..
8708
// So inputing "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches.
8709
int match_len = (int)(word_end - word_start);
8710
for (;;)
8711
{
8712
int c = 0;
8713
bool all_candidates_matches = true;
8714
for (int i = 0; i < candidates.Size && all_candidates_matches; i++)
8715
if (i == 0)
8716
c = toupper(candidates[i][match_len]);
8717
else if (c == 0 || c != toupper(candidates[i][match_len]))
8718
all_candidates_matches = false;
8719
if (!all_candidates_matches)
8720
break;
8721
match_len++;
8722
}
8723
8724
if (match_len > 0)
8725
{
8726
data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start));
8727
data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len);
8728
}
8729
8730
// List matches
8731
AddLog("Possible matches:\n");
8732
for (int i = 0; i < candidates.Size; i++)
8733
AddLog("- %s\n", candidates[i]);
8734
}
8735
8736
break;
8737
}
8738
case ImGuiInputTextFlags_CallbackHistory:
8739
{
8740
// Example of HISTORY
8741
const int prev_history_pos = HistoryPos;
8742
if (data->EventKey == ImGuiKey_UpArrow)
8743
{
8744
if (HistoryPos == -1)
8745
HistoryPos = History.Size - 1;
8746
else if (HistoryPos > 0)
8747
HistoryPos--;
8748
}
8749
else if (data->EventKey == ImGuiKey_DownArrow)
8750
{
8751
if (HistoryPos != -1)
8752
if (++HistoryPos >= History.Size)
8753
HistoryPos = -1;
8754
}
8755
8756
// A better implementation would preserve the data on the current input line along with cursor position.
8757
if (prev_history_pos != HistoryPos)
8758
{
8759
const char* history_str = (HistoryPos >= 0) ? History[HistoryPos] : "";
8760
data->DeleteChars(0, data->BufTextLen);
8761
data->InsertChars(0, history_str);
8762
}
8763
}
8764
}
8765
return 0;
8766
}
8767
};
8768
8769
static void ShowExampleAppConsole(bool* p_open)
8770
{
8771
static ExampleAppConsole console;
8772
console.Draw("Example: Console", p_open);
8773
}
8774
8775
//-----------------------------------------------------------------------------
8776
// [SECTION] Example App: Debug Log / ShowExampleAppLog()
8777
//-----------------------------------------------------------------------------
8778
8779
// Usage:
8780
// static ExampleAppLog my_log;
8781
// my_log.AddLog("Hello %d world\n", 123);
8782
// my_log.Draw("title");
8783
struct ExampleAppLog
8784
{
8785
ImGuiTextBuffer Buf;
8786
ImGuiTextFilter Filter;
8787
ImVector<int> LineOffsets; // Index to lines offset. We maintain this with AddLog() calls.
8788
bool AutoScroll; // Keep scrolling if already at the bottom.
8789
8790
ExampleAppLog()
8791
{
8792
AutoScroll = true;
8793
Clear();
8794
}
8795
8796
void Clear()
8797
{
8798
Buf.clear();
8799
LineOffsets.clear();
8800
LineOffsets.push_back(0);
8801
}
8802
8803
void AddLog(const char* fmt, ...) IM_FMTARGS(2)
8804
{
8805
int old_size = Buf.size();
8806
va_list args;
8807
va_start(args, fmt);
8808
Buf.appendfv(fmt, args);
8809
va_end(args);
8810
for (int new_size = Buf.size(); old_size < new_size; old_size++)
8811
if (Buf[old_size] == '\n')
8812
LineOffsets.push_back(old_size + 1);
8813
}
8814
8815
void Draw(const char* title, bool* p_open = NULL)
8816
{
8817
if (!ImGui::Begin(title, p_open))
8818
{
8819
ImGui::End();
8820
return;
8821
}
8822
8823
// Options menu
8824
if (ImGui::BeginPopup("Options"))
8825
{
8826
ImGui::Checkbox("Auto-scroll", &AutoScroll);
8827
ImGui::EndPopup();
8828
}
8829
8830
// Main window
8831
if (ImGui::Button("Options"))
8832
ImGui::OpenPopup("Options");
8833
ImGui::SameLine();
8834
bool clear = ImGui::Button("Clear");
8835
ImGui::SameLine();
8836
bool copy = ImGui::Button("Copy");
8837
ImGui::SameLine();
8838
Filter.Draw("Filter", -100.0f);
8839
8840
ImGui::Separator();
8841
8842
if (ImGui::BeginChild("scrolling", ImVec2(0, 0), ImGuiChildFlags_None, ImGuiWindowFlags_HorizontalScrollbar))
8843
{
8844
if (clear)
8845
Clear();
8846
if (copy)
8847
ImGui::LogToClipboard();
8848
8849
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
8850
const char* buf = Buf.begin();
8851
const char* buf_end = Buf.end();
8852
if (Filter.IsActive())
8853
{
8854
// In this example we don't use the clipper when Filter is enabled.
8855
// This is because we don't have random access to the result of our filter.
8856
// A real application processing logs with ten of thousands of entries may want to store the result of
8857
// search/filter.. especially if the filtering function is not trivial (e.g. reg-exp).
8858
for (int line_no = 0; line_no < LineOffsets.Size; line_no++)
8859
{
8860
const char* line_start = buf + LineOffsets[line_no];
8861
const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
8862
if (Filter.PassFilter(line_start, line_end))
8863
ImGui::TextUnformatted(line_start, line_end);
8864
}
8865
}
8866
else
8867
{
8868
// The simplest and easy way to display the entire buffer:
8869
// ImGui::TextUnformatted(buf_begin, buf_end);
8870
// And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward
8871
// to skip non-visible lines. Here we instead demonstrate using the clipper to only process lines that are
8872
// within the visible area.
8873
// If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them
8874
// on your side is recommended. Using ImGuiListClipper requires
8875
// - A) random access into your data
8876
// - B) items all being the same height,
8877
// both of which we can handle since we have an array pointing to the beginning of each line of text.
8878
// When using the filter (in the block of code above) we don't have random access into the data to display
8879
// anymore, which is why we don't use the clipper. Storing or skimming through the search result would make
8880
// it possible (and would be recommended if you want to search through tens of thousands of entries).
8881
ImGuiListClipper clipper;
8882
clipper.Begin(LineOffsets.Size);
8883
while (clipper.Step())
8884
{
8885
for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++)
8886
{
8887
const char* line_start = buf + LineOffsets[line_no];
8888
const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
8889
ImGui::TextUnformatted(line_start, line_end);
8890
}
8891
}
8892
clipper.End();
8893
}
8894
ImGui::PopStyleVar();
8895
8896
// Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame.
8897
// Using a scrollbar or mouse-wheel will take away from the bottom edge.
8898
if (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())
8899
ImGui::SetScrollHereY(1.0f);
8900
}
8901
ImGui::EndChild();
8902
ImGui::End();
8903
}
8904
};
8905
8906
// Demonstrate creating a simple log window with basic filtering.
8907
static void ShowExampleAppLog(bool* p_open)
8908
{
8909
static ExampleAppLog log;
8910
8911
// For the demo: add a debug button _BEFORE_ the normal log window contents
8912
// We take advantage of a rarely used feature: multiple calls to Begin()/End() are appending to the _same_ window.
8913
// Most of the contents of the window will be added by the log.Draw() call.
8914
ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver);
8915
ImGui::Begin("Example: Log", p_open);
8916
IMGUI_DEMO_MARKER("Examples/Log");
8917
if (ImGui::SmallButton("[Debug] Add 5 entries"))
8918
{
8919
static int counter = 0;
8920
const char* categories[3] = { "info", "warn", "error" };
8921
const char* words[] = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" };
8922
for (int n = 0; n < 5; n++)
8923
{
8924
const char* category = categories[counter % IM_ARRAYSIZE(categories)];
8925
const char* word = words[counter % IM_ARRAYSIZE(words)];
8926
log.AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n",
8927
ImGui::GetFrameCount(), category, ImGui::GetTime(), word);
8928
counter++;
8929
}
8930
}
8931
ImGui::End();
8932
8933
// Actually call in the regular Log helper (which will Begin() into the same window as we just did)
8934
log.Draw("Example: Log", p_open);
8935
}
8936
8937
//-----------------------------------------------------------------------------
8938
// [SECTION] Example App: Simple Layout / ShowExampleAppLayout()
8939
//-----------------------------------------------------------------------------
8940
8941
// Demonstrate create a window with multiple child windows.
8942
static void ShowExampleAppLayout(bool* p_open)
8943
{
8944
ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiCond_FirstUseEver);
8945
if (ImGui::Begin("Example: Simple layout", p_open, ImGuiWindowFlags_MenuBar))
8946
{
8947
IMGUI_DEMO_MARKER("Examples/Simple layout");
8948
if (ImGui::BeginMenuBar())
8949
{
8950
if (ImGui::BeginMenu("File"))
8951
{
8952
if (ImGui::MenuItem("Close", "Ctrl+W")) { *p_open = false; }
8953
ImGui::EndMenu();
8954
}
8955
ImGui::EndMenuBar();
8956
}
8957
8958
// Left
8959
static int selected = 0;
8960
{
8961
ImGui::BeginChild("left pane", ImVec2(150, 0), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeX);
8962
for (int i = 0; i < 100; i++)
8963
{
8964
// FIXME: Good candidate to use ImGuiSelectableFlags_SelectOnNav
8965
char label[128];
8966
sprintf(label, "MyObject %d", i);
8967
if (ImGui::Selectable(label, selected == i))
8968
selected = i;
8969
}
8970
ImGui::EndChild();
8971
}
8972
ImGui::SameLine();
8973
8974
// Right
8975
{
8976
ImGui::BeginGroup();
8977
ImGui::BeginChild("item view", ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us
8978
ImGui::Text("MyObject: %d", selected);
8979
ImGui::Separator();
8980
if (ImGui::BeginTabBar("##Tabs", ImGuiTabBarFlags_None))
8981
{
8982
if (ImGui::BeginTabItem("Description"))
8983
{
8984
ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ");
8985
ImGui::EndTabItem();
8986
}
8987
if (ImGui::BeginTabItem("Details"))
8988
{
8989
ImGui::Text("ID: 0123456789");
8990
ImGui::EndTabItem();
8991
}
8992
ImGui::EndTabBar();
8993
}
8994
ImGui::EndChild();
8995
if (ImGui::Button("Revert")) {}
8996
ImGui::SameLine();
8997
if (ImGui::Button("Save")) {}
8998
ImGui::EndGroup();
8999
}
9000
}
9001
ImGui::End();
9002
}
9003
9004
//-----------------------------------------------------------------------------
9005
// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor()
9006
//-----------------------------------------------------------------------------
9007
// Some of the interactions are a bit lack-luster:
9008
// - We would want pressing validating or leaving the filter to somehow restore focus.
9009
// - We may want more advanced filtering (child nodes) and clipper support: both will need extra work.
9010
// - We would want to customize some keyboard interactions to easily keyboard navigate between the tree and the properties.
9011
//-----------------------------------------------------------------------------
9012
9013
struct ExampleAppPropertyEditor
9014
{
9015
ImGuiTextFilter Filter;
9016
ExampleTreeNode* VisibleNode = NULL;
9017
9018
void Draw(ExampleTreeNode* root_node)
9019
{
9020
// Left side: draw tree
9021
// - Currently using a table to benefit from RowBg feature
9022
if (ImGui::BeginChild("##tree", ImVec2(300, 0), ImGuiChildFlags_ResizeX | ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened))
9023
{
9024
ImGui::SetNextItemWidth(-FLT_MIN);
9025
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F, ImGuiInputFlags_Tooltip);
9026
ImGui::PushItemFlag(ImGuiItemFlags_NoNavDefaultFocus, true);
9027
if (ImGui::InputTextWithHint("##Filter", "incl,-excl", Filter.InputBuf, IM_ARRAYSIZE(Filter.InputBuf), ImGuiInputTextFlags_EscapeClearsAll))
9028
Filter.Build();
9029
ImGui::PopItemFlag();
9030
9031
if (ImGui::BeginTable("##bg", 1, ImGuiTableFlags_RowBg))
9032
{
9033
for (ExampleTreeNode* node : root_node->Childs)
9034
if (Filter.PassFilter(node->Name)) // Filter root node
9035
DrawTreeNode(node);
9036
ImGui::EndTable();
9037
}
9038
}
9039
ImGui::EndChild();
9040
9041
// Right side: draw properties
9042
ImGui::SameLine();
9043
9044
ImGui::BeginGroup(); // Lock X position
9045
if (ExampleTreeNode* node = VisibleNode)
9046
{
9047
ImGui::Text("%s", node->Name);
9048
ImGui::TextDisabled("UID: 0x%08X", node->UID);
9049
ImGui::Separator();
9050
if (ImGui::BeginTable("##properties", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY))
9051
{
9052
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed);
9053
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 2.0f); // Default twice larger
9054
if (node->HasData)
9055
{
9056
// In a typical application, the structure description would be derived from a data-driven system.
9057
// - We try to mimic this with our ExampleMemberInfo structure and the ExampleTreeNodeMemberInfos[] array.
9058
// - Limits and some details are hard-coded to simplify the demo.
9059
for (const ExampleMemberInfo& field_desc : ExampleTreeNodeMemberInfos)
9060
{
9061
ImGui::TableNextRow();
9062
ImGui::PushID(field_desc.Name);
9063
ImGui::TableNextColumn();
9064
ImGui::AlignTextToFramePadding();
9065
ImGui::TextUnformatted(field_desc.Name);
9066
ImGui::TableNextColumn();
9067
void* field_ptr = (void*)(((unsigned char*)node) + field_desc.Offset);
9068
switch (field_desc.DataType)
9069
{
9070
case ImGuiDataType_Bool:
9071
{
9072
IM_ASSERT(field_desc.DataCount == 1);
9073
ImGui::Checkbox("##Editor", (bool*)field_ptr);
9074
break;
9075
}
9076
case ImGuiDataType_S32:
9077
{
9078
int v_min = INT_MIN, v_max = INT_MAX;
9079
ImGui::SetNextItemWidth(-FLT_MIN);
9080
ImGui::DragScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, 1.0f, &v_min, &v_max);
9081
break;
9082
}
9083
case ImGuiDataType_Float:
9084
{
9085
float v_min = 0.0f, v_max = 1.0f;
9086
ImGui::SetNextItemWidth(-FLT_MIN);
9087
ImGui::SliderScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, &v_min, &v_max);
9088
break;
9089
}
9090
}
9091
ImGui::PopID();
9092
}
9093
}
9094
ImGui::EndTable();
9095
}
9096
}
9097
ImGui::EndGroup();
9098
}
9099
9100
void DrawTreeNode(ExampleTreeNode* node)
9101
{
9102
ImGui::TableNextRow();
9103
ImGui::TableNextColumn();
9104
ImGui::PushID(node->UID);
9105
ImGuiTreeNodeFlags tree_flags = ImGuiTreeNodeFlags_None;
9106
tree_flags |= ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; // Standard opening mode as we are likely to want to add selection afterwards
9107
tree_flags |= ImGuiTreeNodeFlags_NavLeftJumpsBackHere; // Left arrow support
9108
if (node == VisibleNode)
9109
tree_flags |= ImGuiTreeNodeFlags_Selected;
9110
if (node->Childs.Size == 0)
9111
tree_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet;
9112
if (node->DataMyBool == false)
9113
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]);
9114
bool node_open = ImGui::TreeNodeEx("", tree_flags, "%s", node->Name);
9115
if (node->DataMyBool == false)
9116
ImGui::PopStyleColor();
9117
if (ImGui::IsItemFocused())
9118
VisibleNode = node;
9119
if (node_open)
9120
{
9121
for (ExampleTreeNode* child : node->Childs)
9122
DrawTreeNode(child);
9123
ImGui::TreePop();
9124
}
9125
ImGui::PopID();
9126
}
9127
};
9128
9129
// Demonstrate creating a simple property editor.
9130
static void ShowExampleAppPropertyEditor(bool* p_open, ImGuiDemoWindowData* demo_data)
9131
{
9132
ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver);
9133
if (!ImGui::Begin("Example: Property editor", p_open))
9134
{
9135
ImGui::End();
9136
return;
9137
}
9138
9139
IMGUI_DEMO_MARKER("Examples/Property Editor");
9140
static ExampleAppPropertyEditor property_editor;
9141
if (demo_data->DemoTree == NULL)
9142
demo_data->DemoTree = ExampleTree_CreateDemoTree();
9143
property_editor.Draw(demo_data->DemoTree);
9144
9145
ImGui::End();
9146
}
9147
9148
//-----------------------------------------------------------------------------
9149
// [SECTION] Example App: Long Text / ShowExampleAppLongText()
9150
//-----------------------------------------------------------------------------
9151
9152
// Demonstrate/test rendering huge amount of text, and the incidence of clipping.
9153
static void ShowExampleAppLongText(bool* p_open)
9154
{
9155
ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
9156
if (!ImGui::Begin("Example: Long text display", p_open))
9157
{
9158
ImGui::End();
9159
return;
9160
}
9161
IMGUI_DEMO_MARKER("Examples/Long text display");
9162
9163
static int test_type = 0;
9164
static ImGuiTextBuffer log;
9165
static int lines = 0;
9166
ImGui::Text("Printing unusually long amount of text.");
9167
ImGui::Combo("Test type", &test_type,
9168
"Single call to TextUnformatted()\0"
9169
"Multiple calls to Text(), clipped\0"
9170
"Multiple calls to Text(), not clipped (slow)\0");
9171
ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size());
9172
if (ImGui::Button("Clear")) { log.clear(); lines = 0; }
9173
ImGui::SameLine();
9174
if (ImGui::Button("Add 1000 lines"))
9175
{
9176
for (int i = 0; i < 1000; i++)
9177
log.appendf("%i The quick brown fox jumps over the lazy dog\n", lines + i);
9178
lines += 1000;
9179
}
9180
ImGui::BeginChild("Log");
9181
switch (test_type)
9182
{
9183
case 0:
9184
// Single call to TextUnformatted() with a big buffer
9185
ImGui::TextUnformatted(log.begin(), log.end());
9186
break;
9187
case 1:
9188
{
9189
// Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper.
9190
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
9191
ImGuiListClipper clipper;
9192
clipper.Begin(lines);
9193
while (clipper.Step())
9194
for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
9195
ImGui::Text("%i The quick brown fox jumps over the lazy dog", i);
9196
ImGui::PopStyleVar();
9197
break;
9198
}
9199
case 2:
9200
// Multiple calls to Text(), not clipped (slow)
9201
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
9202
for (int i = 0; i < lines; i++)
9203
ImGui::Text("%i The quick brown fox jumps over the lazy dog", i);
9204
ImGui::PopStyleVar();
9205
break;
9206
}
9207
ImGui::EndChild();
9208
ImGui::End();
9209
}
9210
9211
//-----------------------------------------------------------------------------
9212
// [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize()
9213
//-----------------------------------------------------------------------------
9214
9215
// Demonstrate creating a window which gets auto-resized according to its content.
9216
static void ShowExampleAppAutoResize(bool* p_open)
9217
{
9218
if (!ImGui::Begin("Example: Auto-resizing window", p_open, ImGuiWindowFlags_AlwaysAutoResize))
9219
{
9220
ImGui::End();
9221
return;
9222
}
9223
IMGUI_DEMO_MARKER("Examples/Auto-resizing window");
9224
9225
static int lines = 10;
9226
ImGui::TextUnformatted(
9227
"Window will resize every-frame to the size of its content.\n"
9228
"Note that you probably don't want to query the window size to\n"
9229
"output your content because that would create a feedback loop.");
9230
ImGui::SliderInt("Number of lines", &lines, 1, 20);
9231
for (int i = 0; i < lines; i++)
9232
ImGui::Text("%*sThis is line %d", i * 4, "", i); // Pad with space to extend size horizontally
9233
ImGui::End();
9234
}
9235
9236
//-----------------------------------------------------------------------------
9237
// [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize()
9238
//-----------------------------------------------------------------------------
9239
9240
// Demonstrate creating a window with custom resize constraints.
9241
// Note that size constraints currently don't work on a docked window (when in 'docking' branch)
9242
static void ShowExampleAppConstrainedResize(bool* p_open)
9243
{
9244
struct CustomConstraints
9245
{
9246
// Helper functions to demonstrate programmatic constraints
9247
// FIXME: This doesn't take account of decoration size (e.g. title bar), library should make this easier.
9248
// FIXME: None of the three demos works consistently when resizing from borders.
9249
static void AspectRatio(ImGuiSizeCallbackData* data)
9250
{
9251
float aspect_ratio = *(float*)data->UserData;
9252
data->DesiredSize.y = (float)(int)(data->DesiredSize.x / aspect_ratio);
9253
}
9254
static void Square(ImGuiSizeCallbackData* data)
9255
{
9256
data->DesiredSize.x = data->DesiredSize.y = IM_MAX(data->DesiredSize.x, data->DesiredSize.y);
9257
}
9258
static void Step(ImGuiSizeCallbackData* data)
9259
{
9260
float step = *(float*)data->UserData;
9261
data->DesiredSize = ImVec2((int)(data->DesiredSize.x / step + 0.5f) * step, (int)(data->DesiredSize.y / step + 0.5f) * step);
9262
}
9263
};
9264
9265
const char* test_desc[] =
9266
{
9267
"Between 100x100 and 500x500",
9268
"At least 100x100",
9269
"Resize vertical + lock current width",
9270
"Resize horizontal + lock current height",
9271
"Width Between 400 and 500",
9272
"Height at least 400",
9273
"Custom: Aspect Ratio 16:9",
9274
"Custom: Always Square",
9275
"Custom: Fixed Steps (100)",
9276
};
9277
9278
// Options
9279
static bool auto_resize = false;
9280
static bool window_padding = true;
9281
static int type = 6; // Aspect Ratio
9282
static int display_lines = 10;
9283
9284
// Submit constraint
9285
float aspect_ratio = 16.0f / 9.0f;
9286
float fixed_step = 100.0f;
9287
if (type == 0) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(500, 500)); // Between 100x100 and 500x500
9288
if (type == 1) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100
9289
if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, FLT_MAX)); // Resize vertical + lock current width
9290
if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(FLT_MAX, -1)); // Resize horizontal + lock current height
9291
if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)); // Width Between and 400 and 500
9292
if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, FLT_MAX)); // Height at least 400
9293
if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::AspectRatio, (void*)&aspect_ratio); // Aspect ratio
9294
if (type == 7) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square
9295
if (type == 8) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)&fixed_step); // Fixed Step
9296
9297
// Submit window
9298
if (!window_padding)
9299
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
9300
const ImGuiWindowFlags window_flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0;
9301
const bool window_open = ImGui::Begin("Example: Constrained Resize", p_open, window_flags);
9302
if (!window_padding)
9303
ImGui::PopStyleVar();
9304
if (window_open)
9305
{
9306
IMGUI_DEMO_MARKER("Examples/Constrained Resizing window");
9307
if (ImGui::GetIO().KeyShift)
9308
{
9309
// Display a dummy viewport (in your real app you would likely use ImageButton() to display a texture.
9310
ImVec2 avail_size = ImGui::GetContentRegionAvail();
9311
ImVec2 pos = ImGui::GetCursorScreenPos();
9312
ImGui::ColorButton("viewport", ImVec4(0.5f, 0.2f, 0.5f, 1.0f), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop, avail_size);
9313
ImGui::SetCursorScreenPos(ImVec2(pos.x + 10, pos.y + 10));
9314
ImGui::Text("%.2f x %.2f", avail_size.x, avail_size.y);
9315
}
9316
else
9317
{
9318
ImGui::Text("(Hold SHIFT to display a dummy viewport)");
9319
if (ImGui::IsWindowDocked())
9320
ImGui::Text("Warning: Sizing Constraints won't work if the window is docked!");
9321
if (ImGui::Button("Set 200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine();
9322
if (ImGui::Button("Set 500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine();
9323
if (ImGui::Button("Set 800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); }
9324
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20);
9325
ImGui::Combo("Constraint", &type, test_desc, IM_ARRAYSIZE(test_desc));
9326
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20);
9327
ImGui::DragInt("Lines", &display_lines, 0.2f, 1, 100);
9328
ImGui::Checkbox("Auto-resize", &auto_resize);
9329
ImGui::Checkbox("Window padding", &window_padding);
9330
for (int i = 0; i < display_lines; i++)
9331
ImGui::Text("%*sHello, sailor! Making this line long enough for the example.", i * 4, "");
9332
}
9333
}
9334
ImGui::End();
9335
}
9336
9337
//-----------------------------------------------------------------------------
9338
// [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay()
9339
//-----------------------------------------------------------------------------
9340
9341
// Demonstrate creating a simple static window with no decoration
9342
// + a context-menu to choose which corner of the screen to use.
9343
static void ShowExampleAppSimpleOverlay(bool* p_open)
9344
{
9345
static int location = 0;
9346
ImGuiIO& io = ImGui::GetIO();
9347
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav;
9348
if (location >= 0)
9349
{
9350
const float PAD = 10.0f;
9351
const ImGuiViewport* viewport = ImGui::GetMainViewport();
9352
ImVec2 work_pos = viewport->WorkPos; // Use work area to avoid menu-bar/task-bar, if any!
9353
ImVec2 work_size = viewport->WorkSize;
9354
ImVec2 window_pos, window_pos_pivot;
9355
window_pos.x = (location & 1) ? (work_pos.x + work_size.x - PAD) : (work_pos.x + PAD);
9356
window_pos.y = (location & 2) ? (work_pos.y + work_size.y - PAD) : (work_pos.y + PAD);
9357
window_pos_pivot.x = (location & 1) ? 1.0f : 0.0f;
9358
window_pos_pivot.y = (location & 2) ? 1.0f : 0.0f;
9359
ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot);
9360
ImGui::SetNextWindowViewport(viewport->ID);
9361
window_flags |= ImGuiWindowFlags_NoMove;
9362
}
9363
else if (location == -2)
9364
{
9365
// Center window
9366
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Always, ImVec2(0.5f, 0.5f));
9367
window_flags |= ImGuiWindowFlags_NoMove;
9368
}
9369
ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background
9370
if (ImGui::Begin("Example: Simple overlay", p_open, window_flags))
9371
{
9372
IMGUI_DEMO_MARKER("Examples/Simple Overlay");
9373
ImGui::Text("Simple overlay\n" "(right-click to change position)");
9374
ImGui::Separator();
9375
if (ImGui::IsMousePosValid())
9376
ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y);
9377
else
9378
ImGui::Text("Mouse Position: <invalid>");
9379
if (ImGui::BeginPopupContextWindow())
9380
{
9381
if (ImGui::MenuItem("Custom", NULL, location == -1)) location = -1;
9382
if (ImGui::MenuItem("Center", NULL, location == -2)) location = -2;
9383
if (ImGui::MenuItem("Top-left", NULL, location == 0)) location = 0;
9384
if (ImGui::MenuItem("Top-right", NULL, location == 1)) location = 1;
9385
if (ImGui::MenuItem("Bottom-left", NULL, location == 2)) location = 2;
9386
if (ImGui::MenuItem("Bottom-right", NULL, location == 3)) location = 3;
9387
if (p_open && ImGui::MenuItem("Close")) *p_open = false;
9388
ImGui::EndPopup();
9389
}
9390
}
9391
ImGui::End();
9392
}
9393
9394
//-----------------------------------------------------------------------------
9395
// [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen()
9396
//-----------------------------------------------------------------------------
9397
9398
// Demonstrate creating a window covering the entire screen/viewport
9399
static void ShowExampleAppFullscreen(bool* p_open)
9400
{
9401
static bool use_work_area = true;
9402
static ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings;
9403
9404
// We demonstrate using the full viewport area or the work area (without menu-bars, task-bars etc.)
9405
// Based on your use case you may want one or the other.
9406
const ImGuiViewport* viewport = ImGui::GetMainViewport();
9407
ImGui::SetNextWindowPos(use_work_area ? viewport->WorkPos : viewport->Pos);
9408
ImGui::SetNextWindowSize(use_work_area ? viewport->WorkSize : viewport->Size);
9409
9410
if (ImGui::Begin("Example: Fullscreen window", p_open, flags))
9411
{
9412
ImGui::Checkbox("Use work area instead of main area", &use_work_area);
9413
ImGui::SameLine();
9414
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.");
9415
9416
ImGui::CheckboxFlags("ImGuiWindowFlags_NoBackground", &flags, ImGuiWindowFlags_NoBackground);
9417
ImGui::CheckboxFlags("ImGuiWindowFlags_NoDecoration", &flags, ImGuiWindowFlags_NoDecoration);
9418
ImGui::Indent();
9419
ImGui::CheckboxFlags("ImGuiWindowFlags_NoTitleBar", &flags, ImGuiWindowFlags_NoTitleBar);
9420
ImGui::CheckboxFlags("ImGuiWindowFlags_NoCollapse", &flags, ImGuiWindowFlags_NoCollapse);
9421
ImGui::CheckboxFlags("ImGuiWindowFlags_NoScrollbar", &flags, ImGuiWindowFlags_NoScrollbar);
9422
ImGui::Unindent();
9423
9424
if (p_open && ImGui::Button("Close this window"))
9425
*p_open = false;
9426
}
9427
ImGui::End();
9428
}
9429
9430
//-----------------------------------------------------------------------------
9431
// [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles()
9432
//-----------------------------------------------------------------------------
9433
9434
// Demonstrate the use of "##" and "###" in identifiers to manipulate ID generation.
9435
// This applies to all regular items as well.
9436
// Read FAQ section "How can I have multiple widgets with the same label?" for details.
9437
static void ShowExampleAppWindowTitles(bool*)
9438
{
9439
const ImGuiViewport* viewport = ImGui::GetMainViewport();
9440
const ImVec2 base_pos = viewport->Pos;
9441
9442
// By default, Windows are uniquely identified by their title.
9443
// You can use the "##" and "###" markers to manipulate the display/ID.
9444
9445
// Using "##" to display same title but have unique identifier.
9446
ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 100), ImGuiCond_FirstUseEver);
9447
ImGui::Begin("Same title as another window##1");
9448
IMGUI_DEMO_MARKER("Examples/Manipulating window titles");
9449
ImGui::Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique.");
9450
ImGui::End();
9451
9452
ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 200), ImGuiCond_FirstUseEver);
9453
ImGui::Begin("Same title as another window##2");
9454
ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique.");
9455
ImGui::End();
9456
9457
// Using "###" to display a changing title but keep a static identifier "AnimatedTitle"
9458
char buf[128];
9459
sprintf(buf, "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime() / 0.25f) & 3], ImGui::GetFrameCount());
9460
ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 300), ImGuiCond_FirstUseEver);
9461
ImGui::Begin(buf);
9462
ImGui::Text("This window has a changing title.");
9463
ImGui::End();
9464
}
9465
9466
//-----------------------------------------------------------------------------
9467
// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering()
9468
//-----------------------------------------------------------------------------
9469
9470
// Add a |_| looking shape
9471
static void PathConcaveShape(ImDrawList* draw_list, float x, float y, float sz)
9472
{
9473
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 } };
9474
for (const ImVec2& p : pos_norms)
9475
draw_list->PathLineTo(ImVec2(x + 0.5f + (int)(sz * p.x), y + 0.5f + (int)(sz * p.y)));
9476
}
9477
9478
// Demonstrate using the low-level ImDrawList to draw custom shapes.
9479
static void ShowExampleAppCustomRendering(bool* p_open)
9480
{
9481
if (!ImGui::Begin("Example: Custom rendering", p_open))
9482
{
9483
ImGui::End();
9484
return;
9485
}
9486
IMGUI_DEMO_MARKER("Examples/Custom Rendering");
9487
9488
// Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of
9489
// overloaded operators, etc. Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your
9490
// types and ImVec2/ImVec4. Dear ImGui defines overloaded operators but they are internal to imgui.cpp and not
9491
// exposed outside (to avoid messing with your types) In this example we are not using the maths operators!
9492
9493
if (ImGui::BeginTabBar("##TabBar"))
9494
{
9495
if (ImGui::BeginTabItem("Primitives"))
9496
{
9497
ImGui::PushItemWidth(-ImGui::GetFontSize() * 15);
9498
ImDrawList* draw_list = ImGui::GetWindowDrawList();
9499
9500
// Draw gradients
9501
// (note that those are currently exacerbating our sRGB/Linear issues)
9502
// Calling ImGui::GetColorU32() multiplies the given colors by the current Style Alpha, but you may pass the IM_COL32() directly as well..
9503
ImGui::Text("Gradients");
9504
ImVec2 gradient_size = ImVec2(ImGui::CalcItemWidth(), ImGui::GetFrameHeight());
9505
{
9506
ImVec2 p0 = ImGui::GetCursorScreenPos();
9507
ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y);
9508
ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 0, 0, 255));
9509
ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 255, 255, 255));
9510
draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a);
9511
ImGui::InvisibleButton("##gradient1", gradient_size);
9512
}
9513
{
9514
ImVec2 p0 = ImGui::GetCursorScreenPos();
9515
ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y);
9516
ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 255, 0, 255));
9517
ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 0, 0, 255));
9518
draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a);
9519
ImGui::InvisibleButton("##gradient2", gradient_size);
9520
}
9521
9522
// Draw a bunch of primitives
9523
ImGui::Text("All primitives");
9524
static float sz = 36.0f;
9525
static float thickness = 3.0f;
9526
static int ngon_sides = 6;
9527
static bool circle_segments_override = false;
9528
static int circle_segments_override_v = 12;
9529
static bool curve_segments_override = false;
9530
static int curve_segments_override_v = 8;
9531
static ImVec4 colf = ImVec4(1.0f, 1.0f, 0.4f, 1.0f);
9532
ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 100.0f, "%.0f");
9533
ImGui::DragFloat("Thickness", &thickness, 0.05f, 1.0f, 8.0f, "%.02f");
9534
ImGui::SliderInt("N-gon sides", &ngon_sides, 3, 12);
9535
ImGui::Checkbox("##circlesegmentoverride", &circle_segments_override);
9536
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
9537
circle_segments_override |= ImGui::SliderInt("Circle segments override", &circle_segments_override_v, 3, 40);
9538
ImGui::Checkbox("##curvessegmentoverride", &curve_segments_override);
9539
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
9540
curve_segments_override |= ImGui::SliderInt("Curves segments override", &curve_segments_override_v, 3, 40);
9541
ImGui::ColorEdit4("Color", &colf.x);
9542
9543
const ImVec2 p = ImGui::GetCursorScreenPos();
9544
const ImU32 col = ImColor(colf);
9545
const float spacing = 10.0f;
9546
const ImDrawFlags corners_tl_br = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersBottomRight;
9547
const float rounding = sz / 5.0f;
9548
const int circle_segments = circle_segments_override ? circle_segments_override_v : 0;
9549
const int curve_segments = curve_segments_override ? curve_segments_override_v : 0;
9550
const ImVec2 cp3[3] = { ImVec2(0.0f, sz * 0.6f), ImVec2(sz * 0.5f, -sz * 0.4f), ImVec2(sz, sz) }; // Control points for curves
9551
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) };
9552
9553
float x = p.x + 4.0f;
9554
float y = p.y + 4.0f;
9555
for (int n = 0; n < 2; n++)
9556
{
9557
// First line uses a thickness of 1.0f, second line uses the configurable thickness
9558
float th = (n == 0) ? 1.0f : thickness;
9559
draw_list->AddNgon(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, ngon_sides, th); x += sz + spacing; // N-gon
9560
draw_list->AddCircle(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments, th); x += sz + spacing; // Circle
9561
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
9562
draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0f, ImDrawFlags_None, th); x += sz + spacing; // Square
9563
draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, ImDrawFlags_None, th); x += sz + spacing; // Square with all rounded corners
9564
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
9565
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
9566
//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
9567
PathConcaveShape(draw_list, x, y, sz); draw_list->PathStroke(col, ImDrawFlags_Closed, th); x += sz + spacing; // Concave Shape
9568
//draw_list->AddPolyline(concave_shape, IM_ARRAYSIZE(concave_shape), col, ImDrawFlags_Closed, th);
9569
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!)
9570
draw_list->AddLine(ImVec2(x, y), ImVec2(x, y + sz), col, th); x += spacing; // Vertical line (note: drawing a filled rectangle will be faster!)
9571
draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y + sz), col, th); x += sz + spacing; // Diagonal line
9572
9573
// Path
9574
draw_list->PathArcTo(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, 3.141592f, 3.141592f * -0.5f);
9575
draw_list->PathStroke(col, ImDrawFlags_None, th);
9576
x += sz + spacing;
9577
9578
// Quadratic Bezier Curve (3 control points)
9579
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);
9580
x += sz + spacing;
9581
9582
// Cubic Bezier Curve (4 control points)
9583
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);
9584
9585
x = p.x + 4;
9586
y += sz + spacing;
9587
}
9588
9589
// Filled shapes
9590
draw_list->AddNgonFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, col, ngon_sides); x += sz + spacing; // N-gon
9591
draw_list->AddCircleFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, col, circle_segments); x += sz + spacing; // Circle
9592
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
9593
draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col); x += sz + spacing; // Square
9594
draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f); x += sz + spacing; // Square with all rounded corners
9595
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
9596
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
9597
//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
9598
PathConcaveShape(draw_list, x, y, sz); draw_list->PathFillConcave(col); x += sz + spacing; // Concave shape
9599
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)
9600
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)
9601
draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + 1, y + 1), col); x += sz; // Pixel (faster than AddLine)
9602
9603
// Path
9604
draw_list->PathArcTo(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, 3.141592f * -0.5f, 3.141592f);
9605
draw_list->PathFillConvex(col);
9606
x += sz + spacing;
9607
9608
// Quadratic Bezier Curve (3 control points)
9609
draw_list->PathLineTo(ImVec2(x + cp3[0].x, y + cp3[0].y));
9610
draw_list->PathBezierQuadraticCurveTo(ImVec2(x + cp3[1].x, y + cp3[1].y), ImVec2(x + cp3[2].x, y + cp3[2].y), curve_segments);
9611
draw_list->PathFillConvex(col);
9612
x += sz + spacing;
9613
9614
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));
9615
x += sz + spacing;
9616
9617
ImGui::Dummy(ImVec2((sz + spacing) * 13.2f, (sz + spacing) * 3.0f));
9618
ImGui::PopItemWidth();
9619
ImGui::EndTabItem();
9620
}
9621
9622
if (ImGui::BeginTabItem("Canvas"))
9623
{
9624
static ImVector<ImVec2> points;
9625
static ImVec2 scrolling(0.0f, 0.0f);
9626
static bool opt_enable_grid = true;
9627
static bool opt_enable_context_menu = true;
9628
static bool adding_line = false;
9629
9630
ImGui::Checkbox("Enable grid", &opt_enable_grid);
9631
ImGui::Checkbox("Enable context menu", &opt_enable_context_menu);
9632
ImGui::Text("Mouse Left: drag to add lines,\nMouse Right: drag to scroll, click for context menu.");
9633
9634
// Typically you would use a BeginChild()/EndChild() pair to benefit from a clipping region + own scrolling.
9635
// Here we demonstrate that this can be replaced by simple offsetting + custom drawing + PushClipRect/PopClipRect() calls.
9636
// To use a child window instead we could use, e.g:
9637
// ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); // Disable padding
9638
// ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(50, 50, 50, 255)); // Set a background color
9639
// ImGui::BeginChild("canvas", ImVec2(0.0f, 0.0f), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove);
9640
// ImGui::PopStyleColor();
9641
// ImGui::PopStyleVar();
9642
// [...]
9643
// ImGui::EndChild();
9644
9645
// Using InvisibleButton() as a convenience 1) it will advance the layout cursor and 2) allows us to use IsItemHovered()/IsItemActive()
9646
ImVec2 canvas_p0 = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates!
9647
ImVec2 canvas_sz = ImGui::GetContentRegionAvail(); // Resize canvas to what's available
9648
if (canvas_sz.x < 50.0f) canvas_sz.x = 50.0f;
9649
if (canvas_sz.y < 50.0f) canvas_sz.y = 50.0f;
9650
ImVec2 canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y);
9651
9652
// Draw border and background color
9653
ImGuiIO& io = ImGui::GetIO();
9654
ImDrawList* draw_list = ImGui::GetWindowDrawList();
9655
draw_list->AddRectFilled(canvas_p0, canvas_p1, IM_COL32(50, 50, 50, 255));
9656
draw_list->AddRect(canvas_p0, canvas_p1, IM_COL32(255, 255, 255, 255));
9657
9658
// This will catch our interactions
9659
ImGui::InvisibleButton("canvas", canvas_sz, ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight);
9660
const bool is_hovered = ImGui::IsItemHovered(); // Hovered
9661
const bool is_active = ImGui::IsItemActive(); // Held
9662
const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y); // Lock scrolled origin
9663
const ImVec2 mouse_pos_in_canvas(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
9664
9665
// Add first and second point
9666
if (is_hovered && !adding_line && ImGui::IsMouseClicked(ImGuiMouseButton_Left))
9667
{
9668
points.push_back(mouse_pos_in_canvas);
9669
points.push_back(mouse_pos_in_canvas);
9670
adding_line = true;
9671
}
9672
if (adding_line)
9673
{
9674
points.back() = mouse_pos_in_canvas;
9675
if (!ImGui::IsMouseDown(ImGuiMouseButton_Left))
9676
adding_line = false;
9677
}
9678
9679
// Pan (we use a zero mouse threshold when there's no context menu)
9680
// You may decide to make that threshold dynamic based on whether the mouse is hovering something etc.
9681
const float mouse_threshold_for_pan = opt_enable_context_menu ? -1.0f : 0.0f;
9682
if (is_active && ImGui::IsMouseDragging(ImGuiMouseButton_Right, mouse_threshold_for_pan))
9683
{
9684
scrolling.x += io.MouseDelta.x;
9685
scrolling.y += io.MouseDelta.y;
9686
}
9687
9688
// Context menu (under default mouse threshold)
9689
ImVec2 drag_delta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Right);
9690
if (opt_enable_context_menu && drag_delta.x == 0.0f && drag_delta.y == 0.0f)
9691
ImGui::OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight);
9692
if (ImGui::BeginPopup("context"))
9693
{
9694
if (adding_line)
9695
points.resize(points.size() - 2);
9696
adding_line = false;
9697
if (ImGui::MenuItem("Remove one", NULL, false, points.Size > 0)) { points.resize(points.size() - 2); }
9698
if (ImGui::MenuItem("Remove all", NULL, false, points.Size > 0)) { points.clear(); }
9699
ImGui::EndPopup();
9700
}
9701
9702
// Draw grid + all lines in the canvas
9703
draw_list->PushClipRect(canvas_p0, canvas_p1, true);
9704
if (opt_enable_grid)
9705
{
9706
const float GRID_STEP = 64.0f;
9707
for (float x = fmodf(scrolling.x, GRID_STEP); x < canvas_sz.x; x += GRID_STEP)
9708
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));
9709
for (float y = fmodf(scrolling.y, GRID_STEP); y < canvas_sz.y; y += GRID_STEP)
9710
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));
9711
}
9712
for (int n = 0; n < points.Size; n += 2)
9713
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);
9714
draw_list->PopClipRect();
9715
9716
ImGui::EndTabItem();
9717
}
9718
9719
if (ImGui::BeginTabItem("BG/FG draw lists"))
9720
{
9721
static bool draw_bg = true;
9722
static bool draw_fg = true;
9723
ImGui::Checkbox("Draw in Background draw list", &draw_bg);
9724
ImGui::SameLine(); HelpMarker("The Background draw list will be rendered below every Dear ImGui windows.");
9725
ImGui::Checkbox("Draw in Foreground draw list", &draw_fg);
9726
ImGui::SameLine(); HelpMarker("The Foreground draw list will be rendered over every Dear ImGui windows.");
9727
ImVec2 window_pos = ImGui::GetWindowPos();
9728
ImVec2 window_size = ImGui::GetWindowSize();
9729
ImVec2 window_center = ImVec2(window_pos.x + window_size.x * 0.5f, window_pos.y + window_size.y * 0.5f);
9730
if (draw_bg)
9731
ImGui::GetBackgroundDrawList()->AddCircle(window_center, window_size.x * 0.6f, IM_COL32(255, 0, 0, 200), 0, 10 + 4);
9732
if (draw_fg)
9733
ImGui::GetForegroundDrawList()->AddCircle(window_center, window_size.y * 0.6f, IM_COL32(0, 255, 0, 200), 0, 10);
9734
ImGui::EndTabItem();
9735
}
9736
9737
// Demonstrate out-of-order rendering via channels splitting
9738
// We use functions in ImDrawList as each draw list contains a convenience splitter,
9739
// but you can also instantiate your own ImDrawListSplitter if you need to nest them.
9740
if (ImGui::BeginTabItem("Draw Channels"))
9741
{
9742
ImDrawList* draw_list = ImGui::GetWindowDrawList();
9743
{
9744
ImGui::Text("Blue shape is drawn first: appears in back");
9745
ImGui::Text("Red shape is drawn after: appears in front");
9746
ImVec2 p0 = ImGui::GetCursorScreenPos();
9747
draw_list->AddRectFilled(ImVec2(p0.x, p0.y), ImVec2(p0.x + 50, p0.y + 50), IM_COL32(0, 0, 255, 255)); // Blue
9748
draw_list->AddRectFilled(ImVec2(p0.x + 25, p0.y + 25), ImVec2(p0.x + 75, p0.y + 75), IM_COL32(255, 0, 0, 255)); // Red
9749
ImGui::Dummy(ImVec2(75, 75));
9750
}
9751
ImGui::Separator();
9752
{
9753
ImGui::Text("Blue shape is drawn first, into channel 1: appears in front");
9754
ImGui::Text("Red shape is drawn after, into channel 0: appears in back");
9755
ImVec2 p1 = ImGui::GetCursorScreenPos();
9756
9757
// Create 2 channels and draw a Blue shape THEN a Red shape.
9758
// You can create any number of channels. Tables API use 1 channel per column in order to better batch draw calls.
9759
draw_list->ChannelsSplit(2);
9760
draw_list->ChannelsSetCurrent(1);
9761
draw_list->AddRectFilled(ImVec2(p1.x, p1.y), ImVec2(p1.x + 50, p1.y + 50), IM_COL32(0, 0, 255, 255)); // Blue
9762
draw_list->ChannelsSetCurrent(0);
9763
draw_list->AddRectFilled(ImVec2(p1.x + 25, p1.y + 25), ImVec2(p1.x + 75, p1.y + 75), IM_COL32(255, 0, 0, 255)); // Red
9764
9765
// Flatten/reorder channels. Red shape is in channel 0 and it appears below the Blue shape in channel 1.
9766
// This works by copying draw indices only (vertices are not copied).
9767
draw_list->ChannelsMerge();
9768
ImGui::Dummy(ImVec2(75, 75));
9769
ImGui::Text("After reordering, contents of channel 0 appears below channel 1.");
9770
}
9771
ImGui::EndTabItem();
9772
}
9773
9774
ImGui::EndTabBar();
9775
}
9776
9777
ImGui::End();
9778
}
9779
9780
//-----------------------------------------------------------------------------
9781
// [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace()
9782
//-----------------------------------------------------------------------------
9783
9784
// Demonstrate using DockSpace() to create an explicit docking node within an existing window.
9785
// Note: You can use most Docking facilities without calling any API. You DO NOT need to call DockSpace() to use Docking!
9786
// - Drag from window title bar or their tab to dock/undock. Hold SHIFT to disable docking.
9787
// - Drag from window menu button (upper-left button) to undock an entire node (all windows).
9788
// - When io.ConfigDockingWithShift == true, you instead need to hold SHIFT to enable docking.
9789
// About dockspaces:
9790
// - Use DockSpace() to create an explicit dock node _within_ an existing window.
9791
// - Use DockSpaceOverViewport() to create an explicit dock node covering the screen or a specific viewport.
9792
// This is often used with ImGuiDockNodeFlags_PassthruCentralNode.
9793
// - Important: Dockspaces need to be submitted _before_ any window they can host. Submit it early in your frame! (*)
9794
// - Important: Dockspaces need to be kept alive if hidden, otherwise windows docked into it will be undocked.
9795
// e.g. if you have multiple tabs with a dockspace inside each tab: submit the non-visible dockspaces with ImGuiDockNodeFlags_KeepAliveOnly.
9796
// (*) because of this constraint, the implicit \"Debug\" window can not be docked into an explicit DockSpace() node,
9797
// because that window is submitted as part of the part of the NewFrame() call. An easy workaround is that you can create
9798
// your own implicit "Debug##2" window after calling DockSpace() and leave it in the window stack for anyone to use.
9799
void ShowExampleAppDockSpace(bool* p_open)
9800
{
9801
// READ THIS !!!
9802
// TL;DR; this demo is more complicated than what most users you would normally use.
9803
// If we remove all options we are showcasing, this demo would become:
9804
// void ShowExampleAppDockSpace()
9805
// {
9806
// ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport());
9807
// }
9808
// In most cases you should be able to just call DockSpaceOverViewport() and ignore all the code below!
9809
// In this specific demo, we are not using DockSpaceOverViewport() because:
9810
// - (1) we allow the host window to be floating/moveable instead of filling the viewport (when opt_fullscreen == false)
9811
// - (2) we allow the host window to have padding (when opt_padding == true)
9812
// - (3) we expose many flags and need a way to have them visible.
9813
// - (4) we have a local menu bar in the host window (vs. you could use BeginMainMenuBar() + DockSpaceOverViewport()
9814
// in your code, but we don't here because we allow the window to be floating)
9815
9816
static bool opt_fullscreen = true;
9817
static bool opt_padding = false;
9818
static ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_None;
9819
9820
// We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into,
9821
// because it would be confusing to have two docking targets within each others.
9822
ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking;
9823
if (opt_fullscreen)
9824
{
9825
const ImGuiViewport* viewport = ImGui::GetMainViewport();
9826
ImGui::SetNextWindowPos(viewport->WorkPos);
9827
ImGui::SetNextWindowSize(viewport->WorkSize);
9828
ImGui::SetNextWindowViewport(viewport->ID);
9829
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
9830
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
9831
window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
9832
window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
9833
}
9834
else
9835
{
9836
dockspace_flags &= ~ImGuiDockNodeFlags_PassthruCentralNode;
9837
}
9838
9839
// When using ImGuiDockNodeFlags_PassthruCentralNode, DockSpace() will render our background
9840
// and handle the pass-thru hole, so we ask Begin() to not render a background.
9841
if (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode)
9842
window_flags |= ImGuiWindowFlags_NoBackground;
9843
9844
// Important: note that we proceed even if Begin() returns false (aka window is collapsed).
9845
// This is because we want to keep our DockSpace() active. If a DockSpace() is inactive,
9846
// all active windows docked into it will lose their parent and become undocked.
9847
// We cannot preserve the docking relationship between an active window and an inactive docking, otherwise
9848
// any change of dockspace/settings would lead to windows being stuck in limbo and never being visible.
9849
if (!opt_padding)
9850
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
9851
ImGui::Begin("DockSpace Demo", p_open, window_flags);
9852
if (!opt_padding)
9853
ImGui::PopStyleVar();
9854
9855
if (opt_fullscreen)
9856
ImGui::PopStyleVar(2);
9857
9858
// Submit the DockSpace
9859
ImGuiIO& io = ImGui::GetIO();
9860
if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
9861
{
9862
ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
9863
ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
9864
}
9865
else
9866
{
9867
ShowDockingDisabledMessage();
9868
}
9869
9870
if (ImGui::BeginMenuBar())
9871
{
9872
if (ImGui::BeginMenu("Options"))
9873
{
9874
// Disabling fullscreen would allow the window to be moved to the front of other windows,
9875
// which we can't undo at the moment without finer window depth/z control.
9876
ImGui::MenuItem("Fullscreen", NULL, &opt_fullscreen);
9877
ImGui::MenuItem("Padding", NULL, &opt_padding);
9878
ImGui::Separator();
9879
9880
if (ImGui::MenuItem("Flag: NoDockingOverCentralNode", "", (dockspace_flags & ImGuiDockNodeFlags_NoDockingOverCentralNode) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoDockingOverCentralNode; }
9881
if (ImGui::MenuItem("Flag: NoDockingSplit", "", (dockspace_flags & ImGuiDockNodeFlags_NoDockingSplit) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoDockingSplit; }
9882
if (ImGui::MenuItem("Flag: NoUndocking", "", (dockspace_flags & ImGuiDockNodeFlags_NoUndocking) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoUndocking; }
9883
if (ImGui::MenuItem("Flag: NoResize", "", (dockspace_flags & ImGuiDockNodeFlags_NoResize) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoResize; }
9884
if (ImGui::MenuItem("Flag: AutoHideTabBar", "", (dockspace_flags & ImGuiDockNodeFlags_AutoHideTabBar) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_AutoHideTabBar; }
9885
if (ImGui::MenuItem("Flag: PassthruCentralNode", "", (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode) != 0, opt_fullscreen)) { dockspace_flags ^= ImGuiDockNodeFlags_PassthruCentralNode; }
9886
ImGui::Separator();
9887
9888
if (ImGui::MenuItem("Close", NULL, false, p_open != NULL))
9889
*p_open = false;
9890
ImGui::EndMenu();
9891
}
9892
HelpMarker(
9893
"When docking is enabled, you can ALWAYS dock MOST window into another! Try it now!" "\n"
9894
"- Drag from window title bar or their tab to dock/undock." "\n"
9895
"- Drag from window menu button (upper-left button) to undock an entire node (all windows)." "\n"
9896
"- Hold SHIFT to disable docking (if io.ConfigDockingWithShift == false, default)" "\n"
9897
"- Hold SHIFT to enable docking (if io.ConfigDockingWithShift == true)" "\n"
9898
"This demo app has nothing to do with enabling docking!" "\n\n"
9899
"This demo app only demonstrate the use of ImGui::DockSpace() which allows you to manually create a docking node _within_ another window." "\n\n"
9900
"Read comments in ShowExampleAppDockSpace() for more details.");
9901
9902
ImGui::EndMenuBar();
9903
}
9904
9905
ImGui::End();
9906
}
9907
9908
//-----------------------------------------------------------------------------
9909
// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
9910
//-----------------------------------------------------------------------------
9911
9912
// Simplified structure to mimic a Document model
9913
struct MyDocument
9914
{
9915
char Name[32]; // Document title
9916
int UID; // Unique ID (necessary as we can change title)
9917
bool Open; // Set when open (we keep an array of all available documents to simplify demo code!)
9918
bool OpenPrev; // Copy of Open from last update.
9919
bool Dirty; // Set when the document has been modified
9920
ImVec4 Color; // An arbitrary variable associated to the document
9921
9922
MyDocument(int uid, const char* name, bool open = true, const ImVec4& color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f))
9923
{
9924
UID = uid;
9925
snprintf(Name, sizeof(Name), "%s", name);
9926
Open = OpenPrev = open;
9927
Dirty = false;
9928
Color = color;
9929
}
9930
void DoOpen() { Open = true; }
9931
void DoForceClose() { Open = false; Dirty = false; }
9932
void DoSave() { Dirty = false; }
9933
};
9934
9935
struct ExampleAppDocuments
9936
{
9937
ImVector<MyDocument> Documents;
9938
ImVector<MyDocument*> CloseQueue;
9939
MyDocument* RenamingDoc = NULL;
9940
bool RenamingStarted = false;
9941
9942
ExampleAppDocuments()
9943
{
9944
Documents.push_back(MyDocument(0, "Lettuce", true, ImVec4(0.4f, 0.8f, 0.4f, 1.0f)));
9945
Documents.push_back(MyDocument(1, "Eggplant", true, ImVec4(0.8f, 0.5f, 1.0f, 1.0f)));
9946
Documents.push_back(MyDocument(2, "Carrot", true, ImVec4(1.0f, 0.8f, 0.5f, 1.0f)));
9947
Documents.push_back(MyDocument(3, "Tomato", false, ImVec4(1.0f, 0.3f, 0.4f, 1.0f)));
9948
Documents.push_back(MyDocument(4, "A Rather Long Title", false, ImVec4(0.4f, 0.8f, 0.8f, 1.0f)));
9949
Documents.push_back(MyDocument(5, "Some Document", false, ImVec4(0.8f, 0.8f, 1.0f, 1.0f)));
9950
}
9951
9952
// As we allow to change document name, we append a never-changing document ID so tabs are stable
9953
void GetTabName(MyDocument* doc, char* out_buf, size_t out_buf_size)
9954
{
9955
snprintf(out_buf, out_buf_size, "%s###doc%d", doc->Name, doc->UID);
9956
}
9957
9958
// Display placeholder contents for the Document
9959
void DisplayDocContents(MyDocument* doc)
9960
{
9961
ImGui::PushID(doc);
9962
ImGui::Text("Document \"%s\"", doc->Name);
9963
ImGui::PushStyleColor(ImGuiCol_Text, doc->Color);
9964
ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.");
9965
ImGui::PopStyleColor();
9966
9967
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_R, ImGuiInputFlags_Tooltip);
9968
if (ImGui::Button("Rename.."))
9969
{
9970
RenamingDoc = doc;
9971
RenamingStarted = true;
9972
}
9973
ImGui::SameLine();
9974
9975
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_M, ImGuiInputFlags_Tooltip);
9976
if (ImGui::Button("Modify"))
9977
doc->Dirty = true;
9978
9979
ImGui::SameLine();
9980
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_S, ImGuiInputFlags_Tooltip);
9981
if (ImGui::Button("Save"))
9982
doc->DoSave();
9983
9984
ImGui::SameLine();
9985
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_W, ImGuiInputFlags_Tooltip);
9986
if (ImGui::Button("Close"))
9987
CloseQueue.push_back(doc);
9988
ImGui::ColorEdit3("color", &doc->Color.x); // Useful to test drag and drop and hold-dragged-to-open-tab behavior.
9989
ImGui::PopID();
9990
}
9991
9992
// Display context menu for the Document
9993
void DisplayDocContextMenu(MyDocument* doc)
9994
{
9995
if (!ImGui::BeginPopupContextItem())
9996
return;
9997
9998
char buf[256];
9999
sprintf(buf, "Save %s", doc->Name);
10000
if (ImGui::MenuItem(buf, "Ctrl+S", false, doc->Open))
10001
doc->DoSave();
10002
if (ImGui::MenuItem("Rename...", "Ctrl+R", false, doc->Open))
10003
RenamingDoc = doc;
10004
if (ImGui::MenuItem("Close", "Ctrl+W", false, doc->Open))
10005
CloseQueue.push_back(doc);
10006
ImGui::EndPopup();
10007
}
10008
10009
// [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface.
10010
// If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo,
10011
// as opposed to clicking on the regular tab closing button) and stops being submitted, it will take a frame for
10012
// 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
10013
// disappeared was the selected one, the tab bar will report no selected tab during the frame. This will effectively
10014
// give the impression of a flicker for one frame.
10015
// We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch.
10016
// Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag.
10017
void NotifyOfDocumentsClosedElsewhere()
10018
{
10019
for (MyDocument& doc : Documents)
10020
{
10021
if (!doc.Open && doc.OpenPrev)
10022
ImGui::SetTabItemClosed(doc.Name);
10023
doc.OpenPrev = doc.Open;
10024
}
10025
}
10026
};
10027
10028
void ShowExampleAppDocuments(bool* p_open)
10029
{
10030
static ExampleAppDocuments app;
10031
10032
// Options
10033
enum Target
10034
{
10035
Target_None,
10036
Target_Tab, // Create documents as local tab into a local tab bar
10037
Target_DockSpaceAndWindow // Create documents as regular windows, and create an embedded dockspace
10038
};
10039
static Target opt_target = Target_Tab;
10040
static bool opt_reorderable = true;
10041
static ImGuiTabBarFlags opt_fitting_flags = ImGuiTabBarFlags_FittingPolicyDefault_;
10042
10043
// When (opt_target == Target_DockSpaceAndWindow) there is the possibily that one of our child Document window (e.g. "Eggplant")
10044
// that we emit gets docked into the same spot as the parent window ("Example: Documents").
10045
// This would create a problematic feedback loop because selecting the "Eggplant" tab would make the "Example: Documents" tab
10046
// not visible, which in turn would stop submitting the "Eggplant" window.
10047
// We avoid this problem by submitting our documents window even if our parent window is not currently visible.
10048
// Another solution may be to make the "Example: Documents" window use the ImGuiWindowFlags_NoDocking.
10049
10050
bool window_contents_visible = ImGui::Begin("Example: Documents", p_open, ImGuiWindowFlags_MenuBar);
10051
if (!window_contents_visible && opt_target != Target_DockSpaceAndWindow)
10052
{
10053
ImGui::End();
10054
return;
10055
}
10056
10057
// Menu
10058
if (ImGui::BeginMenuBar())
10059
{
10060
if (ImGui::BeginMenu("File"))
10061
{
10062
int open_count = 0;
10063
for (MyDocument& doc : app.Documents)
10064
open_count += doc.Open ? 1 : 0;
10065
10066
if (ImGui::BeginMenu("Open", open_count < app.Documents.Size))
10067
{
10068
for (MyDocument& doc : app.Documents)
10069
if (!doc.Open && ImGui::MenuItem(doc.Name))
10070
doc.DoOpen();
10071
ImGui::EndMenu();
10072
}
10073
if (ImGui::MenuItem("Close All Documents", NULL, false, open_count > 0))
10074
for (MyDocument& doc : app.Documents)
10075
app.CloseQueue.push_back(&doc);
10076
if (ImGui::MenuItem("Exit") && p_open)
10077
*p_open = false;
10078
ImGui::EndMenu();
10079
}
10080
ImGui::EndMenuBar();
10081
}
10082
10083
// [Debug] List documents with one checkbox for each
10084
for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
10085
{
10086
MyDocument& doc = app.Documents[doc_n];
10087
if (doc_n > 0)
10088
ImGui::SameLine();
10089
ImGui::PushID(&doc);
10090
if (ImGui::Checkbox(doc.Name, &doc.Open))
10091
if (!doc.Open)
10092
doc.DoForceClose();
10093
ImGui::PopID();
10094
}
10095
ImGui::PushItemWidth(ImGui::GetFontSize() * 12);
10096
ImGui::Combo("Output", (int*)&opt_target, "None\0TabBar+Tabs\0DockSpace+Window\0");
10097
ImGui::PopItemWidth();
10098
bool redock_all = false;
10099
if (opt_target == Target_Tab) { ImGui::SameLine(); ImGui::Checkbox("Reorderable Tabs", &opt_reorderable); }
10100
if (opt_target == Target_DockSpaceAndWindow) { ImGui::SameLine(); redock_all = ImGui::Button("Redock all"); }
10101
10102
ImGui::Separator();
10103
10104
// About the ImGuiWindowFlags_UnsavedDocument / ImGuiTabItemFlags_UnsavedDocument flags.
10105
// They have multiple effects:
10106
// - Display a dot next to the title.
10107
// - Tab is selected when clicking the X close button.
10108
// - Closure is not assumed (will wait for user to stop submitting the tab).
10109
// Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar.
10110
// We need to assume closure by default otherwise waiting for "lack of submission" on the next frame would leave an empty
10111
// hole for one-frame, both in the tab-bar and in tab-contents when closing a tab/window.
10112
// The rarely used SetTabItemClosed() function is a way to notify of programmatic closure to avoid the one-frame hole.
10113
10114
// Tabs
10115
if (opt_target == Target_Tab)
10116
{
10117
ImGuiTabBarFlags tab_bar_flags = (opt_fitting_flags) | (opt_reorderable ? ImGuiTabBarFlags_Reorderable : 0);
10118
tab_bar_flags |= ImGuiTabBarFlags_DrawSelectedOverline;
10119
if (ImGui::BeginTabBar("##tabs", tab_bar_flags))
10120
{
10121
if (opt_reorderable)
10122
app.NotifyOfDocumentsClosedElsewhere();
10123
10124
// [DEBUG] Stress tests
10125
//if ((ImGui::GetFrameCount() % 30) == 0) docs[1].Open ^= 1; // [DEBUG] Automatically show/hide a tab. Test various interactions e.g. dragging with this on.
10126
//if (ImGui::GetIO().KeyCtrl) ImGui::SetTabItemSelected(docs[1].Name); // [DEBUG] Test SetTabItemSelected(), probably not very useful as-is anyway..
10127
10128
// Submit Tabs
10129
for (MyDocument& doc : app.Documents)
10130
{
10131
if (!doc.Open)
10132
continue;
10133
10134
// As we allow to change document name, we append a never-changing document id so tabs are stable
10135
char doc_name_buf[64];
10136
app.GetTabName(&doc, doc_name_buf, sizeof(doc_name_buf));
10137
ImGuiTabItemFlags tab_flags = (doc.Dirty ? ImGuiTabItemFlags_UnsavedDocument : 0);
10138
bool visible = ImGui::BeginTabItem(doc_name_buf, &doc.Open, tab_flags);
10139
10140
// Cancel attempt to close when unsaved add to save queue so we can display a popup.
10141
if (!doc.Open && doc.Dirty)
10142
{
10143
doc.Open = true;
10144
app.CloseQueue.push_back(&doc);
10145
}
10146
10147
app.DisplayDocContextMenu(&doc);
10148
if (visible)
10149
{
10150
app.DisplayDocContents(&doc);
10151
ImGui::EndTabItem();
10152
}
10153
}
10154
10155
ImGui::EndTabBar();
10156
}
10157
}
10158
else if (opt_target == Target_DockSpaceAndWindow)
10159
{
10160
if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_DockingEnable)
10161
{
10162
app.NotifyOfDocumentsClosedElsewhere();
10163
10164
// Create a DockSpace node where any window can be docked
10165
ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
10166
ImGui::DockSpace(dockspace_id);
10167
10168
// Create Windows
10169
for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
10170
{
10171
MyDocument* doc = &app.Documents[doc_n];
10172
if (!doc->Open)
10173
continue;
10174
10175
ImGui::SetNextWindowDockID(dockspace_id, redock_all ? ImGuiCond_Always : ImGuiCond_FirstUseEver);
10176
ImGuiWindowFlags window_flags = (doc->Dirty ? ImGuiWindowFlags_UnsavedDocument : 0);
10177
bool visible = ImGui::Begin(doc->Name, &doc->Open, window_flags);
10178
10179
// Cancel attempt to close when unsaved add to save queue so we can display a popup.
10180
if (!doc->Open && doc->Dirty)
10181
{
10182
doc->Open = true;
10183
app.CloseQueue.push_back(doc);
10184
}
10185
10186
app.DisplayDocContextMenu(doc);
10187
if (visible)
10188
app.DisplayDocContents(doc);
10189
10190
ImGui::End();
10191
}
10192
}
10193
else
10194
{
10195
ShowDockingDisabledMessage();
10196
}
10197
}
10198
10199
// Early out other contents
10200
if (!window_contents_visible)
10201
{
10202
ImGui::End();
10203
return;
10204
}
10205
10206
// Display renaming UI
10207
if (app.RenamingDoc != NULL)
10208
{
10209
if (app.RenamingStarted)
10210
ImGui::OpenPopup("Rename");
10211
if (ImGui::BeginPopup("Rename"))
10212
{
10213
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 30);
10214
if (ImGui::InputText("###Name", app.RenamingDoc->Name, IM_ARRAYSIZE(app.RenamingDoc->Name), ImGuiInputTextFlags_EnterReturnsTrue))
10215
{
10216
ImGui::CloseCurrentPopup();
10217
app.RenamingDoc = NULL;
10218
}
10219
if (app.RenamingStarted)
10220
ImGui::SetKeyboardFocusHere(-1);
10221
ImGui::EndPopup();
10222
}
10223
else
10224
{
10225
app.RenamingDoc = NULL;
10226
}
10227
app.RenamingStarted = false;
10228
}
10229
10230
// Display closing confirmation UI
10231
if (!app.CloseQueue.empty())
10232
{
10233
int close_queue_unsaved_documents = 0;
10234
for (int n = 0; n < app.CloseQueue.Size; n++)
10235
if (app.CloseQueue[n]->Dirty)
10236
close_queue_unsaved_documents++;
10237
10238
if (close_queue_unsaved_documents == 0)
10239
{
10240
// Close documents when all are unsaved
10241
for (int n = 0; n < app.CloseQueue.Size; n++)
10242
app.CloseQueue[n]->DoForceClose();
10243
app.CloseQueue.clear();
10244
}
10245
else
10246
{
10247
if (!ImGui::IsPopupOpen("Save?"))
10248
ImGui::OpenPopup("Save?");
10249
if (ImGui::BeginPopupModal("Save?", NULL, ImGuiWindowFlags_AlwaysAutoResize))
10250
{
10251
ImGui::Text("Save change to the following items?");
10252
float item_height = ImGui::GetTextLineHeightWithSpacing();
10253
if (ImGui::BeginChild(ImGui::GetID("frame"), ImVec2(-FLT_MIN, 6.25f * item_height), ImGuiChildFlags_FrameStyle))
10254
for (MyDocument* doc : app.CloseQueue)
10255
if (doc->Dirty)
10256
ImGui::Text("%s", doc->Name);
10257
ImGui::EndChild();
10258
10259
ImVec2 button_size(ImGui::GetFontSize() * 7.0f, 0.0f);
10260
if (ImGui::Button("Yes", button_size))
10261
{
10262
for (MyDocument* doc : app.CloseQueue)
10263
{
10264
if (doc->Dirty)
10265
doc->DoSave();
10266
doc->DoForceClose();
10267
}
10268
app.CloseQueue.clear();
10269
ImGui::CloseCurrentPopup();
10270
}
10271
ImGui::SameLine();
10272
if (ImGui::Button("No", button_size))
10273
{
10274
for (MyDocument* doc : app.CloseQueue)
10275
doc->DoForceClose();
10276
app.CloseQueue.clear();
10277
ImGui::CloseCurrentPopup();
10278
}
10279
ImGui::SameLine();
10280
if (ImGui::Button("Cancel", button_size))
10281
{
10282
app.CloseQueue.clear();
10283
ImGui::CloseCurrentPopup();
10284
}
10285
ImGui::EndPopup();
10286
}
10287
}
10288
}
10289
10290
ImGui::End();
10291
}
10292
10293
//-----------------------------------------------------------------------------
10294
// [SECTION] Example App: Assets Browser / ShowExampleAppAssetsBrowser()
10295
//-----------------------------------------------------------------------------
10296
10297
//#include "imgui_internal.h" // NavMoveRequestTryWrapping()
10298
10299
struct ExampleAsset
10300
{
10301
ImGuiID ID;
10302
int Type;
10303
10304
ExampleAsset(ImGuiID id, int type) { ID = id; Type = type; }
10305
10306
static const ImGuiTableSortSpecs* s_current_sort_specs;
10307
10308
static void SortWithSortSpecs(ImGuiTableSortSpecs* sort_specs, ExampleAsset* items, int items_count)
10309
{
10310
s_current_sort_specs = sort_specs; // Store in variable accessible by the sort function.
10311
if (items_count > 1)
10312
qsort(items, (size_t)items_count, sizeof(items[0]), ExampleAsset::CompareWithSortSpecs);
10313
s_current_sort_specs = NULL;
10314
}
10315
10316
// Compare function to be used by qsort()
10317
static int IMGUI_CDECL CompareWithSortSpecs(const void* lhs, const void* rhs)
10318
{
10319
const ExampleAsset* a = (const ExampleAsset*)lhs;
10320
const ExampleAsset* b = (const ExampleAsset*)rhs;
10321
for (int n = 0; n < s_current_sort_specs->SpecsCount; n++)
10322
{
10323
const ImGuiTableColumnSortSpecs* sort_spec = &s_current_sort_specs->Specs[n];
10324
int delta = 0;
10325
if (sort_spec->ColumnIndex == 0)
10326
delta = ((int)a->ID - (int)b->ID);
10327
else if (sort_spec->ColumnIndex == 1)
10328
delta = (a->Type - b->Type);
10329
if (delta > 0)
10330
return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? +1 : -1;
10331
if (delta < 0)
10332
return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? -1 : +1;
10333
}
10334
return ((int)a->ID - (int)b->ID);
10335
}
10336
};
10337
const ImGuiTableSortSpecs* ExampleAsset::s_current_sort_specs = NULL;
10338
10339
struct ExampleAssetsBrowser
10340
{
10341
// Options
10342
bool ShowTypeOverlay = true;
10343
bool AllowSorting = true;
10344
bool AllowDragUnselected = false;
10345
bool AllowBoxSelect = true;
10346
float IconSize = 32.0f;
10347
int IconSpacing = 10;
10348
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.
10349
bool StretchSpacing = true;
10350
10351
// State
10352
ImVector<ExampleAsset> Items; // Our items
10353
ExampleSelectionWithDeletion Selection; // Our selection (ImGuiSelectionBasicStorage + helper funcs to handle deletion)
10354
ImGuiID NextItemId = 0; // Unique identifier when creating new items
10355
bool RequestDelete = false; // Deferred deletion request
10356
bool RequestSort = false; // Deferred sort request
10357
float ZoomWheelAccum = 0.0f; // Mouse wheel accumulator to handle smooth wheels better
10358
10359
// Calculated sizes for layout, output of UpdateLayoutSizes(). Could be locals but our code is simpler this way.
10360
ImVec2 LayoutItemSize;
10361
ImVec2 LayoutItemStep; // == LayoutItemSize + LayoutItemSpacing
10362
float LayoutItemSpacing = 0.0f;
10363
float LayoutSelectableSpacing = 0.0f;
10364
float LayoutOuterPadding = 0.0f;
10365
int LayoutColumnCount = 0;
10366
int LayoutLineCount = 0;
10367
10368
// Functions
10369
ExampleAssetsBrowser()
10370
{
10371
AddItems(10000);
10372
}
10373
void AddItems(int count)
10374
{
10375
if (Items.Size == 0)
10376
NextItemId = 0;
10377
Items.reserve(Items.Size + count);
10378
for (int n = 0; n < count; n++, NextItemId++)
10379
Items.push_back(ExampleAsset(NextItemId, (NextItemId % 20) < 15 ? 0 : (NextItemId % 20) < 18 ? 1 : 2));
10380
RequestSort = true;
10381
}
10382
void ClearItems()
10383
{
10384
Items.clear();
10385
Selection.Clear();
10386
}
10387
10388
// Logic would be written in the main code BeginChild() and outputing to local variables.
10389
// We extracted it into a function so we can call it easily from multiple places.
10390
void UpdateLayoutSizes(float avail_width)
10391
{
10392
// Layout: when not stretching: allow extending into right-most spacing.
10393
LayoutItemSpacing = (float)IconSpacing;
10394
if (StretchSpacing == false)
10395
avail_width += floorf(LayoutItemSpacing * 0.5f);
10396
10397
// Layout: calculate number of icon per line and number of lines
10398
LayoutItemSize = ImVec2(floorf(IconSize), floorf(IconSize));
10399
LayoutColumnCount = IM_MAX((int)(avail_width / (LayoutItemSize.x + LayoutItemSpacing)), 1);
10400
LayoutLineCount = (Items.Size + LayoutColumnCount - 1) / LayoutColumnCount;
10401
10402
// Layout: when stretching: allocate remaining space to more spacing. Round before division, so item_spacing may be non-integer.
10403
if (StretchSpacing && LayoutColumnCount > 1)
10404
LayoutItemSpacing = floorf(avail_width - LayoutItemSize.x * LayoutColumnCount) / LayoutColumnCount;
10405
10406
LayoutItemStep = ImVec2(LayoutItemSize.x + LayoutItemSpacing, LayoutItemSize.y + LayoutItemSpacing);
10407
LayoutSelectableSpacing = IM_MAX(floorf(LayoutItemSpacing) - IconHitSpacing, 0.0f);
10408
LayoutOuterPadding = floorf(LayoutItemSpacing * 0.5f);
10409
}
10410
10411
void Draw(const char* title, bool* p_open)
10412
{
10413
ImGui::SetNextWindowSize(ImVec2(IconSize * 25, IconSize * 15), ImGuiCond_FirstUseEver);
10414
if (!ImGui::Begin(title, p_open, ImGuiWindowFlags_MenuBar))
10415
{
10416
ImGui::End();
10417
return;
10418
}
10419
10420
// Menu bar
10421
if (ImGui::BeginMenuBar())
10422
{
10423
if (ImGui::BeginMenu("File"))
10424
{
10425
if (ImGui::MenuItem("Add 10000 items"))
10426
AddItems(10000);
10427
if (ImGui::MenuItem("Clear items"))
10428
ClearItems();
10429
ImGui::Separator();
10430
if (ImGui::MenuItem("Close", NULL, false, p_open != NULL))
10431
*p_open = false;
10432
ImGui::EndMenu();
10433
}
10434
if (ImGui::BeginMenu("Edit"))
10435
{
10436
if (ImGui::MenuItem("Delete", "Del", false, Selection.Size > 0))
10437
RequestDelete = true;
10438
ImGui::EndMenu();
10439
}
10440
if (ImGui::BeginMenu("Options"))
10441
{
10442
ImGui::PushItemWidth(ImGui::GetFontSize() * 10);
10443
10444
ImGui::SeparatorText("Contents");
10445
ImGui::Checkbox("Show Type Overlay", &ShowTypeOverlay);
10446
ImGui::Checkbox("Allow Sorting", &AllowSorting);
10447
10448
ImGui::SeparatorText("Selection Behavior");
10449
ImGui::Checkbox("Allow dragging unselected item", &AllowDragUnselected);
10450
ImGui::Checkbox("Allow box-selection", &AllowBoxSelect);
10451
10452
ImGui::SeparatorText("Layout");
10453
ImGui::SliderFloat("Icon Size", &IconSize, 16.0f, 128.0f, "%.0f");
10454
ImGui::SameLine(); HelpMarker("Use CTRL+Wheel to zoom");
10455
ImGui::SliderInt("Icon Spacing", &IconSpacing, 0, 32);
10456
ImGui::SliderInt("Icon Hit Spacing", &IconHitSpacing, 0, 32);
10457
ImGui::Checkbox("Stretch Spacing", &StretchSpacing);
10458
ImGui::PopItemWidth();
10459
ImGui::EndMenu();
10460
}
10461
ImGui::EndMenuBar();
10462
}
10463
10464
// Show a table with ONLY one header row to showcase the idea/possibility of using this to provide a sorting UI
10465
if (AllowSorting)
10466
{
10467
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
10468
ImGuiTableFlags table_flags_for_sort_specs = ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Borders;
10469
if (ImGui::BeginTable("for_sort_specs_only", 2, table_flags_for_sort_specs, ImVec2(0.0f, ImGui::GetFrameHeight())))
10470
{
10471
ImGui::TableSetupColumn("Index");
10472
ImGui::TableSetupColumn("Type");
10473
ImGui::TableHeadersRow();
10474
if (ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs())
10475
if (sort_specs->SpecsDirty || RequestSort)
10476
{
10477
ExampleAsset::SortWithSortSpecs(sort_specs, Items.Data, Items.Size);
10478
sort_specs->SpecsDirty = RequestSort = false;
10479
}
10480
ImGui::EndTable();
10481
}
10482
ImGui::PopStyleVar();
10483
}
10484
10485
ImGuiIO& io = ImGui::GetIO();
10486
ImGui::SetNextWindowContentSize(ImVec2(0.0f, LayoutOuterPadding + LayoutLineCount * (LayoutItemSize.y + LayoutItemSpacing)));
10487
if (ImGui::BeginChild("Assets", ImVec2(0.0f, -ImGui::GetTextLineHeightWithSpacing()), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove))
10488
{
10489
ImDrawList* draw_list = ImGui::GetWindowDrawList();
10490
10491
const float avail_width = ImGui::GetContentRegionAvail().x;
10492
UpdateLayoutSizes(avail_width);
10493
10494
// Calculate and store start position.
10495
ImVec2 start_pos = ImGui::GetCursorScreenPos();
10496
start_pos = ImVec2(start_pos.x + LayoutOuterPadding, start_pos.y + LayoutOuterPadding);
10497
ImGui::SetCursorScreenPos(start_pos);
10498
10499
// Multi-select
10500
ImGuiMultiSelectFlags ms_flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_ClearOnClickVoid;
10501
10502
// - Enable box-select (in 2D mode, so that changing box-select rectangle X1/X2 boundaries will affect clipped items)
10503
if (AllowBoxSelect)
10504
ms_flags |= ImGuiMultiSelectFlags_BoxSelect2d;
10505
10506
// - This feature allows dragging an unselected item without selecting it (rarely used)
10507
if (AllowDragUnselected)
10508
ms_flags |= ImGuiMultiSelectFlags_SelectOnClickRelease;
10509
10510
// - Enable keyboard wrapping on X axis
10511
// (FIXME-MULTISELECT: We haven't designed/exposed a general nav wrapping api yet, so this flag is provided as a courtesy to avoid doing:
10512
// ImGui::NavMoveRequestTryWrapping(ImGui::GetCurrentWindow(), ImGuiNavMoveFlags_WrapX);
10513
// When we finish implementing a more general API for this, we will obsolete this flag in favor of the new system)
10514
ms_flags |= ImGuiMultiSelectFlags_NavWrapX;
10515
10516
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(ms_flags, Selection.Size, Items.Size);
10517
10518
// Use custom selection adapter: store ID in selection (recommended)
10519
Selection.UserData = this;
10520
Selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self_, int idx) { ExampleAssetsBrowser* self = (ExampleAssetsBrowser*)self_->UserData; return self->Items[idx].ID; };
10521
Selection.ApplyRequests(ms_io);
10522
10523
const bool want_delete = (ImGui::Shortcut(ImGuiKey_Delete, ImGuiInputFlags_Repeat) && (Selection.Size > 0)) || RequestDelete;
10524
const int item_curr_idx_to_focus = want_delete ? Selection.ApplyDeletionPreLoop(ms_io, Items.Size) : -1;
10525
RequestDelete = false;
10526
10527
// Push LayoutSelectableSpacing (which is LayoutItemSpacing minus hit-spacing, if we decide to have hit gaps between items)
10528
// Altering style ItemSpacing may seem unnecessary as we position every items using SetCursorScreenPos()...
10529
// But it is necessary for two reasons:
10530
// - Selectables uses it by default to visually fill the space between two items.
10531
// - The vertical spacing would be measured by Clipper to calculate line height if we didn't provide it explicitly (here we do).
10532
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(LayoutSelectableSpacing, LayoutSelectableSpacing));
10533
10534
// Rendering parameters
10535
const ImU32 icon_type_overlay_colors[3] = { 0, IM_COL32(200, 70, 70, 255), IM_COL32(70, 170, 70, 255) };
10536
const ImU32 icon_bg_color = ImGui::GetColorU32(IM_COL32(35, 35, 35, 220));
10537
const ImVec2 icon_type_overlay_size = ImVec2(4.0f, 4.0f);
10538
const bool display_label = (LayoutItemSize.x >= ImGui::CalcTextSize("999").x);
10539
10540
const int column_count = LayoutColumnCount;
10541
ImGuiListClipper clipper;
10542
clipper.Begin(LayoutLineCount, LayoutItemStep.y);
10543
if (item_curr_idx_to_focus != -1)
10544
clipper.IncludeItemByIndex(item_curr_idx_to_focus / column_count); // Ensure focused item line is not clipped.
10545
if (ms_io->RangeSrcItem != -1)
10546
clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem / column_count); // Ensure RangeSrc item line is not clipped.
10547
while (clipper.Step())
10548
{
10549
for (int line_idx = clipper.DisplayStart; line_idx < clipper.DisplayEnd; line_idx++)
10550
{
10551
const int item_min_idx_for_current_line = line_idx * column_count;
10552
const int item_max_idx_for_current_line = IM_MIN((line_idx + 1) * column_count, Items.Size);
10553
for (int item_idx = item_min_idx_for_current_line; item_idx < item_max_idx_for_current_line; ++item_idx)
10554
{
10555
ExampleAsset* item_data = &Items[item_idx];
10556
ImGui::PushID((int)item_data->ID);
10557
10558
// Position item
10559
ImVec2 pos = ImVec2(start_pos.x + (item_idx % column_count) * LayoutItemStep.x, start_pos.y + line_idx * LayoutItemStep.y);
10560
ImGui::SetCursorScreenPos(pos);
10561
10562
ImGui::SetNextItemSelectionUserData(item_idx);
10563
bool item_is_selected = Selection.Contains((ImGuiID)item_data->ID);
10564
bool item_is_visible = ImGui::IsRectVisible(LayoutItemSize);
10565
ImGui::Selectable("", item_is_selected, ImGuiSelectableFlags_None, LayoutItemSize);
10566
10567
// Update our selection state immediately (without waiting for EndMultiSelect() requests)
10568
// because we use this to alter the color of our text/icon.
10569
if (ImGui::IsItemToggledSelection())
10570
item_is_selected = !item_is_selected;
10571
10572
// Focus (for after deletion)
10573
if (item_curr_idx_to_focus == item_idx)
10574
ImGui::SetKeyboardFocusHere(-1);
10575
10576
// Drag and drop
10577
if (ImGui::BeginDragDropSource())
10578
{
10579
// Create payload with full selection OR single unselected item.
10580
// (the later is only possible when using ImGuiMultiSelectFlags_SelectOnClickRelease)
10581
if (ImGui::GetDragDropPayload() == NULL)
10582
{
10583
ImVector<ImGuiID> payload_items;
10584
void* it = NULL;
10585
ImGuiID id = 0;
10586
if (!item_is_selected)
10587
payload_items.push_back(item_data->ID);
10588
else
10589
while (Selection.GetNextSelectedItem(&it, &id))
10590
payload_items.push_back(id);
10591
ImGui::SetDragDropPayload("ASSETS_BROWSER_ITEMS", payload_items.Data, (size_t)payload_items.size_in_bytes());
10592
}
10593
10594
// Display payload content in tooltip, by extracting it from the payload data
10595
// (we could read from selection, but it is more correct and reusable to read from payload)
10596
const ImGuiPayload* payload = ImGui::GetDragDropPayload();
10597
const int payload_count = (int)payload->DataSize / (int)sizeof(ImGuiID);
10598
ImGui::Text("%d assets", payload_count);
10599
10600
ImGui::EndDragDropSource();
10601
}
10602
10603
// Render icon (a real app would likely display an image/thumbnail here)
10604
// Because we use ImGuiMultiSelectFlags_BoxSelect2d, clipping vertical may occasionally be larger, so we coarse-clip our rendering as well.
10605
if (item_is_visible)
10606
{
10607
ImVec2 box_min(pos.x - 1, pos.y - 1);
10608
ImVec2 box_max(box_min.x + LayoutItemSize.x + 2, box_min.y + LayoutItemSize.y + 2); // Dubious
10609
draw_list->AddRectFilled(box_min, box_max, icon_bg_color); // Background color
10610
if (ShowTypeOverlay && item_data->Type != 0)
10611
{
10612
ImU32 type_col = icon_type_overlay_colors[item_data->Type % IM_ARRAYSIZE(icon_type_overlay_colors)];
10613
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);
10614
}
10615
if (display_label)
10616
{
10617
ImU32 label_col = ImGui::GetColorU32(item_is_selected ? ImGuiCol_Text : ImGuiCol_TextDisabled);
10618
char label[32];
10619
sprintf(label, "%d", item_data->ID);
10620
draw_list->AddText(ImVec2(box_min.x, box_max.y - ImGui::GetFontSize()), label_col, label);
10621
}
10622
}
10623
10624
ImGui::PopID();
10625
}
10626
}
10627
}
10628
clipper.End();
10629
ImGui::PopStyleVar(); // ImGuiStyleVar_ItemSpacing
10630
10631
// Context menu
10632
if (ImGui::BeginPopupContextWindow())
10633
{
10634
ImGui::Text("Selection: %d items", Selection.Size);
10635
ImGui::Separator();
10636
if (ImGui::MenuItem("Delete", "Del", false, Selection.Size > 0))
10637
RequestDelete = true;
10638
ImGui::EndPopup();
10639
}
10640
10641
ms_io = ImGui::EndMultiSelect();
10642
Selection.ApplyRequests(ms_io);
10643
if (want_delete)
10644
Selection.ApplyDeletionPostLoop(ms_io, Items, item_curr_idx_to_focus);
10645
10646
// Zooming with CTRL+Wheel
10647
if (ImGui::IsWindowAppearing())
10648
ZoomWheelAccum = 0.0f;
10649
if (ImGui::IsWindowHovered() && io.MouseWheel != 0.0f && ImGui::IsKeyDown(ImGuiMod_Ctrl) && ImGui::IsAnyItemActive() == false)
10650
{
10651
ZoomWheelAccum += io.MouseWheel;
10652
if (fabsf(ZoomWheelAccum) >= 1.0f)
10653
{
10654
// Calculate hovered item index from mouse location
10655
// FIXME: Locking aiming on 'hovered_item_idx' (with a cool-down timer) would ensure zoom keeps on it.
10656
const float hovered_item_nx = (io.MousePos.x - start_pos.x + LayoutItemSpacing * 0.5f) / LayoutItemStep.x;
10657
const float hovered_item_ny = (io.MousePos.y - start_pos.y + LayoutItemSpacing * 0.5f) / LayoutItemStep.y;
10658
const int hovered_item_idx = ((int)hovered_item_ny * LayoutColumnCount) + (int)hovered_item_nx;
10659
//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
10660
10661
// Zoom
10662
IconSize *= powf(1.1f, (float)(int)ZoomWheelAccum);
10663
IconSize = IM_CLAMP(IconSize, 16.0f, 128.0f);
10664
ZoomWheelAccum -= (int)ZoomWheelAccum;
10665
UpdateLayoutSizes(avail_width);
10666
10667
// Manipulate scroll to that we will land at the same Y location of currently hovered item.
10668
// - Calculate next frame position of item under mouse
10669
// - Set new scroll position to be used in next ImGui::BeginChild() call.
10670
float hovered_item_rel_pos_y = ((float)(hovered_item_idx / LayoutColumnCount) + fmodf(hovered_item_ny, 1.0f)) * LayoutItemStep.y;
10671
hovered_item_rel_pos_y += ImGui::GetStyle().WindowPadding.y;
10672
float mouse_local_y = io.MousePos.y - ImGui::GetWindowPos().y;
10673
ImGui::SetScrollY(hovered_item_rel_pos_y - mouse_local_y);
10674
}
10675
}
10676
}
10677
ImGui::EndChild();
10678
10679
ImGui::Text("Selected: %d/%d items", Selection.Size, Items.Size);
10680
ImGui::End();
10681
}
10682
};
10683
10684
void ShowExampleAppAssetsBrowser(bool* p_open)
10685
{
10686
IMGUI_DEMO_MARKER("Examples/Assets Browser");
10687
static ExampleAssetsBrowser assets_browser;
10688
assets_browser.Draw("Example: Assets Browser", p_open);
10689
}
10690
10691
// End of Demo code
10692
#else
10693
10694
void ImGui::ShowAboutWindow(bool*) {}
10695
void ImGui::ShowDemoWindow(bool*) {}
10696
void ImGui::ShowUserGuide() {}
10697
void ImGui::ShowStyleEditor(ImGuiStyle*) {}
10698
bool ImGui::ShowStyleSelector(const char* label) { return false; }
10699
void ImGui::ShowFontSelector(const char* label) {}
10700
10701
#endif
10702
10703
#endif // #ifndef IMGUI_DISABLE
10704
10705